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