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