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 2007-2010 Sun Microsystems, Inc. 015 * Portions Copyright 2011-2016 ForgeRock AS. 016 * Portions Copyright 2012 profiq s.r.o. 017 */ 018package org.opends.server.tools.dsreplication; 019 020import java.io.BufferedWriter; 021import java.io.File; 022import java.io.FileWriter; 023import java.io.IOException; 024import java.io.OutputStream; 025import java.io.PrintStream; 026import java.util.ArrayList; 027import java.util.Arrays; 028import java.util.Collection; 029import java.util.Comparator; 030import java.util.Date; 031import java.util.HashMap; 032import java.util.HashSet; 033import java.util.LinkedHashMap; 034import java.util.LinkedHashSet; 035import java.util.LinkedList; 036import java.util.List; 037import java.util.Map; 038import java.util.Objects; 039import java.util.Set; 040import java.util.SortedSet; 041import java.util.TreeMap; 042import java.util.TreeSet; 043import java.util.concurrent.atomic.AtomicReference; 044 045import javax.naming.NameAlreadyBoundException; 046import javax.naming.NameNotFoundException; 047import javax.naming.NamingEnumeration; 048import javax.naming.NamingException; 049import javax.naming.NoPermissionException; 050import javax.naming.directory.BasicAttributes; 051import javax.naming.directory.DirContext; 052import javax.naming.directory.SearchControls; 053import javax.naming.directory.SearchResult; 054import javax.naming.ldap.InitialLdapContext; 055import javax.naming.ldap.LdapName; 056import javax.net.ssl.KeyManager; 057import javax.net.ssl.SSLException; 058import javax.net.ssl.SSLHandshakeException; 059import javax.net.ssl.TrustManager; 060 061import org.forgerock.i18n.LocalizableMessage; 062import org.forgerock.i18n.LocalizableMessageBuilder; 063import org.forgerock.i18n.LocalizedIllegalArgumentException; 064import org.forgerock.i18n.LocalizableMessageDescriptor.Arg0; 065import org.forgerock.i18n.LocalizableMessageDescriptor.Arg1; 066import org.forgerock.i18n.LocalizableMessageDescriptor.Arg2; 067import org.forgerock.i18n.slf4j.LocalizedLogger; 068import org.opends.admin.ads.*; 069import org.opends.admin.ads.ADSContext.ADSPropertySyntax; 070import org.opends.admin.ads.ADSContext.AdministratorProperty; 071import org.opends.admin.ads.ADSContext.ServerProperty; 072import org.opends.admin.ads.util.ApplicationTrustManager; 073import org.opends.admin.ads.util.OpendsCertificateException; 074import org.opends.admin.ads.util.PreferredConnection; 075import org.opends.admin.ads.util.ServerLoader; 076import org.opends.guitools.controlpanel.datamodel.BackendDescriptor; 077import org.opends.guitools.controlpanel.datamodel.BaseDNDescriptor; 078import org.opends.guitools.controlpanel.util.*; 079import org.opends.quicksetup.ApplicationException; 080import org.opends.quicksetup.Constants; 081import org.opends.quicksetup.Installation; 082import org.opends.quicksetup.event.ProgressUpdateEvent; 083import org.opends.quicksetup.event.ProgressUpdateListener; 084import org.opends.quicksetup.installer.Installer; 085import org.opends.quicksetup.installer.InstallerHelper; 086import org.opends.quicksetup.installer.PeerNotFoundException; 087import org.opends.quicksetup.installer.offline.OfflineInstaller; 088import org.opends.quicksetup.util.PlainTextProgressMessageFormatter; 089import org.opends.server.admin.*; 090import org.opends.server.admin.client.ManagementContext; 091import org.opends.server.admin.client.ldap.JNDIDirContextAdaptor; 092import org.opends.server.admin.client.ldap.LDAPManagementContext; 093import org.opends.server.admin.std.client.*; 094import org.opends.server.admin.std.meta.ReplicationDomainCfgDefn; 095import org.opends.server.admin.std.meta.ReplicationServerCfgDefn; 096import org.opends.server.admin.std.meta.ReplicationSynchronizationProviderCfgDefn; 097import org.opends.server.core.DirectoryServer; 098import org.opends.server.tasks.PurgeConflictsHistoricalTask; 099import org.opends.server.tools.dsreplication.EnableReplicationUserData.EnableReplicationServerData; 100import org.opends.server.tools.tasks.TaskEntry; 101import org.opends.server.tools.tasks.TaskScheduleInteraction; 102import org.opends.server.tools.tasks.TaskScheduleUserData; 103import org.forgerock.opendj.ldap.DN; 104import org.opends.server.types.HostPort; 105import org.opends.server.types.InitializationException; 106import org.opends.server.types.NullOutputStream; 107import org.opends.server.types.OpenDsException; 108import org.opends.server.util.BuildVersion; 109import org.opends.server.util.ServerConstants; 110import org.opends.server.util.SetupUtils; 111import org.opends.server.util.StaticUtils; 112import org.opends.server.util.cli.LDAPConnectionConsoleInteraction; 113import org.opends.server.util.cli.PointAdder; 114 115import com.forgerock.opendj.cli.Argument; 116import com.forgerock.opendj.cli.ArgumentException; 117import com.forgerock.opendj.cli.BooleanArgument; 118import com.forgerock.opendj.cli.CliConstants; 119import com.forgerock.opendj.cli.ClientException; 120import com.forgerock.opendj.cli.CommandBuilder; 121import com.forgerock.opendj.cli.ConsoleApplication; 122import com.forgerock.opendj.cli.FileBasedArgument; 123import com.forgerock.opendj.cli.IntegerArgument; 124import com.forgerock.opendj.cli.MenuBuilder; 125import com.forgerock.opendj.cli.MenuResult; 126import com.forgerock.opendj.cli.ReturnCode; 127import com.forgerock.opendj.cli.StringArgument; 128import com.forgerock.opendj.cli.SubCommand; 129import com.forgerock.opendj.cli.TabSeparatedTablePrinter; 130import com.forgerock.opendj.cli.TableBuilder; 131import com.forgerock.opendj.cli.TablePrinter; 132import com.forgerock.opendj.cli.TextTablePrinter; 133import com.forgerock.opendj.cli.ValidationCallback; 134 135import static com.forgerock.opendj.cli.ArgumentConstants.*; 136import static com.forgerock.opendj.cli.Utils.*; 137import static com.forgerock.opendj.util.OperatingSystem.*; 138import static com.forgerock.opendj.cli.CommonArguments.*; 139 140import static java.util.Collections.*; 141import static org.forgerock.util.Utils.*; 142import static org.opends.admin.ads.util.ConnectionUtils.*; 143import static org.opends.admin.ads.util.PreferredConnection.*; 144import static org.opends.admin.ads.ServerDescriptor.getReplicationServer; 145import static org.opends.admin.ads.ServerDescriptor.getServerRepresentation; 146import static org.opends.admin.ads.ServerDescriptor.getSuffixDisplay; 147import static org.opends.messages.AdminToolMessages.*; 148import static org.opends.messages.QuickSetupMessages.*; 149import static org.opends.messages.ToolMessages.*; 150import static org.opends.quicksetup.util.Utils.*; 151import static org.opends.server.tools.dsreplication.ReplicationCliArgumentParser.*; 152import static org.opends.server.tools.dsreplication.ReplicationCliReturnCode.*; 153import static org.opends.server.util.StaticUtils.*; 154 155/** 156 * This class provides a tool that can be used to enable and disable replication 157 * and also to initialize the contents of a replicated suffix with the contents 158 * of another suffix. It also allows to display the replicated status of the 159 * different base DNs of the servers that are registered in the ADS. 160 */ 161public class ReplicationCliMain extends ConsoleApplication 162{ 163 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 164 /** The fully-qualified name of this class. */ 165 private static final String CLASS_NAME = ReplicationCliMain.class.getName(); 166 /** Prefix for log files. */ 167 public static final String LOG_FILE_PREFIX = "opendj-replication-"; 168 /** Suffix for log files. */ 169 public static final String LOG_FILE_SUFFIX = ".log"; 170 171 /** 172 * Property used to call the dsreplication script and ReplicationCliMain to 173 * know which are the java properties to be used (those of dsreplication or 174 * those of dsreplication.offline). 175 */ 176 private static final String SCRIPT_CALL_STATUS = "org.opends.server.dsreplicationcallstatus"; 177 178 /** The value set by the dsreplication script if it is called the first time. */ 179 private static final String FIRST_SCRIPT_CALL = "firstcall"; 180 private static final LocalizableMessage EMPTY_MSG = LocalizableMessage.raw(""); 181 182 private boolean forceNonInteractive; 183 184 /** Always use SSL with the administration connector. */ 185 private final boolean useSSL = true; 186 private final boolean useStartTLS = false; 187 188 /** 189 * The enumeration containing the different options we display when we ask 190 * the user to provide the subcommand interactively. 191 */ 192 private enum SubcommandChoice 193 { 194 /** Enable replication. */ 195 ENABLE(ENABLE_REPLICATION_SUBCMD_NAME, INFO_REPLICATION_ENABLE_MENU_PROMPT.get()), 196 /** Disable replication. */ 197 DISABLE(DISABLE_REPLICATION_SUBCMD_NAME, INFO_REPLICATION_DISABLE_MENU_PROMPT.get()), 198 /** Initialize replication. */ 199 INITIALIZE(INITIALIZE_REPLICATION_SUBCMD_NAME, INFO_REPLICATION_INITIALIZE_MENU_PROMPT.get()), 200 /** Initialize All. */ 201 INITIALIZE_ALL(INITIALIZE_ALL_REPLICATION_SUBCMD_NAME, INFO_REPLICATION_INITIALIZE_ALL_MENU_PROMPT.get()), 202 /** Pre external initialization. */ 203 PRE_EXTERNAL_INITIALIZATION(PRE_EXTERNAL_INITIALIZATION_SUBCMD_NAME, 204 INFO_REPLICATION_PRE_EXTERNAL_INITIALIZATION_MENU_PROMPT.get()), 205 /** Post external initialization. */ 206 POST_EXTERNAL_INITIALIZATION(POST_EXTERNAL_INITIALIZATION_SUBCMD_NAME, 207 INFO_REPLICATION_POST_EXTERNAL_INITIALIZATION_MENU_PROMPT.get()), 208 /** Replication status. */ 209 STATUS(STATUS_REPLICATION_SUBCMD_NAME, INFO_REPLICATION_STATUS_MENU_PROMPT.get()), 210 /** Replication purge historical. */ 211 PURGE_HISTORICAL(PURGE_HISTORICAL_SUBCMD_NAME, INFO_REPLICATION_PURGE_HISTORICAL_MENU_PROMPT.get()), 212 /** Set changelog change number from another server. */ 213 RESET_CHANGE_NUMBER(ReplicationCliArgumentParser.RESET_CHANGE_NUMBER_SUBCMD_NAME, 214 INFO_DESCRIPTION_RESET_CHANGE_NUMBER.get()), 215 /** Cancel operation. */ 216 CANCEL(null, null); 217 218 private final String name; 219 private LocalizableMessage prompt; 220 221 private SubcommandChoice(String name, LocalizableMessage prompt) 222 { 223 this.name = name; 224 this.prompt = prompt; 225 } 226 227 private LocalizableMessage getPrompt() 228 { 229 return prompt; 230 } 231 232 private String getName() 233 { 234 return name; 235 } 236 237 private static SubcommandChoice fromName(String subCommandName) 238 { 239 SubcommandChoice[] f = values(); 240 for (SubcommandChoice subCommand : f) 241 { 242 if (subCommand.name.equals(subCommandName)) 243 { 244 return subCommand; 245 } 246 } 247 return null; 248 } 249 } 250 251 /** Abstract some of the operations when two servers must be queried for information. */ 252 private interface OperationBetweenSourceAndDestinationServers 253 { 254 /** 255 * Returns whether we should stop processing after asking the user for additional information. 256 * Might connect to servers to run configuration checks. 257 * @param baseDNs user specified baseDNs 258 * @param source the source server 259 * @param dest the destination server 260 * @param interactive if user has to input information 261 * @return whether we should stop 262 */ 263 boolean continueAfterUserInput(Collection<String> baseDNs, InitialLdapContext source, InitialLdapContext dest, 264 boolean interactive); 265 266 /** 267 * Confirm with the user whether the current task should continue. 268 * 269 * @param uData servers address and authentication parameters 270 * @param ctxSource LDAP Context for the destination server 271 * @param ctxDestination LDAP Context for the source server 272 * @param defaultValue default yes or no 273 * @return whether the current task should be interrupted 274 */ 275 boolean confirmOperation(SourceDestinationServerUserData uData, InitialLdapContext ctxSource, 276 InitialLdapContext ctxDestination, final boolean defaultValue); 277 } 278 279 /** The argument parser to be used. */ 280 private ReplicationCliArgumentParser argParser; 281 private FileBasedArgument userProvidedAdminPwdFile; 282 private LDAPConnectionConsoleInteraction sourceServerCI; 283 private CommandBuilder firstServerCommandBuilder; 284 /** The message formatter. */ 285 private PlainTextProgressMessageFormatter formatter = new PlainTextProgressMessageFormatter(); 286 287 /** 288 * Constructor for the ReplicationCliMain object. 289 * 290 * @param out the print stream to use for standard output. 291 * @param err the print stream to use for standard error. 292 */ 293 public ReplicationCliMain(PrintStream out, PrintStream err) 294 { 295 super(out, err); 296 } 297 298 /** 299 * The main method for the replication tool. 300 * 301 * @param args the command-line arguments provided to this program. 302 */ 303 304 public static void main(String[] args) 305 { 306 int retCode = mainCLI(args, true, System.out, System.err); 307 System.exit(retCode); 308 } 309 310 /** 311 * Parses the provided command-line arguments and uses that information to 312 * run the replication tool. 313 * 314 * @param args the command-line arguments provided to this program. 315 * 316 * @return The error code. 317 */ 318 319 public static int mainCLI(String[] args) 320 { 321 return mainCLI(args, true, System.out, System.err); 322 } 323 324 /** 325 * Parses the provided command-line arguments and uses that information to 326 * run the replication tool. 327 * 328 * @param args The command-line arguments provided to this 329 * program. 330 * @param initializeServer Indicates whether to initialize the server. 331 * @param outStream The output stream to use for standard output, or 332 * <CODE>null</CODE> if standard output is not 333 * needed. 334 * @param errStream The output stream to use for standard error, or 335 * <CODE>null</CODE> if standard error is not 336 * needed. 337 * @return The error code. 338 */ 339 public static int mainCLI(String[] args, boolean initializeServer, 340 OutputStream outStream, OutputStream errStream) 341 { 342 PrintStream out = NullOutputStream.wrapOrNullStream(outStream); 343 PrintStream err = NullOutputStream.wrapOrNullStream(errStream); 344 345 try 346 { 347 ControlPanelLog.initLogFileHandler( 348 File.createTempFile(LOG_FILE_PREFIX, LOG_FILE_SUFFIX)); 349 } catch (Throwable t) { 350 System.err.println("Unable to initialize log"); 351 t.printStackTrace(); 352 } 353 ReplicationCliMain replicationCli = new ReplicationCliMain(out, err); 354 ReplicationCliReturnCode result = replicationCli.execute(args, initializeServer); 355 if (result.getReturnCode() == 0) 356 { 357 // Delete the temp log file, in case of success. 358 ControlPanelLog.closeAndDeleteLogFile(); 359 } 360 return result.getReturnCode(); 361 } 362 363 /** 364 * Parses the provided command-line arguments and uses that information to 365 * run the replication tool. 366 * 367 * @param args the command-line arguments provided to this program. 368 * @param initializeServer Indicates whether to initialize the server. 369 * 370 * @return The error code. 371 */ 372 public ReplicationCliReturnCode execute(String[] args, boolean initializeServer) 373 { 374 // Create the command-line argument parser for use with this program. 375 try 376 { 377 createArgumenParser(); 378 } 379 catch (ArgumentException ae) 380 { 381 errPrintln(ERR_CANNOT_INITIALIZE_ARGS.get(ae.getMessage())); 382 logger.error(LocalizableMessage.raw("Complete error stack:"), ae); 383 return CANNOT_INITIALIZE_ARGS; 384 } 385 386 argParser.getSecureArgsList().initArgumentsWithConfiguration(argParser); 387 388 // Parse the command-line arguments provided to this program. 389 try 390 { 391 argParser.parseArguments(args); 392 } 393 catch (ArgumentException ae) 394 { 395 argParser.displayMessageAndUsageReference(getErrStream(), ERR_ERROR_PARSING_ARGS.get(ae.getMessage())); 396 logger.error(LocalizableMessage.raw("Complete error stack:"), ae); 397 return ERROR_USER_DATA; 398 } 399 400 // If we should just display usage or version information, then print it and exit. 401 if (argParser.usageOrVersionDisplayed()) 402 { 403 return SUCCESSFUL_NOP; 404 } 405 406 // Checks the version - if upgrade required, the tool is unusable 407 try 408 { 409 BuildVersion.checkVersionMismatch(); 410 } 411 catch (InitializationException e) 412 { 413 errPrintln(e.getMessageObject()); 414 return CANNOT_INITIALIZE_ARGS; 415 } 416 417 // Check that the provided parameters are compatible. 418 LocalizableMessageBuilder buf = new LocalizableMessageBuilder(); 419 argParser.validateOptions(buf); 420 if (buf.length() > 0) 421 { 422 errPrintln(buf.toMessage()); 423 errPrintln(LocalizableMessage.raw(argParser.getUsage())); 424 return ERROR_USER_DATA; 425 } 426 427 if (initializeServer) 428 { 429 DirectoryServer.bootstrapClient(); 430 431 // Bootstrap definition classes. 432 try 433 { 434 if (!ClassLoaderProvider.getInstance().isEnabled()) 435 { 436 ClassLoaderProvider.getInstance().enable(); 437 } 438 // Switch off class name validation in client. 439 ClassPropertyDefinition.setAllowClassValidation(false); 440 441 // Switch off attribute type name validation in client. 442 AttributeTypePropertyDefinition.setCheckSchema(false); 443 } 444 catch (InitializationException ie) 445 { 446 errPrintln(ie.getMessageObject()); 447 return ERROR_INITIALIZING_ADMINISTRATION_FRAMEWORK; 448 } 449 } 450 451 if (argParser.getSecureArgsList().getBindPasswordFileArg().isPresent()) 452 { 453 try 454 { 455 userProvidedAdminPwdFile = FileBasedArgument.builder("adminPasswordFile") 456 .shortIdentifier(OPTION_SHORT_BINDPWD_FILE) 457 .description(INFO_DESCRIPTION_REPLICATION_ADMIN_BINDPASSWORDFILE.get()) 458 .valuePlaceholder(INFO_BINDPWD_FILE_PLACEHOLDER.get()) 459 .buildArgument(); 460 userProvidedAdminPwdFile.getNameToValueMap().putAll( 461 argParser.getSecureArgsList().getBindPasswordFileArg().getNameToValueMap()); 462 } 463 catch (Throwable t) 464 { 465 throw new IllegalStateException("Unexpected error: " + t, t); 466 } 467 } 468 sourceServerCI = new LDAPConnectionConsoleInteraction(this, argParser.getSecureArgsList()); 469 sourceServerCI.setDisplayLdapIfSecureParameters(false); 470 471 ReplicationCliReturnCode returnValue = SUCCESSFUL_NOP; 472 String subCommand = null; 473 final SubcommandChoice subcommandChoice = getSubcommandChoice(argParser.getSubCommand()); 474 if (subcommandChoice != null) 475 { 476 subCommand = subcommandChoice.getName(); 477 returnValue = execute(subcommandChoice); 478 } 479 else if (argParser.isInteractive()) 480 { 481 final SubcommandChoice subCommandChoice = promptForSubcommand(); 482 if (subCommandChoice == null || SubcommandChoice.CANCEL.equals(subCommandChoice)) 483 { 484 return USER_CANCELLED; 485 } 486 487 subCommand = subCommandChoice.getName(); 488 if (subCommand != null) 489 { 490 String[] newArgs = new String[args.length + 1]; 491 newArgs[0] = subCommand; 492 System.arraycopy(args, 0, newArgs, 1, args.length); 493 // The server (if requested) has already been initialized. 494 return execute(newArgs, false); 495 } 496 } 497 else 498 { 499 errPrintln(ERR_REPLICATION_VALID_SUBCOMMAND_NOT_FOUND.get("--" + OPTION_LONG_NO_PROMPT)); 500 errPrintln(LocalizableMessage.raw(argParser.getUsage())); 501 return ERROR_USER_DATA; 502 } 503 504 // Display the log file only if the operation is successful (when there 505 // is a critical error this is already displayed). 506 if (returnValue == SUCCESSFUL && displayLogFileAtEnd(subCommand)) 507 { 508 File logFile = ControlPanelLog.getLogFile(); 509 if (logFile != null) 510 { 511 println(); 512 println(INFO_GENERAL_SEE_FOR_DETAILS.get(logFile.getPath())); 513 println(); 514 } 515 } 516 517 return returnValue; 518 } 519 520 private SubcommandChoice getSubcommandChoice(SubCommand subCommand) 521 { 522 if (subCommand != null) 523 { 524 return SubcommandChoice.fromName(subCommand.getName()); 525 } 526 return null; 527 } 528 529 private ReplicationCliReturnCode execute(SubcommandChoice subcommandChoice) 530 { 531 switch (subcommandChoice) 532 { 533 case ENABLE: 534 return enableReplication(); 535 case DISABLE: 536 return disableReplication(); 537 case INITIALIZE: 538 return initializeReplication(); 539 case INITIALIZE_ALL: 540 return initializeAllReplication(); 541 case PRE_EXTERNAL_INITIALIZATION: 542 return preExternalInitialization(); 543 case POST_EXTERNAL_INITIALIZATION: 544 return postExternalInitialization(); 545 case STATUS: 546 return statusReplication(); 547 case PURGE_HISTORICAL: 548 return purgeHistorical(); 549 case RESET_CHANGE_NUMBER: 550 return resetChangeNumber(); 551 default: 552 return SUCCESSFUL_NOP; 553 } 554 } 555 556 /** 557 * Prompts the user to give the Global Administrator UID. 558 * 559 * @param defaultValue 560 * the default value that will be proposed in the prompt message. 561 * @param logger 562 * the Logger to be used to log the error message. 563 * @return the Global Administrator UID as provided by the user. 564 */ 565 private String askForAdministratorUID(String defaultValue, LocalizedLogger logger) 566 { 567 return ask(logger, INFO_ADMINISTRATOR_UID_PROMPT.get(), defaultValue); 568 } 569 570 /** 571 * Prompts the user to give the Global Administrator password. 572 * 573 * @param logger 574 * the Logger to be used to log the error message. 575 * @return the Global Administrator password as provided by the user. 576 */ 577 private String askForAdministratorPwd(LocalizedLogger logger) 578 { 579 try 580 { 581 return new String(readPassword(INFO_ADMINISTRATOR_PWD_PROMPT.get())); 582 } 583 catch (ClientException ex) 584 { 585 logger.warn(LocalizableMessage.raw("Error reading input: " + ex, ex)); 586 return null; 587 } 588 } 589 590 private String ask(LocalizedLogger logger, LocalizableMessage msgPrompt, String defaultValue) 591 { 592 try 593 { 594 return readInput(msgPrompt, defaultValue); 595 } 596 catch (ClientException ce) 597 { 598 logger.warn(LocalizableMessage.raw("Error reading input: " + ce, ce)); 599 return defaultValue; 600 } 601 } 602 603 /** 604 * Commodity method used to repeatidly ask the user to provide an integer 605 * value. 606 * 607 * @param prompt 608 * the prompt message. 609 * @param defaultValue 610 * the default value to be proposed to the user. 611 * @param logger 612 * the logger where the errors will be written. 613 * @return the value provided by the user. 614 */ 615 private int askInteger(LocalizableMessage prompt, int defaultValue, LocalizedLogger logger) 616 { 617 int newInt = -1; 618 while (newInt == -1) 619 { 620 try 621 { 622 newInt = readInteger(prompt, defaultValue); 623 } 624 catch (ClientException ce) 625 { 626 newInt = -1; 627 logger.warn(LocalizableMessage.raw("Error reading input: " + ce, ce)); 628 } 629 } 630 return newInt; 631 } 632 633 /** 634 * Interactively retrieves an integer value from the console. 635 * 636 * @param prompt 637 * The message prompt. 638 * @param defaultValue 639 * The default value. 640 * @return Returns the value. 641 * @throws ClientException 642 * If the value could not be retrieved for some reason. 643 */ 644 public final int readInteger( 645 LocalizableMessage prompt, final int defaultValue) throws ClientException 646 { 647 ValidationCallback<Integer> callback = new ValidationCallback<Integer>() 648 { 649 @Override 650 public Integer validate(ConsoleApplication app, String input) 651 throws ClientException 652 { 653 String ninput = input.trim(); 654 if (ninput.length() == 0) 655 { 656 return defaultValue; 657 } 658 659 try 660 { 661 int i = Integer.parseInt(ninput); 662 if (i < 1) 663 { 664 throw new NumberFormatException(); 665 } 666 return i; 667 } 668 catch (NumberFormatException e) 669 { 670 // Try again... 671 app.errPrintln(); 672 app.errPrintln(ERR_BAD_INTEGER.get(ninput)); 673 app.errPrintln(); 674 return null; 675 } 676 } 677 678 }; 679 680 if (defaultValue != -1) 681 { 682 prompt = INFO_PROMPT_SINGLE_DEFAULT.get(prompt, defaultValue); 683 } 684 685 return readValidatedInput(prompt, callback, CONFIRMATION_MAX_TRIES); 686 } 687 688 private boolean isFirstCallFromScript() 689 { 690 return FIRST_SCRIPT_CALL.equals(System.getProperty(SCRIPT_CALL_STATUS)); 691 } 692 693 private void createArgumenParser() throws ArgumentException 694 { 695 argParser = new ReplicationCliArgumentParser(CLASS_NAME); 696 argParser.initializeParser(getOutputStream()); 697 } 698 699 /** 700 * Based on the data provided in the command-line it enables replication 701 * between two servers. 702 * @return the error code if the operation failed and 0 if it was successful. 703 */ 704 private ReplicationCliReturnCode enableReplication() 705 { 706 EnableReplicationUserData uData = new EnableReplicationUserData(); 707 if (argParser.isInteractive()) 708 { 709 try 710 { 711 if (promptIfRequired(uData)) 712 { 713 return enableReplication(uData); 714 } 715 else 716 { 717 return USER_CANCELLED; 718 } 719 } 720 catch (ReplicationCliException rce) 721 { 722 errPrintln(); 723 errPrintln(getCriticalExceptionMessage(rce)); 724 return rce.getErrorCode(); 725 } 726 } 727 else 728 { 729 initializeWithArgParser(uData); 730 return enableReplication(uData); 731 } 732 } 733 734 /** 735 * Based on the data provided in the command-line it disables replication 736 * in the server. 737 * @return the error code if the operation failed and SUCCESSFUL if it was 738 * successful. 739 */ 740 private ReplicationCliReturnCode disableReplication() 741 { 742 DisableReplicationUserData uData = new DisableReplicationUserData(); 743 if (argParser.isInteractive()) 744 { 745 try 746 { 747 if (promptIfRequired(uData)) 748 { 749 return disableReplication(uData); 750 } 751 else 752 { 753 return USER_CANCELLED; 754 } 755 } 756 catch (ReplicationCliException rce) 757 { 758 errPrintln(); 759 errPrintln(getCriticalExceptionMessage(rce)); 760 return rce.getErrorCode(); 761 } 762 } 763 else 764 { 765 initializeWithArgParser(uData); 766 return disableReplication(uData); 767 } 768 } 769 770 /** 771 * Based on the data provided in the command-line initialize the contents 772 * of the whole replication topology. 773 * @return the error code if the operation failed and SUCCESSFUL if it was 774 * successful. 775 */ 776 private ReplicationCliReturnCode initializeAllReplication() 777 { 778 InitializeAllReplicationUserData uData = 779 new InitializeAllReplicationUserData(); 780 if (argParser.isInteractive()) 781 { 782 if (promptIfRequired(uData)) 783 { 784 return initializeAllReplication(uData); 785 } 786 else 787 { 788 return USER_CANCELLED; 789 } 790 } 791 else 792 { 793 initializeWithArgParser(uData); 794 return initializeAllReplication(uData); 795 } 796 } 797 798 /** 799 * Based on the data provided in the command-line execute the pre external 800 * initialization operation. 801 * @return the error code if the operation failed and SUCCESSFUL if it was 802 * successful. 803 */ 804 private ReplicationCliReturnCode preExternalInitialization() 805 { 806 PreExternalInitializationUserData uData = 807 new PreExternalInitializationUserData(); 808 if (argParser.isInteractive()) 809 { 810 if (promptIfRequiredForPreOrPost(uData)) 811 { 812 return preExternalInitialization(uData); 813 } 814 else 815 { 816 return USER_CANCELLED; 817 } 818 } 819 else 820 { 821 initializeWithArgParser(uData); 822 return preExternalInitialization(uData); 823 } 824 } 825 826 /** 827 * Based on the data provided in the command-line execute the post external 828 * initialization operation. 829 * @return the error code if the operation failed and SUCCESSFUL if it was 830 * successful. 831 */ 832 private ReplicationCliReturnCode postExternalInitialization() 833 { 834 PostExternalInitializationUserData uData = 835 new PostExternalInitializationUserData(); 836 if (argParser.isInteractive()) 837 { 838 if (promptIfRequiredForPreOrPost(uData)) 839 { 840 return postExternalInitialization(uData); 841 } 842 else 843 { 844 return USER_CANCELLED; 845 } 846 } 847 else 848 { 849 initializeWithArgParser(uData); 850 return postExternalInitialization(uData); 851 } 852 } 853 854 /** 855 * Based on the data provided in the command-line it displays replication 856 * status. 857 * @return the error code if the operation failed and SUCCESSFUL if it was 858 * successful. 859 */ 860 private ReplicationCliReturnCode statusReplication() 861 { 862 StatusReplicationUserData uData = new StatusReplicationUserData(); 863 if (argParser.isInteractive()) 864 { 865 try 866 { 867 if (promptIfRequired(uData)) 868 { 869 return statusReplication(uData); 870 } 871 else 872 { 873 return USER_CANCELLED; 874 } 875 } 876 catch (ReplicationCliException rce) 877 { 878 errPrintln(); 879 errPrintln(getCriticalExceptionMessage(rce)); 880 return rce.getErrorCode(); 881 } 882 } 883 else 884 { 885 initializeWithArgParser(uData); 886 return statusReplication(uData); 887 } 888 } 889 890 /** 891 * Based on the data provided in the command-line it displays replication 892 * status. 893 * @return the error code if the operation failed and SUCCESSFUL if it was 894 * successful. 895 */ 896 private ReplicationCliReturnCode purgeHistorical() 897 { 898 final PurgeHistoricalUserData uData = new PurgeHistoricalUserData(); 899 if (argParser.isInteractive()) 900 { 901 if (promptIfRequired(uData)) 902 { 903 return purgeHistorical(uData); 904 } 905 else 906 { 907 return USER_CANCELLED; 908 } 909 } 910 else 911 { 912 initializeWithArgParser(uData); 913 return purgeHistorical(uData); 914 } 915 } 916 917 /** 918 * Initializes the contents of the provided purge historical replication user 919 * data object with what was provided in the command-line without prompting to 920 * the user. 921 * @param uData the purge historical replication user data object to be 922 * initialized. 923 */ 924 private void initializeWithArgParser(PurgeHistoricalUserData uData) 925 { 926 PurgeHistoricalUserData.initializeWithArgParser(uData, argParser); 927 } 928 929 private ReplicationCliReturnCode purgeHistorical(PurgeHistoricalUserData uData) 930 { 931 return uData.isOnline() 932 ? purgeHistoricalRemotely(uData) 933 : purgeHistoricalLocally(uData); 934 } 935 936 private ReplicationCliReturnCode purgeHistoricalLocally( 937 PurgeHistoricalUserData uData) 938 { 939 List<String> baseDNs = uData.getBaseDNs(); 940 checkSuffixesForLocalPurgeHistorical(baseDNs, false); 941 if (!baseDNs.isEmpty()) 942 { 943 uData.setBaseDNs(baseDNs); 944 if (mustPrintCommandBuilder()) 945 { 946 printNewCommandBuilder(PURGE_HISTORICAL_SUBCMD_NAME, uData); 947 } 948 949 try 950 { 951 return purgeHistoricalLocallyTask(uData); 952 } 953 catch (ReplicationCliException rce) 954 { 955 errPrintln(); 956 errPrintln(getCriticalExceptionMessage(rce)); 957 logger.error(LocalizableMessage.raw("Complete error stack:"), rce); 958 return rce.getErrorCode(); 959 } 960 } 961 else 962 { 963 return HISTORICAL_CANNOT_BE_PURGED_ON_BASEDN; 964 } 965 } 966 967 private void printPurgeProgressMessage(PurgeHistoricalUserData uData) 968 { 969 String separator = formatter.getLineBreak().toString() + formatter.getTab(); 970 println(); 971 LocalizableMessage msg = formatter.getFormattedProgress( 972 INFO_PROGRESS_PURGE_HISTORICAL.get(separator, joinAsString(separator, uData.getBaseDNs()))); 973 print(msg); 974 println(); 975 } 976 977 private ReplicationCliReturnCode purgeHistoricalLocallyTask(PurgeHistoricalUserData uData) 978 throws ReplicationCliException 979 { 980 ReplicationCliReturnCode returnCode = SUCCESSFUL; 981 if (isFirstCallFromScript()) 982 { 983 // Launch the process: launch dsreplication in non-interactive mode with 984 // the recursive property set. 985 ArrayList<String> args = new ArrayList<>(); 986 args.add(getCommandLinePath(getCommandName())); 987 args.add(PURGE_HISTORICAL_SUBCMD_NAME); 988 args.add("--"+argParser.noPromptArg.getLongIdentifier()); 989 args.add("--"+argParser.maximumDurationArg.getLongIdentifier()); 990 args.add(String.valueOf(uData.getMaximumDuration())); 991 for (String baseDN : uData.getBaseDNs()) 992 { 993 args.add("--"+argParser.baseDNsArg.getLongIdentifier()); 994 args.add(baseDN); 995 } 996 ProcessBuilder pb = new ProcessBuilder(args); 997 // Use the java args in the script. 998 Map<String, String> env = pb.environment(); 999 env.put("RECURSIVE_LOCAL_CALL", "true"); 1000 try 1001 { 1002 Process process = pb.start(); 1003 ProcessReader outReader = 1004 new ProcessReader(process, getOutputStream(), false); 1005 ProcessReader errReader = 1006 new ProcessReader(process, getErrorStream(), true); 1007 1008 outReader.startReading(); 1009 errReader.startReading(); 1010 1011 int code = process.waitFor(); 1012 for (ReplicationCliReturnCode c : ReplicationCliReturnCode.values()) 1013 { 1014 if (c.getReturnCode() == code) 1015 { 1016 returnCode = c; 1017 break; 1018 } 1019 } 1020 } 1021 catch (Exception e) 1022 { 1023 LocalizableMessage msg = ERR_LAUNCHING_PURGE_HISTORICAL.get(); 1024 ReplicationCliReturnCode code = ERROR_LAUNCHING_PURGE_HISTORICAL; 1025 throw new ReplicationCliException( 1026 getThrowableMsg(msg, e), code, e); 1027 } 1028 } 1029 else 1030 { 1031 printPurgeProgressMessage(uData); 1032 LocalPurgeHistorical localPurgeHistorical = 1033 new LocalPurgeHistorical(uData, this, formatter, 1034 argParser.getConfigFile(), 1035 argParser.getConfigClass()); 1036 returnCode = localPurgeHistorical.execute(); 1037 1038 if (returnCode == SUCCESSFUL) 1039 { 1040 printSuccessMessage(uData, null); 1041 } 1042 } 1043 return returnCode; 1044 } 1045 1046 /** 1047 * Returns an InitialLdapContext using the provided parameters. We try to 1048 * guarantee that the connection is able to read the configuration. 1049 * 1050 * @param host 1051 * the host name. 1052 * @param port 1053 * the port to connect. 1054 * @param useSSL 1055 * whether to use SSL or not. 1056 * @param useStartTLS 1057 * whether to use StartTLS or not. 1058 * @param bindDn 1059 * the bind dn to be used. 1060 * @param pwd 1061 * the password. 1062 * @param connectTimeout 1063 * the timeout in milliseconds to connect to the server. 1064 * @param trustManager 1065 * the trust manager. 1066 * @return an InitialLdapContext connected. 1067 * @throws NamingException 1068 * if there was an error establishing the connection. 1069 */ 1070 private InitialLdapContext createAdministrativeContext(String host, 1071 int port, boolean useSSL, boolean useStartTLS, String bindDn, String pwd, 1072 int connectTimeout, ApplicationTrustManager trustManager) 1073 throws NamingException 1074 { 1075 InitialLdapContext ctx; 1076 String ldapUrl = getLDAPUrl(host, port, useSSL); 1077 if (useSSL) 1078 { 1079 ctx = createLdapsContext(ldapUrl, bindDn, pwd, connectTimeout, null, trustManager, null); 1080 } 1081 else if (useStartTLS) 1082 { 1083 ctx = createStartTLSContext(ldapUrl, bindDn, pwd, connectTimeout, null, trustManager, null); 1084 } 1085 else 1086 { 1087 ctx = createLdapContext(ldapUrl, bindDn, pwd, connectTimeout, null); 1088 } 1089 if (!connectedAsAdministrativeUser(ctx)) 1090 { 1091 throw new NoPermissionException(ERR_NOT_ADMINISTRATIVE_USER.get().toString()); 1092 } 1093 return ctx; 1094 } 1095 1096 /** 1097 * Creates an Initial LDAP Context interacting with the user if the 1098 * application is interactive. 1099 * 1100 * @param ci 1101 * the LDAPConnectionConsoleInteraction object that is assumed to 1102 * have been already run. 1103 * @return the initial LDAP context or <CODE>null</CODE> if the user did not 1104 * accept to trust the certificates. 1105 * @throws ClientException 1106 * if there was an error establishing the connection. 1107 */ 1108 private InitialLdapContext createInitialLdapContextInteracting(LDAPConnectionConsoleInteraction ci) 1109 throws ClientException 1110 { 1111 return createInitialLdapContextInteracting(ci, isInteractive() && ci.isTrustStoreInMemory()); 1112 } 1113 1114 private OpendsCertificateException getCertificateRootException(Throwable t) 1115 { 1116 while (t != null) 1117 { 1118 t = t.getCause(); 1119 if (t instanceof OpendsCertificateException) 1120 { 1121 return (OpendsCertificateException) t; 1122 } 1123 } 1124 return null; 1125 } 1126 1127 /** 1128 * Creates an Initial LDAP Context interacting with the user if the 1129 * application is interactive. 1130 * 1131 * @param ci 1132 * the LDAPConnectionConsoleInteraction object that is assumed to 1133 * have been already run. 1134 * @param promptForCertificate 1135 * whether we should prompt for the certificate or not. 1136 * @return the initial LDAP context or <CODE>null</CODE> if the user did not 1137 * accept to trust the certificates. 1138 * @throws ClientException 1139 * if there was an error establishing the connection. 1140 */ 1141 private InitialLdapContext createInitialLdapContextInteracting(LDAPConnectionConsoleInteraction ci, 1142 boolean promptForCertificate) throws ClientException 1143 { 1144 // Interact with the user though the console to get 1145 // LDAP connection information 1146 String hostName = getHostNameForLdapUrl(ci.getHostName()); 1147 Integer portNumber = ci.getPortNumber(); 1148 String bindDN = ci.getBindDN(); 1149 String bindPassword = ci.getBindPassword(); 1150 TrustManager trustManager = ci.getTrustManager(); 1151 KeyManager keyManager = ci.getKeyManager(); 1152 1153 InitialLdapContext ctx; 1154 1155 if (ci.useSSL()) 1156 { 1157 String ldapsUrl = "ldaps://" + hostName + ":" + portNumber; 1158 while (true) 1159 { 1160 try 1161 { 1162 ctx = createLdapsContext(ldapsUrl, bindDN, bindPassword, ci.getConnectTimeout(), 1163 null, trustManager, keyManager); 1164 ctx.reconnect(null); 1165 break; 1166 } 1167 catch (NamingException e) 1168 { 1169 if (promptForCertificate) 1170 { 1171 OpendsCertificateException oce = getCertificateRootException(e); 1172 if (oce != null) 1173 { 1174 String authType = null; 1175 if (trustManager instanceof ApplicationTrustManager) 1176 { 1177 ApplicationTrustManager appTrustManager = 1178 (ApplicationTrustManager) trustManager; 1179 authType = appTrustManager.getLastRefusedAuthType(); 1180 } 1181 if (ci.checkServerCertificate(oce.getChain(), authType, hostName)) 1182 { 1183 // If the certificate is trusted, update the trust manager. 1184 trustManager = ci.getTrustManager(); 1185 1186 // Try to connect again. 1187 continue; 1188 } 1189 else 1190 { 1191 // Assume user canceled. 1192 return null; 1193 } 1194 } 1195 } 1196 if (e.getCause() != null) 1197 { 1198 if (!isInteractive() 1199 && !ci.isTrustAll() 1200 && (getCertificateRootException(e) != null 1201 || e.getCause() instanceof SSLHandshakeException)) 1202 { 1203 LocalizableMessage message = 1204 ERR_FAILED_TO_CONNECT_NOT_TRUSTED.get(hostName, portNumber); 1205 throw new ClientException(ReturnCode.CLIENT_SIDE_CONNECT_ERROR, message); 1206 } 1207 if (e.getCause() instanceof SSLException) 1208 { 1209 LocalizableMessage message = 1210 ERR_FAILED_TO_CONNECT_WRONG_PORT.get(hostName, portNumber); 1211 throw new ClientException( 1212 ReturnCode.CLIENT_SIDE_CONNECT_ERROR, message); 1213 } 1214 } 1215 String hostPort = 1216 ServerDescriptor.getServerRepresentation(hostName, portNumber); 1217 LocalizableMessage message = getMessageForException(e, hostPort); 1218 throw new ClientException(ReturnCode.CLIENT_SIDE_CONNECT_ERROR, message); 1219 } 1220 } 1221 } 1222 else if (ci.useStartTLS()) 1223 { 1224 String ldapUrl = "ldap://" + hostName + ":" + portNumber; 1225 while (true) 1226 { 1227 try 1228 { 1229 ctx = createStartTLSContext(ldapUrl, bindDN, 1230 bindPassword, CliConstants.DEFAULT_LDAP_CONNECT_TIMEOUT, null, 1231 trustManager, keyManager, null); 1232 ctx.reconnect(null); 1233 break; 1234 } 1235 catch (NamingException e) 1236 { 1237 if (promptForCertificate) 1238 { 1239 OpendsCertificateException oce = getCertificateRootException(e); 1240 if (oce != null) 1241 { 1242 String authType = null; 1243 if (trustManager instanceof ApplicationTrustManager) 1244 { 1245 ApplicationTrustManager appTrustManager = 1246 (ApplicationTrustManager) trustManager; 1247 authType = appTrustManager.getLastRefusedAuthType(); 1248 } 1249 1250 if (ci.checkServerCertificate(oce.getChain(), authType, hostName)) 1251 { 1252 // If the certificate is trusted, update the trust manager. 1253 trustManager = ci.getTrustManager(); 1254 1255 // Try to connect again. 1256 continue; 1257 } 1258 else 1259 { 1260 // Assume user cancelled. 1261 return null; 1262 } 1263 } 1264 else 1265 { 1266 LocalizableMessage message = 1267 ERR_FAILED_TO_CONNECT.get(hostName, portNumber); 1268 throw new ClientException( 1269 ReturnCode.CLIENT_SIDE_CONNECT_ERROR, message); 1270 } 1271 } 1272 LocalizableMessage message = 1273 ERR_FAILED_TO_CONNECT.get(hostName, portNumber); 1274 throw new ClientException(ReturnCode.CLIENT_SIDE_CONNECT_ERROR, 1275 message); 1276 } 1277 } 1278 } 1279 else 1280 { 1281 String ldapUrl = "ldap://" + hostName + ":" + portNumber; 1282 while (true) 1283 { 1284 try 1285 { 1286 ctx = createLdapContext(ldapUrl, bindDN, bindPassword, 1287 CliConstants.DEFAULT_LDAP_CONNECT_TIMEOUT, null); 1288 ctx.reconnect(null); 1289 break; 1290 } 1291 catch (NamingException e) 1292 { 1293 LocalizableMessage message = 1294 ERR_FAILED_TO_CONNECT.get(hostName, portNumber); 1295 throw new ClientException(ReturnCode.CLIENT_SIDE_CONNECT_ERROR, 1296 message); 1297 } 1298 } 1299 } 1300 return ctx; 1301 } 1302 1303 private ReplicationCliReturnCode purgeHistoricalRemotely( 1304 PurgeHistoricalUserData uData) 1305 { 1306 // Connect to the provided server 1307 InitialLdapContext ctx = createAdministrativeContext(uData); 1308 if (ctx == null) 1309 { 1310 return ERROR_CONNECTING; 1311 } 1312 1313 try 1314 { 1315 List<String> baseDNs = uData.getBaseDNs(); 1316 checkSuffixesForPurgeHistorical(baseDNs, ctx, false); 1317 if (baseDNs.isEmpty()) 1318 { 1319 return HISTORICAL_CANNOT_BE_PURGED_ON_BASEDN; 1320 } 1321 uData.setBaseDNs(baseDNs); 1322 if (mustPrintCommandBuilder()) 1323 { 1324 printNewCommandBuilder(PURGE_HISTORICAL_SUBCMD_NAME, uData); 1325 } 1326 1327 try 1328 { 1329 return purgeHistoricalRemoteTask(ctx, uData); 1330 } 1331 catch (ReplicationCliException rce) 1332 { 1333 errPrintln(); 1334 errPrintln(getCriticalExceptionMessage(rce)); 1335 logger.error(LocalizableMessage.raw("Complete error stack:"), rce); 1336 return rce.getErrorCode(); 1337 } 1338 } 1339 finally 1340 { 1341 close(ctx); 1342 } 1343 } 1344 1345 private ReplicationCliReturnCode resetChangeNumber() 1346 { 1347 final String changeNumber; 1348 final SourceDestinationServerUserData uData = new SourceDestinationServerUserData(); 1349 1350 if (!argParser.isInteractive()) 1351 { 1352 initializeWithArgParser(uData); 1353 return resetChangeNumber(uData); 1354 } 1355 OperationBetweenSourceAndDestinationServers 1356 resetChangeNumberOperations = new OperationBetweenSourceAndDestinationServers() 1357 { 1358 @Override 1359 public boolean continueAfterUserInput(Collection<String> baseDNs, InitialLdapContext source, 1360 InitialLdapContext dest, boolean interactive) 1361 { 1362 TopologyCacheFilter filter = new TopologyCacheFilter(); 1363 filter.setSearchMonitoringInformation(false); 1364 1365 if (!argParser.resetChangeNumber.isPresent()) 1366 { 1367 String cn = getNewestChangeNumber(source); 1368 if (cn.isEmpty()) 1369 { 1370 return true; 1371 } 1372 argParser.setResetChangeNumber( 1373 ask(logger, INFO_RESET_CHANGE_NUMBER_TO.get(uData.getSource(), uData.getDestination()), cn)); 1374 } 1375 return false; 1376 } 1377 1378 @Override 1379 public boolean confirmOperation(SourceDestinationServerUserData uData, InitialLdapContext ctxSource, 1380 InitialLdapContext ctxDestination, boolean defaultValue) 1381 { 1382 return !askConfirmation(INFO_RESET_CHANGE_NUMBER_CONFIRM_RESET.get(uData.getDestinationHostPort()), 1383 defaultValue); 1384 } 1385 }; 1386 1387 return promptIfRequired(uData, resetChangeNumberOperations) ? resetChangeNumber(uData) : USER_CANCELLED; 1388 } 1389 1390 private ReplicationCliReturnCode resetChangeNumber(SourceDestinationServerUserData uData) 1391 { 1392 1393 InitialLdapContext ctxSource = createAdministrativeContext(uData, uData.getSource()); 1394 InitialLdapContext ctxDest = createAdministrativeContext(uData, uData.getDestination()); 1395 if (!getCommonSuffixes(ctxSource, ctxDest, SuffixRelationType.NOT_FULLY_REPLICATED).isEmpty()) 1396 { 1397 errPrintln(ERROR_RESET_CHANGE_NUMBER_SERVERS_BASEDNS_DIFFER.get(uData.getSourceHostPort(), 1398 uData.getDestinationHostPort())); 1399 return ERROR_RESET_CHANGE_NUMBER_BASEDNS_SHOULD_EQUAL; 1400 } 1401 if (mustPrintCommandBuilder()) 1402 { 1403 printNewCommandBuilder(RESET_CHANGE_NUMBER_SUBCMD_NAME, uData); 1404 } 1405 try 1406 { 1407 String newStartCN; 1408 if (argParser.resetChangeNumber.isPresent()) 1409 { 1410 newStartCN = String.valueOf(argParser.getResetChangeNumber()); 1411 } 1412 else 1413 { 1414 newStartCN = getNewestChangeNumber(ctxSource); 1415 if (newStartCN.isEmpty()) 1416 { 1417 return ERROR_UNKNOWN_CHANGE_NUMBER; 1418 } 1419 argParser.setResetChangeNumber(newStartCN); 1420 } 1421 SearchControls ctls = new SearchControls(); 1422 ctls.setSearchScope(SearchControls.SUBTREE_SCOPE); 1423 ctls.setReturningAttributes( 1424 new String[] { 1425 "changeNumber", 1426 "replicationCSN", 1427 "targetDN" 1428 }); 1429 NamingEnumeration<SearchResult> listeners = ctxSource.search(new LdapName("cn=changelog"), 1430 "(changeNumber=" + newStartCN + ")", ctls); 1431 if (!listeners.hasMore()) 1432 { 1433 errPrintln(ERROR_RESET_CHANGE_NUMBER_UNKNOWN_NUMBER.get(newStartCN, uData.getSourceHostPort())); 1434 return ERROR_UNKNOWN_CHANGE_NUMBER; 1435 } 1436 SearchResult sr = listeners.next(); 1437 String newStartCSN = getFirstValue(sr, "replicationCSN"); 1438 if (newStartCSN == null) 1439 { 1440 errPrintln(ERROR_RESET_CHANGE_NUMBER_NO_CSN_FOUND.get(newStartCN, uData.getSourceHostPort())); 1441 return ERROR_RESET_CHANGE_NUMBER_NO_CSN; 1442 } 1443 String targetDN = getFirstValue(sr, "targetDN"); 1444 DN targetBaseDN = DN.rootDN(); 1445 try 1446 { 1447 for (String adn : getCommonSuffixes(ctxSource, ctxDest, SuffixRelationType.REPLICATED)) 1448 { 1449 DN dn = DN.valueOf(adn); 1450 if (DN.valueOf(targetDN).isSubordinateOrEqualTo(dn) && dn.isSubordinateOrEqualTo(targetBaseDN)) 1451 { 1452 targetBaseDN = dn; 1453 } 1454 } 1455 } 1456 catch (LocalizedIllegalArgumentException e) 1457 { 1458 errPrintln(ERROR_RESET_CHANGE_NUMBER_EXCEPTION.get(e.getLocalizedMessage())); 1459 return ERROR_RESET_CHANGE_NUMBER_PROBLEM; 1460 } 1461 if (targetBaseDN.isRootDN()) 1462 { 1463 errPrintln(ERROR_RESET_CHANGE_NUMBER_NO_BASEDN.get(newStartCN, targetDN, newStartCSN)); 1464 return ERROR_RESET_CHANGE_NUMBER_UNKNOWN_BASEDN; 1465 } 1466 logger.info(INFO_RESET_CHANGE_NUMBER_INFO.get(uData.getDestinationHostPort(), 1467 newStartCN, newStartCSN, targetBaseDN.toString())); 1468 Map<String, String> taskAttrs = new TreeMap<>(); 1469 taskAttrs.put("ds-task-reset-change-number-to", newStartCN); 1470 taskAttrs.put("ds-task-reset-change-number-csn", newStartCSN); 1471 taskAttrs.put("ds-task-reset-change-number-base-dn", targetBaseDN.toString()); 1472 String taskDN = createServerTask(ctxDest, 1473 "ds-task-reset-change-number", "org.opends.server.tasks.ResetChangeNumberTask", "dsreplication-reset-cn", 1474 taskAttrs); 1475 waitUntilResetChangeNumberTaskEnds(ctxDest, taskDN); 1476 return SUCCESSFUL; 1477 } 1478 catch (ReplicationCliException | NamingException | NullPointerException e) 1479 { 1480 errPrintln(ERROR_RESET_CHANGE_NUMBER_EXCEPTION.get(e.getLocalizedMessage())); 1481 return ERROR_RESET_CHANGE_NUMBER_PROBLEM; 1482 } 1483 } 1484 1485 private String getNewestChangeNumber(InitialLdapContext source) 1486 { 1487 try 1488 { 1489 SearchControls ctls = new SearchControls(); 1490 ctls.setSearchScope(SearchControls.OBJECT_SCOPE); 1491 ctls.setReturningAttributes(new String[] {"lastChangeNumber"}); 1492 NamingEnumeration<SearchResult> results = source.search(new LdapName(""), "objectclass=*", ctls); 1493 if (results.hasMore()) { 1494 return getFirstValue(results.next(), "lastChangeNumber"); 1495 } 1496 } 1497 catch (NamingException e) 1498 { 1499 errPrintln(ERROR_RESET_CHANGE_NUMBER_EXCEPTION.get(e.getLocalizedMessage())); 1500 } 1501 1502 return ""; 1503 } 1504 1505 private void waitUntilResetChangeNumberTaskEnds(InitialLdapContext server, String taskDN) 1506 throws ReplicationCliException 1507 { 1508 String lastLogMsg = null; 1509 while (true) 1510 { 1511 sleepCatchInterrupt(500); 1512 try 1513 { 1514 SearchResult sr = getLastSearchResult(server, taskDN, "ds-task-log-message", "ds-task-state" ); 1515 String logMsg = getFirstValue(sr, "ds-task-log-message"); 1516 if (logMsg != null && !logMsg.equals(lastLogMsg)) 1517 { 1518 logger.info(LocalizableMessage.raw(logMsg)); 1519 lastLogMsg = logMsg; 1520 } 1521 InstallerHelper helper = new InstallerHelper(); 1522 String state = getFirstValue(sr, "ds-task-state"); 1523 1524 if (helper.isDone(state) || helper.isStoppedByError(state)) 1525 { 1526 LocalizableMessage errorMsg = ERR_UNEXPECTED_DURING_TASK_WITH_LOG.get(lastLogMsg, state, server); 1527 1528 if (helper.isCompletedWithErrors(state)) 1529 { 1530 logger.warn(LocalizableMessage.raw("Completed with error: " + errorMsg)); 1531 errPrintln(errorMsg); 1532 } 1533 else if (!helper.isSuccessful(state) || helper.isStoppedByError(state)) 1534 { 1535 logger.warn(LocalizableMessage.raw("Error: " + errorMsg)); 1536 throw new ReplicationCliException(errorMsg, ERROR_LAUNCHING_RESET_CHANGE_NUMBER, null); 1537 } 1538 else 1539 { 1540 print(INFO_RESET_CHANGE_NUMBER_TASK_FINISHED.get()); 1541 println(); 1542 } 1543 return; 1544 } 1545 } 1546 catch (NameNotFoundException x) 1547 { 1548 return; 1549 } 1550 catch (NamingException ne) 1551 { 1552 throw new ReplicationCliException(getThrowableMsg(ERR_READING_SERVER_TASK_PROGRESS.get(), ne), 1553 ERROR_CONNECTING, ne); 1554 } 1555 } 1556 } 1557 1558 private InitialLdapContext createAdministrativeContext(MonoServerReplicationUserData uData) 1559 { 1560 final String bindDn = getAdministratorDN(uData.getAdminUid()); 1561 return createAdministrativeContext(uData, bindDn); 1562 } 1563 1564 private InitialLdapContext createAdministrativeContext(MonoServerReplicationUserData uData, final String bindDn) 1565 { 1566 try 1567 { 1568 return createAdministrativeContext(uData.getHostName(), uData.getPort(), 1569 useSSL, useStartTLS, bindDn, 1570 uData.getAdminPwd(), getConnectTimeout(), getTrustManager(sourceServerCI)); 1571 } 1572 catch (NamingException ne) 1573 { 1574 String hostPort = getServerRepresentation(uData.getHostName(), uData.getPort()); 1575 errPrintln(); 1576 errPrintln(getMessageForException(ne, hostPort)); 1577 logger.error(LocalizableMessage.raw("Complete error stack:"), ne); 1578 return null; 1579 } 1580 } 1581 1582 private void printSuccessMessage(PurgeHistoricalUserData uData, String taskID) 1583 { 1584 println(); 1585 if (!uData.isOnline()) 1586 { 1587 print( 1588 INFO_PROGRESS_PURGE_HISTORICAL_FINISHED_PROCEDURE.get()); 1589 } 1590 else if (uData.getTaskSchedule().isStartNow()) 1591 { 1592 print(INFO_TASK_TOOL_TASK_SUCESSFULL.get( 1593 INFO_PURGE_HISTORICAL_TASK_NAME.get(), 1594 taskID)); 1595 } 1596 else if (uData.getTaskSchedule().getStartDate() != null) 1597 { 1598 print(INFO_TASK_TOOL_TASK_SCHEDULED_FUTURE.get( 1599 INFO_PURGE_HISTORICAL_TASK_NAME.get(), 1600 taskID, 1601 StaticUtils.formatDateTimeString( 1602 uData.getTaskSchedule().getStartDate()))); 1603 } 1604 else 1605 { 1606 print(INFO_TASK_TOOL_RECURRING_TASK_SCHEDULED.get( 1607 INFO_PURGE_HISTORICAL_TASK_NAME.get(), 1608 taskID)); 1609 } 1610 1611 println(); 1612 } 1613 1614 /** 1615 * Launches the purge historical operation using the 1616 * provided connection. 1617 * @param ctx the connection to the server. 1618 * @throws ReplicationCliException if there is an error performing the 1619 * operation. 1620 */ 1621 private ReplicationCliReturnCode purgeHistoricalRemoteTask( 1622 InitialLdapContext ctx, 1623 PurgeHistoricalUserData uData) 1624 throws ReplicationCliException 1625 { 1626 printPurgeProgressMessage(uData); 1627 ReplicationCliReturnCode returnCode = SUCCESSFUL; 1628 boolean taskCreated = false; 1629 boolean isOver = false; 1630 String dn = null; 1631 String taskID = null; 1632 while (!taskCreated) 1633 { 1634 BasicAttributes attrs = PurgeHistoricalUserData.getTaskAttributes(uData); 1635 dn = PurgeHistoricalUserData.getTaskDN(attrs); 1636 taskID = PurgeHistoricalUserData.getTaskID(attrs); 1637 try 1638 { 1639 DirContext dirCtx = ctx.createSubcontext(dn, attrs); 1640 taskCreated = true; 1641 logger.info(LocalizableMessage.raw("created task entry: "+attrs)); 1642 dirCtx.close(); 1643 } 1644 catch (NamingException ne) 1645 { 1646 logger.error(LocalizableMessage.raw("Error creating task "+attrs, ne)); 1647 LocalizableMessage msg = ERR_LAUNCHING_PURGE_HISTORICAL.get(); 1648 ReplicationCliReturnCode code = ERROR_LAUNCHING_PURGE_HISTORICAL; 1649 throw new ReplicationCliException( 1650 getThrowableMsg(msg, ne), code, ne); 1651 } 1652 } 1653 1654 // Polling only makes sense when we are recurrently scheduling a task 1655 // or the task is being executed now. 1656 String lastLogMsg = null; 1657 while (!isOver && uData.getTaskSchedule().getStartDate() == null) 1658 { 1659 sleepCatchInterrupt(500); 1660 try 1661 { 1662 SearchResult sr = getFirstSearchResult(ctx, dn, 1663 "ds-task-log-message", 1664 "ds-task-state", 1665 "ds-task-purge-conflicts-historical-purged-values-count", 1666 "ds-task-purge-conflicts-historical-purge-completed-in-time", 1667 "ds-task-purge-conflicts-historical-purge-completed-in-time", 1668 "ds-task-purge-conflicts-historical-last-purged-changenumber"); 1669 String logMsg = getFirstValue(sr, "ds-task-log-message"); 1670 if (logMsg != null && !logMsg.equals(lastLogMsg)) 1671 { 1672 logger.info(LocalizableMessage.raw(logMsg)); 1673 lastLogMsg = logMsg; 1674 } 1675 InstallerHelper helper = new InstallerHelper(); 1676 String state = getFirstValue(sr, "ds-task-state"); 1677 1678 if (helper.isDone(state) || helper.isStoppedByError(state)) 1679 { 1680 isOver = true; 1681 LocalizableMessage errorMsg = getPurgeErrorMsg(lastLogMsg, state, ctx); 1682 1683 if (helper.isCompletedWithErrors(state)) 1684 { 1685 logger.warn(LocalizableMessage.raw("Completed with error: "+errorMsg)); 1686 errPrintln(errorMsg); 1687 } 1688 else if (!helper.isSuccessful(state) || 1689 helper.isStoppedByError(state)) 1690 { 1691 logger.warn(LocalizableMessage.raw("Error: "+errorMsg)); 1692 ReplicationCliReturnCode code = ERROR_LAUNCHING_PURGE_HISTORICAL; 1693 throw new ReplicationCliException(errorMsg, code, null); 1694 } 1695 } 1696 } 1697 catch (NameNotFoundException x) 1698 { 1699 isOver = true; 1700 } 1701 catch (NamingException ne) 1702 { 1703 LocalizableMessage msg = ERR_READING_SERVER_TASK_PROGRESS.get(); 1704 throw new ReplicationCliException( 1705 getThrowableMsg(msg, ne), ERROR_CONNECTING, ne); 1706 } 1707 } 1708 1709 if (returnCode == SUCCESSFUL) 1710 { 1711 printSuccessMessage(uData, taskID); 1712 } 1713 return returnCode; 1714 } 1715 1716 private SearchResult getFirstSearchResult(InitialLdapContext ctx, String dn, String... returnedAttributes) 1717 throws NamingException 1718 { 1719 SearchControls searchControls = new SearchControls(); 1720 searchControls.setCountLimit(1); 1721 searchControls.setSearchScope(SearchControls.OBJECT_SCOPE); 1722 searchControls.setReturningAttributes(returnedAttributes); 1723 NamingEnumeration<SearchResult> res = ctx.search(dn, "objectclass=*", searchControls); 1724 try 1725 { 1726 SearchResult sr = null; 1727 sr = res.next(); 1728 return sr; 1729 } 1730 finally 1731 { 1732 res.close(); 1733 } 1734 } 1735 1736 private LocalizableMessage getPurgeErrorMsg(String lastLogMsg, String state, InitialLdapContext ctx) 1737 { 1738 String server = getHostPort(ctx); 1739 if (lastLogMsg != null) 1740 { 1741 return ERR_UNEXPECTED_DURING_TASK_WITH_LOG.get(lastLogMsg, state, server); 1742 } 1743 return ERR_UNEXPECTED_DURING_TASK_NO_LOG.get(state, server); 1744 } 1745 1746 /** 1747 * Checks that historical can actually be purged in the provided baseDNs 1748 * for the server. 1749 * @param suffixes the suffixes provided by the user. This Collection is 1750 * updated with the base DNs that the user provided interactively. 1751 * @param ctx connection to the server. 1752 * @param interactive whether to ask the user to provide interactively 1753 * base DNs if none of the provided base DNs can be purged. 1754 */ 1755 private void checkSuffixesForPurgeHistorical(Collection<String> suffixes, 1756 InitialLdapContext ctx, boolean interactive) 1757 { 1758 checkSuffixesForPurgeHistorical(suffixes, getReplicas(ctx), interactive); 1759 } 1760 1761 /** 1762 * Checks that historical can actually be purged in the provided baseDNs 1763 * for the local server. 1764 * @param suffixes the suffixes provided by the user. This Collection is 1765 * updated with the base DNs that the user provided interactively. 1766 * @param interactive whether to ask the user to provide interactively 1767 * base DNs if none of the provided base DNs can be purged. 1768 */ 1769 private void checkSuffixesForLocalPurgeHistorical(Collection<String> suffixes, 1770 boolean interactive) 1771 { 1772 checkSuffixesForPurgeHistorical(suffixes, getLocalReplicas(), interactive); 1773 } 1774 1775 private Collection<ReplicaDescriptor> getLocalReplicas() 1776 { 1777 Collection<ReplicaDescriptor> replicas = new ArrayList<>(); 1778 ConfigFromFile configFromFile = new ConfigFromFile(); 1779 configFromFile.readConfiguration(); 1780 Collection<BackendDescriptor> backends = configFromFile.getBackends(); 1781 for (BackendDescriptor backend : backends) 1782 { 1783 for (BaseDNDescriptor baseDN : backend.getBaseDns()) 1784 { 1785 SuffixDescriptor suffix = new SuffixDescriptor(); 1786 suffix.setDN(baseDN.getDn().toString()); 1787 1788 ReplicaDescriptor replica = new ReplicaDescriptor(); 1789 1790 if (baseDN.getType() == BaseDNDescriptor.Type.REPLICATED) 1791 { 1792 replica.setReplicationId(baseDN.getReplicaID()); 1793 } 1794 else 1795 { 1796 replica.setReplicationId(-1); 1797 } 1798 replica.setBackendName(backend.getBackendID()); 1799 replica.setSuffix(suffix); 1800 suffix.setReplicas(singleton(replica)); 1801 1802 replicas.add(replica); 1803 } 1804 } 1805 return replicas; 1806 } 1807 1808 private void checkSuffixesForPurgeHistorical(Collection<String> suffixes, Collection<ReplicaDescriptor> replicas, 1809 boolean interactive) 1810 { 1811 TreeSet<String> availableSuffixes = new TreeSet<>(); 1812 TreeSet<String> notReplicatedSuffixes = new TreeSet<>(); 1813 1814 for (ReplicaDescriptor rep : replicas) 1815 { 1816 String dn = rep.getSuffix().getDN(); 1817 if (rep.isReplicated()) 1818 { 1819 availableSuffixes.add(dn); 1820 } 1821 else 1822 { 1823 notReplicatedSuffixes.add(dn); 1824 } 1825 } 1826 1827 checkSuffixesForPurgeHistorical(suffixes, availableSuffixes, notReplicatedSuffixes, interactive); 1828 } 1829 1830 private void checkSuffixesForPurgeHistorical(Collection<String> suffixes, 1831 Collection<String> availableSuffixes, 1832 Collection<String> notReplicatedSuffixes, 1833 boolean interactive) 1834 { 1835 if (availableSuffixes.isEmpty()) 1836 { 1837 errPrintln(); 1838 errPrintln(ERR_NO_SUFFIXES_AVAILABLE_TO_PURGE_HISTORICAL.get()); 1839 suffixes.clear(); 1840 } 1841 else 1842 { 1843 // Verify that the provided suffixes are configured in the servers. 1844 TreeSet<String> notFound = new TreeSet<>(); 1845 TreeSet<String> alreadyNotReplicated = new TreeSet<>(); 1846 for (String dn : suffixes) 1847 { 1848 if (!containsDN(availableSuffixes, dn)) 1849 { 1850 if (containsDN(notReplicatedSuffixes, dn)) 1851 { 1852 alreadyNotReplicated.add(dn); 1853 } 1854 else 1855 { 1856 notFound.add(dn); 1857 } 1858 } 1859 } 1860 suffixes.removeAll(notFound); 1861 suffixes.removeAll(alreadyNotReplicated); 1862 if (!notFound.isEmpty()) 1863 { 1864 errPrintln(); 1865 errPrintln(ERR_REPLICATION_PURGE_SUFFIXES_NOT_FOUND.get(toSingleLine(notFound))); 1866 } 1867 if (interactive) 1868 { 1869 askConfirmations(suffixes, availableSuffixes, 1870 ERR_NO_SUFFIXES_AVAILABLE_TO_PURGE_HISTORICAL, 1871 ERR_NO_SUFFIXES_SELECTED_TO_PURGE_HISTORICAL, 1872 INFO_REPLICATION_PURGE_HISTORICAL_PROMPT); 1873 } 1874 } 1875 } 1876 1877 private void askConfirmations(Collection<String> suffixes, 1878 Collection<String> availableSuffixes, Arg0 noSuffixAvailableMsg, 1879 Arg0 noSuffixSelectedMsg, Arg1<Object> confirmationMsgPromt) 1880 { 1881 if (containsOnlySchemaOrAdminSuffix(availableSuffixes)) 1882 { 1883 // In interactive mode we do not propose to manage the administration suffix. 1884 errPrintln(); 1885 errPrintln(noSuffixAvailableMsg.get()); 1886 return; 1887 } 1888 1889 while (suffixes.isEmpty()) 1890 { 1891 errPrintln(); 1892 errPrintln(noSuffixSelectedMsg.get()); 1893 boolean confirmationLimitReached = askConfirmations(confirmationMsgPromt, availableSuffixes, suffixes); 1894 if (confirmationLimitReached) 1895 { 1896 suffixes.clear(); 1897 break; 1898 } 1899 } 1900 } 1901 1902 private boolean containsOnlySchemaOrAdminSuffix(Collection<String> suffixes) 1903 { 1904 for (String suffix : suffixes) 1905 { 1906 if (!isSchemaOrInternalAdminSuffix(suffix)) 1907 { 1908 return false; 1909 } 1910 } 1911 return true; 1912 } 1913 1914 private boolean isSchemaOrInternalAdminSuffix(String suffix) 1915 { 1916 return areDnsEqual(suffix, ADSContext.getAdministrationSuffixDN()) 1917 || areDnsEqual(suffix, Constants.SCHEMA_DN) 1918 || areDnsEqual(suffix, Constants.REPLICATION_CHANGES_DN); 1919 } 1920 1921 /** 1922 * Based on the data provided in the command-line it initializes replication 1923 * between two servers. 1924 * @return the error code if the operation failed and SUCCESSFUL if it was 1925 * successful. 1926 */ 1927 private ReplicationCliReturnCode initializeReplication() 1928 { 1929 SourceDestinationServerUserData uData = new SourceDestinationServerUserData(); 1930 if (!argParser.isInteractive()) 1931 { 1932 initializeWithArgParser(uData); 1933 return initializeReplication(uData); 1934 } 1935 1936 OperationBetweenSourceAndDestinationServers 1937 initializeReplicationOperations = new OperationBetweenSourceAndDestinationServers() 1938 { 1939 @Override 1940 public boolean continueAfterUserInput(Collection<String> baseDNs, InitialLdapContext source, 1941 InitialLdapContext dest, boolean interactive) 1942 { 1943 checkSuffixesForInitializeReplication(baseDNs, source, dest, interactive); 1944 return baseDNs.isEmpty(); 1945 } 1946 1947 @Override 1948 public boolean confirmOperation(SourceDestinationServerUserData uData, InitialLdapContext ctxSource, 1949 InitialLdapContext ctxDestination, boolean defaultValue) 1950 { 1951 return !askConfirmation(getInitializeReplicationPrompt(uData, ctxSource, ctxDestination), defaultValue); 1952 } 1953 }; 1954 return promptIfRequired(uData, initializeReplicationOperations) ? initializeReplication(uData) : USER_CANCELLED; 1955 } 1956 1957 /** 1958 * Updates the contents of the provided PurgeHistoricalUserData 1959 * object with the information provided in the command-line. If some 1960 * information is missing, ask the user to provide valid data. 1961 * We assume that if this method is called we are in interactive mode. 1962 * @param uData the object to be updated. 1963 * @return <CODE>true</CODE> if the object was successfully updated and 1964 * <CODE>false</CODE> if the user canceled the operation. 1965 */ 1966 private boolean promptIfRequired(PurgeHistoricalUserData uData) 1967 { 1968 InitialLdapContext ctx = null; 1969 try 1970 { 1971 ctx = getInitialLdapContext(uData); 1972 if (ctx == null) 1973 { 1974 return false; 1975 } 1976 1977 /* Prompt for maximum duration */ 1978 int maximumDuration = argParser.getMaximumDuration(); 1979 if (!argParser.maximumDurationArg.isPresent()) 1980 { 1981 println(); 1982 maximumDuration = askInteger(INFO_REPLICATION_PURGE_HISTORICAL_MAXIMUM_DURATION_PROMPT.get(), 1983 getDefaultValue(argParser.maximumDurationArg), logger); 1984 } 1985 uData.setMaximumDuration(maximumDuration); 1986 1987 List<String> suffixes = argParser.getBaseDNs(); 1988 if (uData.isOnline()) 1989 { 1990 checkSuffixesForPurgeHistorical(suffixes, ctx, true); 1991 } 1992 else 1993 { 1994 checkSuffixesForLocalPurgeHistorical(suffixes, true); 1995 } 1996 if (suffixes.isEmpty()) 1997 { 1998 return false; 1999 } 2000 uData.setBaseDNs(suffixes); 2001 2002 if (uData.isOnline()) 2003 { 2004 List<? extends TaskEntry> taskEntries = getAvailableTaskEntries(ctx); 2005 2006 TaskScheduleInteraction interaction = 2007 new TaskScheduleInteraction(uData.getTaskSchedule(), argParser.taskArgs, this, 2008 INFO_PURGE_HISTORICAL_TASK_NAME.get()); 2009 interaction.setFormatter(formatter); 2010 interaction.setTaskEntries(taskEntries); 2011 try 2012 { 2013 interaction.run(); 2014 } 2015 catch (ClientException ce) 2016 { 2017 errPrintln(ce.getMessageObject()); 2018 return false; 2019 } 2020 } 2021 return true; 2022 } 2023 finally 2024 { 2025 close(ctx); 2026 } 2027 } 2028 2029 private InitialLdapContext getInitialLdapContext(PurgeHistoricalUserData uData) 2030 { 2031 boolean firstTry = true; 2032 Boolean serverRunning = null; 2033 2034 while (true) 2035 { 2036 boolean promptForConnection = firstTry && argParser.connectionArgumentsPresent(); 2037 if (!promptForConnection) 2038 { 2039 if (serverRunning == null) 2040 { 2041 serverRunning = Utilities.isServerRunning(Installation.getLocal().getInstanceDirectory()); 2042 } 2043 2044 if (!serverRunning) 2045 { 2046 try 2047 { 2048 println(); 2049 promptForConnection = !askConfirmation( 2050 INFO_REPLICATION_PURGE_HISTORICAL_LOCAL_PROMPT.get(), true, logger); 2051 } 2052 catch (ClientException ce) 2053 { 2054 errPrintln(ce.getMessageObject()); 2055 } 2056 2057 if (!promptForConnection) 2058 { 2059 uData.setOnline(false); 2060 return null; 2061 } 2062 } 2063 } 2064 2065 try 2066 { 2067 sourceServerCI.run(); 2068 2069 InitialLdapContext ctx = createInitialLdapContextInteracting(sourceServerCI); 2070 if (ctx != null) 2071 { 2072 uData.setOnline(true); 2073 uData.setHostName(sourceServerCI.getHostName()); 2074 uData.setPort(sourceServerCI.getPortNumber()); 2075 uData.setAdminUid(sourceServerCI.getAdministratorUID()); 2076 uData.setAdminPwd(sourceServerCI.getBindPassword()); 2077 } 2078 return ctx; 2079 } 2080 catch (ClientException ce) 2081 { 2082 logger.warn(LocalizableMessage.raw("Client exception " + ce)); 2083 errPrintln(); 2084 errPrintln(ce.getMessageObject()); 2085 errPrintln(); 2086 sourceServerCI.resetConnectionArguments(); 2087 } 2088 catch (ArgumentException ae) 2089 { 2090 logger.warn(LocalizableMessage.raw("Argument exception " + ae)); 2091 argParser.displayMessageAndUsageReference(getErrStream(), ae.getMessageObject()); 2092 return null; 2093 } 2094 firstTry = false; 2095 } 2096 } 2097 2098 private List<? extends TaskEntry> getAvailableTaskEntries( 2099 InitialLdapContext ctx) 2100 { 2101 List<TaskEntry> taskEntries = new ArrayList<>(); 2102 List<OpenDsException> exceptions = new ArrayList<>(); 2103 ConfigFromDirContext cfg = new ConfigFromDirContext(); 2104 cfg.updateTaskInformation(ctx, exceptions, taskEntries); 2105 for (OpenDsException ode : exceptions) 2106 { 2107 logger.warn(LocalizableMessage.raw("Error retrieving task entries: "+ode, ode)); 2108 } 2109 return taskEntries; 2110 } 2111 2112 /** 2113 * Updates the contents of the provided EnableReplicationUserData object 2114 * with the information provided in the command-line. If some information 2115 * is missing, ask the user to provide valid data. 2116 * We assume that if this method is called we are in interactive mode. 2117 * @param uData the object to be updated. 2118 * @return <CODE>true</CODE> if the object was successfully updated and 2119 * <CODE>false</CODE> if the user cancelled the operation. 2120 * @throws ReplicationCliException if a critical error occurs reading the 2121 * ADS. 2122 */ 2123 private boolean promptIfRequired(EnableReplicationUserData uData) 2124 throws ReplicationCliException 2125 { 2126 boolean cancelled = false; 2127 2128 boolean administratorDefined = false; 2129 2130 sourceServerCI.setUseAdminOrBindDn(true); 2131 2132 String adminPwd = argParser.getBindPasswordAdmin(); 2133 String adminUid = argParser.getAdministratorUID(); 2134 2135 /* Try to connect to the first server. */ 2136 String host1 = getValue(argParser.server1.hostNameArg); 2137 int port1 = getValue(argParser.server1.portArg); 2138 String bindDn1 = getValue(argParser.server1.bindDnArg); 2139 String pwd1 = argParser.server1.getBindPassword(); 2140 String pwd = null; 2141 Map<String, String> pwdFile = null; 2142 if (argParser.server1.bindPasswordArg.isPresent()) 2143 { 2144 pwd = argParser.server1.bindPasswordArg.getValue(); 2145 } 2146 else if (argParser.server1.bindPasswordFileArg.isPresent()) 2147 { 2148 pwdFile = argParser.server1.bindPasswordFileArg.getNameToValueMap(); 2149 } 2150 else if (bindDn1 == null) 2151 { 2152 pwd = adminPwd; 2153 if (argParser.getSecureArgsList().getBindPasswordFileArg().isPresent()) 2154 { 2155 pwdFile = argParser.getSecureArgsList().getBindPasswordFileArg(). 2156 getNameToValueMap(); 2157 } 2158 } 2159 2160 /* 2161 * Use a copy of the argument properties since the map might be cleared 2162 * in initializeGlobalArguments. 2163 */ 2164 sourceServerCI.initializeGlobalArguments(host1, port1, adminUid, bindDn1, pwd, 2165 pwdFile == null ? null : new LinkedHashMap<String, String>(pwdFile)); 2166 InitialLdapContext ctx1 = null; 2167 2168 while (ctx1 == null && !cancelled) 2169 { 2170 try 2171 { 2172 sourceServerCI.setHeadingMessage(INFO_REPLICATION_ENABLE_HOST1_CONNECTION_PARAMETERS.get()); 2173 sourceServerCI.run(); 2174 host1 = sourceServerCI.getHostName(); 2175 port1 = sourceServerCI.getPortNumber(); 2176 if (sourceServerCI.getProvidedAdminUID() != null) 2177 { 2178 adminUid = sourceServerCI.getProvidedAdminUID(); 2179 if (sourceServerCI.getProvidedBindDN() == null) 2180 { 2181 // If the explicit bind DN is not null, the password corresponds 2182 // to that bind DN. We are in the case where the user provides 2183 // bind DN on first server and admin UID globally. 2184 adminPwd = sourceServerCI.getBindPassword(); 2185 } 2186 } 2187 bindDn1 = sourceServerCI.getBindDN(); 2188 pwd1 = sourceServerCI.getBindPassword(); 2189 2190 ctx1 = createInitialLdapContextInteracting(sourceServerCI); 2191 if (ctx1 == null) 2192 { 2193 cancelled = true; 2194 } 2195 } 2196 catch (ClientException ce) 2197 { 2198 logger.warn(LocalizableMessage.raw("Client exception "+ce)); 2199 errPrintln(); 2200 errPrintln(ce.getMessageObject()); 2201 errPrintln(); 2202 sourceServerCI.resetConnectionArguments(); 2203 } 2204 catch (ArgumentException ae) 2205 { 2206 logger.warn(LocalizableMessage.raw("Argument exception "+ae)); 2207 argParser.displayMessageAndUsageReference(getErrStream(), ae.getMessageObject()); 2208 cancelled = true; 2209 } 2210 } 2211 2212 if (!cancelled) 2213 { 2214 uData.getServer1().setHostName(host1); 2215 uData.getServer1().setPort(port1); 2216 uData.getServer1().setBindDn(bindDn1); 2217 uData.getServer1().setPwd(pwd1); 2218 } 2219 int replicationPort1 = -1; 2220 boolean secureReplication1 = argParser.server1.secureReplicationArg.isPresent(); 2221 boolean configureReplicationServer1 = argParser.server1.configureReplicationServer(); 2222 boolean configureReplicationDomain1 = argParser.server1.configureReplicationDomain(); 2223 if (ctx1 != null) 2224 { 2225 int repPort1 = getReplicationPort(ctx1); 2226 boolean replicationServer1Configured = repPort1 > 0; 2227 if (replicationServer1Configured && !configureReplicationServer1) 2228 { 2229 final LocalizableMessage msg = 2230 INFO_REPLICATION_SERVER_CONFIGURED_WARNING_PROMPT.get(getHostPort(ctx1), repPort1); 2231 if (!askConfirmation(msg, false)) 2232 { 2233 cancelled = true; 2234 } 2235 } 2236 2237 // Try to get the replication port for server 1 only if it is required. 2238 if (!cancelled 2239 && configureReplicationServer1 2240 && !replicationServer1Configured 2241 && argParser.advancedArg.isPresent() 2242 && configureReplicationDomain1) 2243 { 2244 // Only ask if the replication domain will be configured (if not 2245 // the replication server MUST be configured). 2246 try 2247 { 2248 configureReplicationServer1 = askConfirmation( 2249 INFO_REPLICATION_ENABLE_REPLICATION_SERVER1_PROMPT.get(), 2250 true, logger); 2251 } 2252 catch (ClientException ce) 2253 { 2254 errPrintln(ce.getMessageObject()); 2255 cancelled = true; 2256 } 2257 } 2258 if (!cancelled 2259 && configureReplicationServer1 2260 && !replicationServer1Configured) 2261 { 2262 boolean tryWithDefault = argParser.getReplicationPort1() != -1; 2263 while (replicationPort1 == -1) 2264 { 2265 if (tryWithDefault) 2266 { 2267 replicationPort1 = argParser.getReplicationPort1(); 2268 tryWithDefault = false; 2269 } 2270 else 2271 { 2272 replicationPort1 = askPort( 2273 INFO_REPLICATION_ENABLE_REPLICATIONPORT1_PROMPT.get(), 2274 getDefaultValue(argParser.server1.replicationPortArg), logger); 2275 println(); 2276 } 2277 if (!argParser.skipReplicationPortCheck() && isLocalHost(host1)) 2278 { 2279 if (!SetupUtils.canUseAsPort(replicationPort1)) 2280 { 2281 errPrintln(); 2282 errPrintln(getCannotBindToPortError(replicationPort1)); 2283 errPrintln(); 2284 replicationPort1 = -1; 2285 } 2286 } 2287 else if (replicationPort1 == port1) 2288 { 2289 // This is something that we must do in any case... this test is 2290 // already included when we call SetupUtils.canUseAsPort 2291 errPrintln(); 2292 errPrintln(ERR_REPLICATION_PORT_AND_REPLICATION_PORT_EQUAL.get(host1, replicationPort1)); 2293 errPrintln(); 2294 replicationPort1 = -1; 2295 } 2296 } 2297 if (!secureReplication1) 2298 { 2299 try 2300 { 2301 secureReplication1 = 2302 askConfirmation(INFO_REPLICATION_ENABLE_SECURE1_PROMPT.get(replicationPort1), 2303 false, logger); 2304 } 2305 catch (ClientException ce) 2306 { 2307 errPrintln(ce.getMessageObject()); 2308 cancelled = true; 2309 } 2310 println(); 2311 } 2312 } 2313 if (!cancelled && 2314 configureReplicationDomain1 && 2315 configureReplicationServer1 && 2316 argParser.advancedArg.isPresent()) 2317 { 2318 // Only necessary to ask if the replication server will be configured 2319 try 2320 { 2321 configureReplicationDomain1 = askConfirmation( 2322 INFO_REPLICATION_ENABLE_REPLICATION_DOMAIN1_PROMPT.get(), 2323 true, logger); 2324 } 2325 catch (ClientException ce) 2326 { 2327 errPrintln(ce.getMessageObject()); 2328 cancelled = true; 2329 } 2330 } 2331 // If the server contains an ADS. Try to load it and only load it: if 2332 // there are issues with the ADS they will be encountered in the 2333 // enableReplication(EnableReplicationUserData) method. Here we have 2334 // to load the ADS to ask the user to accept the certificates and 2335 // eventually admin authentication data. 2336 if (!cancelled) 2337 { 2338 AtomicReference<InitialLdapContext> aux = new AtomicReference<>(ctx1); 2339 cancelled = !loadADSAndAcceptCertificates(sourceServerCI, aux, uData, true); 2340 ctx1 = aux.get(); 2341 } 2342 if (!cancelled) 2343 { 2344 administratorDefined |= hasAdministrator(ctx1); 2345 if (uData.getAdminPwd() != null) 2346 { 2347 adminPwd = uData.getAdminPwd(); 2348 } 2349 } 2350 } 2351 uData.getServer1().setReplicationPort(replicationPort1); 2352 uData.getServer1().setSecureReplication(secureReplication1); 2353 uData.getServer1().setConfigureReplicationServer(configureReplicationServer1); 2354 uData.getServer1().setConfigureReplicationDomain(configureReplicationDomain1); 2355 firstServerCommandBuilder = new CommandBuilder(); 2356 if (mustPrintCommandBuilder()) 2357 { 2358 firstServerCommandBuilder.append(sourceServerCI.getCommandBuilder()); 2359 } 2360 2361 /* Prompt for information on the second server. */ 2362 String host2 = null; 2363 int port2 = -1; 2364 String bindDn2 = null; 2365 String pwd2 = null; 2366 LDAPConnectionConsoleInteraction destinationServerCI = new LDAPConnectionConsoleInteraction(this, 2367 argParser.getSecureArgsList()); 2368 destinationServerCI.resetHeadingDisplayed(); 2369 2370 boolean doNotDisplayFirstError = false; 2371 2372 if (!cancelled) 2373 { 2374 host2 = getValue(argParser.server2.hostNameArg); 2375 port2 = getValue(argParser.server2.portArg); 2376 bindDn2 = getValue(argParser.server2.bindDnArg); 2377 pwd2 = argParser.server2.getBindPassword(); 2378 2379 pwdFile = null; 2380 pwd = null; 2381 if (argParser.server2.bindPasswordArg.isPresent()) 2382 { 2383 pwd = argParser.server2.bindPasswordArg.getValue(); 2384 } 2385 else if (argParser.server2.bindPasswordFileArg.isPresent()) 2386 { 2387 pwdFile = argParser.server2.bindPasswordFileArg.getNameToValueMap(); 2388 } 2389 else if (bindDn2 == null) 2390 { 2391 doNotDisplayFirstError = true; 2392 pwd = adminPwd; 2393 if (argParser.getSecureArgsList().getBindPasswordFileArg().isPresent()) 2394 { 2395 pwdFile = argParser.getSecureArgsList().getBindPasswordFileArg(). 2396 getNameToValueMap(); 2397 } 2398 } 2399 2400 /* 2401 * Use a copy of the argument properties since the map might be cleared 2402 * in initializeGlobalArguments. 2403 */ 2404 destinationServerCI.initializeGlobalArguments(host2, port2, adminUid, bindDn2, pwd, 2405 pwdFile == null ? null : new LinkedHashMap<String, String>(pwdFile)); 2406 destinationServerCI.setUseAdminOrBindDn(true); 2407 } 2408 InitialLdapContext ctx2 = null; 2409 2410 while (ctx2 == null && !cancelled) 2411 { 2412 try 2413 { 2414 destinationServerCI.setHeadingMessage(INFO_REPLICATION_ENABLE_HOST2_CONNECTION_PARAMETERS.get()); 2415 destinationServerCI.run(); 2416 host2 = destinationServerCI.getHostName(); 2417 port2 = destinationServerCI.getPortNumber(); 2418 if (destinationServerCI.getProvidedAdminUID() != null) 2419 { 2420 adminUid = destinationServerCI.getProvidedAdminUID(); 2421 if (destinationServerCI.getProvidedBindDN() == null) 2422 { 2423 // If the explicit bind DN is not null, the password corresponds 2424 // to that bind DN. We are in the case where the user provides 2425 // bind DN on first server and admin UID globally. 2426 adminPwd = destinationServerCI.getBindPassword(); 2427 } 2428 } 2429 bindDn2 = destinationServerCI.getBindDN(); 2430 pwd2 = destinationServerCI.getBindPassword(); 2431 2432 boolean error = false; 2433 if (host1.equalsIgnoreCase(host2) && port1 == port2) 2434 { 2435 port2 = -1; 2436 errPrintln(); 2437 errPrintln(ERR_REPLICATION_ENABLE_SAME_SERVER_PORT.get(host1, port1)); 2438 errPrintln(); 2439 error = true; 2440 } 2441 2442 if (!error) 2443 { 2444 ctx2 = createInitialLdapContextInteracting(destinationServerCI, true); 2445 if (ctx2 == null) 2446 { 2447 cancelled = true; 2448 } 2449 } 2450 } 2451 catch (ClientException ce) 2452 { 2453 logger.warn(LocalizableMessage.raw("Client exception "+ce)); 2454 if (!doNotDisplayFirstError) 2455 { 2456 errPrintln(); 2457 errPrintln(ce.getMessageObject()); 2458 errPrintln(); 2459 destinationServerCI.resetConnectionArguments(); 2460 } 2461 else 2462 { 2463 // Reset only the credential parameters. 2464 destinationServerCI.resetConnectionArguments(); 2465 destinationServerCI.initializeGlobalArguments(host2, port2, null, null, null, null); 2466 } 2467 } 2468 catch (ArgumentException ae) 2469 { 2470 logger.warn(LocalizableMessage.raw("Argument exception "+ae)); 2471 argParser.displayMessageAndUsageReference(getErrStream(), ae.getMessageObject()); 2472 cancelled = true; 2473 } 2474 finally 2475 { 2476 doNotDisplayFirstError = false; 2477 } 2478 } 2479 2480 if (!cancelled) 2481 { 2482 uData.getServer2().setHostName(host2); 2483 uData.getServer2().setPort(port2); 2484 uData.getServer2().setBindDn(bindDn2); 2485 uData.getServer2().setPwd(pwd2); 2486 } 2487 2488 int replicationPort2 = -1; 2489 boolean secureReplication2 = argParser.server2.secureReplicationArg.isPresent(); 2490 boolean configureReplicationServer2 = argParser.server2.configureReplicationServer(); 2491 boolean configureReplicationDomain2 = argParser.server2.configureReplicationDomain(); 2492 if (ctx2 != null) 2493 { 2494 int repPort2 = getReplicationPort(ctx2); 2495 boolean replicationServer2Configured = repPort2 > 0; 2496 if (replicationServer2Configured && !configureReplicationServer2) 2497 { 2498 final LocalizableMessage prompt = 2499 INFO_REPLICATION_SERVER_CONFIGURED_WARNING_PROMPT.get(getHostPort(ctx2), repPort2); 2500 if (!askConfirmation(prompt, false)) 2501 { 2502 cancelled = true; 2503 } 2504 } 2505 2506 // Try to get the replication port for server 2 only if it is required. 2507 if (!cancelled 2508 && configureReplicationServer2 2509 && !replicationServer2Configured) 2510 { 2511 // Only ask if the replication domain will be configured (if not the 2512 // replication server MUST be configured). 2513 if (argParser.advancedArg.isPresent() && 2514 configureReplicationDomain2) 2515 { 2516 try 2517 { 2518 configureReplicationServer2 = askConfirmation( 2519 INFO_REPLICATION_ENABLE_REPLICATION_SERVER2_PROMPT.get(), 2520 true, logger); 2521 } 2522 catch (ClientException ce) 2523 { 2524 errPrintln(ce.getMessageObject()); 2525 cancelled = true; 2526 } 2527 } 2528 if (!cancelled 2529 && configureReplicationServer2 2530 && !replicationServer2Configured) 2531 { 2532 boolean tryWithDefault = argParser.getReplicationPort2() != -1; 2533 while (replicationPort2 == -1) 2534 { 2535 if (tryWithDefault) 2536 { 2537 replicationPort2 = argParser.getReplicationPort2(); 2538 tryWithDefault = false; 2539 } 2540 else 2541 { 2542 replicationPort2 = askPort( 2543 INFO_REPLICATION_ENABLE_REPLICATIONPORT2_PROMPT.get(), 2544 getDefaultValue(argParser.server2.replicationPortArg), logger); 2545 println(); 2546 } 2547 if (!argParser.skipReplicationPortCheck() && 2548 isLocalHost(host2)) 2549 { 2550 if (!SetupUtils.canUseAsPort(replicationPort2)) 2551 { 2552 errPrintln(); 2553 errPrintln(getCannotBindToPortError(replicationPort2)); 2554 errPrintln(); 2555 replicationPort2 = -1; 2556 } 2557 } 2558 else if (replicationPort2 == port2) 2559 { 2560 // This is something that we must do in any case... this test is 2561 // already included when we call SetupUtils.canUseAsPort 2562 errPrintln(); 2563 errPrintln(ERR_REPLICATION_PORT_AND_REPLICATION_PORT_EQUAL.get(host2, replicationPort2)); 2564 replicationPort2 = -1; 2565 } 2566 if (host1.equalsIgnoreCase(host2) 2567 && replicationPort1 > 0 2568 && replicationPort1 == replicationPort2) 2569 { 2570 errPrintln(); 2571 errPrintln(ERR_REPLICATION_SAME_REPLICATION_PORT.get(replicationPort2, host1)); 2572 errPrintln(); 2573 replicationPort2 = -1; 2574 } 2575 } 2576 if (!secureReplication2) 2577 { 2578 try 2579 { 2580 secureReplication2 = 2581 askConfirmation(INFO_REPLICATION_ENABLE_SECURE2_PROMPT.get(replicationPort2), false, logger); 2582 } 2583 catch (ClientException ce) 2584 { 2585 errPrintln(ce.getMessageObject()); 2586 cancelled = true; 2587 } 2588 println(); 2589 } 2590 } 2591 } 2592 if (!cancelled && 2593 configureReplicationDomain2 && 2594 configureReplicationServer2 && 2595 argParser.advancedArg.isPresent()) 2596 { 2597 // Only necessary to ask if the replication server will be configured 2598 try 2599 { 2600 configureReplicationDomain2 = askConfirmation( 2601 INFO_REPLICATION_ENABLE_REPLICATION_DOMAIN2_PROMPT.get(), 2602 true, logger); 2603 } 2604 catch (ClientException ce) 2605 { 2606 errPrintln(ce.getMessageObject()); 2607 cancelled = true; 2608 } 2609 } 2610 // If the server contains an ADS. Try to load it and only load it: if 2611 // there are issues with the ADS they will be encountered in the 2612 // enableReplication(EnableReplicationUserData) method. Here we have 2613 // to load the ADS to ask the user to accept the certificates. 2614 if (!cancelled) 2615 { 2616 AtomicReference<InitialLdapContext> aux = new AtomicReference<>(ctx2); 2617 cancelled = !loadADSAndAcceptCertificates(destinationServerCI, aux, uData, false); 2618 ctx2 = aux.get(); 2619 } 2620 if (!cancelled) 2621 { 2622 administratorDefined |= hasAdministrator(ctx2); 2623 } 2624 } 2625 uData.getServer2().setReplicationPort(replicationPort2); 2626 uData.getServer2().setSecureReplication(secureReplication2); 2627 uData.getServer2().setConfigureReplicationServer(configureReplicationServer2); 2628 uData.getServer2().setConfigureReplicationDomain(configureReplicationDomain2); 2629 2630 // If the adminUid and adminPwd are not set in the EnableReplicationUserData 2631 // object, that means that there are no administrators and that they 2632 // must be created. The adminUId and adminPwd are updated inside 2633 // loadADSAndAcceptCertificates. 2634 boolean promptedForAdmin = false; 2635 2636 // There is a case where we haven't had need for the administrator 2637 // credentials even if the administrators are defined: where all the servers 2638 // can be accessed with another user (for instance if all the server have 2639 // defined cn=directory manager and all the entries have the same password). 2640 if (!cancelled && uData.getAdminUid() == null && !administratorDefined) 2641 { 2642 if (adminUid == null) 2643 { 2644 println(INFO_REPLICATION_ENABLE_ADMINISTRATOR_MUST_BE_CREATED.get()); 2645 promptedForAdmin = true; 2646 adminUid= askForAdministratorUID( 2647 getDefaultValue(argParser.getAdminUidArg()), logger); 2648 println(); 2649 } 2650 uData.setAdminUid(adminUid); 2651 } 2652 2653 if (uData.getAdminPwd() == null) 2654 { 2655 uData.setAdminPwd(adminPwd); 2656 } 2657 if (!cancelled && uData.getAdminPwd() == null && !administratorDefined) 2658 { 2659 adminPwd = null; 2660 int nPasswordPrompts = 0; 2661 while (adminPwd == null) 2662 { 2663 if (nPasswordPrompts > CONFIRMATION_MAX_TRIES) 2664 { 2665 errPrintln(ERR_CONFIRMATION_TRIES_LIMIT_REACHED.get( 2666 CONFIRMATION_MAX_TRIES)); 2667 cancelled = true; 2668 break; 2669 } 2670 nPasswordPrompts ++; 2671 if (!promptedForAdmin) 2672 { 2673 println(); 2674 println(INFO_REPLICATION_ENABLE_ADMINISTRATOR_MUST_BE_CREATED.get()); 2675 println(); 2676 } 2677 while (adminPwd == null) 2678 { 2679 adminPwd = askForAdministratorPwd(logger); 2680 println(); 2681 } 2682 String adminPwdConfirm = null; 2683 while (adminPwdConfirm == null) 2684 { 2685 try 2686 { 2687 adminPwdConfirm = String.valueOf(readPassword(INFO_ADMINISTRATOR_PWD_CONFIRM_PROMPT.get())); 2688 } 2689 catch (ClientException ex) 2690 { 2691 logger.warn(LocalizableMessage.raw("Error reading input: " + ex, ex)); 2692 } 2693 println(); 2694 } 2695 if (!adminPwd.equals(adminPwdConfirm)) 2696 { 2697 println(); 2698 errPrintln(ERR_ADMINISTRATOR_PWD_DO_NOT_MATCH.get()); 2699 println(); 2700 adminPwd = null; 2701 } 2702 } 2703 uData.setAdminPwd(adminPwd); 2704 } 2705 2706 if (!cancelled) 2707 { 2708 List<String> suffixes = argParser.getBaseDNs(); 2709 checkSuffixesForEnableReplication(suffixes, ctx1, ctx2, true, uData); 2710 cancelled = suffixes.isEmpty(); 2711 2712 uData.setBaseDNs(suffixes); 2713 } 2714 2715 close(ctx1, ctx2); 2716 uData.setReplicateSchema(!argParser.noSchemaReplication()); 2717 2718 return !cancelled; 2719 } 2720 2721 /** 2722 * Updates the contents of the provided DisableReplicationUserData object 2723 * with the information provided in the command-line. If some information 2724 * is missing, ask the user to provide valid data. 2725 * We assume that if this method is called we are in interactive mode. 2726 * @param uData the object to be updated. 2727 * @return <CODE>true</CODE> if the object was successfully updated and 2728 * <CODE>false</CODE> if the user cancelled the operation. 2729 * @throws ReplicationCliException if there is a critical error reading the 2730 * ADS. 2731 */ 2732 private boolean promptIfRequired(DisableReplicationUserData uData) 2733 throws ReplicationCliException 2734 { 2735 boolean cancelled = false; 2736 2737 String adminPwd = argParser.getBindPasswordAdmin(); 2738 String adminUid = argParser.getAdministratorUID(); 2739 String bindDn = argParser.getBindDNToDisable(); 2740 2741 // This is done because we want to ask explicitly for this 2742 2743 String host = argParser.getHostNameToDisable(); 2744 int port = argParser.getPortToDisable(); 2745 2746 /* Try to connect to the server. */ 2747 InitialLdapContext ctx = null; 2748 2749 while (ctx == null && !cancelled) 2750 { 2751 try 2752 { 2753 sourceServerCI.setUseAdminOrBindDn(true); 2754 sourceServerCI.run(); 2755 host = sourceServerCI.getHostName(); 2756 port = sourceServerCI.getPortNumber(); 2757 bindDn = sourceServerCI.getProvidedBindDN(); 2758 adminUid = sourceServerCI.getProvidedAdminUID(); 2759 adminPwd = sourceServerCI.getBindPassword(); 2760 2761 ctx = createInitialLdapContextInteracting(sourceServerCI); 2762 if (ctx == null) 2763 { 2764 cancelled = true; 2765 } 2766 } 2767 catch (ClientException ce) 2768 { 2769 logger.warn(LocalizableMessage.raw("Client exception "+ce)); 2770 errPrintln(); 2771 errPrintln(ce.getMessageObject()); 2772 errPrintln(); 2773 sourceServerCI.resetConnectionArguments(); 2774 } 2775 catch (ArgumentException ae) 2776 { 2777 logger.warn(LocalizableMessage.raw("Argument exception "+ae)); 2778 argParser.displayMessageAndUsageReference(getErrStream(), ae.getMessageObject()); 2779 cancelled = true; 2780 } 2781 } 2782 2783 if (!cancelled) 2784 { 2785 uData.setHostName(host); 2786 uData.setPort(port); 2787 uData.setAdminUid(adminUid); 2788 uData.setBindDn(bindDn); 2789 uData.setAdminPwd(adminPwd); 2790 } 2791 if (ctx != null && adminUid != null) 2792 { 2793 // If the server contains an ADS, try to load it and only load it: if 2794 // there are issues with the ADS they will be encountered in the 2795 // disableReplication(DisableReplicationUserData) method. Here we have 2796 // to load the ADS to ask the user to accept the certificates and 2797 // eventually admin authentication data. 2798 AtomicReference<InitialLdapContext> aux = new AtomicReference<>(ctx); 2799 cancelled = !loadADSAndAcceptCertificates(sourceServerCI, aux, uData, false); 2800 ctx = aux.get(); 2801 } 2802 2803 boolean disableAll = argParser.disableAllArg.isPresent(); 2804 boolean disableReplicationServer = 2805 argParser.disableReplicationServerArg.isPresent(); 2806 if (disableAll || 2807 (argParser.advancedArg.isPresent() && 2808 argParser.getBaseDNs().isEmpty() && 2809 !disableReplicationServer)) 2810 { 2811 try 2812 { 2813 disableAll = askConfirmation(INFO_REPLICATION_PROMPT_DISABLE_ALL.get(), 2814 disableAll, logger); 2815 } 2816 catch (ClientException ce) 2817 { 2818 errPrintln(ce.getMessageObject()); 2819 cancelled = true; 2820 } 2821 } 2822 int repPort = getReplicationPort(ctx); 2823 if (!disableAll 2824 && (argParser.advancedArg.isPresent() || disableReplicationServer) 2825 && repPort > 0) 2826 { 2827 try 2828 { 2829 disableReplicationServer = askConfirmation( 2830 INFO_REPLICATION_PROMPT_DISABLE_REPLICATION_SERVER.get(repPort), 2831 disableReplicationServer, 2832 logger); 2833 } 2834 catch (ClientException ce) 2835 { 2836 errPrintln(ce.getMessageObject()); 2837 cancelled = true; 2838 } 2839 } 2840 if (disableReplicationServer && repPort < 0) 2841 { 2842 disableReplicationServer = false; 2843 final LocalizableMessage msg = INFO_REPLICATION_PROMPT_NO_REPLICATION_SERVER_TO_DISABLE.get(getHostPort(ctx)); 2844 try 2845 { 2846 cancelled = askConfirmation(msg, false, logger); 2847 } 2848 catch (ClientException ce) 2849 { 2850 errPrintln(ce.getMessageObject()); 2851 cancelled = true; 2852 } 2853 } 2854 if (repPort > 0 && disableAll) 2855 { 2856 disableReplicationServer = true; 2857 } 2858 uData.setDisableAll(disableAll); 2859 uData.setDisableReplicationServer(disableReplicationServer); 2860 if (!cancelled && !disableAll) 2861 { 2862 List<String> suffixes = argParser.getBaseDNs(); 2863 checkSuffixesForDisableReplication(suffixes, ctx, true, !disableReplicationServer); 2864 cancelled = suffixes.isEmpty() && !disableReplicationServer; 2865 2866 uData.setBaseDNs(suffixes); 2867 2868 if (!uData.disableReplicationServer() && repPort > 0 && 2869 disableAllBaseDns(ctx, uData) && !argParser.advancedArg.isPresent()) 2870 { 2871 try 2872 { 2873 uData.setDisableReplicationServer(askConfirmation( 2874 INFO_REPLICATION_DISABLE_ALL_SUFFIXES_DISABLE_REPLICATION_SERVER.get(getHostPort(ctx), repPort), true, 2875 logger)); 2876 } 2877 catch (ClientException ce) 2878 { 2879 errPrintln(ce.getMessageObject()); 2880 cancelled = true; 2881 } 2882 } 2883 } 2884 2885 if (!cancelled) 2886 { 2887 // Ask for confirmation to disable if not already done. 2888 boolean disableADS = false; 2889 boolean disableSchema = false; 2890 for (String dn : uData.getBaseDNs()) 2891 { 2892 if (areDnsEqual(ADSContext.getAdministrationSuffixDN(), dn)) 2893 { 2894 disableADS = true; 2895 } 2896 else if (areDnsEqual(Constants.SCHEMA_DN, dn)) 2897 { 2898 disableSchema = true; 2899 } 2900 } 2901 if (disableADS) 2902 { 2903 println(); 2904 LocalizableMessage msg = INFO_REPLICATION_CONFIRM_DISABLE_ADS.get(ADSContext.getAdministrationSuffixDN()); 2905 cancelled = !askConfirmation(msg, true); 2906 println(); 2907 } 2908 if (disableSchema) 2909 { 2910 println(); 2911 LocalizableMessage msg = INFO_REPLICATION_CONFIRM_DISABLE_SCHEMA.get(); 2912 cancelled = !askConfirmation(msg, true); 2913 println(); 2914 } 2915 if (!disableSchema && !disableADS) 2916 { 2917 println(); 2918 if (!uData.disableAll() && !uData.getBaseDNs().isEmpty()) 2919 { 2920 cancelled = !askConfirmation(INFO_REPLICATION_CONFIRM_DISABLE_GENERIC.get(), true); 2921 } 2922 println(); 2923 } 2924 } 2925 2926 close(ctx); 2927 2928 return !cancelled; 2929 } 2930 2931 /** 2932 * Updates the contents of the provided InitializeAllReplicationUserData 2933 * object with the information provided in the command-line. If some 2934 * information is missing, ask the user to provide valid data. 2935 * We assume that if this method is called we are in interactive mode. 2936 * @param uData the object to be updated. 2937 * @return <CODE>true</CODE> if the object was successfully updated and 2938 * <CODE>false</CODE> if the user cancelled the operation. 2939 */ 2940 private boolean promptIfRequired(InitializeAllReplicationUserData uData) 2941 { 2942 InitialLdapContext ctx = null; 2943 try 2944 { 2945 ctx = getInitialLdapContext(uData); 2946 if (ctx == null) 2947 { 2948 return false; 2949 } 2950 2951 List<String> suffixes = argParser.getBaseDNs(); 2952 checkSuffixesForInitializeReplication(suffixes, ctx, true); 2953 if (suffixes.isEmpty()) 2954 { 2955 return false; 2956 } 2957 uData.setBaseDNs(suffixes); 2958 2959 // Ask for confirmation to initialize. 2960 println(); 2961 if (!askConfirmation(getPrompt(uData, ctx), true)) 2962 { 2963 return false; 2964 } 2965 println(); 2966 return true; 2967 } 2968 finally 2969 { 2970 close(ctx); 2971 } 2972 } 2973 2974 private LocalizableMessage getPrompt(InitializeAllReplicationUserData uData, InitialLdapContext ctx) 2975 { 2976 String hostPortSource = getHostPort(ctx); 2977 if (initializeADS(uData.getBaseDNs())) 2978 { 2979 return INFO_REPLICATION_CONFIRM_INITIALIZE_ALL_ADS.get(ADSContext.getAdministrationSuffixDN(), hostPortSource); 2980 } 2981 return INFO_REPLICATION_CONFIRM_INITIALIZE_ALL_GENERIC.get(hostPortSource); 2982 } 2983 2984 private boolean askConfirmation(final LocalizableMessage msg, final boolean defaultValue) 2985 { 2986 try 2987 { 2988 return askConfirmation(msg, defaultValue, logger); 2989 } 2990 catch (ClientException ce) 2991 { 2992 errPrintln(ce.getMessageObject()); 2993 return false; 2994 } 2995 } 2996 2997 /** 2998 * Updates the contents of the provided user data 2999 * object with the information provided in the command-line. 3000 * If some information is missing, ask the user to provide valid data. 3001 * We assume that if this method is called we are in interactive mode. 3002 * @param uData the object to be updated. 3003 * @return <CODE>true</CODE> if the object was successfully updated and 3004 * <CODE>false</CODE> if the user cancelled the operation. 3005 */ 3006 private boolean promptIfRequiredForPreOrPost(MonoServerReplicationUserData uData) 3007 { 3008 InitialLdapContext ctx = null; 3009 try 3010 { 3011 ctx = getInitialLdapContext(uData); 3012 if (ctx == null) 3013 { 3014 return false; 3015 } 3016 List<String> suffixes = argParser.getBaseDNs(); 3017 checkSuffixesForInitializeReplication(suffixes, ctx, true); 3018 uData.setBaseDNs(suffixes); 3019 return !suffixes.isEmpty(); 3020 } 3021 finally 3022 { 3023 close(ctx); 3024 } 3025 } 3026 3027 private InitialLdapContext getInitialLdapContext(MonoServerReplicationUserData uData) 3028 { 3029 // Try to connect to the server. 3030 while (true) 3031 { 3032 try 3033 { 3034 if (uData instanceof InitializeAllReplicationUserData) 3035 { 3036 sourceServerCI.setHeadingMessage(INFO_INITIALIZE_SOURCE_CONNECTION_PARAMETERS.get()); 3037 } 3038 sourceServerCI.run(); 3039 3040 InitialLdapContext ctx = createInitialLdapContextInteracting(sourceServerCI); 3041 if (ctx != null) 3042 { 3043 uData.setHostName(sourceServerCI.getHostName()); 3044 uData.setPort(sourceServerCI.getPortNumber()); 3045 uData.setAdminUid(sourceServerCI.getAdministratorUID()); 3046 uData.setAdminPwd(sourceServerCI.getBindPassword()); 3047 if (uData instanceof StatusReplicationUserData) 3048 { 3049 ((StatusReplicationUserData) uData).setScriptFriendly(argParser.isScriptFriendly()); 3050 } 3051 } 3052 return ctx; 3053 } 3054 catch (ClientException ce) 3055 { 3056 logger.warn(LocalizableMessage.raw("Client exception " + ce)); 3057 errPrintln(); 3058 errPrintln(ce.getMessageObject()); 3059 errPrintln(); 3060 sourceServerCI.resetConnectionArguments(); 3061 } 3062 catch (ArgumentException ae) 3063 { 3064 logger.warn(LocalizableMessage.raw("Argument exception " + ae)); 3065 argParser.displayMessageAndUsageReference(getErrStream(), ae.getMessageObject()); 3066 return null; 3067 } 3068 } 3069 } 3070 3071 /** 3072 * Updates the contents of the provided StatusReplicationUserData object 3073 * with the information provided in the command-line. If some information 3074 * is missing, ask the user to provide valid data. 3075 * We assume that if this method is called we are in interactive mode. 3076 * @param uData the object to be updated. 3077 * @return <CODE>true</CODE> if the object was successfully updated and 3078 * <CODE>false</CODE> if the user cancelled the operation. 3079 * @throws ReplicationCliException if a critical error occurs reading the 3080 * ADS. 3081 */ 3082 private boolean promptIfRequired(StatusReplicationUserData uData) 3083 throws ReplicationCliException 3084 { 3085 InitialLdapContext ctx = null; 3086 try 3087 { 3088 ctx = getInitialLdapContext(uData); 3089 if (ctx == null) 3090 { 3091 return false; 3092 } 3093 3094 // If the server contains an ADS, try to load it and only load it: if 3095 // there are issues with the ADS they will be encountered in the 3096 // statusReplication(StatusReplicationUserData) method. Here we have 3097 // to load the ADS to ask the user to accept the certificates and 3098 // eventually admin authentication data. 3099 AtomicReference<InitialLdapContext> aux = new AtomicReference<>(ctx); 3100 boolean cancelled = !loadADSAndAcceptCertificates(sourceServerCI, aux, uData, false); 3101 ctx = aux.get(); 3102 if (cancelled) 3103 { 3104 return false; 3105 } 3106 3107 if (!cancelled) 3108 { 3109 uData.setBaseDNs(argParser.getBaseDNs()); 3110 } 3111 return !cancelled; 3112 } 3113 finally 3114 { 3115 close(ctx); 3116 } 3117 } 3118 3119 /** 3120 * Updates the contents of the provided InitializeReplicationUserData object 3121 * with the information provided in the command-line. If some information 3122 * is missing, ask the user to provide valid data. 3123 * We assume that if this method is called we are in interactive mode. 3124 * @param uData the object to be updated. 3125 * @param serversOperations Additional processing for the command 3126 * @return <CODE>true</CODE> if the object was successfully updated and 3127 * <CODE>false</CODE> if the user cancelled the operation. 3128 */ 3129 private boolean promptIfRequired(SourceDestinationServerUserData uData, 3130 OperationBetweenSourceAndDestinationServers serversOperations) 3131 { 3132 boolean cancelled = false; 3133 3134 String adminPwd = argParser.getBindPasswordAdmin(); 3135 String adminUid = argParser.getAdministratorUID(); 3136 3137 String hostSource = argParser.getHostNameSource(); 3138 int portSource = argParser.getPortSource(); 3139 3140 Map<String, String> pwdFile = null; 3141 if (argParser.getSecureArgsList().getBindPasswordFileArg().isPresent()) 3142 { 3143 pwdFile = argParser.getSecureArgsList().getBindPasswordFileArg().getNameToValueMap(); 3144 } 3145 3146 /* 3147 * Use a copy of the argument properties since the map might be cleared 3148 * in initializeGlobalArguments. 3149 */ 3150 sourceServerCI.initializeGlobalArguments(hostSource, portSource, adminUid, null, adminPwd, 3151 pwdFile == null ? null : new LinkedHashMap<String, String>(pwdFile)); 3152 /* Try to connect to the source server. */ 3153 InitialLdapContext ctxSource = null; 3154 3155 while (ctxSource == null && !cancelled) 3156 { 3157 try 3158 { 3159 sourceServerCI.setHeadingMessage(INFO_INITIALIZE_SOURCE_CONNECTION_PARAMETERS.get()); 3160 sourceServerCI.run(); 3161 hostSource = sourceServerCI.getHostName(); 3162 portSource = sourceServerCI.getPortNumber(); 3163 adminUid = sourceServerCI.getAdministratorUID(); 3164 adminPwd = sourceServerCI.getBindPassword(); 3165 3166 ctxSource = createInitialLdapContextInteracting(sourceServerCI); 3167 3168 if (ctxSource == null) 3169 { 3170 cancelled = true; 3171 } 3172 } 3173 catch (ClientException ce) 3174 { 3175 logger.warn(LocalizableMessage.raw("Client exception "+ce)); 3176 errPrintln(); 3177 errPrintln(ce.getMessageObject()); 3178 errPrintln(); 3179 sourceServerCI.resetConnectionArguments(); 3180 } 3181 catch (ArgumentException ae) 3182 { 3183 logger.warn(LocalizableMessage.raw("Argument exception "+ae)); 3184 argParser.displayMessageAndUsageReference(getErrStream(), ae.getMessageObject()); 3185 cancelled = true; 3186 } 3187 } 3188 if (!cancelled) 3189 { 3190 uData.setHostNameSource(hostSource); 3191 uData.setPortSource(portSource); 3192 uData.setAdminUid(adminUid); 3193 uData.setAdminPwd(adminPwd); 3194 } 3195 3196 firstServerCommandBuilder = new CommandBuilder(); 3197 if (mustPrintCommandBuilder()) 3198 { 3199 firstServerCommandBuilder.append(sourceServerCI.getCommandBuilder()); 3200 } 3201 3202 /* Prompt for destination server credentials */ 3203 String hostDestination = argParser.getHostNameDestination(); 3204 int portDestination = argParser.getPortDestination(); 3205 3206 /* 3207 * Use a copy of the argument properties since the map might be cleared 3208 * in initializeGlobalArguments. 3209 */ 3210 LDAPConnectionConsoleInteraction destinationServerCI = new LDAPConnectionConsoleInteraction(this, 3211 argParser.getSecureArgsList()); 3212 destinationServerCI.initializeGlobalArguments(hostDestination, portDestination, adminUid, null, adminPwd, 3213 pwdFile == null ? null : new LinkedHashMap<String, String>(pwdFile)); 3214 /* Try to connect to the destination server. */ 3215 InitialLdapContext ctxDestination = null; 3216 3217 destinationServerCI.resetHeadingDisplayed(); 3218 while (ctxDestination == null && !cancelled) 3219 { 3220 try 3221 { 3222 destinationServerCI.setHeadingMessage(INFO_INITIALIZE_DESTINATION_CONNECTION_PARAMETERS.get()); 3223 destinationServerCI.run(); 3224 hostDestination = destinationServerCI.getHostName(); 3225 portDestination = destinationServerCI.getPortNumber(); 3226 3227 boolean error = false; 3228 if (hostSource.equalsIgnoreCase(hostDestination) 3229 && portSource == portDestination) 3230 { 3231 portDestination = -1; 3232 errPrintln(); 3233 errPrintln(ERR_SOURCE_DESTINATION_INITIALIZE_SAME_SERVER_PORT.get(hostSource, portSource)); 3234 errPrintln(); 3235 error = true; 3236 } 3237 3238 if (!error) 3239 { 3240 ctxDestination = createInitialLdapContextInteracting(destinationServerCI, true); 3241 3242 if (ctxDestination == null) 3243 { 3244 cancelled = true; 3245 } 3246 } 3247 } 3248 catch (ClientException ce) 3249 { 3250 logger.warn(LocalizableMessage.raw("Client exception "+ce)); 3251 errPrintln(); 3252 errPrintln(ce.getMessageObject()); 3253 errPrintln(); 3254 destinationServerCI.resetConnectionArguments(); 3255 } 3256 catch (ArgumentException ae) 3257 { 3258 logger.warn(LocalizableMessage.raw("Argument exception "+ae)); 3259 argParser.displayMessageAndUsageReference(getErrStream(), ae.getMessageObject()); 3260 cancelled = true; 3261 } 3262 } 3263 if (!cancelled) 3264 { 3265 uData.setHostNameDestination(hostDestination); 3266 uData.setPortDestination(portDestination); 3267 } 3268 3269 if (!cancelled) 3270 { 3271 List<String> suffixes = argParser.getBaseDNs(); 3272 cancelled = serversOperations.continueAfterUserInput(suffixes, ctxSource, ctxDestination, true); 3273 uData.setBaseDNs(suffixes); 3274 } 3275 3276 if (!cancelled) 3277 { 3278 println(); 3279 cancelled = serversOperations.confirmOperation(uData, ctxSource, ctxDestination, true); 3280 println(); 3281 } 3282 3283 close(ctxSource, ctxDestination); 3284 return !cancelled; 3285 } 3286 3287 private LocalizableMessage getInitializeReplicationPrompt(SourceDestinationServerUserData uData, 3288 InitialLdapContext ctxSource, InitialLdapContext ctxDestination) 3289 { 3290 String hostPortSource = getHostPort(ctxSource); 3291 String hostPortDestination = getHostPort(ctxDestination); 3292 if (initializeADS(uData.getBaseDNs())) 3293 { 3294 final String adminSuffixDN = ADSContext.getAdministrationSuffixDN(); 3295 return INFO_REPLICATION_CONFIRM_INITIALIZE_ADS.get(adminSuffixDN, hostPortDestination, hostPortSource); 3296 } 3297 return INFO_REPLICATION_CONFIRM_INITIALIZE_GENERIC.get(hostPortDestination, hostPortSource); 3298 } 3299 3300 private boolean initializeADS(List<String> baseDNs) 3301 { 3302 for (String dn : baseDNs) 3303 { 3304 if (areDnsEqual(ADSContext.getAdministrationSuffixDN(), dn)) 3305 { 3306 return true; 3307 } 3308 } 3309 return false; 3310 } 3311 3312 /** 3313 * Returns the trust manager to be used by this application. 3314 * @param ci the LDAP connection to the server 3315 * @return the trust manager to be used by this application. 3316 */ 3317 private ApplicationTrustManager getTrustManager(LDAPConnectionConsoleInteraction ci) 3318 { 3319 return isInteractive() ? ci.getTrustManager() : argParser.getTrustManager(); 3320 } 3321 3322 /** 3323 * Initializes the contents of the provided enable replication user data 3324 * object with what was provided in the command-line without prompting to the 3325 * user. 3326 * @param uData the enable replication user data object to be initialized. 3327 */ 3328 private void initializeWithArgParser(EnableReplicationUserData uData) 3329 { 3330 initialize(uData); 3331 3332 final String adminDN = getAdministratorDN(uData.getAdminUid()); 3333 final String adminPwd = uData.getAdminPwd(); 3334 setConnectionDetails(uData.getServer1(), argParser.server1, adminDN, adminPwd); 3335 setConnectionDetails(uData.getServer2(), argParser.server2, adminDN, adminPwd); 3336 3337 uData.setReplicateSchema(!argParser.noSchemaReplication()); 3338 3339 setReplicationDetails(uData.getServer1(), argParser.server1); 3340 setReplicationDetails(uData.getServer2(), argParser.server2); 3341 } 3342 3343 private void setConnectionDetails( 3344 EnableReplicationServerData server, ServerArgs args, String adminDN, String adminPwd) 3345 { 3346 server.setHostName(getValueOrDefault(args.hostNameArg)); 3347 server.setPort(getValueOrDefault(args.portArg)); 3348 3349 String pwd = args.getBindPassword(); 3350 if (pwd == null) 3351 { 3352 server.setBindDn(adminDN); 3353 server.setPwd(adminPwd); 3354 } 3355 else 3356 { 3357 // Best-effort: try to use admin, if it does not work, use bind DN. 3358 try 3359 { 3360 InitialLdapContext ctx = createAdministrativeContext(server.getHostName(), server.getPort(), 3361 useSSL, useStartTLS, adminDN, adminPwd, getConnectTimeout(), getTrustManager(sourceServerCI)); 3362 server.setBindDn(adminDN); 3363 server.setPwd(adminPwd); 3364 ctx.close(); 3365 } 3366 catch (Throwable t) 3367 { 3368 server.setBindDn(getValueOrDefault(args.bindDnArg)); 3369 server.setPwd(pwd); 3370 } 3371 } 3372 } 3373 3374 private void setReplicationDetails(EnableReplicationServerData server, ServerArgs args) 3375 { 3376 server.setSecureReplication(args.secureReplicationArg.isPresent()); 3377 server.setConfigureReplicationDomain(args.configureReplicationDomain()); 3378 server.setConfigureReplicationServer(args.configureReplicationServer()); 3379 if (server.configureReplicationServer()) 3380 { 3381 server.setReplicationPort(getValueOrDefault(args.replicationPortArg)); 3382 } 3383 } 3384 3385 /** 3386 * Initializes the contents of the provided initialize replication user data 3387 * object with what was provided in the command-line without prompting to the 3388 * user. 3389 * @param uData the initialize replication user data object to be initialized. 3390 */ 3391 private void initializeWithArgParser(SourceDestinationServerUserData uData) 3392 { 3393 initialize(uData); 3394 3395 uData.setHostNameSource(argParser.getHostNameSourceOrDefault()); 3396 uData.setPortSource(argParser.getPortSourceOrDefault()); 3397 uData.setHostNameDestination(argParser.getHostNameDestinationOrDefault()); 3398 uData.setPortDestination(argParser.getPortDestinationOrDefault()); 3399 } 3400 3401 /** 3402 * Initializes the contents of the provided disable replication user data 3403 * object with what was provided in the command-line without prompting to the 3404 * user. 3405 * @param uData the disable replication user data object to be initialized. 3406 */ 3407 private void initializeWithArgParser(DisableReplicationUserData uData) 3408 { 3409 uData.setBaseDNs(new LinkedList<String>(argParser.getBaseDNs())); 3410 String adminUid = argParser.getAdministratorUID(); 3411 String bindDn = argParser.getBindDNToDisable(); 3412 if (bindDn == null && adminUid == null) 3413 { 3414 adminUid = argParser.getAdministratorUIDOrDefault(); 3415 bindDn = getAdministratorDN(adminUid); 3416 } 3417 uData.setAdminUid(adminUid); 3418 uData.setBindDn(bindDn); 3419 uData.setAdminPwd(argParser.getBindPasswordAdmin()); 3420 3421 uData.setHostName(argParser.getHostNameToDisableOrDefault()); 3422 uData.setPort(argParser.getPortToDisableOrDefault()); 3423 3424 uData.setDisableAll(argParser.disableAllArg.isPresent()); 3425 uData.setDisableReplicationServer(argParser.disableReplicationServerArg.isPresent()); 3426 } 3427 3428 /** 3429 * Initializes the contents of the provided user data object with what was 3430 * provided in the command-line without prompting to the user. 3431 * @param uData the user data object to be initialized. 3432 */ 3433 private void initializeWithArgParser(MonoServerReplicationUserData uData) 3434 { 3435 initialize(uData); 3436 3437 uData.setHostName(argParser.getHostNameToInitializeAllOrDefault()); 3438 uData.setPort(argParser.getPortToInitializeAllOrDefault()); 3439 } 3440 3441 /** 3442 * Initializes the contents of the provided status replication user data 3443 * object with what was provided in the command-line without prompting to the 3444 * user. 3445 * @param uData the status replication user data object to be initialized. 3446 */ 3447 private void initializeWithArgParser(StatusReplicationUserData uData) 3448 { 3449 initialize(uData); 3450 3451 uData.setHostName(argParser.getHostNameToStatusOrDefault()); 3452 uData.setPort(argParser.getPortToStatusOrDefault()); 3453 uData.setScriptFriendly(argParser.isScriptFriendly()); 3454 } 3455 3456 private void initialize(ReplicationUserData uData) 3457 { 3458 uData.setBaseDNs(new LinkedList<String>(argParser.getBaseDNs())); 3459 uData.setAdminUid(argParser.getAdministratorUIDOrDefault()); 3460 uData.setAdminPwd(argParser.getBindPasswordAdmin()); 3461 } 3462 3463 /** 3464 * Tells whether the server to which the LdapContext is connected has a 3465 * replication port or not. 3466 * @param ctx the InitialLdapContext to be used. 3467 * @return <CODE>true</CODE> if the replication port for the server could 3468 * be found and <CODE>false</CODE> otherwise. 3469 */ 3470 private boolean hasReplicationPort(InitialLdapContext ctx) 3471 { 3472 return getReplicationPort(ctx) != -1; 3473 } 3474 3475 /** 3476 * Returns the replication port of server to which the LdapContext is 3477 * connected and -1 if the replication port could not be found. 3478 * @param ctx the InitialLdapContext to be used. 3479 * @return the replication port of server to which the LdapContext is 3480 * connected and -1 if the replication port could not be found. 3481 */ 3482 private int getReplicationPort(InitialLdapContext ctx) 3483 { 3484 int replicationPort = -1; 3485 try 3486 { 3487 ManagementContext mCtx = LDAPManagementContext.createFromContext( 3488 JNDIDirContextAdaptor.adapt(ctx)); 3489 RootCfgClient root = mCtx.getRootConfiguration(); 3490 3491 ReplicationSynchronizationProviderCfgClient sync = 3492 (ReplicationSynchronizationProviderCfgClient) 3493 root.getSynchronizationProvider("Multimaster Synchronization"); 3494 if (sync.hasReplicationServer()) 3495 { 3496 ReplicationServerCfgClient replicationServer = 3497 sync.getReplicationServer(); 3498 replicationPort = replicationServer.getReplicationPort(); 3499 } 3500 } 3501 catch (Throwable t) 3502 { 3503 logger.warn(LocalizableMessage.raw("Unexpected error retrieving the replication port: " + t, t)); 3504 } 3505 return replicationPort; 3506 } 3507 3508 /** 3509 * Loads the ADS with the provided context. If there are certificates to 3510 * be accepted we prompt them to the user. If there are errors loading the 3511 * servers we display them to the user and we ask for confirmation. If the 3512 * provided ctx is not using Global Administrator credentials, we prompt the 3513 * user to provide them and update the provide ReplicationUserData 3514 * accordingly. 3515 * 3516 * @param ci the LDAP connection to the server 3517 * @param ctx the Ldap context to be used in an array: note the context 3518 * may be modified with the new credentials provided by the user. 3519 * @param uData the ReplicationUserData to be updated. 3520 * @param isFirstOrSourceServer whether this is the first server in the 3521 * enable replication subcommand or the source server in the initialize server 3522 * subcommand. 3523 * @throws ReplicationCliException if a critical error occurred. 3524 * @return <CODE>true</CODE> if everything went fine and the user accepted 3525 * all the certificates and confirmed everything. Returns <CODE>false</CODE> 3526 * if the user did not accept a certificate or any of the confirmation 3527 * messages. 3528 */ 3529 private boolean loadADSAndAcceptCertificates(LDAPConnectionConsoleInteraction ci, 3530 AtomicReference<InitialLdapContext> ctx, ReplicationUserData uData, boolean isFirstOrSourceServer) 3531 throws ReplicationCliException 3532 { 3533 boolean cancelled = false; 3534 boolean triedWithUserProvidedAdmin = false; 3535 final InitialLdapContext ctx1 = ctx.get(); 3536 String host = getHostName(ctx1); 3537 int port = getPort(ctx1); 3538 boolean isSSL = isSSL(ctx1); 3539 boolean isStartTLS = isStartTLS(ctx1); 3540 if (getTrustManager(ci) == null) 3541 { 3542 // This is required when the user did connect to the server using SSL or 3543 // Start TLS. In this case LDAPConnectionConsoleInteraction.run does not 3544 // initialize the keystore and the trust manager is null. 3545 forceTrustManagerInitialization(ci); 3546 } 3547 try 3548 { 3549 ADSContext adsContext = new ADSContext(ctx1); 3550 if (adsContext.hasAdminData()) 3551 { 3552 boolean reloadTopology = true; 3553 LinkedList<LocalizableMessage> exceptionMsgs = new LinkedList<>(); 3554 while (reloadTopology && !cancelled) 3555 { 3556 // We must recreate the cache because the trust manager in the 3557 // LDAPConnectionConsoleInteraction object might have changed. 3558 3559 TopologyCache cache = new TopologyCache(adsContext, 3560 getTrustManager(ci), getConnectTimeout()); 3561 cache.getFilter().setSearchMonitoringInformation(false); 3562 cache.getFilter().setSearchBaseDNInformation(false); 3563 cache.setPreferredConnections(getPreferredConnections(ctx1)); 3564 cache.reloadTopology(); 3565 3566 reloadTopology = false; 3567 exceptionMsgs.clear(); 3568 3569 /* Analyze if we had any exception while loading servers. For the 3570 * moment only throw the exception found if the user did not provide 3571 * the Administrator DN and this caused a problem authenticating in 3572 * one server or if there is a certificate problem. 3573 */ 3574 Set<TopologyCacheException> exceptions = new HashSet<>(); 3575 Set<ServerDescriptor> servers = cache.getServers(); 3576 for (ServerDescriptor server : servers) 3577 { 3578 TopologyCacheException e = server.getLastException(); 3579 if (e != null) 3580 { 3581 exceptions.add(e); 3582 } 3583 } 3584 /* Check the exceptions and see if we throw them or not. */ 3585 boolean notGlobalAdministratorError = false; 3586 for (TopologyCacheException e : exceptions) 3587 { 3588 if (notGlobalAdministratorError) 3589 { 3590 break; 3591 } 3592 3593 switch (e.getType()) 3594 { 3595 case NOT_GLOBAL_ADMINISTRATOR: 3596 notGlobalAdministratorError = true; 3597 boolean connected = false; 3598 3599 String adminUid = uData.getAdminUid(); 3600 String adminPwd = uData.getAdminPwd(); 3601 3602 boolean errorDisplayed = false; 3603 while (!connected) 3604 { 3605 if (!triedWithUserProvidedAdmin && adminPwd == null) 3606 { 3607 adminUid = argParser.getAdministratorUIDOrDefault(); 3608 adminPwd = argParser.getBindPasswordAdmin(); 3609 triedWithUserProvidedAdmin = true; 3610 } 3611 if (adminPwd == null) 3612 { 3613 if (!errorDisplayed) 3614 { 3615 println(); 3616 println( 3617 INFO_NOT_GLOBAL_ADMINISTRATOR_PROVIDED.get()); 3618 errorDisplayed = true; 3619 } 3620 adminUid = askForAdministratorUID( 3621 getDefaultValue(argParser.getAdminUidArg()), logger); 3622 println(); 3623 adminPwd = askForAdministratorPwd(logger); 3624 println(); 3625 } 3626 close(ctx1); 3627 try 3628 { 3629 final InitialLdapContext ctx2 = createAdministrativeContext(host, port, isSSL, 3630 isStartTLS, getAdministratorDN(adminUid), 3631 adminPwd, getConnectTimeout(), getTrustManager(ci)); 3632 ctx.set(ctx2); 3633 adsContext = new ADSContext(ctx2); 3634 cache = new TopologyCache(adsContext, getTrustManager(ci), 3635 getConnectTimeout()); 3636 cache.getFilter().setSearchMonitoringInformation(false); 3637 cache.getFilter().setSearchBaseDNInformation(false); 3638 cache.setPreferredConnections(getPreferredConnections(ctx2)); 3639 connected = true; 3640 } 3641 catch (Throwable t) 3642 { 3643 errPrintln(); 3644 errPrintln( 3645 ERR_ERROR_CONNECTING_TO_SERVER_PROMPT_AGAIN.get( 3646 getServerRepresentation(host, port), t.getMessage())); 3647 logger.warn(LocalizableMessage.raw("Complete error stack:", t)); 3648 errPrintln(); 3649 } 3650 } 3651 uData.setAdminUid(adminUid); 3652 uData.setAdminPwd(adminPwd); 3653 if (uData instanceof EnableReplicationUserData) 3654 { 3655 EnableReplicationUserData enableData = (EnableReplicationUserData) uData; 3656 EnableReplicationServerData server = 3657 isFirstOrSourceServer ? enableData.getServer1() : enableData.getServer2(); 3658 server.setBindDn(getAdministratorDN(adminUid)); 3659 server.setPwd(adminPwd); 3660 } 3661 reloadTopology = true; 3662 break; 3663 case GENERIC_CREATING_CONNECTION: 3664 if (isCertificateException(e.getCause())) 3665 { 3666 reloadTopology = true; 3667 cancelled = !ci.promptForCertificateConfirmation(e.getCause(), 3668 e.getTrustManager(), e.getLdapUrl(), logger); 3669 } 3670 else 3671 { 3672 exceptionMsgs.add(getMessage(e)); 3673 } 3674 break; 3675 default: 3676 exceptionMsgs.add(getMessage(e)); 3677 } 3678 } 3679 } 3680 if (!exceptionMsgs.isEmpty() && !cancelled) 3681 { 3682 if (uData instanceof StatusReplicationUserData) 3683 { 3684 errPrintln( 3685 ERR_REPLICATION_STATUS_READING_REGISTERED_SERVERS.get( 3686 getMessageFromCollection(exceptionMsgs, 3687 Constants.LINE_SEPARATOR))); 3688 errPrintln(); 3689 } 3690 else 3691 { 3692 LocalizableMessage msg = ERR_REPLICATION_READING_REGISTERED_SERVERS_CONFIRM_UPDATE_REMOTE.get( 3693 getMessageFromCollection(exceptionMsgs, Constants.LINE_SEPARATOR)); 3694 cancelled = !askConfirmation(msg, true); 3695 } 3696 } 3697 } 3698 } 3699 catch (ADSContextException ace) 3700 { 3701 logger.error(LocalizableMessage.raw("Complete error stack:"), ace); 3702 throw new ReplicationCliException( 3703 ERR_REPLICATION_READING_ADS.get(ace.getMessage()), 3704 ERROR_READING_ADS, ace); 3705 } 3706 catch (TopologyCacheException tce) 3707 { 3708 logger.error(LocalizableMessage.raw("Complete error stack:"), tce); 3709 throw new ReplicationCliException( 3710 ERR_REPLICATION_READING_ADS.get(tce.getMessage()), 3711 ERROR_READING_TOPOLOGY_CACHE, tce); 3712 } 3713 return !cancelled; 3714 } 3715 3716 /** 3717 * Tells whether there is a Global Administrator defined in the server 3718 * to which the InitialLdapContext is connected. 3719 * @param ctx the InitialLdapContext. 3720 * @return <CODE>true</CODE> if we could find an administrator and 3721 * <CODE>false</CODE> otherwise. 3722 */ 3723 private boolean hasAdministrator(InitialLdapContext ctx) 3724 { 3725 try 3726 { 3727 ADSContext adsContext = new ADSContext(ctx); 3728 if (adsContext.hasAdminData()) 3729 { 3730 Set<?> administrators = adsContext.readAdministratorRegistry(); 3731 return !administrators.isEmpty(); 3732 } 3733 } 3734 catch (Throwable t) 3735 { 3736 logger.warn(LocalizableMessage.raw( 3737 "Unexpected error retrieving the ADS data: "+t, t)); 3738 } 3739 return false; 3740 } 3741 3742 /** 3743 * Tells whether there is a Global Administrator corresponding to the provided 3744 * ReplicationUserData defined in the server to which the InitialLdapContext 3745 * is connected. 3746 * @param ctx the InitialLdapContext. 3747 * @param uData the user data 3748 * @return <CODE>true</CODE> if we could find an administrator and 3749 * <CODE>false</CODE> otherwise. 3750 */ 3751 private boolean hasAdministrator(InitialLdapContext ctx, 3752 ReplicationUserData uData) 3753 { 3754 String adminUid = uData.getAdminUid(); 3755 try 3756 { 3757 ADSContext adsContext = new ADSContext(ctx); 3758 Set<Map<AdministratorProperty, Object>> administrators = 3759 adsContext.readAdministratorRegistry(); 3760 for (Map<AdministratorProperty, Object> admin : administrators) 3761 { 3762 String uid = (String)admin.get(AdministratorProperty.UID); 3763 // If the administrator UID is null it means that we are just 3764 // checking for the existence of an administrator 3765 if (uid != null && (uid.equalsIgnoreCase(adminUid) || adminUid == null)) 3766 { 3767 return true; 3768 } 3769 } 3770 } 3771 catch (Throwable t) 3772 { 3773 logger.warn(LocalizableMessage.raw( 3774 "Unexpected error retrieving the ADS data: "+t, t)); 3775 } 3776 return false; 3777 } 3778 3779 /** Helper type for the {@link #getCommonSuffixes(InitialLdapContext, InitialLdapContext, SuffixRelationType)}. */ 3780 private enum SuffixRelationType 3781 { 3782 NOT_REPLICATED, FULLY_REPLICATED, REPLICATED, NOT_FULLY_REPLICATED, ALL 3783 } 3784 3785 /** 3786 * Returns a Collection containing a list of suffixes that are defined in 3787 * two servers at the same time (depending on the value of the argument 3788 * replicated this list contains only the suffixes that are replicated 3789 * between the servers or the list of suffixes that are not replicated 3790 * between the servers). 3791 * @param ctx1 the connection to the first server. 3792 * @param ctx2 the connection to the second server. 3793 * @param type whether to return a list with the suffixes that are 3794 * replicated, fully replicated (replicas have exactly the same list of 3795 * replication servers), not replicated or all the common suffixes. 3796 * @return a Collection containing a list of suffixes that are replicated 3797 * (or those that can be replicated) in two servers. 3798 */ 3799 private List<String> getCommonSuffixes(InitialLdapContext ctx1, InitialLdapContext ctx2, SuffixRelationType type) 3800 { 3801 LinkedList<String> suffixes = new LinkedList<>(); 3802 try 3803 { 3804 TopologyCacheFilter filter = new TopologyCacheFilter(); 3805 filter.setSearchMonitoringInformation(false); 3806 ServerDescriptor server1 = ServerDescriptor.createStandalone(ctx1, filter); 3807 ServerDescriptor server2 = ServerDescriptor.createStandalone(ctx2, filter); 3808 3809 for (ReplicaDescriptor rep1 : server1.getReplicas()) 3810 { 3811 for (ReplicaDescriptor rep2 : server2.getReplicas()) 3812 { 3813 String rep1SuffixDN = rep1.getSuffix().getDN(); 3814 String rep2SuffixDN = rep2.getSuffix().getDN(); 3815 boolean areDnsEqual = areDnsEqual(rep1SuffixDN, rep2SuffixDN); 3816 switch (type) 3817 { 3818 case NOT_REPLICATED: 3819 if (!areReplicated(rep1, rep2) && areDnsEqual) 3820 { 3821 suffixes.add(rep1SuffixDN); 3822 } 3823 break; 3824 case FULLY_REPLICATED: 3825 if (areFullyReplicated(rep1, rep2)) 3826 { 3827 suffixes.add(rep1SuffixDN); 3828 } 3829 break; 3830 case REPLICATED: 3831 if (areReplicated(rep1, rep2)) 3832 { 3833 suffixes.add(rep1SuffixDN); 3834 } 3835 break; 3836 case NOT_FULLY_REPLICATED: 3837 if (!areFullyReplicated(rep1, rep2) && areDnsEqual) 3838 { 3839 suffixes.add(rep1SuffixDN); 3840 } 3841 break; 3842 case ALL: 3843 if (areDnsEqual) 3844 { 3845 suffixes.add(rep1SuffixDN); 3846 } 3847 break; 3848 default: 3849 throw new IllegalStateException("Unknown type: "+type); 3850 } 3851 } 3852 } 3853 } 3854 catch (Throwable t) 3855 { 3856 logger.warn(LocalizableMessage.raw( 3857 "Unexpected error retrieving the server configuration: "+t, t)); 3858 } 3859 return suffixes; 3860 } 3861 3862 /** 3863 * Tells whether the two provided replicas are fully replicated or not. The 3864 * code in fact checks that both replicas have the same DN that they are 3865 * replicated if both servers are replication servers and that both replicas 3866 * make reference to the other replication server. 3867 * @param rep1 the first replica. 3868 * @param rep2 the second replica. 3869 * @return <CODE>true</CODE> if we can assure that the two replicas are 3870 * replicated using the replication server and replication port information 3871 * and <CODE>false</CODE> otherwise. 3872 */ 3873 private boolean areFullyReplicated(ReplicaDescriptor rep1, 3874 ReplicaDescriptor rep2) 3875 { 3876 if (areDnsEqual(rep1.getSuffix().getDN(), rep2.getSuffix().getDN()) && 3877 rep1.isReplicated() && rep2.isReplicated() && 3878 rep1.getServer().isReplicationServer() && 3879 rep2.getServer().isReplicationServer()) 3880 { 3881 Set<String> servers1 = rep1.getReplicationServers(); 3882 Set<String> servers2 = rep2.getReplicationServers(); 3883 String server1 = rep1.getServer().getReplicationServerHostPort(); 3884 String server2 = rep2.getServer().getReplicationServerHostPort(); 3885 return servers1.contains(server2) && servers2.contains(server1); 3886 } 3887 return false; 3888 } 3889 3890 /** 3891 * Tells whether the two provided replicas are replicated or not. The 3892 * code in fact checks that both replicas have the same DN and that they 3893 * have at least one common replication server referenced. 3894 * @param rep1 the first replica. 3895 * @param rep2 the second replica. 3896 * @return <CODE>true</CODE> if we can assure that the two replicas are 3897 * replicated and <CODE>false</CODE> otherwise. 3898 */ 3899 private boolean areReplicated(ReplicaDescriptor rep1, ReplicaDescriptor rep2) 3900 { 3901 if (areDnsEqual(rep1.getSuffix().getDN(), rep2.getSuffix().getDN()) && 3902 rep1.isReplicated() && rep2.isReplicated()) 3903 { 3904 Set<String> servers1 = rep1.getReplicationServers(); 3905 Set<String> servers2 = rep2.getReplicationServers(); 3906 servers1.retainAll(servers2); 3907 return !servers1.isEmpty(); 3908 } 3909 return false; 3910 } 3911 3912 /** 3913 * Returns a Collection containing a list of replicas in a server. 3914 * @param ctx the connection to the server. 3915 * @return a Collection containing a list of replicas in a server. 3916 */ 3917 private Collection<ReplicaDescriptor> getReplicas(InitialLdapContext ctx) 3918 { 3919 LinkedList<ReplicaDescriptor> suffixes = new LinkedList<>(); 3920 TopologyCacheFilter filter = new TopologyCacheFilter(); 3921 filter.setSearchMonitoringInformation(false); 3922 try 3923 { 3924 ServerDescriptor server = ServerDescriptor.createStandalone(ctx, filter); 3925 suffixes.addAll(server.getReplicas()); 3926 } 3927 catch (Throwable t) 3928 { 3929 logger.warn(LocalizableMessage.raw( 3930 "Unexpected error retrieving the server configuration: "+t, t)); 3931 } 3932 return suffixes; 3933 } 3934 3935 /** 3936 * Enables the replication between two servers using the parameters in the 3937 * provided EnableReplicationUserData. This method does not prompt to the 3938 * user for information if something is missing. 3939 * @param uData the EnableReplicationUserData object. 3940 * @return ReplicationCliReturnCode.SUCCESSFUL if the operation was 3941 * successful and the replication could be enabled and an error code 3942 * otherwise. 3943 */ 3944 private ReplicationCliReturnCode enableReplication(EnableReplicationUserData uData) 3945 { 3946 InitialLdapContext ctx1 = null; 3947 InitialLdapContext ctx2 = null; 3948 try 3949 { 3950 println(); 3951 print(formatter.getFormattedWithPoints(INFO_REPLICATION_CONNECTING.get())); 3952 3953 LinkedList<LocalizableMessage> errorMessages = new LinkedList<>(); 3954 ctx1 = createAdministrativeContext(uData, true, errorMessages); 3955 ctx2 = createAdministrativeContext(uData, false, errorMessages); 3956 3957 if (!errorMessages.isEmpty()) 3958 { 3959 errPrintLn(errorMessages); 3960 return ERROR_CONNECTING; 3961 } 3962 3963 // This done is for the message informing that we are connecting. 3964 print(formatter.getFormattedDone()); 3965 println(); 3966 3967 if (!argParser.isInteractive()) 3968 { 3969 checksForNonInteractiveMode(uData, ctx1, ctx2, errorMessages); 3970 if (!errorMessages.isEmpty()) 3971 { 3972 errPrintLn(errorMessages); 3973 return ERROR_USER_DATA; 3974 } 3975 } 3976 3977 List<String> suffixes = uData.getBaseDNs(); 3978 checkSuffixesForEnableReplication(suffixes, ctx1, ctx2, false, uData); 3979 if (suffixes.isEmpty()) 3980 { 3981 // The error messages are already displayed in the method 3982 // checkSuffixesForEnableReplication. 3983 return REPLICATION_CANNOT_BE_ENABLED_ON_BASEDN; 3984 } 3985 3986 uData.setBaseDNs(suffixes); 3987 if (mustPrintCommandBuilder()) 3988 { 3989 printNewCommandBuilder(ENABLE_REPLICATION_SUBCMD_NAME, uData); 3990 } 3991 3992 if (!isInteractive()) 3993 { 3994 checkReplicationServerAlreadyConfigured(ctx1, uData.getServer1()); 3995 checkReplicationServerAlreadyConfigured(ctx2, uData.getServer2()); 3996 } 3997 3998 try 3999 { 4000 updateConfiguration(ctx1, ctx2, uData); 4001 printSuccessfullyEnabled(ctx1, ctx2); 4002 return SUCCESSFUL; 4003 } 4004 catch (ReplicationCliException rce) 4005 { 4006 errPrintln(); 4007 errPrintln(getCriticalExceptionMessage(rce)); 4008 logger.error(LocalizableMessage.raw("Complete error stack:"), rce); 4009 return rce.getErrorCode(); 4010 } 4011 } 4012 finally 4013 { 4014 close(ctx1, ctx2); 4015 } 4016 } 4017 4018 private void checkReplicationServerAlreadyConfigured(InitialLdapContext ctx, EnableReplicationServerData server) 4019 { 4020 int repPort = getReplicationPort(ctx); 4021 if (!server.configureReplicationServer() && repPort > 0) 4022 { 4023 println(INFO_REPLICATION_SERVER_CONFIGURED_WARNING.get(getHostPort(ctx), repPort)); 4024 println(); 4025 } 4026 } 4027 4028 private void checksForNonInteractiveMode(EnableReplicationUserData uData, 4029 InitialLdapContext ctx1, InitialLdapContext ctx2, LinkedList<LocalizableMessage> errorMessages) 4030 { 4031 EnableReplicationServerData server1 = uData.getServer1(); 4032 EnableReplicationServerData server2 = uData.getServer2(); 4033 String host1 = server1.getHostName(); 4034 String host2 = server2.getHostName(); 4035 4036 int replPort1 = checkReplicationPort(ctx1, server1, errorMessages); 4037 int replPort2 = checkReplicationPort(ctx2, server2, errorMessages); 4038 if (replPort1 > 0 && replPort1 == replPort2 && host1.equalsIgnoreCase(host2)) 4039 { 4040 errorMessages.add(ERR_REPLICATION_SAME_REPLICATION_PORT.get(replPort1, host1)); 4041 } 4042 4043 if (argParser.skipReplicationPortCheck()) 4044 { 4045 // This is something that we must do in any case... this test is 4046 // already included when we call SetupUtils.canUseAsPort 4047 checkAdminAndReplicationPortsAreDifferent(replPort1, server1, errorMessages); 4048 checkAdminAndReplicationPortsAreDifferent(replPort2, server2, errorMessages); 4049 } 4050 } 4051 4052 private int checkReplicationPort( 4053 InitialLdapContext ctx, EnableReplicationServerData server, LinkedList<LocalizableMessage> errorMessages) 4054 { 4055 int replPort = getReplicationPort(ctx); 4056 boolean hasReplicationPort = replPort > 0; 4057 if (replPort < 0 && server.configureReplicationServer()) 4058 { 4059 replPort = server.getReplicationPort(); 4060 } 4061 boolean checkReplicationPort = replPort > 0; 4062 if (!hasReplicationPort 4063 && checkReplicationPort 4064 && !argParser.skipReplicationPortCheck() 4065 && server.configureReplicationServer() 4066 && isLocalHost(server.getHostName()) 4067 && !SetupUtils.canUseAsPort(replPort)) 4068 { 4069 errorMessages.add(getCannotBindToPortError(replPort)); 4070 } 4071 return replPort; 4072 } 4073 4074 private void checkAdminAndReplicationPortsAreDifferent( 4075 int replPort, EnableReplicationServerData server, LinkedList<LocalizableMessage> errorMessages) 4076 { 4077 if (replPort > 0 && replPort == server.getPort()) 4078 { 4079 errorMessages.add(ERR_REPLICATION_PORT_AND_REPLICATION_PORT_EQUAL.get(server.getHostName(), replPort)); 4080 } 4081 } 4082 4083 private void printSuccessfullyEnabled(InitialLdapContext ctx1, InitialLdapContext ctx2) 4084 { 4085 long time1 = getServerClock(ctx1); 4086 long time2 = getServerClock(ctx2); 4087 if (time1 != -1 4088 && time2 != -1 4089 && Math.abs(time1 - time2) > Installer.THRESHOLD_CLOCK_DIFFERENCE_WARNING * 60 * 1000) 4090 { 4091 println(INFO_WARNING_SERVERS_CLOCK_DIFFERENCE.get(getHostPort(ctx1), getHostPort(ctx2), 4092 Installer.THRESHOLD_CLOCK_DIFFERENCE_WARNING)); 4093 } 4094 println(); 4095 println(INFO_REPLICATION_POST_ENABLE_INFO.get("dsreplication", INITIALIZE_REPLICATION_SUBCMD_NAME)); 4096 println(); 4097 } 4098 4099 private void errPrintLn(LinkedList<LocalizableMessage> errorMessages) 4100 { 4101 for (LocalizableMessage msg : errorMessages) 4102 { 4103 errPrintln(); 4104 errPrintln(msg); 4105 } 4106 } 4107 4108 private InitialLdapContext createAdministrativeContext(EnableReplicationUserData uData, boolean isFirstSetOfValues, 4109 LinkedList<LocalizableMessage> errorMessages) 4110 { 4111 EnableReplicationServerData server = isFirstSetOfValues ? uData.getServer1() : uData.getServer2(); 4112 try 4113 { 4114 return createAdministrativeContext( 4115 server.getHostName(), server.getPort(), useSSL, useStartTLS, server.getBindDn(), server.getPwd(), 4116 getConnectTimeout(), getTrustManager(sourceServerCI)); 4117 } 4118 catch (NamingException ne) 4119 { 4120 String hostPort = getServerRepresentation(server.getHostName(), server.getPort()); 4121 errorMessages.add(getMessageForException(ne, hostPort)); 4122 logger.error(LocalizableMessage.raw("Complete error stack:"), ne); 4123 return null; 4124 } 4125 } 4126 4127 /** 4128 * Disables the replication in the server for the provided suffixes using the 4129 * data in the DisableReplicationUserData object. This method does not prompt 4130 * to the user for information if something is missing. 4131 * @param uData the DisableReplicationUserData object. 4132 * @return ReplicationCliReturnCode.SUCCESSFUL if the operation was 4133 * successful and an error code otherwise. 4134 */ 4135 private ReplicationCliReturnCode disableReplication(DisableReplicationUserData uData) 4136 { 4137 print(formatter.getFormattedWithPoints(INFO_REPLICATION_CONNECTING.get())); 4138 String bindDn = uData.getAdminUid() != null 4139 ? getAdministratorDN(uData.getAdminUid()) 4140 : uData.getBindDn(); 4141 4142 InitialLdapContext ctx = createAdministrativeContext(uData, bindDn); 4143 if (ctx == null) 4144 { 4145 return ERROR_CONNECTING; 4146 } 4147 4148 try 4149 { 4150 // This done is for the message informing that we are connecting. 4151 print(formatter.getFormattedDone()); 4152 println(); 4153 4154 List<String> suffixes = uData.getBaseDNs(); 4155 checkSuffixesForDisableReplication(suffixes, ctx, false, !uData.disableReplicationServer()); 4156 if (suffixes.isEmpty() && !uData.disableReplicationServer() && !uData.disableAll()) 4157 { 4158 return REPLICATION_CANNOT_BE_DISABLED_ON_BASEDN; 4159 } 4160 uData.setBaseDNs(suffixes); 4161 4162 if (!isInteractive()) 4163 { 4164 boolean hasReplicationPort = hasReplicationPort(ctx); 4165 if (uData.disableAll() && hasReplicationPort) 4166 { 4167 uData.setDisableReplicationServer(true); 4168 } 4169 else if (uData.disableReplicationServer() && !hasReplicationPort && !uData.disableAll()) 4170 { 4171 uData.setDisableReplicationServer(false); 4172 println(INFO_REPLICATION_WARNING_NO_REPLICATION_SERVER_TO_DISABLE.get(getHostPort(ctx))); 4173 println(); 4174 } 4175 } 4176 4177 if (mustPrintCommandBuilder()) 4178 { 4179 printNewCommandBuilder(DISABLE_REPLICATION_SUBCMD_NAME, uData); 4180 } 4181 4182 if (!isInteractive() && !uData.disableReplicationServer() && !uData.disableAll() && disableAllBaseDns(ctx, uData) 4183 && hasReplicationPort(ctx)) 4184 { 4185 // Inform the user that the replication server will not be disabled. 4186 // Inform also of the user of the disableReplicationServerArg 4187 println(INFO_REPLICATION_DISABLE_ALL_SUFFIXES_KEEP_REPLICATION_SERVER.get(getHostPort(ctx), 4188 argParser.disableReplicationServerArg.getLongIdentifier(), argParser.disableAllArg.getLongIdentifier())); 4189 } 4190 try 4191 { 4192 updateConfiguration(ctx, uData); 4193 return SUCCESSFUL; 4194 } 4195 catch (ReplicationCliException rce) 4196 { 4197 errPrintln(); 4198 errPrintln(getCriticalExceptionMessage(rce)); 4199 logger.error(LocalizableMessage.raw("Complete error stack:"), rce); 4200 return rce.getErrorCode(); 4201 } 4202 } 4203 finally 4204 { 4205 close(ctx); 4206 } 4207 } 4208 4209 /** 4210 * Displays the replication status of the baseDNs specified in the 4211 * StatusReplicationUserData object. This method does not prompt 4212 * to the user for information if something is missing. 4213 * @param uData the StatusReplicationUserData object. 4214 * @return ReplicationCliReturnCode.SUCCESSFUL if the operation was 4215 * successful and an error code otherwise. 4216 */ 4217 private ReplicationCliReturnCode statusReplication( 4218 StatusReplicationUserData uData) 4219 { 4220 final InitialLdapContext ctx = createAdministrativeContext(uData); 4221 if (ctx == null) 4222 { 4223 return ERROR_CONNECTING; 4224 } 4225 4226 try 4227 { 4228 try 4229 { 4230 displayStatus(ctx, uData); 4231 return SUCCESSFUL; 4232 } 4233 catch (ReplicationCliException rce) 4234 { 4235 errPrintln(); 4236 errPrintln(getCriticalExceptionMessage(rce)); 4237 logger.error(LocalizableMessage.raw("Complete error stack:"), rce); 4238 return rce.getErrorCode(); 4239 } 4240 } 4241 finally 4242 { 4243 close(ctx); 4244 } 4245 } 4246 4247 /** 4248 * Initializes the contents of one server with the contents of the other 4249 * using the parameters in the provided InitializeReplicationUserData. 4250 * This method does not prompt to the user for information if something is 4251 * missing. 4252 * @param uData the InitializeReplicationUserData object. 4253 * @return ReplicationCliReturnCode.SUCCESSFUL if the operation was 4254 * successful and an error code otherwise. 4255 */ 4256 private ReplicationCliReturnCode initializeReplication(SourceDestinationServerUserData uData) 4257 { 4258 InitialLdapContext ctxSource = createAdministrativeContext(uData, uData.getSource()); 4259 InitialLdapContext ctxDestination = createAdministrativeContext(uData, uData.getDestination()); 4260 try 4261 { 4262 if (ctxSource == null || ctxDestination == null) 4263 { 4264 return ERROR_CONNECTING; 4265 } 4266 4267 List<String> baseDNs = uData.getBaseDNs(); 4268 checkSuffixesForInitializeReplication(baseDNs, ctxSource, ctxDestination, false); 4269 if (baseDNs.isEmpty()) 4270 { 4271 return REPLICATION_CANNOT_BE_INITIALIZED_ON_BASEDN; 4272 } 4273 if (mustPrintCommandBuilder()) 4274 { 4275 uData.setBaseDNs(baseDNs); 4276 printNewCommandBuilder(INITIALIZE_REPLICATION_SUBCMD_NAME, uData); 4277 } 4278 4279 ReplicationCliReturnCode returnValue = SUCCESSFUL_NOP; 4280 for (String baseDN : baseDNs) 4281 { 4282 try 4283 { 4284 println(); 4285 print(formatter.getFormattedProgress(INFO_PROGRESS_INITIALIZING_SUFFIX.get(baseDN, getHostPort(ctxSource)))); 4286 println(); 4287 initializeSuffix(baseDN, ctxSource, ctxDestination, true); 4288 returnValue = SUCCESSFUL; 4289 } 4290 catch (ReplicationCliException rce) 4291 { 4292 errPrintln(); 4293 errPrintln(getCriticalExceptionMessage(rce)); 4294 returnValue = rce.getErrorCode(); 4295 logger.error(LocalizableMessage.raw("Complete error stack:"), rce); 4296 } 4297 } 4298 return returnValue; 4299 } 4300 finally 4301 { 4302 close(ctxDestination, ctxSource); 4303 } 4304 } 4305 4306 private InitialLdapContext createAdministrativeContext(SourceDestinationServerUserData uData, HostPort server) 4307 { 4308 try 4309 { 4310 return createAdministrativeContext( 4311 server.getHost(), server.getPort(), useSSL, useStartTLS, 4312 getAdministratorDN(uData.getAdminUid()), uData.getAdminPwd(), 4313 getConnectTimeout(), getTrustManager(sourceServerCI)); 4314 } 4315 catch (NamingException ne) 4316 { 4317 errPrintln(); 4318 errPrintln(getMessageForException(ne, server.toString())); 4319 logger.error(LocalizableMessage.raw("Complete error stack:"), ne); 4320 return null; 4321 } 4322 } 4323 4324 /** 4325 * Initializes the contents of a whole topology with the contents of the other 4326 * using the parameters in the provided InitializeAllReplicationUserData. 4327 * This method does not prompt to the user for information if something is 4328 * missing. 4329 * @param uData the InitializeAllReplicationUserData object. 4330 * @return ReplicationCliReturnCode.SUCCESSFUL if the operation was 4331 * successful and an error code otherwise. 4332 */ 4333 private ReplicationCliReturnCode initializeAllReplication( 4334 InitializeAllReplicationUserData uData) 4335 { 4336 final InitialLdapContext ctx = createAdministrativeContext(uData); 4337 if (ctx == null) 4338 { 4339 return ERROR_CONNECTING; 4340 } 4341 4342 try 4343 { 4344 List<String> baseDNs = uData.getBaseDNs(); 4345 checkSuffixesForInitializeReplication(baseDNs, ctx, false); 4346 if (baseDNs.isEmpty()) 4347 { 4348 return REPLICATION_CANNOT_BE_INITIALIZED_ON_BASEDN; 4349 } 4350 if (mustPrintCommandBuilder()) 4351 { 4352 uData.setBaseDNs(baseDNs); 4353 printNewCommandBuilder(INITIALIZE_ALL_REPLICATION_SUBCMD_NAME, uData); 4354 } 4355 4356 ReplicationCliReturnCode returnValue = SUCCESSFUL_NOP; 4357 for (String baseDN : baseDNs) 4358 { 4359 try 4360 { 4361 println(); 4362 print(formatter.getFormattedProgress(INFO_PROGRESS_INITIALIZING_SUFFIX.get(baseDN, getHostPort(ctx)))); 4363 println(); 4364 initializeAllSuffix(baseDN, ctx, true); 4365 returnValue = SUCCESSFUL; 4366 } 4367 catch (ReplicationCliException rce) 4368 { 4369 errPrintln(); 4370 errPrintln(getCriticalExceptionMessage(rce)); 4371 returnValue = rce.getErrorCode(); 4372 logger.error(LocalizableMessage.raw("Complete error stack:"), rce); 4373 } 4374 } 4375 return returnValue; 4376 } 4377 finally 4378 { 4379 close(ctx); 4380 } 4381 } 4382 4383 /** 4384 * Performs the operation that must be made before initializing the topology 4385 * using the import-ldif command or the binary copy. The operation uses 4386 * the parameters in the provided InitializeAllReplicationUserData. 4387 * This method does not prompt to the user for information if something is 4388 * missing. 4389 * @param uData the PreExternalInitializationUserData object. 4390 * @return ReplicationCliReturnCode.SUCCESSFUL if the operation was 4391 * successful and an error code otherwise. 4392 */ 4393 private ReplicationCliReturnCode preExternalInitialization( 4394 PreExternalInitializationUserData uData) 4395 { 4396 InitialLdapContext ctx = createAdministrativeContext(uData); 4397 if (ctx == null) 4398 { 4399 return ERROR_CONNECTING; 4400 } 4401 4402 try 4403 { 4404 List<String> baseDNs = uData.getBaseDNs(); 4405 checkSuffixesForInitializeReplication(baseDNs, ctx, false); 4406 if (baseDNs.isEmpty()) 4407 { 4408 return REPLICATION_CANNOT_BE_INITIALIZED_ON_BASEDN; 4409 } 4410 if (mustPrintCommandBuilder()) 4411 { 4412 uData.setBaseDNs(baseDNs); 4413 printNewCommandBuilder(PRE_EXTERNAL_INITIALIZATION_SUBCMD_NAME, uData); 4414 } 4415 4416 ReplicationCliReturnCode returnValue = SUCCESSFUL; 4417 for (String baseDN : baseDNs) 4418 { 4419 try 4420 { 4421 println(); 4422 print(formatter.getFormattedWithPoints(INFO_PROGRESS_PRE_EXTERNAL_INITIALIZATION.get(baseDN))); 4423 preExternalInitialization(baseDN, ctx); 4424 print(formatter.getFormattedDone()); 4425 println(); 4426 } 4427 catch (ReplicationCliException rce) 4428 { 4429 errPrintln(); 4430 errPrintln(getCriticalExceptionMessage(rce)); 4431 returnValue = rce.getErrorCode(); 4432 logger.error(LocalizableMessage.raw("Complete error stack:"), rce); 4433 } 4434 } 4435 println(); 4436 print(INFO_PROGRESS_PRE_INITIALIZATION_FINISHED_PROCEDURE.get(POST_EXTERNAL_INITIALIZATION_SUBCMD_NAME)); 4437 println(); 4438 return returnValue; 4439 } 4440 finally 4441 { 4442 close(ctx); 4443 } 4444 } 4445 4446 /** 4447 * Performs the operation that must be made after initializing the topology 4448 * using the import-ldif command or the binary copy. The operation uses 4449 * the parameters in the provided InitializeAllReplicationUserData. 4450 * This method does not prompt to the user for information if something is 4451 * missing. 4452 * @param uData the PostExternalInitializationUserData object. 4453 * @return ReplicationCliReturnCode.SUCCESSFUL if the operation was 4454 * successful and an error code otherwise. 4455 */ 4456 private ReplicationCliReturnCode postExternalInitialization( 4457 PostExternalInitializationUserData uData) 4458 { 4459 InitialLdapContext ctx = createAdministrativeContext(uData); 4460 if (ctx == null) 4461 { 4462 return ERROR_CONNECTING; 4463 } 4464 4465 try 4466 { 4467 List<String> baseDNs = uData.getBaseDNs(); 4468 checkSuffixesForInitializeReplication(baseDNs, ctx, false); 4469 if (baseDNs.isEmpty()) 4470 { 4471 return REPLICATION_CANNOT_BE_INITIALIZED_ON_BASEDN; 4472 } 4473 if (mustPrintCommandBuilder()) 4474 { 4475 uData.setBaseDNs(baseDNs); 4476 printNewCommandBuilder(POST_EXTERNAL_INITIALIZATION_SUBCMD_NAME, uData); 4477 } 4478 4479 ReplicationCliReturnCode returnValue = SUCCESSFUL; 4480 for (String baseDN : baseDNs) 4481 { 4482 try 4483 { 4484 println(); 4485 print(formatter.getFormattedWithPoints(INFO_PROGRESS_POST_EXTERNAL_INITIALIZATION.get(baseDN))); 4486 postExternalInitialization(baseDN, ctx); 4487 println(formatter.getFormattedDone()); 4488 println(); 4489 } 4490 catch (ReplicationCliException rce) 4491 { 4492 errPrintln(); 4493 errPrintln(getCriticalExceptionMessage(rce)); 4494 returnValue = rce.getErrorCode(); 4495 logger.error(LocalizableMessage.raw("Complete error stack:"), rce); 4496 } 4497 } 4498 println(); 4499 print(INFO_PROGRESS_POST_INITIALIZATION_FINISHED_PROCEDURE.get()); 4500 println(); 4501 return returnValue; 4502 } 4503 finally 4504 { 4505 close(ctx); 4506 } 4507 } 4508 4509 /** 4510 * Checks that replication can actually be enabled in the provided baseDNs 4511 * for the two servers. 4512 * @param suffixes the suffixes provided by the user. This Collection is 4513 * updated by removing the base DNs that cannot be enabled and with the 4514 * base DNs that the user provided interactively. 4515 * @param ctx1 connection to the first server. 4516 * @param ctx2 connection to the second server. 4517 * @param interactive whether to ask the user to provide interactively 4518 * base DNs if none of the provided base DNs can be enabled. 4519 * @param uData the user data. This object will not be updated by this method 4520 * but it is assumed that it contains information about whether the 4521 * replication domains must be configured or not. 4522 */ 4523 private void checkSuffixesForEnableReplication(Collection<String> suffixes, 4524 InitialLdapContext ctx1, InitialLdapContext ctx2, 4525 boolean interactive, EnableReplicationUserData uData) 4526 { 4527 EnableReplicationServerData server1 = uData.getServer1(); 4528 EnableReplicationServerData server2 = uData.getServer2(); 4529 final TreeSet<String> availableSuffixes = new TreeSet<>(); 4530 final TreeSet<String> alreadyReplicatedSuffixes = new TreeSet<>(); 4531 if (server1.configureReplicationDomain() && 4532 server2.configureReplicationDomain()) 4533 { 4534 availableSuffixes.addAll(getCommonSuffixes(ctx1, ctx2, 4535 SuffixRelationType.NOT_FULLY_REPLICATED)); 4536 alreadyReplicatedSuffixes.addAll(getCommonSuffixes(ctx1, ctx2, 4537 SuffixRelationType.FULLY_REPLICATED)); 4538 } 4539 else if (server1.configureReplicationDomain()) 4540 { 4541 updateAvailableAndReplicatedSuffixesForOneDomain(ctx1, ctx2, 4542 availableSuffixes, alreadyReplicatedSuffixes); 4543 } 4544 else if (server2.configureReplicationDomain()) 4545 { 4546 updateAvailableAndReplicatedSuffixesForOneDomain(ctx2, ctx1, 4547 availableSuffixes, alreadyReplicatedSuffixes); 4548 } 4549 else 4550 { 4551 updateAvailableAndReplicatedSuffixesForNoDomain(ctx1, ctx2, 4552 availableSuffixes, alreadyReplicatedSuffixes); 4553 } 4554 4555 if (availableSuffixes.isEmpty()) 4556 { 4557 println(); 4558 if (!server1.configureReplicationDomain() && 4559 !server1.configureReplicationDomain() && 4560 alreadyReplicatedSuffixes.isEmpty()) 4561 { 4562 // Use a clarifying message: there is no replicated base DN. 4563 errPrintln(ERR_NO_SUFFIXES_AVAILABLE_TO_ENABLE_REPLICATION_NO_DOMAIN.get()); 4564 } 4565 else 4566 { 4567 errPrintln(ERR_NO_SUFFIXES_AVAILABLE_TO_ENABLE_REPLICATION.get()); 4568 } 4569 4570 List<String> userProvidedSuffixes = argParser.getBaseDNs(); 4571 TreeSet<String> userProvidedReplicatedSuffixes = new TreeSet<>(); 4572 4573 for (String s1 : userProvidedSuffixes) 4574 { 4575 for (String s2 : alreadyReplicatedSuffixes) 4576 { 4577 if (areDnsEqual(s1, s2)) 4578 { 4579 userProvidedReplicatedSuffixes.add(s1); 4580 } 4581 } 4582 } 4583 if (!userProvidedReplicatedSuffixes.isEmpty()) 4584 { 4585 println(); 4586 println(INFO_ALREADY_REPLICATED_SUFFIXES.get(toSingleLine(userProvidedReplicatedSuffixes))); 4587 } 4588 suffixes.clear(); 4589 } 4590 else 4591 { 4592 // Verify that the provided suffixes are configured in the servers. 4593 TreeSet<String> notFound = new TreeSet<>(); 4594 TreeSet<String> alreadyReplicated = new TreeSet<>(); 4595 for (String dn : suffixes) 4596 { 4597 if (!containsDN(availableSuffixes, dn)) 4598 { 4599 if (containsDN(alreadyReplicatedSuffixes, dn)) 4600 { 4601 alreadyReplicated.add(dn); 4602 } 4603 else 4604 { 4605 notFound.add(dn); 4606 } 4607 } 4608 } 4609 suffixes.removeAll(notFound); 4610 suffixes.removeAll(alreadyReplicated); 4611 if (!notFound.isEmpty()) 4612 { 4613 errPrintln(); 4614 errPrintln(ERR_REPLICATION_ENABLE_SUFFIXES_NOT_FOUND.get(toSingleLine(notFound))); 4615 } 4616 if (!alreadyReplicated.isEmpty()) 4617 { 4618 println(); 4619 println(INFO_ALREADY_REPLICATED_SUFFIXES.get(toSingleLine(alreadyReplicated))); 4620 } 4621 if (interactive) 4622 { 4623 askConfirmations(suffixes, availableSuffixes, 4624 ERR_NO_SUFFIXES_AVAILABLE_TO_ENABLE_REPLICATION, 4625 ERR_NO_SUFFIXES_SELECTED_TO_REPLICATE, 4626 INFO_REPLICATION_ENABLE_SUFFIX_PROMPT); 4627 } 4628 } 4629 } 4630 4631 /** 4632 * Checks that replication can actually be disabled in the provided baseDNs 4633 * for the server. 4634 * @param suffixes the suffixes provided by the user. This Collection is 4635 * updated by removing the base DNs that cannot be disabled and with the 4636 * base DNs that the user provided interactively. 4637 * @param ctx connection to the server. 4638 * @param interactive whether to ask the user to provide interactively 4639 * base DNs if none of the provided base DNs can be disabled. 4640 * @param displayErrors whether to display errors or not. 4641 */ 4642 private void checkSuffixesForDisableReplication(Collection<String> suffixes, 4643 InitialLdapContext ctx, boolean interactive, boolean displayErrors) 4644 { 4645 // whether the user must provide base DNs or not 4646 // (if it is <CODE>false</CODE> the user will be proposed the suffixes only once) 4647 final boolean areSuffixRequired = displayErrors; 4648 4649 TreeSet<String> availableSuffixes = new TreeSet<>(); 4650 TreeSet<String> notReplicatedSuffixes = new TreeSet<>(); 4651 4652 Collection<ReplicaDescriptor> replicas = getReplicas(ctx); 4653 for (ReplicaDescriptor rep : replicas) 4654 { 4655 String dn = rep.getSuffix().getDN(); 4656 if (rep.isReplicated()) 4657 { 4658 availableSuffixes.add(dn); 4659 } 4660 else 4661 { 4662 notReplicatedSuffixes.add(dn); 4663 } 4664 } 4665 if (availableSuffixes.isEmpty()) 4666 { 4667 if (displayErrors) 4668 { 4669 errPrintln(); 4670 errPrintln(ERR_NO_SUFFIXES_AVAILABLE_TO_DISABLE_REPLICATION.get()); 4671 } 4672 List<String> userProvidedSuffixes = argParser.getBaseDNs(); 4673 TreeSet<String> userProvidedNotReplicatedSuffixes = new TreeSet<>(); 4674 for (String s1 : userProvidedSuffixes) 4675 { 4676 for (String s2 : notReplicatedSuffixes) 4677 { 4678 if (areDnsEqual(s1, s2)) 4679 { 4680 userProvidedNotReplicatedSuffixes.add(s1); 4681 } 4682 } 4683 } 4684 if (!userProvidedNotReplicatedSuffixes.isEmpty() && displayErrors) 4685 { 4686 println(); 4687 println(INFO_ALREADY_NOT_REPLICATED_SUFFIXES.get( 4688 toSingleLine(userProvidedNotReplicatedSuffixes))); 4689 } 4690 suffixes.clear(); 4691 } 4692 else 4693 { 4694 // Verify that the provided suffixes are configured in the servers. 4695 TreeSet<String> notFound = new TreeSet<>(); 4696 TreeSet<String> alreadyNotReplicated = new TreeSet<>(); 4697 for (String dn : suffixes) 4698 { 4699 if (!containsDN(availableSuffixes, dn)) 4700 { 4701 if (containsDN(notReplicatedSuffixes, dn)) 4702 { 4703 alreadyNotReplicated.add(dn); 4704 } 4705 else 4706 { 4707 notFound.add(dn); 4708 } 4709 } 4710 } 4711 suffixes.removeAll(notFound); 4712 suffixes.removeAll(alreadyNotReplicated); 4713 if (!notFound.isEmpty() && displayErrors) 4714 { 4715 errPrintln(); 4716 errPrintln(ERR_REPLICATION_DISABLE_SUFFIXES_NOT_FOUND.get(toSingleLine(notFound))); 4717 } 4718 if (!alreadyNotReplicated.isEmpty() && displayErrors) 4719 { 4720 println(); 4721 println(INFO_ALREADY_NOT_REPLICATED_SUFFIXES.get(toSingleLine(alreadyNotReplicated))); 4722 } 4723 if (interactive) 4724 { 4725 while (suffixes.isEmpty()) 4726 { 4727 if (containsOnlySchemaOrAdminSuffix(availableSuffixes)) 4728 { 4729 // In interactive mode we do not propose to manage the administration suffix. 4730 if (displayErrors) 4731 { 4732 errPrintln(); 4733 errPrintln(ERR_NO_SUFFIXES_AVAILABLE_TO_DISABLE_REPLICATION.get()); 4734 } 4735 break; 4736 } 4737 4738 if (areSuffixRequired) 4739 { 4740 errPrintln(); 4741 errPrintln(ERR_NO_SUFFIXES_SELECTED_TO_DISABLE.get()); 4742 } 4743 boolean confirmationLimitReached = 4744 askConfirmations(INFO_REPLICATION_DISABLE_SUFFIX_PROMPT, availableSuffixes, suffixes); 4745 if (confirmationLimitReached) 4746 { 4747 suffixes.clear(); 4748 break; 4749 } 4750 if (!areSuffixRequired) 4751 { 4752 break; 4753 } 4754 } 4755 } 4756 } 4757 } 4758 4759 private boolean askConfirmations(Arg1<Object> confirmationMsg, 4760 Collection<String> availableSuffixes, Collection<String> suffixes) 4761 { 4762 for (String dn : availableSuffixes) 4763 { 4764 if (!isSchemaOrInternalAdminSuffix(dn)) 4765 { 4766 try 4767 { 4768 if (askConfirmation(confirmationMsg.get(dn), true, logger)) 4769 { 4770 suffixes.add(dn); 4771 } 4772 } 4773 catch (ClientException ce) 4774 { 4775 errPrintln(ce.getMessageObject()); 4776 return true; 4777 } 4778 } 4779 } 4780 return false; 4781 } 4782 4783 /** 4784 * Checks that replication can actually be initialized in the provided baseDNs 4785 * for the server. 4786 * @param suffixes the suffixes provided by the user. This Collection is 4787 * updated by removing the base DNs that cannot be initialized and with the 4788 * base DNs that the user provided interactively. 4789 * @param ctx connection to the server. 4790 * @param interactive whether to ask the user to provide interactively 4791 * base DNs if none of the provided base DNs can be initialized. 4792 */ 4793 private void checkSuffixesForInitializeReplication( 4794 Collection<String> suffixes, InitialLdapContext ctx, boolean interactive) 4795 { 4796 TreeSet<String> availableSuffixes = new TreeSet<>(); 4797 TreeSet<String> notReplicatedSuffixes = new TreeSet<>(); 4798 4799 Collection<ReplicaDescriptor> replicas = getReplicas(ctx); 4800 for (ReplicaDescriptor rep : replicas) 4801 { 4802 String dn = rep.getSuffix().getDN(); 4803 if (rep.isReplicated()) 4804 { 4805 availableSuffixes.add(dn); 4806 } 4807 else 4808 { 4809 notReplicatedSuffixes.add(dn); 4810 } 4811 } 4812 if (availableSuffixes.isEmpty()) 4813 { 4814 println(); 4815 if (argParser.isInitializeAllReplicationSubcommand()) 4816 { 4817 errPrintln(ERR_NO_SUFFIXES_AVAILABLE_TO_INITIALIZE_ALL_REPLICATION.get()); 4818 } 4819 else 4820 { 4821 errPrintln( 4822 ERR_NO_SUFFIXES_AVAILABLE_TO_INITIALIZE_LOCAL_REPLICATION.get()); 4823 } 4824 List<String> userProvidedSuffixes = argParser.getBaseDNs(); 4825 TreeSet<String> userProvidedNotReplicatedSuffixes = new TreeSet<>(); 4826 for (String s1 : userProvidedSuffixes) 4827 { 4828 for (String s2 : notReplicatedSuffixes) 4829 { 4830 if (areDnsEqual(s1, s2)) 4831 { 4832 userProvidedNotReplicatedSuffixes.add(s1); 4833 } 4834 } 4835 } 4836 if (!userProvidedNotReplicatedSuffixes.isEmpty()) 4837 { 4838 println(); 4839 println(INFO_ALREADY_NOT_REPLICATED_SUFFIXES.get( 4840 toSingleLine(userProvidedNotReplicatedSuffixes))); 4841 } 4842 suffixes.clear(); 4843 } 4844 else 4845 { 4846 // Verify that the provided suffixes are configured in the servers. 4847 TreeSet<String> notFound = new TreeSet<>(); 4848 TreeSet<String> alreadyNotReplicated = new TreeSet<>(); 4849 for (String dn : suffixes) 4850 { 4851 if (!containsDN(availableSuffixes, dn)) 4852 { 4853 if (containsDN(notReplicatedSuffixes, dn)) 4854 { 4855 alreadyNotReplicated.add(dn); 4856 } 4857 else 4858 { 4859 notFound.add(dn); 4860 } 4861 } 4862 } 4863 suffixes.removeAll(notFound); 4864 suffixes.removeAll(alreadyNotReplicated); 4865 if (!notFound.isEmpty()) 4866 { 4867 errPrintln(); 4868 errPrintln(ERR_REPLICATION_INITIALIZE_LOCAL_SUFFIXES_NOT_FOUND.get(toSingleLine(notFound))); 4869 } 4870 if (!alreadyNotReplicated.isEmpty()) 4871 { 4872 println(); 4873 println(INFO_ALREADY_NOT_REPLICATED_SUFFIXES.get(toSingleLine(alreadyNotReplicated))); 4874 } 4875 if (interactive) 4876 { 4877 boolean confirmationLimitReached = false; 4878 while (suffixes.isEmpty()) 4879 { 4880 println(); 4881 if (containsOnlySchemaOrAdminSuffix(availableSuffixes)) 4882 { 4883 // In interactive mode we do not propose to manage the administration suffix. 4884 if (argParser.isInitializeAllReplicationSubcommand()) 4885 { 4886 errPrintln(ERR_NO_SUFFIXES_AVAILABLE_TO_INITIALIZE_ALL_REPLICATION.get()); 4887 } 4888 else 4889 { 4890 errPrintln(ERR_NO_SUFFIXES_AVAILABLE_TO_INITIALIZE_LOCAL_REPLICATION.get()); 4891 } 4892 break; 4893 } 4894 else 4895 { 4896 if (argParser.isInitializeAllReplicationSubcommand()) 4897 { 4898 errPrintln(ERR_NO_SUFFIXES_SELECTED_TO_INITIALIZE_ALL.get()); 4899 } 4900 else if (argParser.isPreExternalInitializationSubcommand()) 4901 { 4902 errPrintln(ERR_NO_SUFFIXES_SELECTED_TO_PRE_EXTERNAL_INITIALIZATION.get()); 4903 } 4904 else if (argParser.isPostExternalInitializationSubcommand()) 4905 { 4906 errPrintln(ERR_NO_SUFFIXES_SELECTED_TO_POST_EXTERNAL_INITIALIZATION.get()); 4907 } 4908 4909 for (String dn : availableSuffixes) 4910 { 4911 if (!isSchemaOrInternalAdminSuffix(dn)) 4912 { 4913 boolean addSuffix; 4914 try 4915 { 4916 if (argParser.isPreExternalInitializationSubcommand()) 4917 { 4918 addSuffix = askConfirmation( 4919 INFO_REPLICATION_PRE_EXTERNAL_INITIALIZATION_SUFFIX_PROMPT. 4920 get(dn), true, logger); 4921 } 4922 else if (argParser.isPostExternalInitializationSubcommand()) 4923 { 4924 addSuffix = askConfirmation( 4925 INFO_REPLICATION_POST_EXTERNAL_INITIALIZATION_SUFFIX_PROMPT. 4926 get(dn), true, logger); 4927 } 4928 else 4929 { 4930 addSuffix = askConfirmation( 4931 INFO_REPLICATION_INITIALIZE_ALL_SUFFIX_PROMPT.get(dn), 4932 true, logger); 4933 } 4934 } 4935 catch (ClientException ce) 4936 { 4937 errPrintln(ce.getMessageObject()); 4938 confirmationLimitReached = true; 4939 break; 4940 } 4941 if (addSuffix) 4942 { 4943 suffixes.add(dn); 4944 } 4945 } 4946 } 4947 } 4948 if (confirmationLimitReached) 4949 { 4950 suffixes.clear(); 4951 break; 4952 } 4953 } 4954 } 4955 } 4956 } 4957 4958 private String toSingleLine(Collection<String> notFound) 4959 { 4960 return joinAsString(Constants.LINE_SEPARATOR, notFound); 4961 } 4962 4963 /** 4964 * Checks that we can initialize the provided baseDNs between the two servers. 4965 * @param suffixes the suffixes provided by the user. This Collection is 4966 * updated by removing the base DNs that cannot be enabled and with the 4967 * base DNs that the user provided interactively. 4968 * @param ctxSource connection to the source server. 4969 * @param ctxDestination connection to the destination server. 4970 * @param interactive whether to ask the user to provide interactively 4971 * base DNs if none of the provided base DNs can be initialized. 4972 */ 4973 private void checkSuffixesForInitializeReplication( 4974 Collection<String> suffixes, InitialLdapContext ctxSource, 4975 InitialLdapContext ctxDestination, boolean interactive) 4976 { 4977 TreeSet<String> availableSuffixes = new TreeSet<>( 4978 getCommonSuffixes(ctxSource, ctxDestination, SuffixRelationType.REPLICATED)); 4979 if (availableSuffixes.isEmpty()) 4980 { 4981 errPrintln(); 4982 errPrintln(ERR_NO_SUFFIXES_AVAILABLE_TO_INITIALIZE_REPLICATION.get()); 4983 suffixes.clear(); 4984 } 4985 else 4986 { 4987 // Verify that the provided suffixes are configured in the servers. 4988 LinkedList<String> notFound = new LinkedList<>(); 4989 for (String dn : suffixes) 4990 { 4991 if (!containsDN(availableSuffixes, dn)) 4992 { 4993 notFound.add(dn); 4994 } 4995 } 4996 suffixes.removeAll(notFound); 4997 if (!notFound.isEmpty()) 4998 { 4999 errPrintln(); 5000 errPrintln(ERR_SUFFIXES_CANNOT_BE_INITIALIZED.get(toSingleLine(notFound))); 5001 } 5002 if (interactive) 5003 { 5004 askConfirmations(suffixes, availableSuffixes, 5005 ERR_NO_SUFFIXES_AVAILABLE_TO_INITIALIZE_REPLICATION, 5006 ERR_NO_SUFFIXES_SELECTED_TO_INITIALIZE, 5007 INFO_REPLICATION_INITIALIZE_SUFFIX_PROMPT); 5008 } 5009 } 5010 } 5011 5012 /** 5013 * Updates the configuration in the two servers (and in other servers if 5014 * they are referenced) to enable replication. 5015 * @param ctx1 the connection to the first server. 5016 * @param ctx2 the connection to the second server. 5017 * @param uData the EnableReplicationUserData object containing the required 5018 * parameters to update the configuration. 5019 * @throws ReplicationCliException if there is an error. 5020 */ 5021 private void updateConfiguration(InitialLdapContext ctx1, 5022 InitialLdapContext ctx2, EnableReplicationUserData uData) 5023 throws ReplicationCliException 5024 { 5025 final Set<String> twoReplServers = new LinkedHashSet<>(); 5026 final Set<String> allRepServers = new LinkedHashSet<>(); 5027 final Map<String, Set<String>> hmRepServers = new HashMap<>(); 5028 final Set<Integer> usedReplicationServerIds = new HashSet<>(); 5029 final Map<String, Set<Integer>> hmUsedReplicationDomainIds = new HashMap<>(); 5030 5031 TopologyCacheFilter filter = new TopologyCacheFilter(); 5032 filter.setSearchMonitoringInformation(false); 5033 filter.addBaseDNToSearch(ADSContext.getAdministrationSuffixDN()); 5034 filter.addBaseDNToSearch(Constants.SCHEMA_DN); 5035 addBaseDNs(filter, uData.getBaseDNs()); 5036 ServerDescriptor serverDesc1 = createStandalone(ctx1, filter); 5037 ServerDescriptor serverDesc2 = createStandalone(ctx2, filter); 5038 5039 ADSContext adsCtx1 = new ADSContext(ctx1); 5040 ADSContext adsCtx2 = new ADSContext(ctx2); 5041 5042 if (!argParser.isInteractive()) 5043 { 5044 // Inform the user of the potential errors that we found in the already 5045 // registered servers. 5046 final Set<LocalizableMessage> messages = new LinkedHashSet<>(); 5047 try 5048 { 5049 final Set<PreferredConnection> cnx = new LinkedHashSet<>(); 5050 cnx.addAll(getPreferredConnections(ctx1)); 5051 cnx.addAll(getPreferredConnections(ctx2)); 5052 TopologyCache cache1 = createTopologyCache(adsCtx1, cnx, uData); 5053 if (cache1 != null) 5054 { 5055 messages.addAll(cache1.getErrorMessages()); 5056 } 5057 TopologyCache cache2 = createTopologyCache(adsCtx2, cnx, uData); 5058 if (cache2 != null) 5059 { 5060 messages.addAll(cache2.getErrorMessages()); 5061 } 5062 } 5063 catch (TopologyCacheException tce) 5064 { 5065 throw new ReplicationCliException( 5066 ERR_REPLICATION_READING_ADS.get(tce.getMessage()), 5067 ERROR_READING_TOPOLOGY_CACHE, tce); 5068 } 5069 catch (ADSContextException adce) 5070 { 5071 throw new ReplicationCliException( 5072 ERR_REPLICATION_READING_ADS.get(adce.getMessage()), 5073 ERROR_READING_ADS, adce); 5074 } 5075 if (!messages.isEmpty()) 5076 { 5077 errPrintln(ERR_REPLICATION_READING_REGISTERED_SERVERS_WARNING.get( 5078 getMessageFromCollection(messages, 5079 Constants.LINE_SEPARATOR))); 5080 } 5081 } 5082 // Check whether there is more than one replication server in the topology. 5083 Set<String> baseDNsWithOneReplicationServer = new TreeSet<>(); 5084 Set<String> baseDNsWithNoReplicationServer = new TreeSet<>(); 5085 updateBaseDnsWithNotEnoughReplicationServer(adsCtx1, adsCtx2, uData, 5086 baseDNsWithNoReplicationServer, baseDNsWithOneReplicationServer); 5087 5088 if (!baseDNsWithNoReplicationServer.isEmpty()) 5089 { 5090 LocalizableMessage errorMsg = 5091 ERR_REPLICATION_NO_REPLICATION_SERVER.get(toSingleLine(baseDNsWithNoReplicationServer)); 5092 throw new ReplicationCliException(errorMsg, ERROR_USER_DATA, null); 5093 } 5094 else if (!baseDNsWithOneReplicationServer.isEmpty()) 5095 { 5096 if (isInteractive()) 5097 { 5098 LocalizableMessage confirmMsg = INFO_REPLICATION_ONLY_ONE_REPLICATION_SERVER_CONFIRM.get( 5099 toSingleLine(baseDNsWithOneReplicationServer)); 5100 try 5101 { 5102 if (!confirmAction(confirmMsg, false)) 5103 { 5104 throw new ReplicationCliException( 5105 ERR_REPLICATION_USER_CANCELLED.get(), USER_CANCELLED, null); 5106 } 5107 } 5108 catch (Throwable t) 5109 { 5110 throw new ReplicationCliException( 5111 ERR_REPLICATION_USER_CANCELLED.get(), USER_CANCELLED, t); 5112 } 5113 } 5114 else 5115 { 5116 errPrintln(INFO_REPLICATION_ONLY_ONE_REPLICATION_SERVER_WARNING.get( 5117 toSingleLine(baseDNsWithOneReplicationServer))); 5118 errPrintln(); 5119 } 5120 } 5121 5122 // These are used to identify which server we use to initialize 5123 // the contents of the other server (if any). 5124 InitialLdapContext ctxSource = null; 5125 InitialLdapContext ctxDestination = null; 5126 ADSContext adsCtxSource = null; 5127 5128 boolean adsAlreadyReplicated = false; 5129 boolean adsMergeDone = false; 5130 5131 print(formatter.getFormattedWithPoints( 5132 INFO_REPLICATION_ENABLE_UPDATING_ADS_CONTENTS.get())); 5133 try 5134 { 5135 if (adsCtx1.hasAdminData() && adsCtx2.hasAdminData()) 5136 { 5137 Set<Map<ServerProperty, Object>> registry1 = adsCtx1.readServerRegistry(); 5138 Set<Map<ServerProperty, Object>> registry2 = adsCtx2.readServerRegistry(); 5139 if (registry2.size() <= 1) 5140 { 5141 if (!hasAdministrator(adsCtx1.getDirContext(), uData)) 5142 { 5143 adsCtx1.createAdministrator(getAdministratorProperties(uData)); 5144 } 5145 serverDesc2.updateAdsPropertiesWithServerProperties(); 5146 registerServer(adsCtx1, serverDesc2.getAdsProperties()); 5147 if (!ADSContext.isRegistered(serverDesc1, registry1)) 5148 { 5149 serverDesc1.updateAdsPropertiesWithServerProperties(); 5150 registerServer(adsCtx1, serverDesc1.getAdsProperties()); 5151 } 5152 5153 ctxSource = ctx1; 5154 ctxDestination = ctx2; 5155 adsCtxSource = adsCtx1; 5156 } 5157 else if (registry1.size() <= 1) 5158 { 5159 if (!hasAdministrator(adsCtx2.getDirContext(), uData)) 5160 { 5161 adsCtx2.createAdministrator(getAdministratorProperties(uData)); 5162 } 5163 serverDesc1.updateAdsPropertiesWithServerProperties(); 5164 registerServer(adsCtx2, serverDesc1.getAdsProperties()); 5165 5166 if (!ADSContext.isRegistered(serverDesc2, registry2)) 5167 { 5168 serverDesc2.updateAdsPropertiesWithServerProperties(); 5169 registerServer(adsCtx2, serverDesc2.getAdsProperties()); 5170 } 5171 5172 ctxSource = ctx2; 5173 ctxDestination = ctx1; 5174 adsCtxSource = adsCtx2; 5175 } 5176 else if (!areEqual(registry1, registry2)) 5177 { 5178 print(formatter.getFormattedDone()); 5179 println(); 5180 5181 boolean isFirstSource = mergeRegistries(adsCtx1, adsCtx2); 5182 ctxSource = isFirstSource ? ctx1 : ctx2; 5183 adsMergeDone = true; 5184 } 5185 else 5186 { 5187 // They are already replicated: nothing to do in terms of ADS 5188 // initialization or ADS update data 5189 adsAlreadyReplicated = isBaseDNReplicated(serverDesc1, serverDesc2, ADSContext.getAdministrationSuffixDN()); 5190 5191 if (!adsAlreadyReplicated) 5192 { 5193 // Try to merge if both are replicated 5194 boolean isADS1Replicated = isBaseDNReplicated(serverDesc1, ADSContext.getAdministrationSuffixDN()); 5195 boolean isADS2Replicated = isBaseDNReplicated(serverDesc2, ADSContext.getAdministrationSuffixDN()); 5196 if (isADS1Replicated && isADS2Replicated) 5197 { 5198 // Merge 5199 print(formatter.getFormattedDone()); 5200 println(); 5201 5202 boolean isFirstSource = mergeRegistries(adsCtx1, adsCtx2); 5203 ctxSource = isFirstSource ? ctx1 : ctx2; 5204 adsMergeDone = true; 5205 } 5206 else if (isADS1Replicated || !isADS2Replicated) 5207 { 5208 // The case where only the first ADS is replicated or none 5209 // is replicated. 5210 if (!hasAdministrator(adsCtx1.getDirContext(), uData)) 5211 { 5212 adsCtx1.createAdministrator(getAdministratorProperties(uData)); 5213 } 5214 serverDesc2.updateAdsPropertiesWithServerProperties(); 5215 registerServer(adsCtx1, serverDesc2.getAdsProperties()); 5216 if (!ADSContext.isRegistered(serverDesc1, registry1)) 5217 { 5218 serverDesc1.updateAdsPropertiesWithServerProperties(); 5219 registerServer(adsCtx1, serverDesc1.getAdsProperties()); 5220 } 5221 5222 ctxSource = ctx1; 5223 ctxDestination = ctx2; 5224 adsCtxSource = adsCtx1; 5225 } 5226 else if (isADS2Replicated) 5227 { 5228 if (!hasAdministrator(adsCtx2.getDirContext(), uData)) 5229 { 5230 adsCtx2.createAdministrator(getAdministratorProperties(uData)); 5231 } 5232 serverDesc1.updateAdsPropertiesWithServerProperties(); 5233 registerServer(adsCtx2, serverDesc1.getAdsProperties()); 5234 if (!ADSContext.isRegistered(serverDesc2, registry2)) 5235 { 5236 serverDesc2.updateAdsPropertiesWithServerProperties(); 5237 registerServer(adsCtx2, serverDesc2.getAdsProperties()); 5238 } 5239 5240 ctxSource = ctx2; 5241 ctxDestination = ctx1; 5242 adsCtxSource = adsCtx2; 5243 } 5244 } 5245 } 5246 } 5247 else if (!adsCtx1.hasAdminData() && adsCtx2.hasAdminData()) 5248 { 5249 if (!hasAdministrator(adsCtx2.getDirContext(), uData)) 5250 { 5251 adsCtx2.createAdministrator(getAdministratorProperties(uData)); 5252 } 5253 serverDesc1.updateAdsPropertiesWithServerProperties(); 5254 registerServer(adsCtx2, serverDesc1.getAdsProperties()); 5255 Set<Map<ServerProperty, Object>> registry2 = adsCtx2.readServerRegistry(); 5256 if (!ADSContext.isRegistered(serverDesc2, registry2)) 5257 { 5258 serverDesc2.updateAdsPropertiesWithServerProperties(); 5259 registerServer(adsCtx2, serverDesc2.getAdsProperties()); 5260 } 5261 5262 ctxSource = ctx2; 5263 ctxDestination = ctx1; 5264 adsCtxSource = adsCtx2; 5265 } 5266 else if (adsCtx1.hasAdminData() && !adsCtx2.hasAdminData()) 5267 { 5268 if (!hasAdministrator(adsCtx1.getDirContext(), uData)) 5269 { 5270 adsCtx1.createAdministrator(getAdministratorProperties(uData)); 5271 } 5272 serverDesc2.updateAdsPropertiesWithServerProperties(); 5273 registerServer(adsCtx1, serverDesc2.getAdsProperties()); 5274 Set<Map<ServerProperty, Object>> registry1 = adsCtx1.readServerRegistry(); 5275 if (!ADSContext.isRegistered(serverDesc1, registry1)) 5276 { 5277 serverDesc1.updateAdsPropertiesWithServerProperties(); 5278 registerServer(adsCtx1, serverDesc1.getAdsProperties()); 5279 } 5280 5281 ctxSource = ctx1; 5282 ctxDestination = ctx2; 5283 adsCtxSource = adsCtx1; 5284 } 5285 else 5286 { 5287 adsCtx1.createAdminData(null); 5288 if (!hasAdministrator(ctx1, uData)) 5289 { 5290 // This could occur if the user created an administrator without 5291 // registering any server. 5292 adsCtx1.createAdministrator(getAdministratorProperties(uData)); 5293 } 5294 serverDesc1.updateAdsPropertiesWithServerProperties(); 5295 adsCtx1.registerServer(serverDesc1.getAdsProperties()); 5296 serverDesc2.updateAdsPropertiesWithServerProperties(); 5297 adsCtx1.registerServer(serverDesc2.getAdsProperties()); 5298 5299 ctxSource = ctx1; 5300 ctxDestination = ctx2; 5301 adsCtxSource = adsCtx1; 5302 } 5303 } 5304 catch (ADSContextException adce) 5305 { 5306 throw new ReplicationCliException( 5307 ERR_REPLICATION_UPDATING_ADS.get(adce.getMessageObject()), 5308 ERROR_UPDATING_ADS, adce); 5309 } 5310 if (!adsAlreadyReplicated && !adsMergeDone) 5311 { 5312 try 5313 { 5314 ServerDescriptor.seedAdsTrustStore(ctxDestination, 5315 adsCtxSource.getTrustedCertificates()); 5316 } 5317 catch (Throwable t) 5318 { 5319 logger.error(LocalizableMessage.raw("Error seeding truststores: "+t, t)); 5320 throw new ReplicationCliException( 5321 ERR_REPLICATION_ENABLE_SEEDING_TRUSTSTORE.get(getHostPort(ctxDestination), 5322 getHostPort(adsCtxSource.getDirContext()), toString(t)), 5323 ERROR_SEEDING_TRUSTORE, t); 5324 } 5325 } 5326 if (!adsMergeDone) 5327 { 5328 print(formatter.getFormattedDone()); 5329 println(); 5330 } 5331 List<String> baseDNs = uData.getBaseDNs(); 5332 if (!adsAlreadyReplicated 5333 && !containsDN(baseDNs, ADSContext.getAdministrationSuffixDN())) 5334 { 5335 baseDNs.add(ADSContext.getAdministrationSuffixDN()); 5336 uData.setBaseDNs(baseDNs); 5337 } 5338 5339 if (uData.replicateSchema()) 5340 { 5341 baseDNs = uData.getBaseDNs(); 5342 baseDNs.add(Constants.SCHEMA_DN); 5343 uData.setBaseDNs(baseDNs); 5344 } 5345 5346 TopologyCache cache1 = null; 5347 TopologyCache cache2 = null; 5348 try 5349 { 5350 Set<PreferredConnection> cnx = new LinkedHashSet<>(); 5351 cnx.addAll(getPreferredConnections(ctx1)); 5352 cnx.addAll(getPreferredConnections(ctx2)); 5353 cache1 = createTopologyCache(adsCtx1, cnx, uData); 5354 if (cache1 != null) 5355 { 5356 usedReplicationServerIds.addAll(getReplicationServerIds(cache1)); 5357 } 5358 cache2 = createTopologyCache(adsCtx2, cnx, uData); 5359 if (cache1 != null) 5360 { 5361 usedReplicationServerIds.addAll(getReplicationServerIds(cache1)); 5362 } 5363 } 5364 catch (ADSContextException adce) 5365 { 5366 throw new ReplicationCliException( 5367 ERR_REPLICATION_READING_ADS.get(adce.getMessage()), 5368 ERROR_READING_ADS, adce); 5369 } 5370 catch (TopologyCacheException tce) 5371 { 5372 throw new ReplicationCliException( 5373 ERR_REPLICATION_READING_ADS.get(tce.getMessage()), 5374 ERROR_READING_TOPOLOGY_CACHE, tce); 5375 } 5376 5377 addToSets(serverDesc1, uData.getServer1(), ctx1, twoReplServers, usedReplicationServerIds); 5378 addToSets(serverDesc2, uData.getServer2(), ctx2, twoReplServers, usedReplicationServerIds); 5379 5380 for (String baseDN : uData.getBaseDNs()) 5381 { 5382 Set<String> repServersForBaseDN = new LinkedHashSet<>(); 5383 repServersForBaseDN.addAll(getReplicationServers(baseDN, cache1, serverDesc1)); 5384 repServersForBaseDN.addAll(getReplicationServers(baseDN, cache2, serverDesc2)); 5385 repServersForBaseDN.addAll(twoReplServers); 5386 hmRepServers.put(baseDN, repServersForBaseDN); 5387 5388 Set<Integer> ids = new HashSet<>(); 5389 ids.addAll(getReplicationDomainIds(baseDN, serverDesc1)); 5390 ids.addAll(getReplicationDomainIds(baseDN, serverDesc2)); 5391 if (cache1 != null) 5392 { 5393 for (ServerDescriptor server : cache1.getServers()) 5394 { 5395 ids.addAll(getReplicationDomainIds(baseDN, server)); 5396 } 5397 } 5398 if (cache2 != null) 5399 { 5400 for (ServerDescriptor server : cache2.getServers()) 5401 { 5402 ids.addAll(getReplicationDomainIds(baseDN, server)); 5403 } 5404 } 5405 hmUsedReplicationDomainIds.put(baseDN, ids); 5406 } 5407 for (Set<String> v : hmRepServers.values()) 5408 { 5409 allRepServers.addAll(v); 5410 } 5411 5412 Set<String> alreadyConfiguredReplicationServers = new HashSet<>(); 5413 configureServer(ctx1, serverDesc1, uData.getServer1(), argParser.server1.replicationPortArg, 5414 usedReplicationServerIds, allRepServers, alreadyConfiguredReplicationServers, 5415 WARN_FIRST_REPLICATION_SERVER_ALREADY_CONFIGURED); 5416 configureServer(ctx2, serverDesc2, uData.getServer2(), argParser.server2.replicationPortArg, 5417 usedReplicationServerIds, allRepServers, alreadyConfiguredReplicationServers, 5418 WARN_SECOND_REPLICATION_SERVER_ALREADY_CONFIGURED); 5419 5420 for (String baseDN : uData.getBaseDNs()) 5421 { 5422 Set<String> repServers = hmRepServers.get(baseDN); 5423 Set<Integer> usedIds = hmUsedReplicationDomainIds.get(baseDN); 5424 Set<String> alreadyConfiguredServers = new HashSet<>(); 5425 5426 configureToReplicateBaseDN(uData.getServer1(), ctx1, serverDesc1, cache1, baseDN, 5427 usedIds, alreadyConfiguredServers, repServers, allRepServers, alreadyConfiguredReplicationServers); 5428 5429 configureToReplicateBaseDN(uData.getServer2(), ctx2, serverDesc2, cache2, baseDN, 5430 usedIds, alreadyConfiguredServers, repServers, allRepServers, alreadyConfiguredReplicationServers); 5431 } 5432 5433 // Now that replication is configured in all servers, simply try to 5434 // initialize the contents of one ADS with the other (in the case where 5435 // already both servers were replicating the same ADS there is nothing to be done). 5436 if (adsMergeDone) 5437 { 5438 PointAdder pointAdder = new PointAdder(this); 5439 print(INFO_ENABLE_REPLICATION_INITIALIZING_ADS_ALL.get(getHostPort(ctxSource))); 5440 pointAdder.start(); 5441 try 5442 { 5443 initializeAllSuffix(ADSContext.getAdministrationSuffixDN(), ctxSource, false); 5444 } 5445 finally 5446 { 5447 pointAdder.stop(); 5448 } 5449 print(formatter.getSpace()); 5450 print(formatter.getFormattedDone()); 5451 println(); 5452 } 5453 else if (ctxSource != null && ctxDestination != null) 5454 { 5455 print(formatter.getFormattedWithPoints( 5456 INFO_ENABLE_REPLICATION_INITIALIZING_ADS.get( 5457 getHostPort(ctxDestination), getHostPort(ctxSource)))); 5458 5459 initializeSuffix(ADSContext.getAdministrationSuffixDN(), ctxSource, ctxDestination, false); 5460 print(formatter.getFormattedDone()); 5461 println(); 5462 } 5463 5464 // If we must initialize the schema do so. 5465 if (mustInitializeSchema(serverDesc1, serverDesc2, uData)) 5466 { 5467 if (argParser.useSecondServerAsSchemaSource()) 5468 { 5469 ctxSource = ctx2; 5470 ctxDestination = ctx1; 5471 } 5472 else 5473 { 5474 ctxSource = ctx1; 5475 ctxDestination = ctx2; 5476 } 5477 if (adsMergeDone) 5478 { 5479 PointAdder pointAdder = new PointAdder(this); 5480 println(INFO_ENABLE_REPLICATION_INITIALIZING_SCHEMA.get( 5481 getHostPort(ctxDestination), getHostPort(ctxSource))); 5482 pointAdder.start(); 5483 try 5484 { 5485 initializeAllSuffix(Constants.SCHEMA_DN, ctxSource, false); 5486 } 5487 finally 5488 { 5489 pointAdder.stop(); 5490 } 5491 print(formatter.getSpace()); 5492 } 5493 else 5494 { 5495 print(formatter.getFormattedWithPoints(INFO_ENABLE_REPLICATION_INITIALIZING_SCHEMA.get( 5496 getHostPort(ctxDestination), getHostPort(ctxSource)))); 5497 initializeSuffix(Constants.SCHEMA_DN, ctxSource, ctxDestination, false); 5498 } 5499 print(formatter.getFormattedDone()); 5500 println(); 5501 } 5502 } 5503 5504 private void addToSets(ServerDescriptor serverDesc, EnableReplicationServerData serverData, InitialLdapContext ctx, 5505 final Set<String> twoReplServers, final Set<Integer> usedReplicationServerIds) 5506 { 5507 if (serverDesc.isReplicationServer()) 5508 { 5509 twoReplServers.add(serverDesc.getReplicationServerHostPort()); 5510 usedReplicationServerIds.add(serverDesc.getReplicationServerId()); 5511 } 5512 else if (serverData.configureReplicationServer()) 5513 { 5514 twoReplServers.add(getReplicationServer(getHostName(ctx), serverData.getReplicationPort())); 5515 } 5516 } 5517 5518 private void configureToReplicateBaseDN(EnableReplicationServerData server, InitialLdapContext ctx, 5519 ServerDescriptor serverDesc, TopologyCache cache, String baseDN, Set<Integer> usedIds, 5520 Set<String> alreadyConfiguredServers, Set<String> repServers, final Set<String> allRepServers, 5521 Set<String> alreadyConfiguredReplicationServers) throws ReplicationCliException 5522 { 5523 if (server.configureReplicationDomain() 5524 || areDnsEqual(baseDN, ADSContext.getAdministrationSuffixDN())) 5525 { 5526 try 5527 { 5528 configureToReplicateBaseDN(ctx, baseDN, repServers, usedIds); 5529 } 5530 catch (OpenDsException ode) 5531 { 5532 LocalizableMessage msg = getMessageForEnableException(getHostPort(ctx), baseDN); 5533 throw new ReplicationCliException(msg, ERROR_ENABLING_REPLICATION_ON_BASEDN, ode); 5534 } 5535 } 5536 alreadyConfiguredServers.add(serverDesc.getId()); 5537 5538 if (cache != null) 5539 { 5540 configureToReplicateBaseDN(baseDN, repServers, usedIds, cache, serverDesc, alreadyConfiguredServers, 5541 allRepServers, alreadyConfiguredReplicationServers); 5542 } 5543 } 5544 5545 private void configureServer(InitialLdapContext ctx, ServerDescriptor serverDesc, 5546 EnableReplicationServerData enableServer, IntegerArgument replicationPortArg, 5547 Set<Integer> usedReplicationServerIds, Set<String> allRepServers, 5548 Set<String> alreadyConfiguredReplicationServers, Arg2<Number, Number> replicationServerAlreadyConfiguredMsg) 5549 throws ReplicationCliException 5550 { 5551 if (!serverDesc.isReplicationServer() && enableServer.configureReplicationServer()) 5552 { 5553 try 5554 { 5555 configureAsReplicationServer(ctx, enableServer.getReplicationPort(), enableServer.isSecureReplication(), 5556 allRepServers, usedReplicationServerIds); 5557 } 5558 catch (OpenDsException ode) 5559 { 5560 throw errorConfiguringReplicationServer(ctx, ode); 5561 } 5562 } 5563 else if (serverDesc.isReplicationServer()) 5564 { 5565 try 5566 { 5567 updateReplicationServer(ctx, allRepServers); 5568 } 5569 catch (OpenDsException ode) 5570 { 5571 throw errorConfiguringReplicationServer(ctx, ode); 5572 } 5573 if (replicationPortArg.isPresent() && enableServer.getReplicationPort() != serverDesc.getReplicationServerPort()) 5574 { 5575 LocalizableMessage msg = replicationServerAlreadyConfiguredMsg.get( 5576 serverDesc.getReplicationServerPort(), enableServer.getReplicationPort()); 5577 logger.warn(msg); 5578 errPrintln(msg); 5579 } 5580 } 5581 alreadyConfiguredReplicationServers.add(serverDesc.getId()); 5582 } 5583 5584 private ReplicationCliException errorConfiguringReplicationServer(InitialLdapContext ctx, OpenDsException ode) 5585 { 5586 return new ReplicationCliException( 5587 ERR_REPLICATION_CONFIGURING_REPLICATIONSERVER.get(getHostPort(ctx)), 5588 ERROR_CONFIGURING_REPLICATIONSERVER, ode); 5589 } 5590 5591 private TopologyCache createTopologyCache(ADSContext adsCtx, Set<PreferredConnection> cnx, ReplicationUserData uData) 5592 throws ADSContextException, TopologyCacheException 5593 { 5594 if (adsCtx.hasAdminData()) 5595 { 5596 TopologyCache cache = new TopologyCache(adsCtx, getTrustManager(sourceServerCI), getConnectTimeout()); 5597 cache.setPreferredConnections(cnx); 5598 cache.getFilter().setSearchMonitoringInformation(false); 5599 addBaseDNs(cache.getFilter(), uData.getBaseDNs()); 5600 cache.reloadTopology(); 5601 return cache; 5602 } 5603 return null; 5604 } 5605 5606 private ServerDescriptor createStandalone(InitialLdapContext ctx, TopologyCacheFilter filter) 5607 throws ReplicationCliException 5608 { 5609 try 5610 { 5611 return ServerDescriptor.createStandalone(ctx, filter); 5612 } 5613 catch (NamingException ne) 5614 { 5615 throw new ReplicationCliException( 5616 getMessageForException(ne, getHostPort(ctx)), 5617 ERROR_READING_CONFIGURATION, ne); 5618 } 5619 } 5620 5621 /** 5622 * Updates the configuration in the server (and in other servers if 5623 * they are referenced) to disable replication. 5624 * @param ctx the connection to the server. 5625 * @param uData the DisableReplicationUserData object containing the required 5626 * parameters to update the configuration. 5627 * @throws ReplicationCliException if there is an error. 5628 */ 5629 private void updateConfiguration(InitialLdapContext ctx, 5630 DisableReplicationUserData uData) throws ReplicationCliException 5631 { 5632 TopologyCacheFilter filter = new TopologyCacheFilter(); 5633 filter.setSearchMonitoringInformation(false); 5634 if (!uData.disableAll()) 5635 { 5636 filter.addBaseDNToSearch(ADSContext.getAdministrationSuffixDN()); 5637 addBaseDNs(filter, uData.getBaseDNs()); 5638 } 5639 ServerDescriptor server = createStandalone(ctx, filter); 5640 5641 ADSContext adsCtx = new ADSContext(ctx); 5642 5643 TopologyCache cache = null; 5644 // Only try to update remote server if the user provided a Global 5645 // Administrator to authenticate. 5646 boolean tryToUpdateRemote = uData.getAdminUid() != null; 5647 try 5648 { 5649 if (adsCtx.hasAdminData() && tryToUpdateRemote) 5650 { 5651 cache = new TopologyCache(adsCtx, getTrustManager(sourceServerCI), getConnectTimeout()); 5652 cache.setPreferredConnections(getPreferredConnections(ctx)); 5653 cache.getFilter().setSearchMonitoringInformation(false); 5654 if (!uData.disableAll()) 5655 { 5656 addBaseDNs(cache.getFilter(), uData.getBaseDNs()); 5657 } 5658 cache.reloadTopology(); 5659 } 5660 } 5661 catch (ADSContextException adce) 5662 { 5663 throw new ReplicationCliException( 5664 ERR_REPLICATION_READING_ADS.get(adce.getMessage()), 5665 ERROR_READING_ADS, adce); 5666 } 5667 catch (TopologyCacheException tce) 5668 { 5669 throw new ReplicationCliException( 5670 ERR_REPLICATION_READING_ADS.get(tce.getMessage()), 5671 ERROR_READING_TOPOLOGY_CACHE, tce); 5672 } 5673 if (!argParser.isInteractive()) 5674 { 5675 // Inform the user of the potential errors that we found. 5676 Set<LocalizableMessage> messages = new LinkedHashSet<>(); 5677 if (cache != null) 5678 { 5679 messages.addAll(cache.getErrorMessages()); 5680 } 5681 if (!messages.isEmpty()) 5682 { 5683 errPrintln( 5684 ERR_REPLICATION_READING_REGISTERED_SERVERS_WARNING.get( 5685 getMessageFromCollection(messages, 5686 Constants.LINE_SEPARATOR))); 5687 } 5688 } 5689 5690 final boolean disableReplicationServer = server.isReplicationServer() 5691 && (uData.disableReplicationServer() || uData.disableAll()); 5692 if (cache != null && disableReplicationServer) 5693 { 5694 String replicationServer = server.getReplicationServerHostPort(); 5695 // Figure out if this is the last replication server for a given 5696 // topology (containing a different replica) or there will be only 5697 // another replication server left (single point of failure). 5698 Set<SuffixDescriptor> lastRepServer = new TreeSet<>(new SuffixComparator()); 5699 Set<SuffixDescriptor> beforeLastRepServer = new TreeSet<>(new SuffixComparator()); 5700 5701 for (SuffixDescriptor suffix : cache.getSuffixes()) 5702 { 5703 if (isSchemaOrInternalAdminSuffix(suffix.getDN())) 5704 { 5705 // Do not display these suffixes. 5706 continue; 5707 } 5708 5709 Set<String> repServers = suffix.getReplicationServers(); 5710 if (repServers.size() <= 2 5711 && containsIgnoreCase(repServers, replicationServer)) 5712 { 5713 if (repServers.size() == 2) 5714 { 5715 beforeLastRepServer.add(suffix); 5716 } 5717 else 5718 { 5719 lastRepServer.add(suffix); 5720 } 5721 } 5722 } 5723 5724 // Inform the user 5725 if (!beforeLastRepServer.isEmpty()) 5726 { 5727 Set<String> baseDNs = new LinkedHashSet<>(); 5728 for (SuffixDescriptor suffix : beforeLastRepServer) 5729 { 5730 if (!isSchemaOrInternalAdminSuffix(suffix.getDN())) 5731 { 5732 // Do not display these suffixes. 5733 baseDNs.add(suffix.getDN()); 5734 } 5735 } 5736 if (!baseDNs.isEmpty()) 5737 { 5738 String arg = toSingleLine(baseDNs); 5739 if (!isInteractive()) 5740 { 5741 println(INFO_DISABLE_REPLICATION_ONE_POINT_OF_FAILURE.get(arg)); 5742 } 5743 else 5744 { 5745 LocalizableMessage msg = INFO_DISABLE_REPLICATION_ONE_POINT_OF_FAILURE_PROMPT.get(arg); 5746 if (!askConfirmation(msg, false)) 5747 { 5748 throw new ReplicationCliException(ERR_REPLICATION_USER_CANCELLED.get(), USER_CANCELLED, null); 5749 } 5750 } 5751 } 5752 } 5753 if (!lastRepServer.isEmpty()) 5754 { 5755 // Check that there are other replicas and that this message, really 5756 // makes sense to be displayed. 5757 Set<String> suffixArg = new LinkedHashSet<>(); 5758 for (SuffixDescriptor suffix : lastRepServer) 5759 { 5760 boolean baseDNSpecified = false; 5761 for (String baseDN : uData.getBaseDNs()) 5762 { 5763 if (!isSchemaOrInternalAdminSuffix(baseDN) && areDnsEqual(baseDN, suffix.getDN())) 5764 { 5765 baseDNSpecified = true; 5766 break; 5767 } 5768 } 5769 if (!baseDNSpecified) 5770 { 5771 Set<ServerDescriptor> servers = new TreeSet<>(new ServerComparator()); 5772 for (ReplicaDescriptor replica : suffix.getReplicas()) 5773 { 5774 servers.add(replica.getServer()); 5775 } 5776 suffixArg.add(getSuffixDisplay(suffix.getDN(), servers)); 5777 } 5778 else if (suffix.getReplicas().size() > 1) 5779 { 5780 // If there is just one replica, it is the one in this server. 5781 Set<ServerDescriptor> servers = new TreeSet<>(new ServerComparator()); 5782 for (ReplicaDescriptor replica : suffix.getReplicas()) 5783 { 5784 if (!replica.getServer().isSameServer(server)) 5785 { 5786 servers.add(replica.getServer()); 5787 } 5788 } 5789 if (!servers.isEmpty()) 5790 { 5791 suffixArg.add(getSuffixDisplay(suffix.getDN(), servers)); 5792 } 5793 } 5794 } 5795 5796 if (!suffixArg.isEmpty()) 5797 { 5798 String arg = toSingleLine(suffixArg); 5799 if (!isInteractive()) 5800 { 5801 println(INFO_DISABLE_REPLICATION_DISABLE_IN_REMOTE.get(arg)); 5802 } 5803 else 5804 { 5805 LocalizableMessage msg = INFO_DISABLE_REPLICATION_DISABLE_IN_REMOTE_PROMPT.get(arg); 5806 if (!askConfirmation(msg, false)) 5807 { 5808 throw new ReplicationCliException(ERR_REPLICATION_USER_CANCELLED.get(), USER_CANCELLED, null); 5809 } 5810 } 5811 } 5812 } 5813 } 5814 5815 /** 5816 * Try to figure out if we must explicitly disable replication on 5817 * cn=admin data and cn=schema. 5818 */ 5819 boolean forceDisableSchema = false; 5820 boolean forceDisableADS = false; 5821 boolean schemaReplicated = false; 5822 boolean adsReplicated = false; 5823 boolean disableAllBaseDns = disableAllBaseDns(ctx, uData); 5824 5825 Collection<ReplicaDescriptor> replicas = getReplicas(ctx); 5826 for (ReplicaDescriptor rep : replicas) 5827 { 5828 String dn = rep.getSuffix().getDN(); 5829 if (rep.isReplicated()) 5830 { 5831 if (areDnsEqual(ADSContext.getAdministrationSuffixDN(), dn)) 5832 { 5833 adsReplicated = true; 5834 } 5835 else if (areDnsEqual(Constants.SCHEMA_DN, dn)) 5836 { 5837 schemaReplicated = true; 5838 } 5839 } 5840 } 5841 5842 if (disableAllBaseDns && 5843 (disableReplicationServer || !server.isReplicationServer())) 5844 { 5845 // Unregister the server from the ADS if no other server has dependencies 5846 // with it (no replicated base DNs and no replication server). 5847 server.updateAdsPropertiesWithServerProperties(); 5848 try 5849 { 5850 adsCtx.unregisterServer(server.getAdsProperties()); 5851 // To be sure that the change gets propagated 5852 sleepCatchInterrupt(2000); 5853 } 5854 catch (ADSContextException adce) 5855 { 5856 logger.error(LocalizableMessage.raw("Error unregistering server: "+ 5857 server.getAdsProperties(), adce)); 5858 if (adce.getError() != ADSContextException.ErrorType.NOT_YET_REGISTERED) 5859 { 5860 throw new ReplicationCliException( 5861 ERR_REPLICATION_UPDATING_ADS.get(adce.getMessageObject()), 5862 ERROR_READING_ADS, adce); 5863 } 5864 } 5865 } 5866 5867 Set<String> suffixesToDisable = new HashSet<>(); 5868 if (uData.disableAll()) 5869 { 5870 for (ReplicaDescriptor replica : server.getReplicas()) 5871 { 5872 if (replica.isReplicated()) 5873 { 5874 suffixesToDisable.add(replica.getSuffix().getDN()); 5875 } 5876 } 5877 } 5878 else 5879 { 5880 suffixesToDisable.addAll(uData.getBaseDNs()); 5881 5882 if (disableAllBaseDns && 5883 (disableReplicationServer || !server.isReplicationServer())) 5884 { 5885 forceDisableSchema = schemaReplicated; 5886 forceDisableADS = adsReplicated; 5887 } 5888 for (String dn : uData.getBaseDNs()) 5889 { 5890 if (areDnsEqual(ADSContext.getAdministrationSuffixDN(), dn)) 5891 { 5892 // The user already asked this to be explicitly disabled 5893 forceDisableADS = false; 5894 } 5895 else if (areDnsEqual(Constants.SCHEMA_DN, dn)) 5896 { 5897 // The user already asked this to be explicitly disabled 5898 forceDisableSchema = false; 5899 } 5900 } 5901 5902 if (forceDisableSchema) 5903 { 5904 suffixesToDisable.add(Constants.SCHEMA_DN); 5905 } 5906 if (forceDisableADS) 5907 { 5908 suffixesToDisable.add(ADSContext.getAdministrationSuffixDN()); 5909 } 5910 } 5911 5912 String replicationServerHostPort = 5913 server.isReplicationServer() ? server.getReplicationServerHostPort() : null; 5914 5915 for (String baseDN : suffixesToDisable) 5916 { 5917 try 5918 { 5919 deleteReplicationDomain(ctx, baseDN); 5920 } 5921 catch (OpenDsException ode) 5922 { 5923 LocalizableMessage msg = getMessageForDisableException(getHostPort(ctx), baseDN); 5924 throw new ReplicationCliException(msg, 5925 ERROR_DISABLING_REPLICATION_ON_BASEDN, ode); 5926 } 5927 } 5928 5929 boolean replicationServerDisabled = false; 5930 if (replicationServerHostPort != null && cache != null) 5931 { 5932 Set<ServerDescriptor> serversToUpdate = new LinkedHashSet<>(); 5933 Set<String> baseDNsToUpdate = new HashSet<>(suffixesToDisable); 5934 for (String baseDN : baseDNsToUpdate) 5935 { 5936 SuffixDescriptor suffix = getSuffix(baseDN, cache, server); 5937 if (suffix != null) 5938 { 5939 for (ReplicaDescriptor replica : suffix.getReplicas()) 5940 { 5941 serversToUpdate.add(replica.getServer()); 5942 } 5943 } 5944 } 5945 if (disableReplicationServer) 5946 { 5947 // Find references in all servers. 5948 for (SuffixDescriptor suffix : cache.getSuffixes()) 5949 { 5950 if (containsIgnoreCase(suffix.getReplicationServers(), replicationServerHostPort)) 5951 { 5952 baseDNsToUpdate.add(suffix.getDN()); 5953 for (ReplicaDescriptor replica : suffix.getReplicas()) 5954 { 5955 serversToUpdate.add(replica.getServer()); 5956 } 5957 } 5958 } 5959 } 5960 String bindDn = getBindDN(ctx); 5961 String pwd = getBindPassword(ctx); 5962 for (ServerDescriptor s : serversToUpdate) 5963 { 5964 removeReferencesInServer(s, replicationServerHostPort, bindDn, pwd, 5965 baseDNsToUpdate, disableReplicationServer, 5966 getPreferredConnections(ctx)); 5967 } 5968 5969 if (disableReplicationServer) 5970 { 5971 // Disable replication server 5972 disableReplicationServer(ctx); 5973 replicationServerDisabled = true; 5974 // Wait to be sure that changes are taken into account and reset the 5975 // contents of the ADS. 5976 sleepCatchInterrupt(5000); 5977 } 5978 } 5979 if (disableReplicationServer && !replicationServerDisabled) 5980 { 5981 // This can happen if we could not retrieve the TopologyCache 5982 disableReplicationServer(ctx); 5983 replicationServerDisabled = true; 5984 } 5985 5986 if (uData.disableAll()) 5987 { 5988 try 5989 { 5990 // Delete all contents from ADSContext. 5991 print(formatter.getFormattedWithPoints( 5992 INFO_REPLICATION_REMOVE_ADS_CONTENTS.get())); 5993 adsCtx.removeAdminData(false /* avoid self-disconnect */); 5994 print(formatter.getFormattedDone()); 5995 println(); 5996 } 5997 catch (ADSContextException adce) 5998 { 5999 logger.error(LocalizableMessage.raw("Error removing contents of cn=admin data: "+ 6000 adce, adce)); 6001 throw new ReplicationCliException( 6002 ERR_REPLICATION_UPDATING_ADS.get(adce.getMessageObject()), 6003 ERROR_UPDATING_ADS, adce); 6004 } 6005 } 6006 else if (disableAllBaseDns && 6007 (disableReplicationServer || !server.isReplicationServer())) 6008 { 6009 // Unregister the servers from the ADS of the local server. 6010 try 6011 { 6012 for (Map<ADSContext.ServerProperty, Object> s : adsCtx.readServerRegistry()) 6013 { 6014 adsCtx.unregisterServer(s); 6015 } 6016 // To be sure that the change gets propagated 6017 sleepCatchInterrupt(2000); 6018 } 6019 catch (ADSContextException adce) 6020 { 6021 // This is not critical, do not send an error 6022 logger.warn(LocalizableMessage.raw("Error unregistering server: "+ 6023 server.getAdsProperties(), adce)); 6024 } 6025 } 6026 } 6027 6028 private void addBaseDNs(TopologyCacheFilter filter, List<String> baseDNs) 6029 { 6030 for (String dn : baseDNs) 6031 { 6032 filter.addBaseDNToSearch(dn); 6033 } 6034 } 6035 6036 /** 6037 * Displays the replication status of the different base DNs in the servers 6038 * registered in the ADS. 6039 * @param ctx the connection to the server. 6040 * @param uData the StatusReplicationUserData object containing the required 6041 * parameters to update the configuration. 6042 * @throws ReplicationCliException if there is an error. 6043 */ 6044 private void displayStatus(InitialLdapContext ctx, 6045 StatusReplicationUserData uData) throws ReplicationCliException 6046 { 6047 ADSContext adsCtx = new ADSContext(ctx); 6048 6049 boolean somethingDisplayed = false; 6050 TopologyCache cache; 6051 try 6052 { 6053 cache = new TopologyCache(adsCtx, getTrustManager(sourceServerCI), getConnectTimeout()); 6054 cache.setPreferredConnections(getPreferredConnections(ctx)); 6055 addBaseDNs(cache.getFilter(), uData.getBaseDNs()); 6056 cache.reloadTopology(); 6057 } 6058 catch (TopologyCacheException tce) 6059 { 6060 throw new ReplicationCliException( 6061 ERR_REPLICATION_READING_ADS.get(tce.getMessage()), 6062 ERROR_READING_TOPOLOGY_CACHE, tce); 6063 } 6064 if (mustPrintCommandBuilder()) 6065 { 6066 printNewCommandBuilder(STATUS_REPLICATION_SUBCMD_NAME, uData); 6067 } 6068 if (!argParser.isInteractive()) 6069 { 6070 // Inform the user of the potential errors that we found. 6071 Set<LocalizableMessage> messages = new LinkedHashSet<>(cache.getErrorMessages()); 6072 if (!messages.isEmpty()) 6073 { 6074 errPrintln(ERR_REPLICATION_STATUS_READING_REGISTERED_SERVERS.get( 6075 getMessageFromCollection(messages, Constants.LINE_SEPARATOR))); 6076 } 6077 } 6078 6079 List<String> userBaseDNs = uData.getBaseDNs(); 6080 List<Set<ReplicaDescriptor>> replicaLists = new LinkedList<>(); 6081 6082 boolean oneReplicated = false; 6083 6084 boolean displayAll = userBaseDNs.isEmpty(); 6085 for (SuffixDescriptor suffix : cache.getSuffixes()) 6086 { 6087 String dn = suffix.getDN(); 6088 6089 // If no base DNs where specified display all the base DNs but the schema 6090 // and cn=admin data. 6091 boolean found = containsDN(userBaseDNs, dn) || (displayAll && !isSchemaOrInternalAdminSuffix(dn)); 6092 if (found) 6093 { 6094 if (isAnyReplicated(suffix)) 6095 { 6096 oneReplicated = true; 6097 replicaLists.add(suffix.getReplicas()); 6098 } 6099 else 6100 { 6101 // Check if there are already some non replicated base DNs. 6102 found = false; 6103 for (Set<ReplicaDescriptor> replicas : replicaLists) 6104 { 6105 ReplicaDescriptor replica = replicas.iterator().next(); 6106 if (!replica.isReplicated() && 6107 areDnsEqual(dn, replica.getSuffix().getDN())) 6108 { 6109 replicas.addAll(suffix.getReplicas()); 6110 found = true; 6111 break; 6112 } 6113 } 6114 if (!found) 6115 { 6116 replicaLists.add(suffix.getReplicas()); 6117 } 6118 } 6119 } 6120 } 6121 6122 if (!oneReplicated && displayAll) 6123 { 6124 // Maybe there are some replication server configured... 6125 SortedSet<ServerDescriptor> rServers = new TreeSet<>(new ReplicationServerComparator()); 6126 for (ServerDescriptor server : cache.getServers()) 6127 { 6128 if (server.isReplicationServer()) 6129 { 6130 rServers.add(server); 6131 } 6132 } 6133 if (!rServers.isEmpty()) 6134 { 6135 displayStatus(rServers, uData.isScriptFriendly(), getPreferredConnections(ctx)); 6136 somethingDisplayed = true; 6137 } 6138 } 6139 6140 if (!replicaLists.isEmpty()) 6141 { 6142 List<Set<ReplicaDescriptor>> orderedReplicaLists = new LinkedList<>(); 6143 for (Set<ReplicaDescriptor> replicas : replicaLists) 6144 { 6145 String dn1 = replicas.iterator().next().getSuffix().getDN(); 6146 boolean inserted = false; 6147 for (int i=0; i<orderedReplicaLists.size() && !inserted; i++) 6148 { 6149 String dn2 = 6150 orderedReplicaLists.get(i).iterator().next().getSuffix().getDN(); 6151 if (dn1.compareTo(dn2) < 0) 6152 { 6153 orderedReplicaLists.add(i, replicas); 6154 inserted = true; 6155 } 6156 } 6157 if (!inserted) 6158 { 6159 orderedReplicaLists.add(replicas); 6160 } 6161 } 6162 Set<ReplicaDescriptor> replicasWithNoReplicationServer = new HashSet<>(); 6163 Set<ServerDescriptor> serversWithNoReplica = new HashSet<>(); 6164 displayStatus(orderedReplicaLists, uData.isScriptFriendly(), 6165 getPreferredConnections(ctx), 6166 cache.getServers(), 6167 replicasWithNoReplicationServer, serversWithNoReplica); 6168 somethingDisplayed = true; 6169 6170 if (oneReplicated && !uData.isScriptFriendly()) 6171 { 6172 println(); 6173 print(INFO_REPLICATION_STATUS_REPLICATED_LEGEND.get()); 6174 6175 if (!replicasWithNoReplicationServer.isEmpty() || 6176 !serversWithNoReplica.isEmpty()) 6177 { 6178 println(); 6179 print( 6180 INFO_REPLICATION_STATUS_NOT_A_REPLICATION_SERVER_LEGEND.get()); 6181 6182 println(); 6183 print( 6184 INFO_REPLICATION_STATUS_NOT_A_REPLICATION_DOMAIN_LEGEND.get()); 6185 } 6186 println(); 6187 somethingDisplayed = true; 6188 } 6189 } 6190 if (!somethingDisplayed) 6191 { 6192 if (displayAll) 6193 { 6194 print(INFO_REPLICATION_STATUS_NO_REPLICATION_INFORMATION.get()); 6195 println(); 6196 } 6197 else 6198 { 6199 print(INFO_REPLICATION_STATUS_NO_BASEDNS.get()); 6200 println(); 6201 } 6202 } 6203 } 6204 6205 private boolean isAnyReplicated(SuffixDescriptor suffix) 6206 { 6207 for (ReplicaDescriptor replica : suffix.getReplicas()) 6208 { 6209 if (replica.isReplicated()) 6210 { 6211 return true; 6212 } 6213 } 6214 return false; 6215 } 6216 6217 /** 6218 * Displays the replication status of the replicas provided. The code assumes 6219 * that all the replicas have the same baseDN and that if they are replicated 6220 * all the replicas are replicated with each other. 6221 * Note: the code assumes that all the objects come from the same read of the 6222 * topology cache. So comparisons in terms of pointers can be made. 6223 * @param orderedReplicaLists the list of replicas that we are trying to 6224 * display. 6225 * @param scriptFriendly whether to display it on script-friendly mode or not. 6226 * @param cnx the preferred connections used to connect to the server. 6227 * @param servers all the servers configured in the topology. 6228 * @param replicasWithNoReplicationServer the set of replicas that will be 6229 * updated with all the replicas that have no replication server. 6230 * @param serversWithNoReplica the set of servers that will be updated with 6231 * all the servers that act as replication server in the topology but have 6232 * no replica. 6233 */ 6234 private void displayStatus( 6235 List<Set<ReplicaDescriptor>> orderedReplicaLists, 6236 boolean scriptFriendly, Set<PreferredConnection> cnx, 6237 Set<ServerDescriptor> servers, 6238 Set<ReplicaDescriptor> replicasWithNoReplicationServer, 6239 Set<ServerDescriptor> serversWithNoReplica) 6240 { 6241 Set<ReplicaDescriptor> orderedReplicas = new LinkedHashSet<>(); 6242 Set<String> hostPorts = new TreeSet<>(); 6243 Set<ServerDescriptor> notAddedReplicationServers = new TreeSet<>(new ReplicationServerComparator()); 6244 for (Set<ReplicaDescriptor> replicas : orderedReplicaLists) 6245 { 6246 for (ReplicaDescriptor replica : replicas) 6247 { 6248 hostPorts.add(getHostPort2(replica.getServer(), cnx)); 6249 } 6250 for (String hostPort : hostPorts) 6251 { 6252 for (ReplicaDescriptor replica : replicas) 6253 { 6254 if (getHostPort2(replica.getServer(), cnx).equals(hostPort)) 6255 { 6256 orderedReplicas.add(replica); 6257 } 6258 } 6259 } 6260 for (ServerDescriptor server : servers) 6261 { 6262 if (server.isReplicationServer() && isRepServerNotInDomain(replicas, server)) 6263 { 6264 notAddedReplicationServers.add(server); 6265 } 6266 } 6267 } 6268 6269 /* 6270 * The table has the following columns: 6271 * - suffix DN; 6272 * - server; 6273 * - number of entries; 6274 * - replication enabled indicator; 6275 * - directory server instance ID; 6276 * - replication server; 6277 * - replication server ID; 6278 * - missing changes; 6279 * - age of the oldest change, and 6280 * - security enabled indicator. 6281 */ 6282 TableBuilder tableBuilder = new TableBuilder(); 6283 6284 /* Table headings. */ 6285 tableBuilder.appendHeading( 6286 INFO_REPLICATION_STATUS_HEADER_SUFFIX_DN.get()); 6287 tableBuilder.appendHeading( 6288 INFO_REPLICATION_STATUS_HEADER_SERVERPORT.get()); 6289 tableBuilder.appendHeading( 6290 INFO_REPLICATION_STATUS_HEADER_NUMBER_ENTRIES.get()); 6291 tableBuilder.appendHeading( 6292 INFO_REPLICATION_STATUS_HEADER_REPLICATION_ENABLED.get()); 6293 tableBuilder.appendHeading(INFO_REPLICATION_STATUS_HEADER_DS_ID.get()); 6294 tableBuilder.appendHeading(INFO_REPLICATION_STATUS_HEADER_RS_ID.get()); 6295 tableBuilder.appendHeading( 6296 INFO_REPLICATION_STATUS_HEADER_REPLICATION_PORT.get()); 6297 tableBuilder.appendHeading( 6298 INFO_REPLICATION_STATUS_HEADER_MISSING_CHANGES.get()); 6299 tableBuilder.appendHeading( 6300 INFO_REPLICATION_STATUS_HEADER_AGE_OF_OLDEST_MISSING_CHANGE.get()); 6301 tableBuilder.appendHeading( 6302 INFO_REPLICATION_STATUS_HEADER_SECURE.get()); 6303 6304 /* Table data. */ 6305 for (ReplicaDescriptor replica : orderedReplicas) 6306 { 6307 tableBuilder.startRow(); 6308 // Suffix DN 6309 tableBuilder.appendCell(LocalizableMessage.raw(replica.getSuffix().getDN())); 6310 // Server port 6311 tableBuilder.appendCell( 6312 LocalizableMessage.raw(getHostPort2(replica.getServer(), cnx))); 6313 // Number of entries 6314 int nEntries = replica.getEntries(); 6315 if (nEntries >= 0) 6316 { 6317 tableBuilder.appendCell(LocalizableMessage.raw(String.valueOf(nEntries))); 6318 } 6319 else 6320 { 6321 tableBuilder.appendCell(EMPTY_MSG); 6322 } 6323 6324 if (!replica.isReplicated()) 6325 { 6326 tableBuilder.appendCell(EMPTY_MSG); 6327 } 6328 else 6329 { 6330 // Replication enabled 6331 tableBuilder.appendCell( 6332 LocalizableMessage.raw(Boolean.toString(replica.isReplicationEnabled()))); 6333 6334 // DS instance ID 6335 tableBuilder.appendCell( 6336 LocalizableMessage.raw(Integer.toString(replica.getReplicationId()))); 6337 6338 // RS ID and port. 6339 if (replica.getServer().isReplicationServer()) 6340 { 6341 tableBuilder.appendCell(Integer.toString(replica.getServer() 6342 .getReplicationServerId())); 6343 tableBuilder.appendCell(LocalizableMessage.raw(String.valueOf(replica 6344 .getServer().getReplicationServerPort()))); 6345 } 6346 else 6347 { 6348 if (scriptFriendly) 6349 { 6350 tableBuilder.appendCell(EMPTY_MSG); 6351 } 6352 else 6353 { 6354 tableBuilder.appendCell( 6355 INFO_REPLICATION_STATUS_NOT_A_REPLICATION_SERVER_SHORT.get()); 6356 } 6357 tableBuilder.appendCell(EMPTY_MSG); 6358 replicasWithNoReplicationServer.add(replica); 6359 } 6360 6361 // Missing changes 6362 int missingChanges = replica.getMissingChanges(); 6363 if (missingChanges >= 0) 6364 { 6365 tableBuilder.appendCell(LocalizableMessage.raw(String.valueOf(missingChanges))); 6366 } 6367 else 6368 { 6369 tableBuilder.appendCell(EMPTY_MSG); 6370 } 6371 6372 // Age of oldest missing change 6373 long ageOfOldestMissingChange = replica.getAgeOfOldestMissingChange(); 6374 if (ageOfOldestMissingChange > 0) 6375 { 6376 Date date = new Date(ageOfOldestMissingChange); 6377 tableBuilder.appendCell(LocalizableMessage.raw(date.toString())); 6378 } 6379 else 6380 { 6381 tableBuilder.appendCell(EMPTY_MSG); 6382 } 6383 6384 // Secure 6385 if (!replica.getServer().isReplicationServer()) 6386 { 6387 tableBuilder.appendCell(EMPTY_MSG); 6388 } 6389 else 6390 { 6391 tableBuilder.appendCell( 6392 LocalizableMessage.raw(Boolean.toString( 6393 replica.getServer().isReplicationSecure()))); 6394 } 6395 } 6396 } 6397 6398 for (ServerDescriptor server : notAddedReplicationServers) 6399 { 6400 tableBuilder.startRow(); 6401 serversWithNoReplica.add(server); 6402 6403 // Suffix DN 6404 tableBuilder.appendCell(EMPTY_MSG); 6405 // Server port 6406 tableBuilder.appendCell(LocalizableMessage.raw(getHostPort2(server, cnx))); 6407 // Number of entries 6408 if (scriptFriendly) 6409 { 6410 tableBuilder.appendCell(EMPTY_MSG); 6411 } 6412 else 6413 { 6414 tableBuilder.appendCell( 6415 INFO_REPLICATION_STATUS_NOT_A_REPLICATION_DOMAIN_SHORT.get()); 6416 } 6417 6418 // Replication enabled 6419 tableBuilder.appendCell(Boolean.toString(true)); 6420 6421 // DS ID 6422 tableBuilder.appendCell(EMPTY_MSG); 6423 6424 // RS ID 6425 tableBuilder.appendCell( 6426 LocalizableMessage.raw(Integer.toString(server.getReplicationServerId()))); 6427 6428 // Replication port 6429 int replicationPort = server.getReplicationServerPort(); 6430 if (replicationPort >= 0) 6431 { 6432 tableBuilder.appendCell( 6433 LocalizableMessage.raw(String.valueOf(replicationPort))); 6434 } 6435 else 6436 { 6437 tableBuilder.appendCell(EMPTY_MSG); 6438 } 6439 6440 // Missing changes 6441 tableBuilder.appendCell(EMPTY_MSG); 6442 6443 // Age of oldest change 6444 tableBuilder.appendCell(EMPTY_MSG); 6445 6446 // Secure 6447 tableBuilder.appendCell( 6448 LocalizableMessage.raw(Boolean.toString(server.isReplicationSecure()))); 6449 } 6450 6451 TablePrinter printer; 6452 PrintStream out = getOutputStream(); 6453 if (scriptFriendly) 6454 { 6455 printer = new TabSeparatedTablePrinter(out); 6456 } 6457 else 6458 { 6459 final TextTablePrinter ttPrinter = new TextTablePrinter(out); 6460 ttPrinter.setColumnSeparator(LIST_TABLE_SEPARATOR); 6461 printer = ttPrinter; 6462 } 6463 tableBuilder.print(printer); 6464 } 6465 6466 private boolean isRepServerNotInDomain(Set<ReplicaDescriptor> replicas, ServerDescriptor server) 6467 { 6468 boolean isDomain = false; 6469 boolean isRepServer = false; 6470 String replicationServer = server.getReplicationServerHostPort(); 6471 for (ReplicaDescriptor replica : replicas) 6472 { 6473 if (!isRepServer) 6474 { 6475 isRepServer = containsIgnoreCase(replica.getReplicationServers(), replicationServer); 6476 } 6477 if (replica.getServer() == server) 6478 { 6479 isDomain = true; 6480 } 6481 if (isDomain && isRepServer) 6482 { 6483 break; 6484 } 6485 } 6486 return !isDomain && isRepServer; 6487 } 6488 6489 /** 6490 * Displays the replication status of the replication servers provided. The 6491 * code assumes that all the servers have a replication server and that there 6492 * are associated with no replication domain. 6493 * @param servers the servers 6494 * @param cnx the preferred connections used to connect to the server. 6495 * @param scriptFriendly wheter to display it on script-friendly mode or not. 6496 */ 6497 private void displayStatus(Set<ServerDescriptor> servers, 6498 boolean scriptFriendly, Set<PreferredConnection> cnx) 6499 { 6500 TableBuilder tableBuilder = new TableBuilder(); 6501 tableBuilder.appendHeading(INFO_REPLICATION_STATUS_HEADER_SERVERPORT.get()); 6502 tableBuilder.appendHeading( 6503 INFO_REPLICATION_STATUS_HEADER_REPLICATION_PORT.get()); 6504 tableBuilder.appendHeading(INFO_REPLICATION_STATUS_HEADER_SECURE.get()); 6505 6506 for (ServerDescriptor server : servers) 6507 { 6508 tableBuilder.startRow(); 6509 // Server port 6510 tableBuilder.appendCell(LocalizableMessage.raw(getHostPort2(server, cnx))); 6511 // Replication port 6512 int replicationPort = server.getReplicationServerPort(); 6513 if (replicationPort >= 0) 6514 { 6515 tableBuilder.appendCell(LocalizableMessage.raw(String.valueOf(replicationPort))); 6516 } 6517 else 6518 { 6519 tableBuilder.appendCell(EMPTY_MSG); 6520 } 6521 // Secure 6522 tableBuilder.appendCell(LocalizableMessage.raw(Boolean.toString(server.isReplicationSecure()))); 6523 } 6524 6525 PrintStream out = getOutputStream(); 6526 TablePrinter printer; 6527 6528 if (scriptFriendly) 6529 { 6530 print(INFO_REPLICATION_STATUS_INDEPENDENT_REPLICATION_SERVERS.get()); 6531 println(); 6532 printer = new TabSeparatedTablePrinter(out); 6533 } 6534 else 6535 { 6536 LocalizableMessage msg = INFO_REPLICATION_STATUS_INDEPENDENT_REPLICATION_SERVERS.get(); 6537 print(msg); 6538 println(); 6539 int length = msg.length(); 6540 StringBuilder buf = new StringBuilder(); 6541 for (int i=0; i<length; i++) 6542 { 6543 buf.append("="); 6544 } 6545 print(LocalizableMessage.raw(buf.toString())); 6546 println(); 6547 6548 printer = new TextTablePrinter(getOutputStream()); 6549 ((TextTablePrinter)printer).setColumnSeparator( 6550 LIST_TABLE_SEPARATOR); 6551 } 6552 tableBuilder.print(printer); 6553 } 6554 6555 /** 6556 * Retrieves all the replication servers for a given baseDN. The 6557 * ServerDescriptor is used to identify the server where the suffix is 6558 * defined and it cannot be null. The TopologyCache is used to retrieve 6559 * replication servers defined in other replicas but not in the one we 6560 * get in the ServerDescriptor. 6561 * @param baseDN the base DN. 6562 * @param cache the TopologyCache (might be null). 6563 * @param server the ServerDescriptor. 6564 * @return a Set containing the replication servers currently being used 6565 * to replicate the baseDN defined in the server described by the 6566 * ServerDescriptor. 6567 */ 6568 private Set<String> getReplicationServers(String baseDN, 6569 TopologyCache cache, ServerDescriptor server) 6570 { 6571 Set<String> servers = getAllReplicationServers(baseDN, server); 6572 if (cache != null) 6573 { 6574 for (SuffixDescriptor suffix : cache.getSuffixes()) 6575 { 6576 if (areDnsEqual(suffix.getDN(), baseDN)) 6577 { 6578 Set<String> s = suffix.getReplicationServers(); 6579 // Test that at least we share one of the replication servers. 6580 // If we do: we are dealing with the same replication topology 6581 // (we must consider the case of disjoint replication topologies 6582 // replicating the same base DN). 6583 Set<String> copy = new HashSet<>(s); 6584 copy.retainAll(servers); 6585 if (!copy.isEmpty()) 6586 { 6587 servers.addAll(s); 6588 break; 6589 } 6590 else if (server.isReplicationServer() 6591 && containsIgnoreCase(s, server.getReplicationServerHostPort())) 6592 { 6593 // this server is acting as replication server with no domain. 6594 servers.addAll(s); 6595 break; 6596 } 6597 } 6598 } 6599 } 6600 return servers; 6601 } 6602 6603 private boolean containsIgnoreCase(Set<String> col, String toFind) 6604 { 6605 for (String s : col) 6606 { 6607 if (s.equalsIgnoreCase(toFind)) 6608 { 6609 return true; 6610 } 6611 } 6612 return false; 6613 } 6614 6615 private String findIgnoreCase(Set<String> col, String toFind) 6616 { 6617 for (String s : col) 6618 { 6619 if (toFind.equalsIgnoreCase(s)) 6620 { 6621 return s; 6622 } 6623 } 6624 return null; 6625 } 6626 6627 /** 6628 * Retrieves the suffix in the TopologyCache for a given baseDN. The 6629 * ServerDescriptor is used to identify the server where the suffix is 6630 * defined. 6631 * @param baseDN the base DN. 6632 * @param cache the TopologyCache. 6633 * @param server the ServerDescriptor. 6634 * @return the suffix in the TopologyCache for a given baseDN. 6635 */ 6636 private SuffixDescriptor getSuffix(String baseDN, TopologyCache cache, 6637 ServerDescriptor server) 6638 { 6639 String replicationServer = null; 6640 if (server.isReplicationServer()) 6641 { 6642 replicationServer = server.getReplicationServerHostPort(); 6643 } 6644 6645 SuffixDescriptor returnValue = null; 6646 Set<String> servers = getAllReplicationServers(baseDN, server); 6647 for (SuffixDescriptor suffix : cache.getSuffixes()) 6648 { 6649 if (areDnsEqual(suffix.getDN(), baseDN)) 6650 { 6651 Set<String> s = suffix.getReplicationServers(); 6652 // Test that at least we share one of the replication servers. 6653 // If we do: we are dealing with the same replication topology 6654 // (we must consider the case of disjoint replication topologies 6655 // replicating the same base DN). 6656 HashSet<String> copy = new HashSet<>(s); 6657 copy.retainAll(servers); 6658 if (!copy.isEmpty()) 6659 { 6660 return suffix; 6661 } 6662 else if (replicationServer != null && containsIgnoreCase(s, replicationServer)) 6663 { 6664 returnValue = suffix; 6665 } 6666 } 6667 } 6668 return returnValue; 6669 } 6670 6671 private Set<String> getAllReplicationServers(String baseDN, ServerDescriptor server) 6672 { 6673 Set<String> servers = new LinkedHashSet<>(); 6674 for (ReplicaDescriptor replica : server.getReplicas()) 6675 { 6676 if (areDnsEqual(replica.getSuffix().getDN(), baseDN)) 6677 { 6678 servers.addAll(replica.getReplicationServers()); 6679 break; 6680 } 6681 } 6682 return servers; 6683 } 6684 6685 /** 6686 * Retrieves all the replication domain IDs for a given baseDN in the 6687 * ServerDescriptor. 6688 * @param baseDN the base DN. 6689 * @param server the ServerDescriptor. 6690 * @return a Set containing the replication domain IDs for a given baseDN in 6691 * the ServerDescriptor. 6692 */ 6693 private Set<Integer> getReplicationDomainIds(String baseDN, 6694 ServerDescriptor server) 6695 { 6696 Set<Integer> ids = new HashSet<>(); 6697 for (ReplicaDescriptor replica : server.getReplicas()) 6698 { 6699 if (replica.isReplicated() 6700 && areDnsEqual(replica.getSuffix().getDN(), baseDN)) 6701 { 6702 ids.add(replica.getReplicationId()); 6703 break; 6704 } 6705 } 6706 return ids; 6707 } 6708 6709 /** 6710 * Configures the server to which the provided InitialLdapContext is connected 6711 * as a replication server. The replication server listens in the provided 6712 * port. 6713 * @param ctx the context connected to the server that we want to configure. 6714 * @param replicationPort the replication port of the replication server. 6715 * @param useSecureReplication whether to have encrypted communication with 6716 * the replication port or not. 6717 * @param replicationServers the list of replication servers to which the 6718 * replication server will communicate with. 6719 * @param usedReplicationServerIds the set of replication server IDs that 6720 * are already in use. The set will be updated with the replication ID 6721 * that will be used by the newly configured replication server. 6722 * @throws OpenDsException if there is an error updating the configuration. 6723 */ 6724 private void configureAsReplicationServer(InitialLdapContext ctx, 6725 int replicationPort, boolean useSecureReplication, 6726 Set<String> replicationServers, 6727 Set<Integer> usedReplicationServerIds) throws OpenDsException 6728 { 6729 print(formatter.getFormattedWithPoints( 6730 INFO_REPLICATION_ENABLE_CONFIGURING_REPLICATION_SERVER.get(getHostPort(ctx)))); 6731 6732 ManagementContext mCtx = LDAPManagementContext.createFromContext( 6733 JNDIDirContextAdaptor.adapt(ctx)); 6734 RootCfgClient root = mCtx.getRootConfiguration(); 6735 6736 /* Configure Synchronization plugin. */ 6737 ReplicationSynchronizationProviderCfgClient sync = null; 6738 try 6739 { 6740 sync = (ReplicationSynchronizationProviderCfgClient) 6741 root.getSynchronizationProvider("Multimaster Synchronization"); 6742 } 6743 catch (ManagedObjectNotFoundException monfe) 6744 { 6745 logger.info(LocalizableMessage.raw("Synchronization server does not exist in " + getHostPort(ctx))); 6746 } 6747 if (sync == null) 6748 { 6749 ReplicationSynchronizationProviderCfgDefn provider = 6750 ReplicationSynchronizationProviderCfgDefn.getInstance(); 6751 sync = root.createSynchronizationProvider(provider, 6752 "Multimaster Synchronization", 6753 new ArrayList<PropertyException>()); 6754 sync.setJavaClass( 6755 org.opends.server.replication.plugin.MultimasterReplication.class. 6756 getName()); 6757 sync.setEnabled(Boolean.TRUE); 6758 } 6759 else if (!sync.isEnabled()) 6760 { 6761 sync.setEnabled(Boolean.TRUE); 6762 } 6763 sync.commit(); 6764 6765 /* Configure the replication server. */ 6766 ReplicationServerCfgClient replicationServer; 6767 6768 boolean mustCommit = false; 6769 6770 if (!sync.hasReplicationServer()) 6771 { 6772 CryptoManagerCfgClient crypto = root.getCryptoManager(); 6773 if (useSecureReplication != crypto.isSSLEncryption()) 6774 { 6775 crypto.setSSLEncryption(useSecureReplication); 6776 crypto.commit(); 6777 } 6778 int id = InstallerHelper.getReplicationId(usedReplicationServerIds); 6779 usedReplicationServerIds.add(id); 6780 replicationServer = sync.createReplicationServer( 6781 ReplicationServerCfgDefn.getInstance(), 6782 new ArrayList<PropertyException>()); 6783 replicationServer.setReplicationServerId(id); 6784 replicationServer.setReplicationPort(replicationPort); 6785 replicationServer.setReplicationServer(replicationServers); 6786 mustCommit = true; 6787 } 6788 else 6789 { 6790 replicationServer = sync.getReplicationServer(); 6791 usedReplicationServerIds.add( 6792 replicationServer.getReplicationServerId()); 6793 Set<String> servers = replicationServer.getReplicationServer(); 6794 if (servers == null) 6795 { 6796 replicationServer.setReplicationServer(replicationServers); 6797 mustCommit = true; 6798 } 6799 else if (!areReplicationServersEqual(servers, replicationServers)) 6800 { 6801 replicationServer.setReplicationServer( 6802 mergeReplicationServers(replicationServers, servers)); 6803 mustCommit = true; 6804 } 6805 } 6806 if (mustCommit) 6807 { 6808 replicationServer.commit(); 6809 } 6810 6811 print(formatter.getFormattedDone()); 6812 println(); 6813 } 6814 6815 /** 6816 * Updates the configuration of the replication server with the list of 6817 * replication servers provided. 6818 * @param ctx the context connected to the server that we want to update. 6819 * @param replicationServers the list of replication servers to which the 6820 * replication server will communicate with. 6821 * @throws OpenDsException if there is an error updating the configuration. 6822 */ 6823 private void updateReplicationServer(InitialLdapContext ctx, 6824 Set<String> replicationServers) throws OpenDsException 6825 { 6826 print(formatter.getFormattedWithPoints( 6827 INFO_REPLICATION_ENABLE_UPDATING_REPLICATION_SERVER.get(getHostPort(ctx)))); 6828 6829 ManagementContext mCtx = LDAPManagementContext.createFromContext( 6830 JNDIDirContextAdaptor.adapt(ctx)); 6831 RootCfgClient root = mCtx.getRootConfiguration(); 6832 6833 ReplicationSynchronizationProviderCfgClient sync = 6834 (ReplicationSynchronizationProviderCfgClient) 6835 root.getSynchronizationProvider("Multimaster Synchronization"); 6836 boolean mustCommit = false; 6837 ReplicationServerCfgClient replicationServer = sync.getReplicationServer(); 6838 Set<String> servers = replicationServer.getReplicationServer(); 6839 if (servers == null) 6840 { 6841 replicationServer.setReplicationServer(replicationServers); 6842 mustCommit = true; 6843 } 6844 else if (!areReplicationServersEqual(servers, replicationServers)) 6845 { 6846 replicationServers.addAll(servers); 6847 replicationServer.setReplicationServer( 6848 mergeReplicationServers(replicationServers, servers)); 6849 mustCommit = true; 6850 } 6851 if (mustCommit) 6852 { 6853 replicationServer.commit(); 6854 } 6855 6856 print(formatter.getFormattedDone()); 6857 println(); 6858 } 6859 6860 /** 6861 * Returns a Set containing all the replication server ids found in the 6862 * servers of a given TopologyCache object. 6863 * @param cache the TopologyCache object to use. 6864 * @return a Set containing all the replication server ids found in a given 6865 * TopologyCache object. 6866 */ 6867 private Set<Integer> getReplicationServerIds(TopologyCache cache) 6868 { 6869 Set<Integer> ids = new HashSet<>(); 6870 for (ServerDescriptor server : cache.getServers()) 6871 { 6872 if (server.isReplicationServer()) 6873 { 6874 ids.add(server.getReplicationServerId()); 6875 } 6876 } 6877 return ids; 6878 } 6879 6880 /** 6881 * Configures a replication domain for a given base DN in the server to which 6882 * the provided InitialLdapContext is connected. 6883 * @param ctx the context connected to the server that we want to configure. 6884 * @param baseDN the base DN of the replication domain to configure. 6885 * @param replicationServers the list of replication servers to which the 6886 * replication domain will communicate with. 6887 * @param usedReplicationDomainIds the set of replication domain IDs that 6888 * are already in use. The set will be updated with the replication ID 6889 * that will be used by the newly configured replication server. 6890 * @throws OpenDsException if there is an error updating the configuration. 6891 */ 6892 private void configureToReplicateBaseDN(InitialLdapContext ctx, 6893 String baseDN, 6894 Set<String> replicationServers, 6895 Set<Integer> usedReplicationDomainIds) throws OpenDsException 6896 { 6897 boolean userSpecifiedAdminBaseDN = false; 6898 List<String> l = argParser.getBaseDNs(); 6899 if (l != null) 6900 { 6901 userSpecifiedAdminBaseDN = containsDN(l, ADSContext.getAdministrationSuffixDN()); 6902 } 6903 if (!userSpecifiedAdminBaseDN 6904 && areDnsEqual(baseDN, ADSContext.getAdministrationSuffixDN())) 6905 { 6906 print(formatter.getFormattedWithPoints( 6907 INFO_REPLICATION_ENABLE_CONFIGURING_ADS.get(getHostPort(ctx)))); 6908 } 6909 else 6910 { 6911 print(formatter.getFormattedWithPoints( 6912 INFO_REPLICATION_ENABLE_CONFIGURING_BASEDN.get(baseDN, getHostPort(ctx)))); 6913 } 6914 ManagementContext mCtx = LDAPManagementContext.createFromContext( 6915 JNDIDirContextAdaptor.adapt(ctx)); 6916 RootCfgClient root = mCtx.getRootConfiguration(); 6917 6918 ReplicationSynchronizationProviderCfgClient sync = 6919 (ReplicationSynchronizationProviderCfgClient) 6920 root.getSynchronizationProvider("Multimaster Synchronization"); 6921 6922 String[] domainNames = sync.listReplicationDomains(); 6923 if (domainNames == null) 6924 { 6925 domainNames = new String[]{}; 6926 } 6927 ReplicationDomainCfgClient[] domains = 6928 new ReplicationDomainCfgClient[domainNames.length]; 6929 for (int i=0; i<domains.length; i++) 6930 { 6931 domains[i] = sync.getReplicationDomain(domainNames[i]); 6932 } 6933 ReplicationDomainCfgClient domain = null; 6934 for (ReplicationDomainCfgClient domain2 : domains) 6935 { 6936 if (areDnsEqual(baseDN, domain2.getBaseDN().toString())) 6937 { 6938 domain = domain2; 6939 break; 6940 } 6941 } 6942 boolean mustCommit = false; 6943 if (domain == null) 6944 { 6945 int domainId = InstallerHelper.getReplicationId(usedReplicationDomainIds); 6946 usedReplicationDomainIds.add(domainId); 6947 String domainName = InstallerHelper.getDomainName(domainNames, baseDN); 6948 domain = sync.createReplicationDomain( 6949 ReplicationDomainCfgDefn.getInstance(), domainName, 6950 new ArrayList<PropertyException>()); 6951 domain.setServerId(domainId); 6952 domain.setBaseDN(DN.valueOf(baseDN)); 6953 domain.setReplicationServer(replicationServers); 6954 mustCommit = true; 6955 } 6956 else 6957 { 6958 Set<String> servers = domain.getReplicationServer(); 6959 if (servers == null) 6960 { 6961 domain.setReplicationServer(null); 6962 mustCommit = true; 6963 } 6964 else if (!areReplicationServersEqual(servers, replicationServers)) 6965 { 6966 domain.setReplicationServer(mergeReplicationServers(replicationServers, servers)); 6967 mustCommit = true; 6968 } 6969 } 6970 6971 if (mustCommit) 6972 { 6973 domain.commit(); 6974 } 6975 6976 print(formatter.getFormattedDone()); 6977 println(); 6978 } 6979 6980 /** 6981 * Configures the baseDN to replicate in all the Replicas found in a Topology 6982 * Cache that are replicated with the Replica of the same base DN in the 6983 * provided ServerDescriptor object. 6984 * @param baseDN the base DN to replicate. 6985 * @param repServers the replication servers to be defined in the domain. 6986 * @param usedIds the replication domain Ids already used. This Set is 6987 * updated with the new domains that are used. 6988 * @param cache the TopologyCache used to retrieve the different defined 6989 * replicas. 6990 * @param server the ServerDescriptor that is used to identify the 6991 * replication topology that we are interested at (we only update the replicas 6992 * that are already replicated with this server). 6993 * @param alreadyConfiguredServers the list of already configured servers. If 6994 * a server is in this list no updates are performed to the domain. 6995 * @param alreadyConfiguredReplicationServers the list of already configured 6996 * servers. If a server is in this list no updates are performed to the 6997 * replication server. 6998 * @throws ReplicationCliException if something goes wrong. 6999 */ 7000 private void configureToReplicateBaseDN(String baseDN, 7001 Set<String> repServers, Set<Integer> usedIds, 7002 TopologyCache cache, ServerDescriptor server, 7003 Set<String> alreadyConfiguredServers, Set<String> allRepServers, 7004 Set<String> alreadyConfiguredReplicationServers) 7005 throws ReplicationCliException 7006 { 7007 logger.info(LocalizableMessage.raw("Configuring base DN '"+baseDN+ 7008 "' the replication servers are "+repServers)); 7009 Set<ServerDescriptor> serversToConfigureDomain = new HashSet<>(); 7010 Set<ServerDescriptor> replicationServersToConfigure = new HashSet<>(); 7011 SuffixDescriptor suffix = getSuffix(baseDN, cache, server); 7012 if (suffix != null) 7013 { 7014 for (ReplicaDescriptor replica: suffix.getReplicas()) 7015 { 7016 ServerDescriptor s = replica.getServer(); 7017 if (!alreadyConfiguredServers.contains(s.getId())) 7018 { 7019 serversToConfigureDomain.add(s); 7020 } 7021 } 7022 } 7023 // Now check the replication servers. 7024 for (ServerDescriptor s : cache.getServers()) 7025 { 7026 if (s.isReplicationServer() 7027 && !alreadyConfiguredReplicationServers.contains(s.getId()) 7028 // Check if it is part of the replication topology 7029 && containsIgnoreCase(repServers, s.getReplicationServerHostPort())) 7030 { 7031 replicationServersToConfigure.add(s); 7032 } 7033 } 7034 7035 Set<ServerDescriptor> allServers = new HashSet<>(serversToConfigureDomain); 7036 allServers.addAll(replicationServersToConfigure); 7037 7038 for (ServerDescriptor s : allServers) 7039 { 7040 logger.info(LocalizableMessage.raw("Configuring server "+server.getHostPort(true))); 7041 InitialLdapContext ctx = null; 7042 try 7043 { 7044 ctx = getDirContextForServer(cache, s); 7045 if (serversToConfigureDomain.contains(s)) 7046 { 7047 configureToReplicateBaseDN(ctx, baseDN, repServers, usedIds); 7048 } 7049 if (replicationServersToConfigure.contains(s)) 7050 { 7051 updateReplicationServer(ctx, allRepServers); 7052 } 7053 } 7054 catch (NamingException ne) 7055 { 7056 String hostPort = getHostPort2(s, cache.getPreferredConnections()); 7057 LocalizableMessage msg = getMessageForException(ne, hostPort); 7058 throw new ReplicationCliException(msg, ERROR_CONNECTING, ne); 7059 } 7060 catch (OpenDsException ode) 7061 { 7062 String hostPort = getHostPort2(s, cache.getPreferredConnections()); 7063 LocalizableMessage msg = getMessageForEnableException(hostPort, baseDN); 7064 throw new ReplicationCliException(msg, 7065 ERROR_ENABLING_REPLICATION_ON_BASEDN, ode); 7066 } 7067 finally 7068 { 7069 close(ctx); 7070 } 7071 alreadyConfiguredServers.add(s.getId()); 7072 alreadyConfiguredReplicationServers.add(s.getId()); 7073 } 7074 } 7075 7076 /** 7077 * Returns the Map of properties to be used to update the ADS. 7078 * This map uses the data provided by the user. 7079 * @return the Map of properties to be used to update the ADS. 7080 * This map uses the data provided by the user 7081 */ 7082 private Map<ADSContext.AdministratorProperty, Object> 7083 getAdministratorProperties(ReplicationUserData uData) 7084 { 7085 Map<ADSContext.AdministratorProperty, Object> adminProperties = new HashMap<>(); 7086 adminProperties.put(ADSContext.AdministratorProperty.UID, uData.getAdminUid()); 7087 adminProperties.put(ADSContext.AdministratorProperty.PASSWORD, uData.getAdminPwd()); 7088 adminProperties.put(ADSContext.AdministratorProperty.DESCRIPTION, 7089 INFO_GLOBAL_ADMINISTRATOR_DESCRIPTION.get().toString()); 7090 return adminProperties; 7091 } 7092 7093 private void initializeSuffix(String baseDN, InitialLdapContext ctxSource, 7094 InitialLdapContext ctxDestination, boolean displayProgress) 7095 throws ReplicationCliException 7096 { 7097 int replicationId = -1; 7098 try 7099 { 7100 TopologyCacheFilter filter = new TopologyCacheFilter(); 7101 filter.setSearchMonitoringInformation(false); 7102 filter.addBaseDNToSearch(baseDN); 7103 ServerDescriptor source = ServerDescriptor.createStandalone(ctxSource, filter); 7104 for (ReplicaDescriptor replica : source.getReplicas()) 7105 { 7106 if (areDnsEqual(replica.getSuffix().getDN(), baseDN)) 7107 { 7108 replicationId = replica.getReplicationId(); 7109 break; 7110 } 7111 } 7112 } 7113 catch (NamingException ne) 7114 { 7115 String hostPort = getHostPort(ctxSource); 7116 LocalizableMessage msg = getMessageForException(ne, hostPort); 7117 throw new ReplicationCliException(msg, ERROR_READING_CONFIGURATION, ne); 7118 } 7119 7120 if (replicationId == -1) 7121 { 7122 throw new ReplicationCliException( 7123 ERR_INITIALIZING_REPLICATIONID_NOT_FOUND.get(getHostPort(ctxSource), baseDN), 7124 REPLICATIONID_NOT_FOUND, null); 7125 } 7126 7127 OfflineInstaller installer = new OfflineInstaller(); 7128 installer.setProgressMessageFormatter(formatter); 7129 installer.addProgressUpdateListener(new ProgressUpdateListener() 7130 { 7131 @Override 7132 public void progressUpdate(ProgressUpdateEvent ev) 7133 { 7134 LocalizableMessage newLogDetails = ev.getNewLogs(); 7135 if (newLogDetails != null && !"".equals(newLogDetails.toString().trim())) 7136 { 7137 print(newLogDetails); 7138 println(); 7139 } 7140 } 7141 }); 7142 int nTries = 5; 7143 boolean initDone = false; 7144 while (!initDone) 7145 { 7146 try 7147 { 7148 installer.initializeSuffix(ctxDestination, replicationId, baseDN, displayProgress, getHostPort(ctxSource)); 7149 initDone = true; 7150 } 7151 catch (PeerNotFoundException pnfe) 7152 { 7153 logger.info(LocalizableMessage.raw("Peer could not be found")); 7154 if (nTries == 1) 7155 { 7156 throw new ReplicationCliException( 7157 ERR_REPLICATION_INITIALIZING_TRIES_COMPLETED.get( 7158 pnfe.getMessageObject()), INITIALIZING_TRIES_COMPLETED, pnfe); 7159 } 7160 sleepCatchInterrupt((5 - nTries) * 3000); 7161 } 7162 catch (ApplicationException ae) 7163 { 7164 throw new ReplicationCliException(ae.getMessageObject(), 7165 ERROR_INITIALIZING_BASEDN_GENERIC, ae); 7166 } 7167 nTries--; 7168 } 7169 } 7170 7171 /** 7172 * Initializes all the replicas in the topology with the contents of a 7173 * given replica. 7174 * @param ctx the connection to the server where the source replica of the 7175 * initialization is. 7176 * @param baseDN the dn of the suffix. 7177 * @param displayProgress whether we want to display progress or not. 7178 * @throws ReplicationCliException if an unexpected error occurs. 7179 */ 7180 public void initializeAllSuffix(String baseDN, InitialLdapContext ctx, 7181 boolean displayProgress) throws ReplicationCliException 7182 { 7183 if (argParser == null) 7184 { 7185 try 7186 { 7187 createArgumenParser(); 7188 } 7189 catch (ArgumentException ae) 7190 { 7191 throw new RuntimeException("Error creating argument parser: "+ae, ae); 7192 } 7193 } 7194 int nTries = 5; 7195 boolean initDone = false; 7196 while (!initDone) 7197 { 7198 try 7199 { 7200 initializeAllSuffixTry(baseDN, ctx, displayProgress); 7201 postPreExternalInitialization(baseDN, ctx, false); 7202 initDone = true; 7203 } 7204 catch (PeerNotFoundException pnfe) 7205 { 7206 logger.info(LocalizableMessage.raw("Peer could not be found")); 7207 if (nTries == 1) 7208 { 7209 throw new ReplicationCliException( 7210 ERR_REPLICATION_INITIALIZING_TRIES_COMPLETED.get( 7211 pnfe.getMessageObject()), INITIALIZING_TRIES_COMPLETED, pnfe); 7212 } 7213 sleepCatchInterrupt((5 - nTries) * 3000); 7214 } 7215 catch (ClientException ae) 7216 { 7217 throw new ReplicationCliException(ae.getMessageObject(), 7218 ERROR_INITIALIZING_BASEDN_GENERIC, ae); 7219 } 7220 nTries--; 7221 } 7222 } 7223 7224 /** 7225 * Launches the pre external initialization operation using the provided 7226 * connection on a given base DN. 7227 * @param baseDN the base DN that we want to reset. 7228 * @param ctx the connection to the server. 7229 * @throws ReplicationCliException if there is an error performing the 7230 * operation. 7231 */ 7232 private void preExternalInitialization(String baseDN, InitialLdapContext ctx) throws ReplicationCliException 7233 { 7234 postPreExternalInitialization(baseDN, ctx, true); 7235 } 7236 7237 /** 7238 * Launches the post external initialization operation using the provided 7239 * connection on a given base DN required for replication to work. 7240 * @param baseDN the base DN that we want to reset. 7241 * @param ctx the connection to the server. 7242 * @throws ReplicationCliException if there is an error performing the 7243 * operation. 7244 */ 7245 private void postExternalInitialization(String baseDN, InitialLdapContext ctx) throws ReplicationCliException 7246 { 7247 postPreExternalInitialization(baseDN, ctx, false); 7248 } 7249 7250 /** 7251 * Launches the pre or post external initialization operation using the 7252 * provided connection on a given base DN. 7253 * @param baseDN the base DN that we want to reset. 7254 * @param ctx the connection to the server. 7255 * @param isPre whether this is the pre operation or the post operation. 7256 * @throws ReplicationCliException if there is an error performing the 7257 * operation. 7258 */ 7259 private void postPreExternalInitialization(String baseDN, 7260 InitialLdapContext ctx, boolean isPre) throws ReplicationCliException 7261 { 7262 boolean isOver = false; 7263 String dn = null; 7264 Map<String, String> attrMap = new TreeMap<>(); 7265 if (isPre) 7266 { 7267 attrMap.put("ds-task-reset-generation-id-new-value", "-1"); 7268 } 7269 attrMap.put("ds-task-reset-generation-id-domain-base-dn", baseDN); 7270 7271 try { 7272 dn = createServerTask(ctx, "ds-task-reset-generation-id", "org.opends.server.tasks.SetGenerationIdTask", 7273 "dsreplication-reset-generation-id", attrMap); 7274 } 7275 catch (NamingException ne) 7276 { 7277 LocalizableMessage msg = isPre ? 7278 ERR_LAUNCHING_PRE_EXTERNAL_INITIALIZATION.get(): 7279 ERR_LAUNCHING_POST_EXTERNAL_INITIALIZATION.get(); 7280 ReplicationCliReturnCode code = isPre? 7281 ERROR_LAUNCHING_PRE_EXTERNAL_INITIALIZATION: 7282 ERROR_LAUNCHING_POST_EXTERNAL_INITIALIZATION; 7283 throw new ReplicationCliException(getThrowableMsg(msg, ne), code, ne); 7284 } 7285 7286 String lastLogMsg = null; 7287 while (!isOver) 7288 { 7289 sleepCatchInterrupt(500); 7290 try 7291 { 7292 SearchResult sr = getLastSearchResult(ctx, dn, "ds-task-log-message", "ds-task-state"); 7293 String logMsg = getFirstValue(sr, "ds-task-log-message"); 7294 if (logMsg != null && !logMsg.equals(lastLogMsg)) 7295 { 7296 logger.info(LocalizableMessage.raw(logMsg)); 7297 lastLogMsg = logMsg; 7298 } 7299 InstallerHelper helper = new InstallerHelper(); 7300 String state = getFirstValue(sr, "ds-task-state"); 7301 7302 if (helper.isDone(state) || helper.isStoppedByError(state)) 7303 { 7304 isOver = true; 7305 LocalizableMessage errorMsg = getPrePostErrorMsg(lastLogMsg, state, ctx); 7306 7307 if (helper.isCompletedWithErrors(state)) 7308 { 7309 logger.warn(LocalizableMessage.raw("Completed with error: "+errorMsg)); 7310 errPrintln(errorMsg); 7311 } 7312 else if (!helper.isSuccessful(state) || 7313 helper.isStoppedByError(state)) 7314 { 7315 logger.warn(LocalizableMessage.raw("Error: "+errorMsg)); 7316 ReplicationCliReturnCode code = isPre? 7317 ERROR_LAUNCHING_PRE_EXTERNAL_INITIALIZATION: 7318 ERROR_LAUNCHING_POST_EXTERNAL_INITIALIZATION; 7319 throw new ReplicationCliException(errorMsg, code, null); 7320 } 7321 } 7322 } 7323 catch (NameNotFoundException x) 7324 { 7325 isOver = true; 7326 } 7327 catch (NamingException ne) 7328 { 7329 throw new ReplicationCliException(getThrowableMsg(ERR_READING_SERVER_TASK_PROGRESS.get(), ne), 7330 ERROR_CONNECTING, ne); 7331 } 7332 } 7333 } 7334 7335 private LocalizableMessage getPrePostErrorMsg(String lastLogMsg, String state, InitialLdapContext ctx) 7336 { 7337 String server = getHostPort(ctx); 7338 if (lastLogMsg != null) 7339 { 7340 return ERR_UNEXPECTED_DURING_TASK_WITH_LOG.get(lastLogMsg, state, server); 7341 } 7342 return ERR_UNEXPECTED_DURING_TASK_NO_LOG.get(state, server); 7343 } 7344 7345 private void sleepCatchInterrupt(long millis) 7346 { 7347 try 7348 { 7349 Thread.sleep(millis); 7350 } 7351 catch (InterruptedException e) 7352 { 7353 } 7354 } 7355 7356 /** 7357 * Initializes all the replicas in the topology with the contents of a 7358 * given replica. This method will try to create the task only once. 7359 * @param ctx the connection to the server where the source replica of the 7360 * initialization is. 7361 * @param baseDN the dn of the suffix. 7362 * @param displayProgress whether we want to display progress or not. 7363 * @throws ClientException if an unexpected error occurs. 7364 * @throws PeerNotFoundException if the replication mechanism cannot find 7365 * a peer. 7366 */ 7367 public void initializeAllSuffixTry(String baseDN, InitialLdapContext ctx, 7368 boolean displayProgress) 7369 throws ClientException, PeerNotFoundException 7370 { 7371 boolean isOver = false; 7372 String dn = null; 7373 String serverDisplay = getHostPort(ctx); 7374 Map<String, String> attrsMap = new TreeMap<>(); 7375 attrsMap.put("ds-task-initialize-domain-dn", baseDN); 7376 attrsMap.put("ds-task-initialize-replica-server-id", "all"); 7377 try 7378 { 7379 dn = createServerTask(ctx, "ds-task-initialize-remote-replica", "org.opends.server.tasks.InitializeTargetTask", 7380 "dsreplication-initialize", attrsMap); 7381 } 7382 catch (NamingException ne) 7383 { 7384 throw new ClientException(ReturnCode.APPLICATION_ERROR, 7385 getThrowableMsg(INFO_ERROR_LAUNCHING_INITIALIZATION.get(serverDisplay), ne), ne); 7386 } 7387 7388 LocalizableMessage lastDisplayedMsg = null; 7389 String lastLogMsg = null; 7390 long lastTimeMsgDisplayed = -1; 7391 long lastTimeMsgLogged = -1; 7392 long totalEntries = 0; 7393 while (!isOver) 7394 { 7395 sleepCatchInterrupt(500); 7396 try 7397 { 7398 SearchResult sr = getLastSearchResult(ctx, dn, "ds-task-unprocessed-entry-count", 7399 "ds-task-processed-entry-count", "ds-task-log-message", "ds-task-state" ); 7400 7401 // Get the number of entries that have been handled and a percentage... 7402 String sProcessed = getFirstValue(sr, "ds-task-processed-entry-count"); 7403 String sUnprocessed = getFirstValue(sr, "ds-task-unprocessed-entry-count"); 7404 long processed = -1; 7405 long unprocessed = -1; 7406 if (sProcessed != null) 7407 { 7408 processed = Integer.parseInt(sProcessed); 7409 } 7410 if (sUnprocessed != null) 7411 { 7412 unprocessed = Integer.parseInt(sUnprocessed); 7413 } 7414 totalEntries = Math.max(totalEntries, processed+unprocessed); 7415 7416 LocalizableMessage msg = getMsg(lastDisplayedMsg, processed, unprocessed); 7417 if (msg != null) 7418 { 7419 long currentTime = System.currentTimeMillis(); 7420 /* Refresh period: to avoid having too many lines in the log */ 7421 long minRefreshPeriod = getMinRefreshPeriod(totalEntries); 7422 if (currentTime - minRefreshPeriod > lastTimeMsgLogged) 7423 { 7424 lastTimeMsgLogged = currentTime; 7425 logger.info(LocalizableMessage.raw("Progress msg: "+msg)); 7426 } 7427 if (displayProgress 7428 && currentTime - minRefreshPeriod > lastTimeMsgDisplayed 7429 && !msg.equals(lastDisplayedMsg)) 7430 { 7431 print(msg); 7432 lastDisplayedMsg = msg; 7433 println(); 7434 lastTimeMsgDisplayed = currentTime; 7435 } 7436 } 7437 7438 String logMsg = getFirstValue(sr, "ds-task-log-message"); 7439 if (logMsg != null && !logMsg.equals(lastLogMsg)) 7440 { 7441 logger.info(LocalizableMessage.raw(logMsg)); 7442 lastLogMsg = logMsg; 7443 } 7444 InstallerHelper helper = new InstallerHelper(); 7445 String state = getFirstValue(sr, "ds-task-state"); 7446 7447 if (helper.isDone(state) || helper.isStoppedByError(state)) 7448 { 7449 isOver = true; 7450 logger.info(LocalizableMessage.raw("Last task entry: "+sr)); 7451 if (displayProgress && msg != null && !msg.equals(lastDisplayedMsg)) 7452 { 7453 print(msg); 7454 lastDisplayedMsg = msg; 7455 println(); 7456 } 7457 7458 LocalizableMessage errorMsg = getInitializeAllErrorMsg(serverDisplay, lastLogMsg, state); 7459 if (helper.isCompletedWithErrors(state)) 7460 { 7461 logger.warn(LocalizableMessage.raw("Processed errorMsg: "+errorMsg)); 7462 if (displayProgress) 7463 { 7464 errPrintln(errorMsg); 7465 } 7466 } 7467 else if (!helper.isSuccessful(state) || 7468 helper.isStoppedByError(state)) 7469 { 7470 logger.warn(LocalizableMessage.raw("Processed errorMsg: "+errorMsg)); 7471 ClientException ce = new ClientException( 7472 ReturnCode.APPLICATION_ERROR, errorMsg, 7473 null); 7474 if (lastLogMsg == null 7475 || helper.isPeersNotFoundError(lastLogMsg)) 7476 { 7477 logger.warn(LocalizableMessage.raw("Throwing peer not found error. "+ 7478 "Last Log Msg: "+lastLogMsg)); 7479 // Assume that this is a peer not found error. 7480 throw new PeerNotFoundException(errorMsg); 7481 } 7482 else 7483 { 7484 logger.error(LocalizableMessage.raw("Throwing ApplicationException.")); 7485 throw ce; 7486 } 7487 } 7488 else 7489 { 7490 if (displayProgress) 7491 { 7492 print(INFO_SUFFIX_INITIALIZED_SUCCESSFULLY.get()); 7493 println(); 7494 } 7495 logger.info(LocalizableMessage.raw("Processed msg: "+errorMsg)); 7496 logger.info(LocalizableMessage.raw("Initialization completed successfully.")); 7497 } 7498 } 7499 } 7500 catch (NameNotFoundException x) 7501 { 7502 isOver = true; 7503 logger.info(LocalizableMessage.raw("Initialization entry not found.")); 7504 if (displayProgress) 7505 { 7506 print(INFO_SUFFIX_INITIALIZED_SUCCESSFULLY.get()); 7507 println(); 7508 } 7509 } 7510 catch (NamingException ne) 7511 { 7512 throw new ClientException( 7513 ReturnCode.APPLICATION_ERROR, 7514 getThrowableMsg(INFO_ERROR_POOLING_INITIALIZATION.get( 7515 serverDisplay), ne), ne); 7516 } 7517 } 7518 } 7519 7520 private SearchResult getLastSearchResult(InitialLdapContext ctx, String dn, String... returnedAttributes) 7521 throws NamingException 7522 { 7523 SearchControls searchControls = new SearchControls(); 7524 searchControls.setSearchScope(SearchControls.OBJECT_SCOPE); 7525 searchControls.setReturningAttributes(returnedAttributes); 7526 NamingEnumeration<SearchResult> res = ctx.search(dn, "objectclass=*", searchControls); 7527 try 7528 { 7529 SearchResult sr = null; 7530 while (res.hasMore()) 7531 { 7532 sr = res.next(); 7533 } 7534 return sr; 7535 } 7536 finally 7537 { 7538 res.close(); 7539 } 7540 } 7541 7542 private String createServerTask(InitialLdapContext ctx, String taskObjectclass, 7543 String taskJavaClass, String taskID, Map<String, String> taskAttrs) throws NamingException 7544 { 7545 int i = 1; 7546 String dn = ""; 7547 BasicAttributes attrs = new BasicAttributes(); 7548 attrs.put("objectclass", taskObjectclass); 7549 attrs.put("ds-task-class-name", taskJavaClass); 7550 for (Map.Entry<String, String> attr : taskAttrs.entrySet()) 7551 { 7552 attrs.put(attr.getKey(), attr.getValue()); 7553 } 7554 7555 while (true) 7556 { 7557 String id = taskID + "-" + i; 7558 dn = "ds-task-id=" + id + ",cn=Scheduled Tasks,cn=Tasks"; 7559 try 7560 { 7561 DirContext dirCtx = ctx.createSubcontext(dn, attrs); 7562 logger.info(LocalizableMessage.raw("created task entry: " + attrs)); 7563 dirCtx.close(); 7564 return dn; 7565 } 7566 catch (NameAlreadyBoundException x) 7567 { 7568 logger.warn(LocalizableMessage.raw("A task with dn: " + dn + " already existed.")); 7569 } 7570 catch (NamingException ne) 7571 { 7572 logger.error(LocalizableMessage.raw("Error creating task " + attrs, ne)); 7573 throw ne; 7574 } 7575 i++; 7576 } 7577 } 7578 7579 private LocalizableMessage getInitializeAllErrorMsg(String serverDisplay, String lastLogMsg, String state) 7580 { 7581 if (lastLogMsg != null) 7582 { 7583 return INFO_ERROR_DURING_INITIALIZATION_LOG.get(serverDisplay, lastLogMsg, state, serverDisplay); 7584 } 7585 return INFO_ERROR_DURING_INITIALIZATION_NO_LOG.get(serverDisplay, state, serverDisplay); 7586 } 7587 7588 private LocalizableMessage getMsg(LocalizableMessage lastDisplayedMsg, long processed, long unprocessed) 7589 { 7590 if (processed != -1 && unprocessed != -1) 7591 { 7592 if (processed + unprocessed > 0) 7593 { 7594 long perc = (100 * processed) / (processed + unprocessed); 7595 return INFO_INITIALIZE_PROGRESS_WITH_PERCENTAGE.get(processed, perc); 7596 } 7597 else 7598 { 7599 // return INFO_NO_ENTRIES_TO_INITIALIZE.get(); 7600 return null; 7601 } 7602 } 7603 else if (processed != -1) 7604 { 7605 return INFO_INITIALIZE_PROGRESS_WITH_PROCESSED.get(processed); 7606 } 7607 else if (unprocessed != -1) 7608 { 7609 return INFO_INITIALIZE_PROGRESS_WITH_UNPROCESSED.get(unprocessed); 7610 } 7611 else 7612 { 7613 return lastDisplayedMsg; 7614 } 7615 } 7616 7617 private long getMinRefreshPeriod(long totalEntries) 7618 { 7619 if (totalEntries < 100) 7620 { 7621 return 0; 7622 } 7623 else if (totalEntries < 1000) 7624 { 7625 return 1000; 7626 } 7627 else if (totalEntries < 10000) 7628 { 7629 return 5000; 7630 } 7631 return 10000; 7632 } 7633 7634 /** 7635 * Removes the references to a replication server in the base DNs of a 7636 * given server. 7637 * @param server the server that we want to update. 7638 * @param replicationServer the replication server whose references we want 7639 * to remove. 7640 * @param bindDn the bindDn that must be used to log to the server. 7641 * @param pwd the password that must be used to log to the server. 7642 * @param baseDNs the list of base DNs where we want to remove the references 7643 * to the provided replication server. 7644 * @param updateReplicationServers if references in the replication servers 7645 * must be updated. 7646 * @param cnx the preferred LDAP URLs to be used to connect to the 7647 * server. 7648 * @throws ReplicationCliException if there is an error updating the 7649 * configuration. 7650 */ 7651 private void removeReferencesInServer(ServerDescriptor server, 7652 String replicationServer, String bindDn, String pwd, 7653 Collection<String> baseDNs, boolean updateReplicationServers, 7654 Set<PreferredConnection> cnx) 7655 throws ReplicationCliException 7656 { 7657 TopologyCacheFilter filter = new TopologyCacheFilter(); 7658 filter.setSearchMonitoringInformation(false); 7659 filter.setSearchBaseDNInformation(false); 7660 ServerLoader loader = new ServerLoader(server.getAdsProperties(), bindDn, 7661 pwd, getTrustManager(sourceServerCI), getConnectTimeout(), cnx, filter); 7662 InitialLdapContext ctx = null; 7663 String lastBaseDN = null; 7664 String hostPort = null; 7665 7666 try 7667 { 7668 ctx = loader.createContext(); 7669 hostPort = getHostPort(ctx); 7670 ManagementContext mCtx = LDAPManagementContext.createFromContext( 7671 JNDIDirContextAdaptor.adapt(ctx)); 7672 RootCfgClient root = mCtx.getRootConfiguration(); 7673 ReplicationSynchronizationProviderCfgClient sync = null; 7674 try 7675 { 7676 sync = (ReplicationSynchronizationProviderCfgClient) 7677 root.getSynchronizationProvider("Multimaster Synchronization"); 7678 } 7679 catch (ManagedObjectNotFoundException monfe) 7680 { 7681 // It does not exist. 7682 logger.info(LocalizableMessage.raw("No synchronization found on "+ hostPort +".", 7683 monfe)); 7684 } 7685 if (sync != null) 7686 { 7687 String[] domainNames = sync.listReplicationDomains(); 7688 if (domainNames != null) 7689 { 7690 for (String domainName : domainNames) 7691 { 7692 ReplicationDomainCfgClient domain = 7693 sync.getReplicationDomain(domainName); 7694 for (String baseDN : baseDNs) 7695 { 7696 lastBaseDN = baseDN; 7697 if (areDnsEqual(domain.getBaseDN().toString(), baseDN)) 7698 { 7699 print(formatter.getFormattedWithPoints( 7700 INFO_REPLICATION_REMOVING_REFERENCES_ON_REMOTE.get(baseDN, hostPort))); 7701 Set<String> replServers = domain.getReplicationServer(); 7702 if (replServers != null) 7703 { 7704 String replServer = findIgnoreCase(replServers, replicationServer); 7705 if (replServer != null) 7706 { 7707 logger.info(LocalizableMessage.raw("Updating references in domain " + 7708 domain.getBaseDN()+" on " + hostPort + ".")); 7709 replServers.remove(replServer); 7710 if (!replServers.isEmpty()) 7711 { 7712 domain.setReplicationServer(replServers); 7713 domain.commit(); 7714 } 7715 else 7716 { 7717 sync.removeReplicationDomain(domainName); 7718 sync.commit(); 7719 } 7720 } 7721 } 7722 print(formatter.getFormattedDone()); 7723 println(); 7724 } 7725 } 7726 } 7727 } 7728 if (updateReplicationServers && sync.hasReplicationServer()) 7729 { 7730 ReplicationServerCfgClient rServerObj = sync.getReplicationServer(); 7731 Set<String> replServers = rServerObj.getReplicationServer(); 7732 if (replServers != null) 7733 { 7734 String replServer = findIgnoreCase(replServers, replicationServer); 7735 if (replServer != null) 7736 { 7737 replServers.remove(replServer); 7738 if (!replServers.isEmpty()) 7739 { 7740 rServerObj.setReplicationServer(replServers); 7741 rServerObj.commit(); 7742 } 7743 else 7744 { 7745 sync.removeReplicationServer(); 7746 sync.commit(); 7747 } 7748 } 7749 } 7750 } 7751 } 7752 } 7753 catch (NamingException ne) 7754 { 7755 hostPort = getHostPort2(server, cnx); 7756 LocalizableMessage msg = getMessageForException(ne, hostPort); 7757 throw new ReplicationCliException(msg, ERROR_CONNECTING, ne); 7758 } 7759 catch (OpenDsException ode) 7760 { 7761 if (lastBaseDN != null) 7762 { 7763 LocalizableMessage msg = getMessageForDisableException(hostPort, lastBaseDN); 7764 throw new ReplicationCliException(msg, 7765 ERROR_DISABLING_REPLICATION_REMOVE_REFERENCE_ON_BASEDN, ode); 7766 } 7767 else 7768 { 7769 LocalizableMessage msg = ERR_REPLICATION_ERROR_READING_CONFIGURATION.get(hostPort, 7770 ode.getMessage()); 7771 throw new ReplicationCliException(msg, ERROR_CONNECTING, ode); 7772 } 7773 } 7774 finally 7775 { 7776 close(ctx); 7777 } 7778 } 7779 7780 /** 7781 * Deletes a replication domain in a server for a given base DN (disable 7782 * replication of the base DN). 7783 * @param ctx the connection to the server. 7784 * @param baseDN the base DN of the replication domain that we want to 7785 * delete. 7786 * @throws ReplicationCliException if there is an error updating the 7787 * configuration of the server. 7788 */ 7789 private void deleteReplicationDomain(InitialLdapContext ctx, 7790 String baseDN) throws ReplicationCliException 7791 { 7792 String hostPort = getHostPort(ctx); 7793 try 7794 { 7795 ManagementContext mCtx = LDAPManagementContext.createFromContext( 7796 JNDIDirContextAdaptor.adapt(ctx)); 7797 RootCfgClient root = mCtx.getRootConfiguration(); 7798 ReplicationSynchronizationProviderCfgClient sync = null; 7799 try 7800 { 7801 sync = (ReplicationSynchronizationProviderCfgClient) 7802 root.getSynchronizationProvider("Multimaster Synchronization"); 7803 } 7804 catch (ManagedObjectNotFoundException monfe) 7805 { 7806 // It does not exist. 7807 logger.info(LocalizableMessage.raw("No synchronization found on "+ hostPort +".", 7808 monfe)); 7809 } 7810 if (sync != null) 7811 { 7812 String[] domainNames = sync.listReplicationDomains(); 7813 if (domainNames != null) 7814 { 7815 for (String domainName : domainNames) 7816 { 7817 ReplicationDomainCfgClient domain = 7818 sync.getReplicationDomain(domainName); 7819 if (areDnsEqual(domain.getBaseDN().toString(), baseDN)) 7820 { 7821 print(formatter.getFormattedWithPoints( 7822 INFO_REPLICATION_DISABLING_BASEDN.get(baseDN, hostPort))); 7823 sync.removeReplicationDomain(domainName); 7824 sync.commit(); 7825 7826 print(formatter.getFormattedDone()); 7827 println(); 7828 } 7829 } 7830 } 7831 } 7832 } 7833 catch (OpenDsException ode) 7834 { 7835 LocalizableMessage msg = getMessageForDisableException(hostPort, baseDN); 7836 throw new ReplicationCliException(msg, 7837 ERROR_DISABLING_REPLICATION_REMOVE_REFERENCE_ON_BASEDN, ode); 7838 } 7839 } 7840 7841 /** 7842 * Disables the replication server for a given server. 7843 * @param ctx the connection to the server. 7844 * @throws ReplicationCliException if there is an error updating the 7845 * configuration of the server. 7846 */ 7847 private void disableReplicationServer(InitialLdapContext ctx) 7848 throws ReplicationCliException 7849 { 7850 String hostPort = getHostPort(ctx); 7851 try 7852 { 7853 ManagementContext mCtx = LDAPManagementContext.createFromContext( 7854 JNDIDirContextAdaptor.adapt(ctx)); 7855 RootCfgClient root = mCtx.getRootConfiguration(); 7856 ReplicationSynchronizationProviderCfgClient sync = null; 7857 ReplicationServerCfgClient replicationServer = null; 7858 try 7859 { 7860 sync = (ReplicationSynchronizationProviderCfgClient) 7861 root.getSynchronizationProvider("Multimaster Synchronization"); 7862 if (sync.hasReplicationServer()) 7863 { 7864 replicationServer = sync.getReplicationServer(); 7865 } 7866 } 7867 catch (ManagedObjectNotFoundException monfe) 7868 { 7869 // It does not exist. 7870 logger.info(LocalizableMessage.raw("No synchronization found on "+ hostPort +".", 7871 monfe)); 7872 } 7873 if (replicationServer != null) 7874 { 7875 String s = String.valueOf(replicationServer.getReplicationPort()); 7876 print(formatter.getFormattedWithPoints( 7877 INFO_REPLICATION_DISABLING_REPLICATION_SERVER.get(s, 7878 hostPort))); 7879 7880 sync.removeReplicationServer(); 7881 sync.commit(); 7882 print(formatter.getFormattedDone()); 7883 println(); 7884 } 7885 } 7886 catch (OpenDsException ode) 7887 { 7888 throw new ReplicationCliException( 7889 ERR_REPLICATION_DISABLING_REPLICATIONSERVER.get(hostPort), 7890 ERROR_DISABLING_REPLICATION_SERVER, 7891 ode); 7892 } 7893 } 7894 7895 /** 7896 * Returns a message for a given OpenDsException (we assume that was an 7897 * exception generated updating the configuration of the server) that 7898 * occurred when we were configuring some replication domain (creating 7899 * the replication domain or updating the list of replication servers of 7900 * the replication domain). 7901 * @param hostPort the hostPort representation of the server we were 7902 * contacting when the OpenDsException occurred. 7903 * @return a message for a given OpenDsException (we assume that was an 7904 * exception generated updating the configuration of the server) that 7905 * occurred when we were configuring some replication domain (creating 7906 * the replication domain or updating the list of replication servers of 7907 * the replication domain). 7908 */ 7909 private LocalizableMessage getMessageForEnableException(String hostPort, String baseDN) 7910 { 7911 return ERR_REPLICATION_CONFIGURING_BASEDN.get(baseDN, hostPort); 7912 } 7913 7914 /** 7915 * Returns a message for a given OpenDsException (we assume that was an 7916 * exception generated updating the configuration of the server) that 7917 * occurred when we were configuring some replication domain (deleting 7918 * the replication domain or updating the list of replication servers of 7919 * the replication domain). 7920 * @param hostPort the hostPort representation of the server we were 7921 * contacting when the OpenDsException occurred. 7922 * @return a message for a given OpenDsException (we assume that was an 7923 * exception generated updating the configuration of the server) that 7924 * occurred when we were configuring some replication domain (deleting 7925 * the replication domain or updating the list of replication servers of 7926 * the replication domain). 7927 */ 7928 private LocalizableMessage getMessageForDisableException(String hostPort, String baseDN) 7929 { 7930 return ERR_REPLICATION_CONFIGURING_BASEDN.get(baseDN, hostPort); 7931 } 7932 7933 /** 7934 * Returns a message informing the user that the provided port cannot be used. 7935 * @param port the port that cannot be used. 7936 * @return a message informing the user that the provided port cannot be used. 7937 */ 7938 private LocalizableMessage getCannotBindToPortError(int port) 7939 { 7940 if (SetupUtils.isPrivilegedPort(port)) 7941 { 7942 return ERR_CANNOT_BIND_TO_PRIVILEGED_PORT.get(port); 7943 } 7944 return ERR_CANNOT_BIND_TO_PORT.get(port); 7945 } 7946 7947 /** 7948 * Convenience method used to know if one Set of replication servers equals 7949 * another set of replication servers. 7950 * @param s1 the first set of replication servers. 7951 * @param s2 the second set of replication servers. 7952 * @return <CODE>true</CODE> if the two sets represent the same replication 7953 * servers and <CODE>false</CODE> otherwise. 7954 */ 7955 private boolean areReplicationServersEqual(Set<String> s1, Set<String> s2) 7956 { 7957 Set<String> c1 = new HashSet<>(); 7958 for (String s : s1) 7959 { 7960 c1.add(s.toLowerCase()); 7961 } 7962 Set<String> c2 = new HashSet<>(); 7963 for (String s : s2) 7964 { 7965 c2.add(s.toLowerCase()); 7966 } 7967 return c1.equals(c2); 7968 } 7969 7970 /** 7971 * Convenience method used to merge two Sets of replication servers. 7972 * @param s1 the first set of replication servers. 7973 * @param s2 the second set of replication servers. 7974 * @return a Set of replication servers containing all the replication servers 7975 * specified in the provided Sets. 7976 */ 7977 private Set<String> mergeReplicationServers(Set<String> s1, Set<String> s2) 7978 { 7979 Set<String> c1 = new HashSet<>(); 7980 for (String s : s1) 7981 { 7982 c1.add(s.toLowerCase()); 7983 } 7984 for (String s : s2) 7985 { 7986 c1.add(s.toLowerCase()); 7987 } 7988 return c1; 7989 } 7990 7991 /** 7992 * Returns the message that must be displayed to the user for a given 7993 * exception. This is assumed to be a critical exception that stops all 7994 * the processing. 7995 * @param rce the ReplicationCliException. 7996 * @return a message to be displayed to the user. 7997 */ 7998 private LocalizableMessage getCriticalExceptionMessage(ReplicationCliException rce) 7999 { 8000 LocalizableMessageBuilder mb = new LocalizableMessageBuilder(); 8001 mb.append(rce.getMessageObject()); 8002 File logFile = ControlPanelLog.getLogFile(); 8003 if (logFile != null && rce.getErrorCode() != USER_CANCELLED) 8004 { 8005 mb.append(Constants.LINE_SEPARATOR); 8006 mb.append(INFO_GENERAL_SEE_FOR_DETAILS.get(logFile.getPath())); 8007 } 8008 // Check if the cause has already been included in the message 8009 Throwable c = rce.getCause(); 8010 if (c != null) 8011 { 8012 String s; 8013 if (c instanceof NamingException) 8014 { 8015 s = ((NamingException)c).toString(true); 8016 } 8017 else if (c instanceof OpenDsException) 8018 { 8019 LocalizableMessage msg = ((OpenDsException)c).getMessageObject(); 8020 if (msg != null) 8021 { 8022 s = msg.toString(); 8023 } 8024 else 8025 { 8026 s = c.toString(); 8027 } 8028 } 8029 else 8030 { 8031 s = c.toString(); 8032 } 8033 if (!mb.toString().contains(s)) 8034 { 8035 mb.append(Constants.LINE_SEPARATOR); 8036 mb.append(INFO_REPLICATION_CRITICAL_ERROR_DETAILS.get(s)); 8037 } 8038 } 8039 return mb.toMessage(); 8040 } 8041 8042 private boolean mustInitializeSchema(ServerDescriptor server1, 8043 ServerDescriptor server2, EnableReplicationUserData uData) 8044 { 8045 boolean mustInitializeSchema = false; 8046 if (!argParser.noSchemaReplication()) 8047 { 8048 String id1 = server1.getSchemaReplicationID(); 8049 String id2 = server2.getSchemaReplicationID(); 8050 mustInitializeSchema = id1 == null || !id1.equals(id2); 8051 } 8052 if (mustInitializeSchema) 8053 { 8054 // Check that both will contain replication data 8055 mustInitializeSchema = uData.getServer1().configureReplicationDomain() 8056 && uData.getServer2().configureReplicationDomain(); 8057 } 8058 return mustInitializeSchema; 8059 } 8060 8061 /** 8062 * This method registers a server in a given ADSContext. If the server was 8063 * already registered it unregisters it and registers again (some properties 8064 * might have changed). 8065 * @param adsContext the ADS Context to be used. 8066 * @param serverProperties the properties of the server to be registered. 8067 * @throws ADSContextException if an error occurs during the registration or 8068 * unregistration of the server. 8069 */ 8070 private void registerServer(ADSContext adsContext, Map<ServerProperty, Object> serverProperties) 8071 throws ADSContextException 8072 { 8073 try 8074 { 8075 adsContext.registerServer(serverProperties); 8076 } 8077 catch (ADSContextException ade) 8078 { 8079 if (ade.getError() == 8080 ADSContextException.ErrorType.ALREADY_REGISTERED) 8081 { 8082 logger.warn(LocalizableMessage.raw("The server was already registered: "+ 8083 serverProperties)); 8084 adsContext.unregisterServer(serverProperties); 8085 adsContext.registerServer(serverProperties); 8086 } 8087 else 8088 { 8089 throw ade; 8090 } 8091 } 8092 } 8093 8094 /** {@inheritDoc} */ 8095 @Override 8096 public boolean isAdvancedMode() { 8097 return false; 8098 } 8099 8100 /** {@inheritDoc} */ 8101 @Override 8102 public boolean isInteractive() { 8103 return !forceNonInteractive && argParser.isInteractive(); 8104 } 8105 8106 /** {@inheritDoc} */ 8107 @Override 8108 public boolean isMenuDrivenMode() { 8109 return true; 8110 } 8111 8112 /** {@inheritDoc} */ 8113 @Override 8114 public boolean isQuiet() 8115 { 8116 return argParser.isQuiet(); 8117 } 8118 8119 /** {@inheritDoc} */ 8120 @Override 8121 public boolean isScriptFriendly() { 8122 return argParser.isScriptFriendly(); 8123 } 8124 8125 /** {@inheritDoc} */ 8126 @Override 8127 public boolean isVerbose() { 8128 return true; 8129 } 8130 8131 /** 8132 * Forces the initialization of the trust manager in the LDAPConnectionInteraction object. 8133 * @param ci the LDAP connection to the server 8134 */ 8135 private void forceTrustManagerInitialization(LDAPConnectionConsoleInteraction ci) 8136 { 8137 forceNonInteractive = true; 8138 try 8139 { 8140 ci.initializeTrustManagerIfRequired(); 8141 } 8142 catch (ArgumentException ae) 8143 { 8144 logger.warn(LocalizableMessage.raw("Error initializing trust store: "+ae, ae)); 8145 } 8146 forceNonInteractive = false; 8147 } 8148 8149 /** 8150 * Method used to compare two server registries. 8151 * @param registry1 the first registry to compare. 8152 * @param registry2 the second registry to compare. 8153 * @return <CODE>true</CODE> if the registries are equal and 8154 * <CODE>false</CODE> otherwise. 8155 */ 8156 private boolean areEqual(Set<Map<ServerProperty, Object>> registry1, Set<Map<ServerProperty, Object>> registry2) 8157 { 8158 return registry1.size() == registry2.size() 8159 && equals(registry1, registry2, getPropertiesToCompare()); 8160 } 8161 8162 private Set<ServerProperty> getPropertiesToCompare() 8163 { 8164 final Set<ServerProperty> propertiesToCompare = new HashSet<>(); 8165 for (ServerProperty property : ServerProperty.values()) 8166 { 8167 if (property.getAttributeSyntax() != ADSPropertySyntax.CERTIFICATE_BINARY) 8168 { 8169 propertiesToCompare.add(property); 8170 } 8171 } 8172 return propertiesToCompare; 8173 } 8174 8175 private boolean equals(Set<Map<ServerProperty, Object>> registry1, Set<Map<ServerProperty, Object>> registry2, 8176 Set<ServerProperty> propertiesToCompare) 8177 { 8178 for (Map<ServerProperty, Object> server1 : registry1) 8179 { 8180 if (!exists(registry2, server1, propertiesToCompare)) 8181 { 8182 return false; 8183 } 8184 } 8185 return true; 8186 } 8187 8188 private boolean exists(Set<Map<ServerProperty, Object>> registry2, Map<ServerProperty, Object> server1, 8189 Set<ServerProperty> propertiesToCompare) 8190 { 8191 for (Map<ServerProperty, Object> server2 : registry2) 8192 { 8193 if (equals(server1, server2, propertiesToCompare)) 8194 { 8195 return true; 8196 } 8197 } 8198 return false; 8199 } 8200 8201 private boolean equals(Map<ServerProperty, Object> server1, Map<ServerProperty, Object> server2, 8202 Set<ServerProperty> propertiesToCompare) 8203 { 8204 for (ServerProperty prop : propertiesToCompare) 8205 { 8206 if (!Objects.equals(server1.get(prop), server2.get(prop))) 8207 { 8208 return false; 8209 } 8210 } 8211 return true; 8212 } 8213 8214 /** 8215 * Tells whether we are trying to disable all the replicated suffixes. 8216 * @param uData the disable replication data provided by the user. 8217 * @return <CODE>true</CODE> if we want to disable all the replicated suffixes 8218 * and <CODE>false</CODE> otherwise. 8219 */ 8220 private boolean disableAllBaseDns(InitialLdapContext ctx, 8221 DisableReplicationUserData uData) 8222 { 8223 if (uData.disableAll()) 8224 { 8225 return true; 8226 } 8227 8228 Collection<ReplicaDescriptor> replicas = getReplicas(ctx); 8229 Set<String> replicatedSuffixes = new HashSet<>(); 8230 for (ReplicaDescriptor rep : replicas) 8231 { 8232 String dn = rep.getSuffix().getDN(); 8233 if (rep.isReplicated()) 8234 { 8235 replicatedSuffixes.add(dn); 8236 } 8237 } 8238 8239 for (String dn1 : replicatedSuffixes) 8240 { 8241 if (!areDnsEqual(ADSContext.getAdministrationSuffixDN(), dn1) 8242 && !areDnsEqual(Constants.SCHEMA_DN, dn1) 8243 && !containsDN(uData.getBaseDNs(), dn1)) 8244 { 8245 return false; 8246 } 8247 } 8248 return true; 8249 } 8250 8251 private boolean containsDN(final Collection<String> dns, String dnToFind) 8252 { 8253 for (String dn : dns) 8254 { 8255 if (areDnsEqual(dn, dnToFind)) 8256 { 8257 return true; 8258 } 8259 } 8260 return false; 8261 } 8262 8263 /** 8264 * Returns the host port representation of the server to be used in progress, 8265 * status and error messages. It takes into account the fact the host and 8266 * port provided by the user. 8267 * @param server the ServerDescriptor. 8268 * @param cnx the preferred connections list. 8269 * @return the host port string representation of the provided server. 8270 */ 8271 private String getHostPort2(ServerDescriptor server, 8272 Collection<PreferredConnection> cnx) 8273 { 8274 String hostPort = null; 8275 for (PreferredConnection connection : cnx) 8276 { 8277 String url = connection.getLDAPURL(); 8278 if (url.equals(server.getLDAPURL())) 8279 { 8280 hostPort = server.getHostPort(false); 8281 } 8282 else if (url.equals(server.getLDAPsURL())) 8283 { 8284 hostPort = server.getHostPort(true); 8285 } 8286 } 8287 if (hostPort != null) 8288 { 8289 return hostPort; 8290 } 8291 return server.getHostPort(true); 8292 } 8293 8294 /** 8295 * Prompts the user for the subcommand that should be executed. 8296 * @return the subcommand choice of the user. 8297 */ 8298 private SubcommandChoice promptForSubcommand() 8299 { 8300 MenuBuilder<SubcommandChoice> builder = new MenuBuilder<>(this); 8301 builder.setPrompt(INFO_REPLICATION_SUBCOMMAND_PROMPT.get()); 8302 builder.addCancelOption(false); 8303 for (SubcommandChoice choice : SubcommandChoice.values()) 8304 { 8305 if (choice != SubcommandChoice.CANCEL) 8306 { 8307 builder.addNumberedOption(choice.getPrompt(), 8308 MenuResult.success(choice)); 8309 } 8310 } 8311 try 8312 { 8313 MenuResult<SubcommandChoice> m = builder.toMenu().run(); 8314 if (m.isSuccess()) 8315 { 8316 return m.getValue(); 8317 } 8318 // The user cancelled 8319 return SubcommandChoice.CANCEL; 8320 } 8321 catch (ClientException ce) 8322 { 8323 logger.warn(LocalizableMessage.raw("Error reading input: "+ce, ce)); 8324 return SubcommandChoice.CANCEL; 8325 } 8326 } 8327 8328 private boolean mustPrintCommandBuilder() 8329 { 8330 return argParser.isInteractive() && 8331 (argParser.displayEquivalentArgument.isPresent() || 8332 argParser.equivalentCommandFileArgument.isPresent()); 8333 } 8334 8335 /** 8336 * Prints the contents of a command builder. This method has been created 8337 * since SetPropSubCommandHandler calls it. All the logic of DSConfig is on 8338 * this method. Currently it simply writes the content of the CommandBuilder 8339 * to the standard output, but if we provide an option to write the content 8340 * to a file only the implementation of this method must be changed. 8341 * @param subCommandName the command builder to be printed. 8342 * @param uData input parameters from cli 8343 */ 8344 private void printNewCommandBuilder(String subCommandName, ReplicationUserData uData) 8345 { 8346 try 8347 { 8348 final CommandBuilder commandBuilder = createCommandBuilder(sourceServerCI, subCommandName, uData); 8349 if (argParser.displayEquivalentArgument.isPresent()) 8350 { 8351 println(); 8352 // We assume that the app we are running is this one. 8353 println(INFO_REPLICATION_NON_INTERACTIVE.get(commandBuilder)); 8354 } 8355 if (argParser.equivalentCommandFileArgument.isPresent()) 8356 { 8357 // Write to the file. 8358 String file = argParser.equivalentCommandFileArgument.getValue(); 8359 try 8360 { 8361 BufferedWriter writer = new BufferedWriter(new FileWriter(file, true)); 8362 8363 writer.write(SHELL_COMMENT_SEPARATOR+getCurrentOperationDateMessage()); 8364 writer.newLine(); 8365 8366 writer.write(commandBuilder.toString()); 8367 writer.newLine(); 8368 writer.newLine(); 8369 8370 writer.flush(); 8371 writer.close(); 8372 } 8373 catch (IOException ioe) 8374 { 8375 errPrintln(ERR_REPLICATION_ERROR_WRITING_EQUIVALENT_COMMAND_LINE.get(file, ioe)); 8376 } 8377 } 8378 } 8379 catch (Throwable t) 8380 { 8381 logger.error(LocalizableMessage.raw("Error printing equivalent command-line: " + t), t); 8382 } 8383 } 8384 8385 /** 8386 * Creates a command builder with the global options: script friendly, 8387 * verbose, etc. for a given subcommand name. It also adds systematically the 8388 * no-prompt option. 8389 * 8390 * @param ci the LDAP connection to the server 8391 * @param subcommandName the subcommand name. 8392 * @param uData the user data. 8393 * @return the command builder that has been created with the specified 8394 * subcommandName. 8395 */ 8396 private CommandBuilder createCommandBuilder(LDAPConnectionConsoleInteraction ci, String subcommandName, 8397 ReplicationUserData uData) throws ArgumentException 8398 { 8399 String commandName = getCommandName(); 8400 8401 CommandBuilder commandBuilder = new CommandBuilder(commandName, subcommandName); 8402 8403 if (ENABLE_REPLICATION_SUBCMD_NAME.equals(subcommandName)) 8404 { 8405 // All the arguments for enable replication are update here. 8406 updateCommandBuilder(commandBuilder, (EnableReplicationUserData)uData); 8407 } 8408 else if (INITIALIZE_REPLICATION_SUBCMD_NAME.equals(subcommandName) || 8409 RESET_CHANGE_NUMBER_SUBCMD_NAME.equals(subcommandName)) 8410 { 8411 // All the arguments for initialize replication are update here. 8412 updateCommandBuilder(commandBuilder, (SourceDestinationServerUserData)uData); 8413 } 8414 else if (PURGE_HISTORICAL_SUBCMD_NAME.equals(subcommandName)) 8415 { 8416 // All the arguments for initialize replication are update here. 8417 updateCommandBuilder(ci, commandBuilder, (PurgeHistoricalUserData)uData); 8418 } 8419 else 8420 { 8421 // Update the arguments used in the console interaction with the 8422 // actual arguments of dsreplication. 8423 updateCommandBuilderWithConsoleInteraction(commandBuilder, ci); 8424 } 8425 8426 if (DISABLE_REPLICATION_SUBCMD_NAME.equals(subcommandName)) 8427 { 8428 DisableReplicationUserData disableData = 8429 (DisableReplicationUserData)uData; 8430 if (disableData.disableAll()) 8431 { 8432 commandBuilder.addArgument(newBooleanArgument( 8433 argParser.disableAllArg, INFO_DESCRIPTION_DISABLE_ALL)); 8434 } 8435 else if (disableData.disableReplicationServer()) 8436 { 8437 commandBuilder.addArgument(newBooleanArgument( 8438 argParser.disableReplicationServerArg, INFO_DESCRIPTION_DISABLE_REPLICATION_SERVER)); 8439 } 8440 } 8441 8442 addGlobalArguments(commandBuilder, uData); 8443 return commandBuilder; 8444 } 8445 8446 private String getCommandName() 8447 { 8448 String commandName = System.getProperty(ServerConstants.PROPERTY_SCRIPT_NAME); 8449 if (commandName != null) 8450 { 8451 return commandName; 8452 } 8453 return "dsreplication"; 8454 } 8455 8456 private void updateCommandBuilderWithConsoleInteraction(CommandBuilder commandBuilder, 8457 LDAPConnectionConsoleInteraction ci) throws ArgumentException 8458 { 8459 if (ci != null && ci.getCommandBuilder() != null) 8460 { 8461 CommandBuilder interactionBuilder = ci.getCommandBuilder(); 8462 for (Argument arg : interactionBuilder.getArguments()) 8463 { 8464 if (OPTION_LONG_BINDPWD.equals(arg.getLongIdentifier())) 8465 { 8466 commandBuilder.addObfuscatedArgument(getAdminPasswordArg(arg)); 8467 } 8468 else if (OPTION_LONG_BINDPWD_FILE.equals(arg.getLongIdentifier())) 8469 { 8470 commandBuilder.addArgument(getAdminPasswordFileArg(arg)); 8471 } 8472 else 8473 { 8474 addArgument(commandBuilder, arg, interactionBuilder.isObfuscated(arg)); 8475 } 8476 } 8477 } 8478 } 8479 8480 private void updateCommandBuilder(LDAPConnectionConsoleInteraction ci, CommandBuilder commandBuilder, 8481 PurgeHistoricalUserData uData) throws ArgumentException 8482 { 8483 if (uData.isOnline()) 8484 { 8485 updateCommandBuilderWithConsoleInteraction(commandBuilder, ci); 8486 if (uData.getTaskSchedule() != null) 8487 { 8488 updateCommandBuilderWithTaskSchedule(commandBuilder, 8489 uData.getTaskSchedule()); 8490 } 8491 } 8492 8493 IntegerArgument maximumDurationArg = IntegerArgument.builder(argParser.maximumDurationArg.getLongIdentifier()) 8494 .shortIdentifier(argParser.maximumDurationArg.getShortIdentifier()) 8495 .description(argParser.maximumDurationArg.getDescription()) 8496 .required() 8497 .defaultValue(PurgeConflictsHistoricalTask.DEFAULT_MAX_DURATION) 8498 .valuePlaceholder(argParser.maximumDurationArg.getValuePlaceholder()) 8499 .buildArgument(); 8500 maximumDurationArg.addValue(String.valueOf(uData.getMaximumDuration())); 8501 commandBuilder.addArgument(maximumDurationArg); 8502 } 8503 8504 private void updateCommandBuilderWithTaskSchedule( 8505 CommandBuilder commandBuilder, 8506 TaskScheduleUserData taskSchedule) 8507 { 8508 TaskScheduleUserData.updateCommandBuilderWithTaskSchedule( 8509 commandBuilder, taskSchedule); 8510 } 8511 8512 private void addGlobalArguments(CommandBuilder commandBuilder, ReplicationUserData uData) 8513 throws ArgumentException 8514 { 8515 List<String> baseDNs = uData.getBaseDNs(); 8516 StringArgument baseDNsArg = 8517 StringArgument.builder(OPTION_LONG_BASEDN) 8518 .shortIdentifier(OPTION_SHORT_BASEDN) 8519 .description(INFO_DESCRIPTION_REPLICATION_BASEDNS.get()) 8520 .multiValued() 8521 .valuePlaceholder(INFO_BASEDN_PLACEHOLDER.get()) 8522 .buildArgument(); 8523 for (String baseDN : baseDNs) 8524 { 8525 baseDNsArg.addValue(baseDN); 8526 } 8527 commandBuilder.addArgument(baseDNsArg); 8528 8529 if (argParser.resetChangeNumber.isPresent()) 8530 { 8531 commandBuilder.addArgument(argParser.resetChangeNumber); 8532 } 8533 8534 // Try to find some arguments and put them at the end. 8535 String[] identifiersToMove ={ 8536 OPTION_LONG_ADMIN_UID, 8537 "adminPassword", 8538 "adminPasswordFile", 8539 OPTION_LONG_SASLOPTION, 8540 OPTION_LONG_TRUSTALL, 8541 OPTION_LONG_TRUSTSTOREPATH, 8542 OPTION_LONG_TRUSTSTORE_PWD, 8543 OPTION_LONG_TRUSTSTORE_PWD_FILE, 8544 OPTION_LONG_KEYSTOREPATH, 8545 OPTION_LONG_KEYSTORE_PWD, 8546 OPTION_LONG_KEYSTORE_PWD_FILE, 8547 OPTION_LONG_CERT_NICKNAME 8548 }; 8549 8550 ArrayList<Argument> toMoveArgs = new ArrayList<>(); 8551 for (String longID : identifiersToMove) 8552 { 8553 final Argument arg = findArg(commandBuilder, longID); 8554 if (arg != null) 8555 { 8556 toMoveArgs.add(arg); 8557 } 8558 } 8559 for (Argument argToMove : toMoveArgs) 8560 { 8561 boolean toObfuscate = commandBuilder.isObfuscated(argToMove); 8562 commandBuilder.removeArgument(argToMove); 8563 if (toObfuscate) 8564 { 8565 commandBuilder.addObfuscatedArgument(argToMove); 8566 } 8567 else 8568 { 8569 commandBuilder.addArgument(argToMove); 8570 } 8571 } 8572 8573 if (argParser.isVerbose()) 8574 { 8575 commandBuilder.addArgument( 8576 BooleanArgument.builder(OPTION_LONG_VERBOSE) 8577 .shortIdentifier(OPTION_SHORT_VERBOSE) 8578 .description(INFO_DESCRIPTION_VERBOSE.get()) 8579 .buildArgument()); 8580 } 8581 8582 if (argParser.isScriptFriendly()) 8583 { 8584 commandBuilder.addArgument(argParser.scriptFriendlyArg); 8585 } 8586 8587 commandBuilder.addArgument(argParser.noPromptArg); 8588 8589 if (argParser.propertiesFileArgument.isPresent()) 8590 { 8591 commandBuilder.addArgument(argParser.propertiesFileArgument); 8592 } 8593 8594 if (argParser.noPropertiesFileArgument.isPresent()) 8595 { 8596 commandBuilder.addArgument(argParser.noPropertiesFileArgument); 8597 } 8598 } 8599 8600 private Argument findArg(CommandBuilder commandBuilder, String longIdentifier) 8601 { 8602 for (Argument arg : commandBuilder.getArguments()) 8603 { 8604 if (longIdentifier.equals(arg.getLongIdentifier())) 8605 { 8606 return arg; 8607 } 8608 } 8609 return null; 8610 } 8611 8612 private boolean existsArg(CommandBuilder commandBuilder, String longIdentifier) 8613 { 8614 return findArg(commandBuilder, longIdentifier) != null; 8615 } 8616 8617 private void addArgument(CommandBuilder commandBuilder, Argument arg, boolean isObfuscated) 8618 { 8619 if (isObfuscated) 8620 { 8621 commandBuilder.addObfuscatedArgument(arg); 8622 } 8623 else 8624 { 8625 commandBuilder.addArgument(arg); 8626 } 8627 } 8628 8629 private void updateCommandBuilder(CommandBuilder commandBuilder, EnableReplicationUserData uData) 8630 throws ArgumentException 8631 { 8632 // Update the arguments used in the console interaction with the 8633 // actual arguments of dsreplication. 8634 boolean adminInformationAdded = false; 8635 8636 EnableReplicationServerData server1 = uData.getServer1(); 8637 if (firstServerCommandBuilder != null) 8638 { 8639 boolean useAdminUID = existsArg(firstServerCommandBuilder, OPTION_LONG_ADMIN_UID); 8640 // This is required when both the bindDN and the admin UID are provided 8641 // in the command-line. 8642 boolean forceAddBindDN1 = false; 8643 boolean forceAddBindPwdFile1 = false; 8644 if (useAdminUID) 8645 { 8646 String bindDN1 = server1.getBindDn(); 8647 String adminUID = uData.getAdminUid(); 8648 if (bindDN1 != null 8649 && adminUID != null 8650 && !areDnsEqual(getAdministratorDN(adminUID), bindDN1)) 8651 { 8652 forceAddBindDN1 = true; 8653 forceAddBindPwdFile1 = existsArg(firstServerCommandBuilder, OPTION_LONG_BINDPWD_FILE); 8654 } 8655 } 8656 for (Argument arg : firstServerCommandBuilder.getArguments()) 8657 { 8658 if (OPTION_LONG_HOST.equals(arg.getLongIdentifier())) 8659 { 8660 commandBuilder.addArgument(getHostArg("host1", OPTION_SHORT_HOST, server1.getHostName(), 8661 INFO_DESCRIPTION_ENABLE_REPLICATION_HOST1)); 8662 } 8663 else if (OPTION_LONG_PORT.equals(arg.getLongIdentifier())) 8664 { 8665 commandBuilder.addArgument(getPortArg("port1", OPTION_SHORT_PORT, server1.getPort(), 8666 INFO_DESCRIPTION_ENABLE_REPLICATION_SERVER_PORT1)); 8667 8668 if (forceAddBindDN1) 8669 { 8670 commandBuilder.addArgument(getBindDN1Arg(uData)); 8671 if (forceAddBindPwdFile1) 8672 { 8673 FileBasedArgument bindPasswordFileArg = getBindPasswordFile1Arg(); 8674 bindPasswordFileArg.getNameToValueMap().put("{password file}", 8675 "{password file}"); 8676 commandBuilder.addArgument(bindPasswordFileArg); 8677 } 8678 else 8679 { 8680 commandBuilder.addObfuscatedArgument(getBindPassword1Arg(arg)); 8681 } 8682 } 8683 } 8684 else if (OPTION_LONG_BINDDN.equals(arg.getLongIdentifier())) 8685 { 8686 commandBuilder.addArgument(getBindDN1Arg(uData)); 8687 } 8688 else if (OPTION_LONG_BINDPWD.equals(arg.getLongIdentifier())) 8689 { 8690 if (useAdminUID) 8691 { 8692 adminInformationAdded = true; 8693 commandBuilder.addObfuscatedArgument(getAdminPasswordArg(arg)); 8694 } 8695 else 8696 { 8697 commandBuilder.addObfuscatedArgument(getBindPassword1Arg(arg)); 8698 } 8699 } 8700 else if (OPTION_LONG_BINDPWD_FILE.equals(arg.getLongIdentifier())) 8701 { 8702 if (useAdminUID) 8703 { 8704 commandBuilder.addArgument(getAdminPasswordFileArg(arg)); 8705 } 8706 else 8707 { 8708 FileBasedArgument bindPasswordFileArg = getBindPasswordFile1Arg(); 8709 bindPasswordFileArg.getNameToValueMap().putAll( 8710 ((FileBasedArgument)arg).getNameToValueMap()); 8711 commandBuilder.addArgument(bindPasswordFileArg); 8712 } 8713 } 8714 else 8715 { 8716 if (OPTION_LONG_ADMIN_UID.equals(arg.getLongIdentifier())) 8717 { 8718 adminInformationAdded = true; 8719 } 8720 8721 addArgument(commandBuilder, arg, firstServerCommandBuilder.isObfuscated(arg)); 8722 } 8723 } 8724 } 8725 8726 EnableReplicationServerData server2 = uData.getServer2(); 8727 if (sourceServerCI != null && sourceServerCI.getCommandBuilder() != null) 8728 { 8729 CommandBuilder interactionBuilder = sourceServerCI.getCommandBuilder(); 8730 boolean useAdminUID = existsArg(interactionBuilder, OPTION_LONG_ADMIN_UID); 8731 boolean hasBindDN = existsArg(interactionBuilder, OPTION_LONG_BINDDN); 8732// This is required when both the bindDN and the admin UID are provided 8733 // in the command-line. 8734 boolean forceAddBindDN2 = false; 8735 boolean forceAddBindPwdFile2 = false; 8736 if (useAdminUID) 8737 { 8738 String bindDN2 = server2.getBindDn(); 8739 String adminUID = uData.getAdminUid(); 8740 if (bindDN2 != null 8741 && adminUID != null 8742 && !areDnsEqual(getAdministratorDN(adminUID), bindDN2)) 8743 { 8744 forceAddBindDN2 = true; 8745 forceAddBindPwdFile2 = existsArg(interactionBuilder, OPTION_LONG_BINDPWD_FILE); 8746 } 8747 } 8748 ArrayList<Argument> argsToAnalyze = new ArrayList<>(); 8749 for (Argument arg : interactionBuilder.getArguments()) 8750 { 8751 if (OPTION_LONG_HOST.equals(arg.getLongIdentifier())) 8752 { 8753 commandBuilder.addArgument( 8754 getHostArg("host2", 'O', server2.getHostName(), INFO_DESCRIPTION_ENABLE_REPLICATION_HOST2)); 8755 } 8756 else if (OPTION_LONG_PORT.equals(arg.getLongIdentifier())) 8757 { 8758 commandBuilder.addArgument(getPortArg("port2", null, server2.getPort(), 8759 INFO_DESCRIPTION_ENABLE_REPLICATION_SERVER_PORT2)); 8760 8761 if (forceAddBindDN2) 8762 { 8763 commandBuilder.addArgument(getBindDN2Arg(uData, OPTION_SHORT_BINDDN)); 8764 if (forceAddBindPwdFile2) 8765 { 8766 FileBasedArgument bindPasswordFileArg = getBindPasswordFile2Arg(); 8767 bindPasswordFileArg.getNameToValueMap().put("{password file}", 8768 "{password file}"); 8769 commandBuilder.addArgument(bindPasswordFileArg); 8770 } 8771 else 8772 { 8773 commandBuilder.addObfuscatedArgument(getBindPassword2Arg(arg)); 8774 } 8775 } 8776 } 8777 else if (OPTION_LONG_BINDDN.equals(arg.getLongIdentifier())) 8778 { 8779 commandBuilder.addArgument(getBindDN2Arg(uData, null)); 8780 } 8781 else if (OPTION_LONG_BINDPWD.equals(arg.getLongIdentifier())) 8782 { 8783 if (useAdminUID && !adminInformationAdded) 8784 { 8785 adminInformationAdded = true; 8786 commandBuilder.addObfuscatedArgument(getAdminPasswordArg(arg)); 8787 } 8788 else if (hasBindDN) 8789 { 8790 commandBuilder.addObfuscatedArgument(getBindPassword2Arg(arg)); 8791 } 8792 } 8793 else if (OPTION_LONG_BINDPWD_FILE.equals(arg.getLongIdentifier())) 8794 { 8795 if (useAdminUID && !adminInformationAdded) 8796 { 8797 adminInformationAdded = true; 8798 commandBuilder.addArgument(getAdminPasswordFileArg(arg)); 8799 } 8800 else if (hasBindDN) 8801 { 8802 FileBasedArgument bindPasswordFileArg = getBindPasswordFile2Arg(); 8803 bindPasswordFileArg.getNameToValueMap().putAll( 8804 ((FileBasedArgument)arg).getNameToValueMap()); 8805 commandBuilder.addArgument(bindPasswordFileArg); 8806 } 8807 } 8808 else 8809 { 8810 argsToAnalyze.add(arg); 8811 } 8812 } 8813 8814 for (Argument arg : argsToAnalyze) 8815 { 8816 // Just check that the arguments have not already been added. 8817 if (!existsArg(commandBuilder, arg.getLongIdentifier())) 8818 { 8819 addArgument(commandBuilder, arg, interactionBuilder.isObfuscated(arg)); 8820 } 8821 } 8822 } 8823 8824 // Try to add the new administration information. 8825 if (!adminInformationAdded) 8826 { 8827 if (uData.getAdminUid() != null) 8828 { 8829 final StringArgument adminUID = adminUid( 8830 INFO_DESCRIPTION_REPLICATION_ADMIN_UID.get(ENABLE_REPLICATION_SUBCMD_NAME)); 8831 adminUID.addValue(uData.getAdminUid()); 8832 commandBuilder.addArgument(adminUID); 8833 } 8834 8835 if (userProvidedAdminPwdFile != null) 8836 { 8837 commandBuilder.addArgument(userProvidedAdminPwdFile); 8838 } 8839 else if (uData.getAdminPwd() != null) 8840 { 8841 Argument bindPasswordArg = getAdminPasswordArg(); 8842 bindPasswordArg.addValue(uData.getAdminPwd()); 8843 commandBuilder.addObfuscatedArgument(bindPasswordArg); 8844 } 8845 } 8846 8847 if (server1.configureReplicationServer() && 8848 !server1.configureReplicationDomain()) 8849 { 8850 commandBuilder.addArgument(newBooleanArgument( 8851 argParser.server1.onlyReplicationServerArg, INFO_DESCRIPTION_ENABLE_REPLICATION_ONLY_REPLICATION_SERVER1)); 8852 } 8853 8854 if (!server1.configureReplicationServer() && 8855 server1.configureReplicationDomain()) 8856 { 8857 commandBuilder.addArgument(newBooleanArgument( 8858 argParser.server1.noReplicationServerArg, INFO_DESCRIPTION_ENABLE_REPLICATION_NO_REPLICATION_SERVER1)); 8859 } 8860 8861 if (server1.configureReplicationServer() && 8862 server1.getReplicationPort() > 0) 8863 { 8864 commandBuilder.addArgument(getReplicationPortArg( 8865 "replicationPort1", server1, 8989, INFO_DESCRIPTION_ENABLE_REPLICATION_PORT1)); 8866 } 8867 if (server1.isSecureReplication()) 8868 { 8869 commandBuilder.addArgument( 8870 newBooleanArgument("secureReplication1", INFO_DESCRIPTION_ENABLE_SECURE_REPLICATION1)); 8871 } 8872 8873 if (server2.configureReplicationServer() && 8874 !server2.configureReplicationDomain()) 8875 { 8876 commandBuilder.addArgument(newBooleanArgument( 8877 argParser.server2.onlyReplicationServerArg, INFO_DESCRIPTION_ENABLE_REPLICATION_ONLY_REPLICATION_SERVER2)); 8878 } 8879 8880 if (!server2.configureReplicationServer() && 8881 server2.configureReplicationDomain()) 8882 { 8883 commandBuilder.addArgument(newBooleanArgument( 8884 argParser.server2.noReplicationServerArg, INFO_DESCRIPTION_ENABLE_REPLICATION_NO_REPLICATION_SERVER2)); 8885 } 8886 if (server2.configureReplicationServer() && 8887 server2.getReplicationPort() > 0) 8888 { 8889 commandBuilder.addArgument(getReplicationPortArg( 8890 "replicationPort2", server2, server2.getReplicationPort(), INFO_DESCRIPTION_ENABLE_REPLICATION_PORT2)); 8891 } 8892 if (server2.isSecureReplication()) 8893 { 8894 commandBuilder.addArgument( 8895 newBooleanArgument("secureReplication2", INFO_DESCRIPTION_ENABLE_SECURE_REPLICATION2)); 8896 } 8897 8898 if (!uData.replicateSchema()) 8899 { 8900 commandBuilder.addArgument( 8901 BooleanArgument.builder("noSchemaReplication") 8902 .description(INFO_DESCRIPTION_ENABLE_REPLICATION_NO_SCHEMA_REPLICATION.get()) 8903 .buildArgument()); 8904 } 8905 if (argParser.skipReplicationPortCheck()) 8906 { 8907 commandBuilder.addArgument( 8908 BooleanArgument.builder("skipPortCheck") 8909 .shortIdentifier('S') 8910 .description(INFO_DESCRIPTION_ENABLE_REPLICATION_SKIPPORT.get()) 8911 .buildArgument()); 8912 } 8913 if (argParser.useSecondServerAsSchemaSource()) 8914 { 8915 commandBuilder.addArgument( 8916 BooleanArgument.builder("useSecondServerAsSchemaSource") 8917 .description(INFO_DESCRIPTION_ENABLE_REPLICATION_USE_SECOND_AS_SCHEMA_SOURCE.get( 8918 "--" + argParser.noSchemaReplicationArg.getLongIdentifier())) 8919 .buildArgument()); 8920 } 8921 } 8922 8923 private IntegerArgument getReplicationPortArg( 8924 String name, EnableReplicationServerData server, int defaultValue, Arg0 description) throws ArgumentException 8925 { 8926 IntegerArgument replicationPort = 8927 IntegerArgument.builder(name) 8928 .shortIdentifier('r') 8929 .description(description.get()) 8930 .defaultValue(defaultValue) 8931 .valuePlaceholder(INFO_PORT_PLACEHOLDER.get()) 8932 .buildArgument(); 8933 replicationPort.addValue(String.valueOf(server.getReplicationPort())); 8934 return replicationPort; 8935 } 8936 8937 private BooleanArgument newBooleanArgument(String name, Arg0 msg) throws ArgumentException 8938 { 8939 return BooleanArgument.builder(name) 8940 .description(msg.get()) 8941 .buildArgument(); 8942 } 8943 8944 private BooleanArgument newBooleanArgument(BooleanArgument arg, Arg0 msg) throws ArgumentException 8945 { 8946 return BooleanArgument.builder(arg.getLongIdentifier()) 8947 .shortIdentifier(arg.getShortIdentifier()) 8948 .description(msg.get()) 8949 .buildArgument(); 8950 } 8951 8952 private StringArgument getBindPassword1Arg(Argument arg) throws ArgumentException 8953 { 8954 return getBindPasswordArg("bindPassword1", arg, INFO_DESCRIPTION_ENABLE_REPLICATION_BINDPASSWORD1); 8955 } 8956 8957 private StringArgument getBindPassword2Arg(Argument arg) throws ArgumentException 8958 { 8959 return getBindPasswordArg("bindPassword2", arg, INFO_DESCRIPTION_ENABLE_REPLICATION_BINDPASSWORD2); 8960 } 8961 8962 private StringArgument getBindPasswordArg(String name, Argument arg, Arg0 bindPwdMsg) throws ArgumentException 8963 { 8964 StringArgument bindPasswordArg = 8965 StringArgument.builder(name) 8966 .description(bindPwdMsg.get()) 8967 .valuePlaceholder(INFO_BINDPWD_PLACEHOLDER.get()) 8968 .buildArgument(); 8969 bindPasswordArg.addValue(arg.getValue()); 8970 return bindPasswordArg; 8971 } 8972 8973 private FileBasedArgument getBindPasswordFile1Arg() throws ArgumentException 8974 { 8975 return FileBasedArgument.builder("bindPasswordFile1") 8976 .description(INFO_DESCRIPTION_ENABLE_REPLICATION_BINDPASSWORDFILE1.get()) 8977 .valuePlaceholder(INFO_BINDPWD_FILE_PLACEHOLDER.get()) 8978 .buildArgument(); 8979 } 8980 8981 private FileBasedArgument getBindPasswordFile2Arg() throws ArgumentException 8982 { 8983 return FileBasedArgument.builder("bindPasswordFile2") 8984 .description(INFO_DESCRIPTION_ENABLE_REPLICATION_BINDPASSWORDFILE2.get()) 8985 .valuePlaceholder(INFO_BINDPWD_FILE_PLACEHOLDER.get()) 8986 .buildArgument(); 8987 } 8988 8989 private StringArgument getBindDN1Arg(EnableReplicationUserData uData) throws ArgumentException 8990 { 8991 StringArgument bindDN = 8992 StringArgument.builder("bindDN1") 8993 .shortIdentifier(OPTION_SHORT_BINDDN) 8994 .description(INFO_DESCRIPTION_ENABLE_REPLICATION_BINDDN1.get()) 8995 .defaultValue("cn=Directory Manager") 8996 .valuePlaceholder(INFO_BINDDN_PLACEHOLDER.get()) 8997 .buildArgument(); 8998 bindDN.addValue(uData.getServer1().getBindDn()); 8999 return bindDN; 9000 } 9001 9002 private StringArgument getBindDN2Arg(EnableReplicationUserData uData, Character shortIdentifier) 9003 throws ArgumentException 9004 { 9005 StringArgument bindDN = 9006 StringArgument.builder("bindDN2") 9007 .shortIdentifier(shortIdentifier) 9008 .description(INFO_DESCRIPTION_ENABLE_REPLICATION_BINDDN2.get()) 9009 .defaultValue("cn=Directory Manager") 9010 .valuePlaceholder(INFO_BINDDN_PLACEHOLDER.get()) 9011 .buildArgument(); 9012 bindDN.addValue(uData.getServer2().getBindDn()); 9013 return bindDN; 9014 } 9015 9016 private void updateCommandBuilder(CommandBuilder commandBuilder, 9017 SourceDestinationServerUserData uData) 9018 throws ArgumentException 9019 { 9020 // Update the arguments used in the console interaction with the 9021 // actual arguments of dsreplication. 9022 9023 if (firstServerCommandBuilder != null) 9024 { 9025 for (Argument arg : firstServerCommandBuilder.getArguments()) 9026 { 9027 if (OPTION_LONG_HOST.equals(arg.getLongIdentifier())) 9028 { 9029 commandBuilder.addArgument(getHostArg("hostSource", 'O', uData.getHostNameSource(), 9030 INFO_DESCRIPTION_INITIALIZE_REPLICATION_HOST_SOURCE)); 9031 } 9032 else if (OPTION_LONG_PORT.equals(arg.getLongIdentifier())) 9033 { 9034 commandBuilder.addArgument(getPortArg("portSource", null, uData.getPortSource(), 9035 INFO_DESCRIPTION_INITIALIZE_REPLICATION_SERVER_PORT_SOURCE)); 9036 } 9037 else if (OPTION_LONG_BINDPWD.equals(arg.getLongIdentifier())) 9038 { 9039 commandBuilder.addObfuscatedArgument(getAdminPasswordArg(arg)); 9040 } 9041 else if (OPTION_LONG_BINDPWD_FILE.equals(arg.getLongIdentifier())) 9042 { 9043 commandBuilder.addArgument(getAdminPasswordFileArg(arg)); 9044 } 9045 else 9046 { 9047 addArgument(commandBuilder, arg, firstServerCommandBuilder.isObfuscated(arg)); 9048 } 9049 } 9050 } 9051 9052 if (sourceServerCI != null && sourceServerCI.getCommandBuilder() != null) 9053 { 9054 CommandBuilder interactionBuilder = sourceServerCI.getCommandBuilder(); 9055 for (Argument arg : interactionBuilder.getArguments()) 9056 { 9057 if (OPTION_LONG_HOST.equals(arg.getLongIdentifier())) 9058 { 9059 commandBuilder.addArgument(getHostArg("hostDestination", 'O', uData.getHostNameDestination(), 9060 INFO_DESCRIPTION_INITIALIZE_REPLICATION_HOST_DESTINATION)); 9061 } 9062 else if (OPTION_LONG_PORT.equals(arg.getLongIdentifier())) 9063 { 9064 commandBuilder.addArgument(getPortArg("portDestination", null, uData.getPortDestination(), 9065 INFO_DESCRIPTION_INITIALIZE_REPLICATION_SERVER_PORT_DESTINATION)); 9066 } 9067 } 9068 } 9069 } 9070 9071 private StringArgument getAdminPasswordArg(Argument arg) throws ArgumentException 9072 { 9073 StringArgument sArg = getAdminPasswordArg(); 9074 sArg.addValue(arg.getValue()); 9075 return sArg; 9076 } 9077 9078 private StringArgument getAdminPasswordArg() throws ArgumentException 9079 { 9080 return StringArgument.builder("adminPassword") 9081 .shortIdentifier(OPTION_SHORT_BINDPWD) 9082 .description(INFO_DESCRIPTION_REPLICATION_ADMIN_BINDPASSWORD.get()) 9083 .valuePlaceholder(INFO_BINDPWD_PLACEHOLDER.get()) 9084 .buildArgument(); 9085 } 9086 9087 private FileBasedArgument getAdminPasswordFileArg(Argument arg) throws ArgumentException 9088 { 9089 FileBasedArgument fbArg = 9090 FileBasedArgument.builder("adminPasswordFile") 9091 .shortIdentifier(OPTION_SHORT_BINDPWD_FILE) 9092 .description(INFO_DESCRIPTION_REPLICATION_ADMIN_BINDPASSWORDFILE.get()) 9093 .valuePlaceholder(INFO_BINDPWD_FILE_PLACEHOLDER.get()) 9094 .buildArgument(); 9095 fbArg.getNameToValueMap().putAll(((FileBasedArgument) arg).getNameToValueMap()); 9096 return fbArg; 9097 } 9098 9099 private IntegerArgument getPortArg(String longIdentifier, Character shortIdentifier, int value, Arg0 arg) 9100 throws ArgumentException 9101 { 9102 IntegerArgument iArg = 9103 IntegerArgument.builder(longIdentifier) 9104 .shortIdentifier(shortIdentifier) 9105 .description(arg.get()) 9106 .defaultValue(4444) 9107 .valuePlaceholder(INFO_PORT_PLACEHOLDER.get()) 9108 .buildArgument(); 9109 iArg.addValue(String.valueOf(value)); 9110 return iArg; 9111 } 9112 9113 private StringArgument getHostArg(String longIdentifier, char shortIdentifier, String value, 9114 Arg0 description) throws ArgumentException 9115 { 9116 StringArgument sArg = 9117 StringArgument.builder(longIdentifier) 9118 .shortIdentifier(shortIdentifier) 9119 .description(description.get()) 9120 .valuePlaceholder(INFO_HOST_PLACEHOLDER.get()) 9121 .buildArgument(); 9122 sArg.addValue(value); 9123 return sArg; 9124 } 9125 9126 private void updateAvailableAndReplicatedSuffixesForOneDomain( 9127 InitialLdapContext ctxDomain, InitialLdapContext ctxOther, 9128 Set<String> availableSuffixes, Set<String> alreadyReplicatedSuffixes) 9129 { 9130 Collection<ReplicaDescriptor> replicas = getReplicas(ctxDomain); 9131 int replicationPort = getReplicationPort(ctxOther); 9132 boolean isReplicationServerConfigured = replicationPort != -1; 9133 String replicationServer = getReplicationServer(getHostName(ctxOther), replicationPort); 9134 for (ReplicaDescriptor replica : replicas) 9135 { 9136 if (!isReplicationServerConfigured) 9137 { 9138 if (replica.isReplicated()) 9139 { 9140 alreadyReplicatedSuffixes.add(replica.getSuffix().getDN()); 9141 } 9142 availableSuffixes.add(replica.getSuffix().getDN()); 9143 } 9144 9145 if (!isReplicationServerConfigured) 9146 { 9147 availableSuffixes.add(replica.getSuffix().getDN()); 9148 } 9149 else if (!replica.isReplicated()) 9150 { 9151 availableSuffixes.add(replica.getSuffix().getDN()); 9152 } 9153 else if (containsIgnoreCase(replica.getReplicationServers(), replicationServer)) 9154 { 9155 alreadyReplicatedSuffixes.add(replica.getSuffix().getDN()); 9156 } 9157 else 9158 { 9159 availableSuffixes.add(replica.getSuffix().getDN()); 9160 } 9161 } 9162 } 9163 9164 private void updateAvailableAndReplicatedSuffixesForNoDomain( 9165 InitialLdapContext ctx1, InitialLdapContext ctx2, 9166 Set<String> availableSuffixes, Set<String> alreadyReplicatedSuffixes) 9167 { 9168 int replicationPort1 = getReplicationPort(ctx1); 9169 boolean isReplicationServer1Configured = replicationPort1 != -1; 9170 String replicationServer1 = getReplicationServer(getHostName(ctx1), replicationPort1); 9171 9172 int replicationPort2 = getReplicationPort(ctx2); 9173 boolean isReplicationServer2Configured = replicationPort2 != -1; 9174 String replicationServer2 = getReplicationServer(getHostName(ctx2), replicationPort2); 9175 9176 TopologyCache cache1 = isReplicationServer1Configured ? createTopologyCache(ctx1) : null; 9177 TopologyCache cache2 = isReplicationServer2Configured ? createTopologyCache(ctx2) : null; 9178 if (cache1 != null && cache2 != null) 9179 { 9180 updateAvailableAndReplicatedSuffixesForNoDomainOneSense(cache1, cache2, 9181 replicationServer1, replicationServer2, availableSuffixes, 9182 alreadyReplicatedSuffixes); 9183 updateAvailableAndReplicatedSuffixesForNoDomainOneSense(cache2, cache1, 9184 replicationServer2, replicationServer1, availableSuffixes, 9185 alreadyReplicatedSuffixes); 9186 } 9187 else if (cache1 != null) 9188 { 9189 addAllAvailableSuffixes(availableSuffixes, cache1.getSuffixes(), replicationServer1); 9190 } 9191 else if (cache2 != null) 9192 { 9193 addAllAvailableSuffixes(availableSuffixes, cache2.getSuffixes(), replicationServer2); 9194 } 9195 } 9196 9197 private TopologyCache createTopologyCache(InitialLdapContext ctx) 9198 { 9199 try 9200 { 9201 ADSContext adsContext = new ADSContext(ctx); 9202 if (adsContext.hasAdminData()) 9203 { 9204 TopologyCache cache = new TopologyCache(adsContext, getTrustManager(sourceServerCI), getConnectTimeout()); 9205 cache.getFilter().setSearchMonitoringInformation(false); 9206 cache.setPreferredConnections(getPreferredConnections(ctx)); 9207 cache.reloadTopology(); 9208 return cache; 9209 } 9210 } 9211 catch (Throwable t) 9212 { 9213 logger.warn(LocalizableMessage.raw("Error loading topology cache in " + getLdapUrl(ctx) + ": " + t, t)); 9214 } 9215 return null; 9216 } 9217 9218 private void addAllAvailableSuffixes(Collection<String> availableSuffixes, 9219 Set<SuffixDescriptor> suffixes, String rsToFind) 9220 { 9221 for (SuffixDescriptor suffix : suffixes) 9222 { 9223 for (String rs : suffix.getReplicationServers()) 9224 { 9225 if (rs.equalsIgnoreCase(rsToFind)) 9226 { 9227 availableSuffixes.add(suffix.getDN()); 9228 } 9229 } 9230 } 9231 } 9232 9233 private void updateAvailableAndReplicatedSuffixesForNoDomainOneSense( 9234 TopologyCache cache1, TopologyCache cache2, String replicationServer1, 9235 String replicationServer2, 9236 Set<String> availableSuffixes, Set<String> alreadyReplicatedSuffixes) 9237 { 9238 for (SuffixDescriptor suffix : cache1.getSuffixes()) 9239 { 9240 for (String rServer : suffix.getReplicationServers()) 9241 { 9242 if (rServer.equalsIgnoreCase(replicationServer1)) 9243 { 9244 boolean isSecondReplicatedInSameTopology = false; 9245 boolean isSecondReplicated = false; 9246 boolean isFirstReplicated = false; 9247 for (SuffixDescriptor suffix2 : cache2.getSuffixes()) 9248 { 9249 if (areDnsEqual(suffix.getDN(), suffix2.getDN())) 9250 { 9251 for (String rServer2 : suffix2.getReplicationServers()) 9252 { 9253 if (rServer2.equalsIgnoreCase(replicationServer2)) 9254 { 9255 isSecondReplicated = true; 9256 } 9257 if (rServer.equalsIgnoreCase(replicationServer2)) 9258 { 9259 isFirstReplicated = true; 9260 } 9261 if (isFirstReplicated && isSecondReplicated) 9262 { 9263 isSecondReplicatedInSameTopology = true; 9264 break; 9265 } 9266 } 9267 break; 9268 } 9269 } 9270 if (!isSecondReplicatedInSameTopology) 9271 { 9272 availableSuffixes.add(suffix.getDN()); 9273 } 9274 else 9275 { 9276 alreadyReplicatedSuffixes.add(suffix.getDN()); 9277 } 9278 break; 9279 } 9280 } 9281 } 9282 } 9283 9284 private void updateBaseDnsWithNotEnoughReplicationServer(ADSContext adsCtx1, 9285 ADSContext adsCtx2, EnableReplicationUserData uData, 9286 Set<String> baseDNsWithNoReplicationServer, 9287 Set<String> baseDNsWithOneReplicationServer) 9288 { 9289 EnableReplicationServerData server1 = uData.getServer1(); 9290 EnableReplicationServerData server2 = uData.getServer2(); 9291 if (server1.configureReplicationServer() && 9292 server2.configureReplicationServer()) 9293 { 9294 return; 9295 } 9296 9297 Set<SuffixDescriptor> suffixes = new HashSet<>(); 9298 createTopologyCache(adsCtx1, uData, suffixes); 9299 createTopologyCache(adsCtx2, uData, suffixes); 9300 9301 int repPort1 = getReplicationPort(adsCtx1.getDirContext()); 9302 String repServer1 = getReplicationServer(server1.getHostName(), repPort1); 9303 int repPort2 = getReplicationPort(adsCtx2.getDirContext()); 9304 String repServer2 = getReplicationServer(server2.getHostName(), repPort2); 9305 for (String baseDN : uData.getBaseDNs()) 9306 { 9307 int nReplicationServers = 0; 9308 for (SuffixDescriptor suffix : suffixes) 9309 { 9310 if (areDnsEqual(suffix.getDN(), baseDN)) 9311 { 9312 Set<String> replicationServers = suffix.getReplicationServers(); 9313 nReplicationServers += replicationServers.size(); 9314 for (String repServer : replicationServers) 9315 { 9316 if (server1.configureReplicationServer() && 9317 repServer.equalsIgnoreCase(repServer1)) 9318 { 9319 nReplicationServers --; 9320 } 9321 if (server2.configureReplicationServer() && 9322 repServer.equalsIgnoreCase(repServer2)) 9323 { 9324 nReplicationServers --; 9325 } 9326 } 9327 } 9328 } 9329 if (server1.configureReplicationServer()) 9330 { 9331 nReplicationServers ++; 9332 } 9333 if (server2.configureReplicationServer()) 9334 { 9335 nReplicationServers ++; 9336 } 9337 if (nReplicationServers == 1) 9338 { 9339 baseDNsWithOneReplicationServer.add(baseDN); 9340 } 9341 else if (nReplicationServers == 0) 9342 { 9343 baseDNsWithNoReplicationServer.add(baseDN); 9344 } 9345 } 9346 } 9347 9348 private void createTopologyCache(ADSContext adsCtx, ReplicationUserData uData, Set<SuffixDescriptor> suffixes) 9349 { 9350 try 9351 { 9352 if (adsCtx.hasAdminData()) 9353 { 9354 TopologyCache cache = new TopologyCache(adsCtx, getTrustManager(sourceServerCI), getConnectTimeout()); 9355 cache.getFilter().setSearchMonitoringInformation(false); 9356 addBaseDNs(cache.getFilter(), uData.getBaseDNs()); 9357 cache.reloadTopology(); 9358 suffixes.addAll(cache.getSuffixes()); 9359 } 9360 } 9361 catch (Throwable t) 9362 { 9363 String msg = "Error loading topology cache from " + getHostPort(adsCtx.getDirContext()) + ": " + t; 9364 logger.warn(LocalizableMessage.raw(msg, t)); 9365 } 9366 } 9367 9368 /** 9369 * Merge the contents of the two registries but only does it partially. 9370 * Only one of the two ADSContext will be updated (in terms of data in 9371 * cn=admin data), while the other registry's replication servers will have 9372 * their truststore updated to be able to initialize all the contents. 9373 * 9374 * This method does NOT configure replication between topologies or initialize 9375 * replication. 9376 * 9377 * @param adsCtx1 the ADSContext of the first registry. 9378 * @param adsCtx2 the ADSContext of the second registry. 9379 * @return <CODE>true</CODE> if the registry containing all the data is 9380 * the first registry and <CODE>false</CODE> otherwise. 9381 * @throws ReplicationCliException if there is a problem reading or updating 9382 * the registries. 9383 */ 9384 private boolean mergeRegistries(ADSContext adsCtx1, ADSContext adsCtx2) 9385 throws ReplicationCliException 9386 { 9387 PointAdder pointAdder = new PointAdder(this); 9388 try 9389 { 9390 Set<PreferredConnection> cnx = new LinkedHashSet<>(getPreferredConnections(adsCtx1.getDirContext())); 9391 cnx.addAll(getPreferredConnections(adsCtx2.getDirContext())); 9392 TopologyCache cache1 = createTopologyCache(adsCtx1, cnx); 9393 TopologyCache cache2 = createTopologyCache(adsCtx2, cnx); 9394 9395 // Look for the cache with biggest number of replication servers: 9396 // that one is going to be source. 9397 int nRepServers1 = countReplicationServers(cache1); 9398 int nRepServers2 = countReplicationServers(cache2); 9399 9400 InitialLdapContext ctxSource; 9401 InitialLdapContext ctxDestination; 9402 if (nRepServers1 >= nRepServers2) 9403 { 9404 ctxSource = adsCtx1.getDirContext(); 9405 ctxDestination = adsCtx2.getDirContext(); 9406 } 9407 else 9408 { 9409 ctxSource = adsCtx2.getDirContext(); 9410 ctxDestination = adsCtx1.getDirContext(); 9411 } 9412 9413 String hostPortSource = getHostPort(ctxSource); 9414 String hostPortDestination = getHostPort(ctxDestination); 9415 if (isInteractive()) 9416 { 9417 LocalizableMessage msg = INFO_REPLICATION_MERGING_REGISTRIES_CONFIRMATION.get(hostPortSource, 9418 hostPortDestination, hostPortSource, hostPortDestination); 9419 if (!askConfirmation(msg, true)) 9420 { 9421 throw new ReplicationCliException(ERR_REPLICATION_USER_CANCELLED.get(), USER_CANCELLED, null); 9422 } 9423 } 9424 else 9425 { 9426 LocalizableMessage msg = INFO_REPLICATION_MERGING_REGISTRIES_DESCRIPTION.get(hostPortSource, 9427 hostPortDestination, hostPortSource, hostPortDestination); 9428 println(msg); 9429 println(); 9430 } 9431 9432 print(INFO_REPLICATION_MERGING_REGISTRIES_PROGRESS.get()); 9433 pointAdder.start(); 9434 9435 checkCanMergeReplicationTopologies(adsCtx1, cache1); 9436 checkCanMergeReplicationTopologies(adsCtx2, cache2); 9437 9438 Set<LocalizableMessage> commonRepServerIDErrors = new HashSet<>(); 9439 for (ServerDescriptor server1 : cache1.getServers()) 9440 { 9441 if (findSameReplicationServer(server1, cache2.getServers(), commonRepServerIDErrors)) 9442 { 9443 break; 9444 } 9445 } 9446 Set<LocalizableMessage> commonDomainIDErrors = new HashSet<>(); 9447 for (SuffixDescriptor suffix1 : cache1.getSuffixes()) 9448 { 9449 for (ReplicaDescriptor replica1 : suffix1.getReplicas()) 9450 { 9451 if (replica1.isReplicated()) 9452 { 9453 for (SuffixDescriptor suffix2 : cache2.getSuffixes()) 9454 { 9455 if (findReplicaInSuffix2(replica1, suffix2, suffix1.getDN(), commonDomainIDErrors)) 9456 { 9457 break; 9458 } 9459 } 9460 } 9461 } 9462 } 9463 if (!commonRepServerIDErrors.isEmpty() || !commonDomainIDErrors.isEmpty()) 9464 { 9465 LocalizableMessageBuilder mb = new LocalizableMessageBuilder(); 9466 if (!commonRepServerIDErrors.isEmpty()) 9467 { 9468 mb.append(ERR_REPLICATION_ENABLE_COMMON_REPLICATION_SERVER_ID.get( 9469 getMessageFromCollection(commonRepServerIDErrors, Constants.LINE_SEPARATOR))); 9470 } 9471 if (!commonDomainIDErrors.isEmpty()) 9472 { 9473 if (mb.length() > 0) 9474 { 9475 mb.append(Constants.LINE_SEPARATOR); 9476 } 9477 mb.append(ERR_REPLICATION_ENABLE_COMMON_DOMAIN_ID.get( 9478 getMessageFromCollection(commonDomainIDErrors, Constants.LINE_SEPARATOR))); 9479 } 9480 throw new ReplicationCliException(mb.toMessage(), 9481 REPLICATION_ADS_MERGE_NOT_SUPPORTED, null); 9482 } 9483 9484 ADSContext adsCtxSource; 9485 ADSContext adsCtxDestination; 9486 TopologyCache cacheDestination; 9487 if (nRepServers1 >= nRepServers2) 9488 { 9489 adsCtxSource = adsCtx1; 9490 adsCtxDestination = adsCtx2; 9491 cacheDestination = cache2; 9492 } 9493 else 9494 { 9495 adsCtxSource = adsCtx2; 9496 adsCtxDestination = adsCtx1; 9497 cacheDestination = cache1; 9498 } 9499 9500 try 9501 { 9502 adsCtxSource.mergeWithRegistry(adsCtxDestination); 9503 } 9504 catch (ADSContextException adce) 9505 { 9506 logger.error(LocalizableMessage.raw("Error merging registry of "+ 9507 getHostPort(adsCtxSource.getDirContext())+ 9508 " with registry of "+ 9509 getHostPort(adsCtxDestination.getDirContext())+" "+ 9510 adce, adce)); 9511 if (adce.getError() == ADSContextException.ErrorType.ERROR_MERGING) 9512 { 9513 throw new ReplicationCliException(adce.getMessageObject(), 9514 REPLICATION_ADS_MERGE_NOT_SUPPORTED, adce); 9515 } 9516 else 9517 { 9518 throw new ReplicationCliException( 9519 ERR_REPLICATION_UPDATING_ADS.get(adce.getMessageObject()), 9520 ERROR_UPDATING_ADS, adce); 9521 } 9522 } 9523 9524 try 9525 { 9526 for (ServerDescriptor server : cacheDestination.getServers()) 9527 { 9528 if (server.isReplicationServer()) 9529 { 9530 logger.info(LocalizableMessage.raw("Seeding to replication server on "+ 9531 server.getHostPort(true)+" with certificates of "+ 9532 getHostPort(adsCtxSource.getDirContext()))); 9533 InitialLdapContext ctx = null; 9534 try 9535 { 9536 ctx = getDirContextForServer(cacheDestination, server); 9537 ServerDescriptor.seedAdsTrustStore(ctx, 9538 adsCtxSource.getTrustedCertificates()); 9539 } 9540 finally 9541 { 9542 close(ctx); 9543 } 9544 } 9545 } 9546 } 9547 catch (Throwable t) 9548 { 9549 logger.error(LocalizableMessage.raw("Error seeding truststore: "+t, t)); 9550 LocalizableMessage msg = ERR_REPLICATION_ENABLE_SEEDING_TRUSTSTORE.get(getHostPort(adsCtx2.getDirContext()), 9551 getHostPort(adsCtx1.getDirContext()), toString(t)); 9552 throw new ReplicationCliException(msg, ERROR_SEEDING_TRUSTORE, t); 9553 } 9554 pointAdder.stop(); 9555 print(formatter.getSpace()); 9556 print(formatter.getFormattedDone()); 9557 println(); 9558 9559 return adsCtxSource == adsCtx1; 9560 } 9561 finally 9562 { 9563 pointAdder.stop(); 9564 } 9565 } 9566 9567 private int countReplicationServers(TopologyCache cache) 9568 { 9569 int nbRepServers = 0; 9570 for (ServerDescriptor server : cache.getServers()) 9571 { 9572 if (server.isReplicationServer()) 9573 { 9574 nbRepServers++; 9575 } 9576 } 9577 return nbRepServers; 9578 } 9579 9580 private void checkCanMergeReplicationTopologies(ADSContext adsCtx, TopologyCache cache) 9581 throws ReplicationCliException 9582 { 9583 Set<LocalizableMessage> cacheErrors = cache.getErrorMessages(); 9584 if (!cacheErrors.isEmpty()) 9585 { 9586 LocalizableMessage msg = getMessageFromCollection(cacheErrors, Constants.LINE_SEPARATOR); 9587 throw new ReplicationCliException( 9588 ERR_REPLICATION_CANNOT_MERGE_WITH_ERRORS.get(getHostPort(adsCtx.getDirContext()), msg), 9589 ERROR_READING_ADS, null); 9590 } 9591 } 9592 9593 private boolean findSameReplicationServer(ServerDescriptor serverToFind, Set<ServerDescriptor> servers, 9594 Set<LocalizableMessage> commonRepServerIDErrors) 9595 { 9596 if (!serverToFind.isReplicationServer()) 9597 { 9598 return false; 9599 } 9600 9601 int replicationID1 = serverToFind.getReplicationServerId(); 9602 String replServerHostPort1 = serverToFind.getReplicationServerHostPort(); 9603 for (ServerDescriptor server2 : servers) 9604 { 9605 if (server2.isReplicationServer() && server2.getReplicationServerId() == replicationID1 9606 && !server2.getReplicationServerHostPort().equalsIgnoreCase(replServerHostPort1)) 9607 { 9608 commonRepServerIDErrors.add(ERR_REPLICATION_ENABLE_COMMON_REPLICATION_SERVER_ID_ARG.get( 9609 serverToFind.getHostPort(true), server2.getHostPort(true), replicationID1)); 9610 return true; 9611 } 9612 } 9613 return false; 9614 } 9615 9616 private boolean findReplicaInSuffix2(ReplicaDescriptor replica1, SuffixDescriptor suffix2, String suffix1DN, 9617 Set<LocalizableMessage> commonDomainIDErrors) 9618 { 9619 if (!areDnsEqual(suffix2.getDN(), replica1.getSuffix().getDN())) 9620 { 9621 // Conflicting domain names must apply to same suffix. 9622 return false; 9623 } 9624 9625 int domain1Id = replica1.getReplicationId(); 9626 for (ReplicaDescriptor replica2 : suffix2.getReplicas()) 9627 { 9628 if (replica2.isReplicated() 9629 && domain1Id == replica2.getReplicationId()) 9630 { 9631 commonDomainIDErrors.add( 9632 ERR_REPLICATION_ENABLE_COMMON_DOMAIN_ID_ARG.get(replica1.getServer().getHostPort(true), suffix1DN, 9633 replica2.getServer().getHostPort(true), suffix2.getDN(), domain1Id)); 9634 return true; 9635 } 9636 } 9637 return false; 9638 } 9639 9640 private String toString(Throwable t) 9641 { 9642 return (t instanceof OpenDsException) ? 9643 ((OpenDsException) t).getMessageObject().toString() : t.toString(); 9644 } 9645 9646 private TopologyCache createTopologyCache(ADSContext adsCtx, Set<PreferredConnection> cnx) 9647 throws ReplicationCliException 9648 { 9649 TopologyCache cache = new TopologyCache(adsCtx, getTrustManager(sourceServerCI), getConnectTimeout()); 9650 cache.setPreferredConnections(cnx); 9651 cache.getFilter().setSearchBaseDNInformation(false); 9652 try 9653 { 9654 cache.reloadTopology(); 9655 return cache; 9656 } 9657 catch (TopologyCacheException te) 9658 { 9659 logger.error(LocalizableMessage.raw( 9660 "Error reading topology cache of " + getHostPort(adsCtx.getDirContext()) + " " + te, te)); 9661 throw new ReplicationCliException(ERR_REPLICATION_READING_ADS.get(te.getMessageObject()), ERROR_UPDATING_ADS, te); 9662 } 9663 } 9664 9665 private InitialLdapContext getDirContextForServer(TopologyCache cache, ServerDescriptor server) 9666 throws NamingException 9667 { 9668 String dn = getBindDN(cache.getAdsContext().getDirContext()); 9669 String pwd = getBindPassword(cache.getAdsContext().getDirContext()); 9670 TopologyCacheFilter filter = new TopologyCacheFilter(); 9671 filter.setSearchMonitoringInformation(false); 9672 filter.setSearchBaseDNInformation(false); 9673 ServerLoader loader = new ServerLoader(server.getAdsProperties(), 9674 dn, pwd, getTrustManager(sourceServerCI), getConnectTimeout(), 9675 cache.getPreferredConnections(), filter); 9676 return loader.createContext(); 9677 } 9678 9679 /** 9680 * Returns <CODE>true</CODE> if the provided baseDN is replicated in the 9681 * provided server, <CODE>false</CODE> otherwise. 9682 * @param server the server. 9683 * @param baseDN the base DN. 9684 * @return <CODE>true</CODE> if the provided baseDN is replicated in the 9685 * provided server, <CODE>false</CODE> otherwise. 9686 */ 9687 private boolean isBaseDNReplicated(ServerDescriptor server, String baseDN) 9688 { 9689 return findReplicated(server.getReplicas(), baseDN) != null; 9690 } 9691 9692 /** 9693 * Returns <CODE>true</CODE> if the provided baseDN is replicated between 9694 * both servers, <CODE>false</CODE> otherwise. 9695 * @param server1 the first server. 9696 * @param server2 the second server. 9697 * @param baseDN the base DN. 9698 * @return <CODE>true</CODE> if the provided baseDN is replicated between 9699 * both servers, <CODE>false</CODE> otherwise. 9700 */ 9701 private boolean isBaseDNReplicated(ServerDescriptor server1, 9702 ServerDescriptor server2, String baseDN) 9703 { 9704 final ReplicaDescriptor replica1 = findReplicated(server1.getReplicas(), baseDN); 9705 final ReplicaDescriptor replica2 = findReplicated(server2.getReplicas(), baseDN); 9706 if (replica1 != null && replica2 != null) 9707 { 9708 Set<String> replServers1 = replica1.getSuffix().getReplicationServers(); 9709 Set<String> replServers2 = replica1.getSuffix().getReplicationServers(); 9710 for (String replServer1 : replServers1) 9711 { 9712 if (containsIgnoreCase(replServers2, replServer1)) 9713 { 9714 // it is replicated in both 9715 return true; 9716 } 9717 } 9718 } 9719 return false; 9720 } 9721 9722 private ReplicaDescriptor findReplicated(Set<ReplicaDescriptor> replicas, String baseDN) 9723 { 9724 for (ReplicaDescriptor replica : replicas) 9725 { 9726 if (areDnsEqual(replica.getSuffix().getDN(), baseDN)) 9727 { 9728 return replica; 9729 } 9730 } 9731 return null; 9732 } 9733 9734 private boolean displayLogFileAtEnd(String subCommand) 9735 { 9736 final List<String> subCommands = Arrays.asList(ENABLE_REPLICATION_SUBCMD_NAME, DISABLE_REPLICATION_SUBCMD_NAME, 9737 INITIALIZE_ALL_REPLICATION_SUBCMD_NAME, INITIALIZE_REPLICATION_SUBCMD_NAME, RESET_CHANGE_NUMBER_SUBCMD_NAME); 9738 return subCommands.contains(subCommand); 9739 } 9740 9741 /** 9742 * Returns the timeout to be used to connect in milliseconds. The method 9743 * must be called after parsing the arguments. 9744 * @return the timeout to be used to connect in milliseconds. Returns 9745 * {@code 0} if there is no timeout. 9746 */ 9747 private int getConnectTimeout() 9748 { 9749 return argParser.getConnectTimeout(); 9750 } 9751 9752 private String binDir; 9753 9754 /** 9755 * Returns the binary/script directory. 9756 * @return the binary/script directory. 9757 */ 9758 private String getBinaryDir() 9759 { 9760 if (binDir == null) 9761 { 9762 File f = Installation.getLocal().getBinariesDirectory(); 9763 try 9764 { 9765 binDir = f.getCanonicalPath(); 9766 } 9767 catch (Throwable t) 9768 { 9769 binDir = f.getAbsolutePath(); 9770 } 9771 if (binDir.lastIndexOf(File.separatorChar) != binDir.length() - 1) 9772 { 9773 binDir += File.separatorChar; 9774 } 9775 } 9776 return binDir; 9777 } 9778 9779 /** 9780 * Returns the full path of the command-line for a given script name. 9781 * @param scriptBasicName the script basic name (with no extension). 9782 * @return the full path of the command-line for a given script name. 9783 */ 9784 private String getCommandLinePath(String scriptBasicName) 9785 { 9786 if (isWindows()) 9787 { 9788 return getBinaryDir() + scriptBasicName + ".bat"; 9789 } 9790 return getBinaryDir() + scriptBasicName; 9791 } 9792} 9793 9794/** Class used to compare replication servers. */ 9795class ReplicationServerComparator implements Comparator<ServerDescriptor> 9796{ 9797 /** {@inheritDoc} */ 9798 @Override 9799 public int compare(ServerDescriptor s1, ServerDescriptor s2) 9800 { 9801 int compare = s1.getHostName().compareTo(s2.getHostName()); 9802 if (compare == 0) 9803 { 9804 if (s1.getReplicationServerPort() > s2.getReplicationServerPort()) 9805 { 9806 return 1; 9807 } 9808 else if (s1.getReplicationServerPort() < s2.getReplicationServerPort()) 9809 { 9810 return -1; 9811 } 9812 } 9813 return compare; 9814 } 9815} 9816 9817/** Class used to compare suffixes. */ 9818class SuffixComparator implements Comparator<SuffixDescriptor> 9819{ 9820 @Override 9821 public int compare(SuffixDescriptor s1, SuffixDescriptor s2) 9822 { 9823 return s1.getId().compareTo(s2.getId()); 9824 } 9825} 9826 9827/** Class used to compare servers. */ 9828class ServerComparator implements Comparator<ServerDescriptor> 9829{ 9830 @Override 9831 public int compare(ServerDescriptor s1, ServerDescriptor s2) 9832 { 9833 return s1.getId().compareTo(s2.getId()); 9834 } 9835}