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