001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2007-2010 Sun Microsystems, Inc. 015 * Portions Copyright 2012-2016 ForgeRock AS. 016 */ 017package org.opends.server.tools.dsreplication; 018 019import static com.forgerock.opendj.cli.ArgumentConstants.*; 020import static com.forgerock.opendj.cli.CliMessages.INFO_BINDPWD_FILE_PLACEHOLDER; 021import static com.forgerock.opendj.cli.CliMessages.INFO_PORT_PLACEHOLDER; 022import static com.forgerock.opendj.cli.CommonArguments.*; 023import static com.forgerock.opendj.cli.Utils.*; 024 025import static org.opends.messages.AdminToolMessages.*; 026import static org.opends.messages.ToolMessages.*; 027 028import java.io.File; 029import java.io.OutputStream; 030import java.util.ArrayList; 031import java.util.Collection; 032import java.util.List; 033 034import org.forgerock.i18n.LocalizableMessage; 035import org.forgerock.i18n.LocalizableMessageBuilder; 036import org.opends.quicksetup.Constants; 037import org.opends.server.admin.client.cli.SecureConnectionCliArgs; 038import org.opends.server.admin.client.cli.SecureConnectionCliParser; 039import org.opends.server.admin.client.cli.TaskScheduleArgs; 040import org.opends.server.config.AdministrationConnector; 041import org.opends.server.core.DirectoryServer.DirectoryServerVersionHandler; 042import org.opends.server.tasks.PurgeConflictsHistoricalTask; 043 044import com.forgerock.opendj.cli.Argument; 045import com.forgerock.opendj.cli.ArgumentException; 046import com.forgerock.opendj.cli.ArgumentGroup; 047import com.forgerock.opendj.cli.BooleanArgument; 048import com.forgerock.opendj.cli.ClientException; 049import com.forgerock.opendj.cli.CommonArguments; 050import com.forgerock.opendj.cli.FileBasedArgument; 051import com.forgerock.opendj.cli.IntegerArgument; 052import com.forgerock.opendj.cli.StringArgument; 053import com.forgerock.opendj.cli.SubCommand; 054 055/** 056 * This class is used to parse the arguments passed to the replication CLI. 057 * It also checks the compatibility between the values and that all the 058 * required information has been provided. However it does not do any 059 * verification that require connection to any server. 060 */ 061public class ReplicationCliArgumentParser extends SecureConnectionCliParser 062{ 063 /** Arguments used when enabling replication for a server. */ 064 static class ServerArgs 065 { 066 /** The 'hostName' argument for the first server. */ 067 StringArgument hostNameArg; 068 /** The 'port' argument for the first server. */ 069 IntegerArgument portArg; 070 /** The 'bindDN' argument for the first server. */ 071 StringArgument bindDnArg; 072 /** The 'bindPasswordFile' argument for the first server. */ 073 FileBasedArgument bindPasswordFileArg; 074 /** The 'bindPassword' argument for the first server. */ 075 StringArgument bindPasswordArg; 076 /** The 'replicationPort' argument for the first server. */ 077 IntegerArgument replicationPortArg; 078 /** The 'noReplicationServer' argument for the first server. */ 079 BooleanArgument noReplicationServerArg; 080 /** The 'onlyReplicationServer' argument for the first server. */ 081 BooleanArgument onlyReplicationServerArg; 082 /** The 'secureReplication' argument for the first server. */ 083 BooleanArgument secureReplicationArg; 084 085 /** 086 * Get the password which has to be used for the command to connect to this server without 087 * prompting the user in the enable replication subcommand. If no password was specified return 088 * null. 089 * 090 * @return the password which has to be used for the command to connect to this server without 091 * prompting the user in the enable replication subcommand. If no password was specified 092 * return null. 093 */ 094 String getBindPassword() 095 { 096 return ReplicationCliArgumentParser.getBindPassword(bindPasswordArg, bindPasswordFileArg); 097 } 098 099 boolean configureReplicationDomain() 100 { 101 return !onlyReplicationServerArg.isPresent(); 102 } 103 104 boolean configureReplicationServer() 105 { 106 return !noReplicationServerArg.isPresent(); 107 } 108 } 109 110 private SubCommand enableReplicationSubCmd; 111 private SubCommand disableReplicationSubCmd; 112 private SubCommand initializeReplicationSubCmd; 113 private SubCommand initializeAllReplicationSubCmd; 114 private SubCommand postExternalInitializationSubCmd; 115 private SubCommand preExternalInitializationSubCmd; 116 private SubCommand resetChangelogNumber; 117 private SubCommand statusReplicationSubCmd; 118 private SubCommand purgeHistoricalSubCmd; 119 120 private int defaultAdminPort = 121 AdministrationConnector.DEFAULT_ADMINISTRATION_CONNECTOR_PORT; 122 123 /** No-prompt argument. */ 124 BooleanArgument noPromptArg; 125 126 /** Arguments for the first server. */ 127 ServerArgs server1 = new ServerArgs(); 128 /** Arguments for the second server. */ 129 ServerArgs server2 = new ServerArgs(); 130 131 /** The 'skipPortCheckArg' argument to not check replication ports. */ 132 private BooleanArgument skipPortCheckArg; 133 /** The 'noSchemaReplication' argument to not replicate schema. */ 134 BooleanArgument noSchemaReplicationArg; 135 /** The 'useSecondServerAsSchemaSource' argument to not replicate schema. */ 136 private BooleanArgument useSecondServerAsSchemaSourceArg; 137 /** The 'disableAll' argument to disable all the replication configuration of server. */ 138 BooleanArgument disableAllArg; 139 /** The 'disableReplicationServer' argument to disable the replication server. */ 140 BooleanArgument disableReplicationServerArg; 141 /** The 'hostName' argument for the source server. */ 142 private StringArgument hostNameSourceArg; 143 /** The 'port' argument for the source server. */ 144 private IntegerArgument portSourceArg; 145 /** The 'hostName' argument for the destination server. */ 146 private StringArgument hostNameDestinationArg; 147 /** The 'port' argument for the destination server. */ 148 private IntegerArgument portDestinationArg; 149 /** The 'suffixes' global argument. */ 150 StringArgument baseDNsArg; 151 /** The 'quiet' argument. */ 152 private BooleanArgument quietArg; 153 /** The 'scriptFriendly' argument. */ 154 BooleanArgument scriptFriendlyArg; 155 /** Properties file argument. */ 156 StringArgument propertiesFileArgument; 157 /** No-properties file argument. */ 158 BooleanArgument noPropertiesFileArgument; 159 /** The argument that the user must set to display the equivalent non-interactive mode argument. */ 160 BooleanArgument displayEquivalentArgument; 161 /** The argument that allows the user to dump the equivalent non-interactive command to a file. */ 162 StringArgument equivalentCommandFileArgument; 163 /** The argument that the user must set to have advanced options in interactive mode. */ 164 BooleanArgument advancedArg; 165 166 /** 167 * The argument set by the user to specify the configuration file 168 * (useful when dsreplication purge-historical runs locally). 169 */ 170 private StringArgument configFileArg; 171 172 TaskScheduleArgs taskArgs; 173 174 /** The 'maximumDuration' argument for the purge of historical. */ 175 IntegerArgument maximumDurationArg; 176 177 /** The 'change-number' argument for task reset-changenumber. */ 178 IntegerArgument resetChangeNumber; 179 180 /** The text of the enable replication subcommand. */ 181 static final String ENABLE_REPLICATION_SUBCMD_NAME = "enable"; 182 /** The text of the disable replication subcommand. */ 183 static final String DISABLE_REPLICATION_SUBCMD_NAME = "disable"; 184 /** The text of the initialize replication subcommand. */ 185 static final String INITIALIZE_REPLICATION_SUBCMD_NAME = "initialize"; 186 /** The text of the initialize all replication subcommand. */ 187 public static final String INITIALIZE_ALL_REPLICATION_SUBCMD_NAME = "initialize-all"; 188 /** The text of the pre external initialization subcommand. */ 189 static final String PRE_EXTERNAL_INITIALIZATION_SUBCMD_NAME = "pre-external-initialization"; 190 /** The text of the initialize all replication subcommand. */ 191 static final String POST_EXTERNAL_INITIALIZATION_SUBCMD_NAME = "post-external-initialization"; 192 /** The text of the reset changenumber subcommand. */ 193 static final String RESET_CHANGE_NUMBER_SUBCMD_NAME = "reset-change-number"; 194 195 /** The text of the status replication subcommand. */ 196 static final String STATUS_REPLICATION_SUBCMD_NAME = "status"; 197 /** The text of the purge historical subcommand. */ 198 static final String PURGE_HISTORICAL_SUBCMD_NAME = "purge-historical"; 199 /** This CLI is always using the administration connector with SSL. */ 200 private static final boolean alwaysSSL = true; 201 202 /** 203 * Creates a new instance of this argument parser with no arguments. 204 * 205 * @param mainClassName 206 * The fully-qualified name of the Java class that should 207 * be invoked to launch the program with which this 208 * argument parser is associated. 209 */ 210 ReplicationCliArgumentParser(String mainClassName) 211 { 212 super(mainClassName, 213 INFO_REPLICATION_TOOL_DESCRIPTION.get(ENABLE_REPLICATION_SUBCMD_NAME, INITIALIZE_REPLICATION_SUBCMD_NAME), 214 false); 215 setShortToolDescription(REF_SHORT_DESC_DSREPLICATION.get()); 216 setVersionHandler(new DirectoryServerVersionHandler()); 217 } 218 219 /** 220 * Initialize the parser with the Global options and subcommands. 221 * 222 * @param outStream 223 * The output stream to use for standard output, or {@code null} 224 * if standard output is not needed. 225 * @throws ArgumentException 226 * If there is a problem with any of the parameters used to create this argument. 227 */ 228 void initializeParser(OutputStream outStream) 229 throws ArgumentException 230 { 231 taskArgs = new TaskScheduleArgs(); 232 initializeGlobalArguments(outStream); 233 try 234 { 235 defaultAdminPort = secureArgsList.getAdminPortFromConfig(); 236 } 237 catch (Throwable t) 238 { 239 // Ignore 240 } 241 242 secureArgsList.initArgumentsWithConfiguration(this); 243 244 createEnableReplicationSubCommand(); 245 createDisableReplicationSubCommand(); 246 createRelatedServersOptions(); 247 createInitializeReplicationSubCommand(); 248 createInitializeAllReplicationSubCommand(); 249 createPreExternalInitializationSubCommand(); 250 createPostExternalInitializationSubCommand(); 251 createResetChangeNumberSubCommand(); 252 createStatusReplicationSubCommand(); 253 createPurgeHistoricalSubCommand(); 254 } 255 256 /** 257 * Checks all the options parameters and updates the provided LocalizableMessageBuilder 258 * with the errors that where encountered. 259 * 260 * This method assumes that the method parseArguments for the parser has 261 * already been called. 262 * @param buf the LocalizableMessageBuilder object where we add the error messages 263 * describing the errors encountered. 264 */ 265 void validateOptions(LocalizableMessageBuilder buf) 266 { 267 validateGlobalOptions(buf); 268 validateSubcommandOptions(buf); 269 } 270 271 @Override 272 public int validateGlobalOptions(LocalizableMessageBuilder buf) 273 { 274 int returnValue; 275 super.validateGlobalOptions(buf); 276 277 final List<LocalizableMessage> errors = new ArrayList<>(); 278 // Check that we can write on the provided path where we write the 279 // equivalent non-interactive commands. 280 if (equivalentCommandFileArgument.isPresent()) 281 { 282 String file = equivalentCommandFileArgument.getValue(); 283 if (!canWrite(file)) 284 { 285 errors.add(ERR_REPLICATION_CANNOT_WRITE_EQUIVALENT_COMMAND_LINE_FILE.get(file)); 286 } 287 else 288 { 289 File f = new File(file); 290 if (f.isDirectory()) 291 { 292 errors.add( 293 ERR_REPLICATION_EQUIVALENT_COMMAND_LINE_FILE_DIRECTORY.get(file)); 294 } 295 } 296 } 297 298 addErrorMessageIfArgumentsConflict(errors, noPromptArg, advancedArg); 299 300 if (!isInteractive()) 301 { 302 // Check that we have the required data 303 if (!baseDNsArg.isPresent() && 304 !isStatusReplicationSubcommand() && 305 !isResetChangeNumber() && 306 !disableAllArg.isPresent() && 307 !disableReplicationServerArg.isPresent()) 308 { 309 errors.add(ERR_REPLICATION_NO_BASE_DN_PROVIDED.get()); 310 } 311 if (getBindPasswordAdmin() == null && 312 !isPurgeHistoricalSubcommand()) 313 { 314 errors.add(ERR_REPLICATION_NO_ADMINISTRATOR_PASSWORD_PROVIDED.get( 315 "--"+ secureArgsList.getBindPasswordArg().getLongIdentifier(), 316 "--"+ secureArgsList.getBindPasswordFileArg().getLongIdentifier())); 317 } 318 } 319 320 if (baseDNsArg.isPresent()) 321 { 322 List<String> baseDNs = baseDNsArg.getValues(); 323 for (String dn : baseDNs) 324 { 325 if (!isDN(dn)) 326 { 327 errors.add(ERR_REPLICATION_NOT_A_VALID_BASEDN.get(dn)); 328 } 329 if (Constants.REPLICATION_CHANGES_DN.equalsIgnoreCase(dn)) 330 { 331 errors.add(ERR_REPLICATION_NOT_A_USER_SUFFIX.get(Constants.REPLICATION_CHANGES_DN)); 332 } 333 } 334 } 335 if (!errors.isEmpty()) 336 { 337 for (LocalizableMessage error : errors) 338 { 339 addMessage(buf, error); 340 } 341 } 342 343 if (buf.length() > 0) 344 { 345 returnValue = ReplicationCliReturnCode.CONFLICTING_ARGS.getReturnCode(); 346 } 347 else 348 { 349 returnValue = ReplicationCliReturnCode.SUCCESSFUL_NOP.getReturnCode(); 350 } 351 return returnValue; 352 } 353 354 /** 355 * Initialize Global option. 356 * 357 * @param outStream 358 * The output stream used for the usage. 359 * @throws ArgumentException 360 * If there is a problem with any of the parameters used 361 * to create this argument. 362 */ 363 private void initializeGlobalArguments(OutputStream outStream) 364 throws ArgumentException 365 { 366 ArrayList<Argument> defaultArgs = new ArrayList<>(createGlobalArguments(outStream, alwaysSSL)); 367 368 Argument[] argsToRemove = { 369 secureArgsList.getHostNameArg(), 370 secureArgsList.getPortArg(), 371 secureArgsList.getBindDnArg(), 372 secureArgsList.getBindPasswordFileArg(), 373 secureArgsList.getBindPasswordArg() 374 }; 375 376 for (Argument arg : argsToRemove) 377 { 378 defaultArgs.remove(arg); 379 } 380 defaultArgs.remove(super.noPropertiesFileArg); 381 defaultArgs.remove(super.propertiesFileArg); 382 // Remove it from the default location and redefine it. 383 defaultArgs.remove(getAdminUidArg()); 384 385 int index = 0; 386 387 baseDNsArg = 388 StringArgument.builder(OPTION_LONG_BASEDN) 389 .shortIdentifier(OPTION_SHORT_BASEDN) 390 .description(INFO_DESCRIPTION_REPLICATION_BASEDNS.get()) 391 .multiValued() 392 .valuePlaceholder(INFO_BASEDN_PLACEHOLDER.get()) 393 .buildArgument(); 394 defaultArgs.add(index++, baseDNsArg); 395 396 secureArgsList.createVisibleAdminUidArgument( 397 INFO_DESCRIPTION_REPLICATION_ADMIN_UID.get(ENABLE_REPLICATION_SUBCMD_NAME)); 398 defaultArgs.add(index++, secureArgsList.getAdminUidArg()); 399 400 secureArgsList.setBindPasswordArgument( 401 StringArgument.builder(OPTION_LONG_ADMIN_PWD) 402 .shortIdentifier(OPTION_SHORT_BINDPWD) 403 .description(INFO_DESCRIPTION_REPLICATION_ADMIN_BINDPASSWORD.get()) 404 .valuePlaceholder(INFO_BINDPWD_PLACEHOLDER.get()) 405 .buildArgument()); 406 defaultArgs.add(index++, secureArgsList.getBindPasswordArg()); 407 408 secureArgsList.setBindPasswordFileArgument( 409 FileBasedArgument.builder(OPTION_LONG_ADMIN_PWD_FILE) 410 .shortIdentifier(OPTION_SHORT_BINDPWD_FILE) 411 .description(INFO_DESCRIPTION_REPLICATION_ADMIN_BINDPASSWORDFILE.get()) 412 .valuePlaceholder(INFO_BINDPWD_FILE_PLACEHOLDER.get()) 413 .buildArgument()); 414 defaultArgs.add(index++, secureArgsList.getBindPasswordFileArg()); 415 416 defaultArgs.remove(verboseArg); 417 418 quietArg = quietArgument(); 419 defaultArgs.add(index++, quietArg); 420 421 noPromptArg = noPromptArgument(); 422 defaultArgs.add(index++, noPromptArg); 423 424 displayEquivalentArgument = displayEquivalentCommandArgument(); 425 426 defaultArgs.add(index++, displayEquivalentArgument); 427 428 equivalentCommandFileArgument = 429 CommonArguments 430 .equivalentCommandFileArgument( 431 INFO_REPLICATION_DESCRIPTION_EQUIVALENT_COMMAND_FILE_PATH.get()); 432 defaultArgs.add(index++, equivalentCommandFileArgument); 433 434 advancedArg = advancedModeArgument(); 435 defaultArgs.add(index++, advancedArg); 436 437 configFileArg = configFileArgument(); 438 defaultArgs.add(index++, configFileArg); 439 440 this.propertiesFileArgument = propertiesFileArgument(); 441 defaultArgs.add(this.propertiesFileArgument); 442 setFilePropertiesArgument(this.propertiesFileArgument); 443 444 this.noPropertiesFileArgument = noPropertiesFileArgument(); 445 defaultArgs.add(this.noPropertiesFileArgument); 446 setNoPropertiesFileArgument(this.noPropertiesFileArgument); 447 448 initializeGlobalArguments(defaultArgs, null); 449 } 450 451 /** 452 * Initialize the global options with the provided set of arguments. 453 * @param args the arguments to use to initialize the global options. 454 * @param argGroup the group to which args will be added. 455 * @throws ArgumentException if there is a conflict with the provided 456 * arguments. 457 */ 458 @Override 459 protected void initializeGlobalArguments( 460 Collection<Argument> args, 461 ArgumentGroup argGroup) 462 throws ArgumentException 463 { 464 for (Argument arg : args) 465 { 466 if (arg == advancedArg) 467 { 468 ArgumentGroup toolOptionsGroup = new ArgumentGroup( 469 INFO_DESCRIPTION_CONFIG_OPTIONS_ARGS.get(), 2); 470 addGlobalArgument(advancedArg, toolOptionsGroup); 471 } 472 else 473 { 474 addGlobalArgument(arg, argGroup); 475 } 476 } 477 478 // Set the propertiesFile argument 479 setFilePropertiesArgument(propertiesFileArg); 480 } 481 482 /** Creates the enable replication subcommand and all the specific options for the subcommand. */ 483 private void createEnableReplicationSubCommand() throws ArgumentException 484 { 485 createServerArgs1(); 486 createServerArgs2(); 487 488 skipPortCheckArg = 489 BooleanArgument.builder("skipPortCheck") 490 .shortIdentifier('S') 491 .description(INFO_DESCRIPTION_ENABLE_REPLICATION_SKIPPORT.get()) 492 .buildArgument(); 493 noSchemaReplicationArg = 494 BooleanArgument.builder("noSchemaReplication") 495 .description(INFO_DESCRIPTION_ENABLE_REPLICATION_NO_SCHEMA_REPLICATION.get()) 496 .buildArgument(); 497 useSecondServerAsSchemaSourceArg = 498 BooleanArgument.builder("useSecondServerAsSchemaSource") 499 .description(INFO_DESCRIPTION_ENABLE_REPLICATION_USE_SECOND_AS_SCHEMA_SOURCE.get( 500 "--" + noSchemaReplicationArg.getLongIdentifier())) 501 .buildArgument(); 502 503 enableReplicationSubCmd = new SubCommand(this, 504 ENABLE_REPLICATION_SUBCMD_NAME, 505 INFO_DESCRIPTION_SUBCMD_ENABLE_REPLICATION.get()); 506 addArgumentsToSubCommand(enableReplicationSubCmd, 507 server1.hostNameArg, server1.portArg, server1.bindDnArg, server1.bindPasswordArg, 508 server1.bindPasswordFileArg, server1.replicationPortArg, server1.secureReplicationArg, 509 server1.noReplicationServerArg, server1.onlyReplicationServerArg, 510 server2.hostNameArg, server2.portArg, server2.bindDnArg, server2.bindPasswordArg, 511 server2.bindPasswordFileArg, server2.replicationPortArg, server2.secureReplicationArg, 512 server2.noReplicationServerArg, server2.onlyReplicationServerArg, 513 skipPortCheckArg, noSchemaReplicationArg, useSecondServerAsSchemaSourceArg); 514 } 515 516 private void createServerArgs1() throws ArgumentException 517 { 518 ServerArgs server = server1; 519 server.hostNameArg = 520 StringArgument.builder("host1") 521 .shortIdentifier(OPTION_SHORT_HOST) 522 .description(INFO_DESCRIPTION_ENABLE_REPLICATION_HOST1.get()) 523 .defaultValue(secureArgsList.getDefaultHostName()) 524 .valuePlaceholder(INFO_HOST_PLACEHOLDER.get()) 525 .buildArgument(); 526 server.portArg = 527 IntegerArgument.builder("port1") 528 .shortIdentifier(OPTION_SHORT_PORT) 529 .description(INFO_DESCRIPTION_ENABLE_REPLICATION_SERVER_PORT1.get()) 530 .range(1, 65336) 531 .defaultValue(defaultAdminPort) 532 .valuePlaceholder(INFO_PORT_PLACEHOLDER.get()) 533 .buildArgument(); 534 server.bindDnArg = 535 StringArgument.builder("bindDN1") 536 .shortIdentifier(OPTION_SHORT_BINDDN) 537 .description(INFO_DESCRIPTION_ENABLE_REPLICATION_BINDDN1.get()) 538 .defaultValue("cn=Directory Manager") 539 .valuePlaceholder(INFO_BINDDN_PLACEHOLDER.get()) 540 .buildArgument(); 541 server.bindPasswordArg = 542 StringArgument.builder("bindPassword1") 543 .description(INFO_DESCRIPTION_ENABLE_REPLICATION_BINDPASSWORD1.get()) 544 .valuePlaceholder(INFO_BINDPWD_PLACEHOLDER.get()) 545 .buildArgument(); 546 server.bindPasswordFileArg = 547 FileBasedArgument.builder("bindPasswordFile1") 548 .description(INFO_DESCRIPTION_ENABLE_REPLICATION_BINDPASSWORDFILE1.get()) 549 .valuePlaceholder(INFO_BINDPWD_FILE_PLACEHOLDER.get()) 550 .buildArgument(); 551 server.replicationPortArg = 552 IntegerArgument.builder("replicationPort1") 553 .shortIdentifier('r') 554 .description(INFO_DESCRIPTION_ENABLE_REPLICATION_PORT1.get()) 555 .range(1, 65336) 556 .defaultValue(8989) 557 .valuePlaceholder(INFO_PORT_PLACEHOLDER.get()) 558 .buildArgument(); 559 server.secureReplicationArg = 560 BooleanArgument.builder("secureReplication1") 561 .description(INFO_DESCRIPTION_ENABLE_SECURE_REPLICATION1.get()) 562 .buildArgument(); 563 server.noReplicationServerArg = 564 BooleanArgument.builder("noReplicationServer1") 565 .description(INFO_DESCRIPTION_ENABLE_REPLICATION_NO_REPLICATION_SERVER1.get()) 566 .buildArgument(); 567 server.onlyReplicationServerArg = 568 BooleanArgument.builder("onlyReplicationServer1") 569 .description(INFO_DESCRIPTION_ENABLE_REPLICATION_ONLY_REPLICATION_SERVER1.get()) 570 .buildArgument(); 571 } 572 573 private void createServerArgs2() throws ArgumentException 574 { 575 ServerArgs server = server2; 576 server.hostNameArg = 577 StringArgument.builder("host2") 578 .shortIdentifier('O') 579 .description(INFO_DESCRIPTION_ENABLE_REPLICATION_HOST2.get()) 580 .defaultValue(secureArgsList.getDefaultHostName()) 581 .valuePlaceholder(INFO_HOST_PLACEHOLDER.get()) 582 .buildArgument(); 583 server.portArg = 584 IntegerArgument.builder("port2") 585 .description(INFO_DESCRIPTION_ENABLE_REPLICATION_SERVER_PORT2.get()) 586 .range(1, 65336) 587 .defaultValue(defaultAdminPort) 588 .valuePlaceholder(INFO_PORT_PLACEHOLDER.get()) 589 .buildArgument(); 590 server.bindDnArg = 591 StringArgument.builder("bindDN2") 592 .description(INFO_DESCRIPTION_ENABLE_REPLICATION_BINDDN2.get()) 593 .defaultValue("cn=Directory Manager") 594 .valuePlaceholder(INFO_BINDDN_PLACEHOLDER.get()) 595 .buildArgument(); 596 server.bindPasswordArg = 597 StringArgument.builder("bindPassword2") 598 .description(INFO_DESCRIPTION_ENABLE_REPLICATION_BINDPASSWORD2.get()) 599 .valuePlaceholder(INFO_BINDPWD_PLACEHOLDER.get()) 600 .buildArgument(); 601 server.bindPasswordFileArg = 602 FileBasedArgument.builder("bindPasswordFile2") 603 .shortIdentifier('F') 604 .description(INFO_DESCRIPTION_ENABLE_REPLICATION_BINDPASSWORDFILE2.get()) 605 .valuePlaceholder(INFO_BINDPWD_FILE_PLACEHOLDER.get()) 606 .buildArgument(); 607 server.replicationPortArg = 608 IntegerArgument.builder("replicationPort2") 609 .shortIdentifier('R') 610 .description(INFO_DESCRIPTION_ENABLE_REPLICATION_PORT2.get()) 611 .range(1, 65336) 612 .defaultValue(8989) 613 .valuePlaceholder(INFO_PORT_PLACEHOLDER.get()) 614 .buildArgument(); 615 server.secureReplicationArg = 616 BooleanArgument.builder("secureReplication2") 617 .description(INFO_DESCRIPTION_ENABLE_SECURE_REPLICATION2.get()) 618 .buildArgument(); 619 server.noReplicationServerArg = 620 BooleanArgument.builder("noReplicationServer2") 621 .description(INFO_DESCRIPTION_ENABLE_REPLICATION_NO_REPLICATION_SERVER2.get()) 622 .buildArgument(); 623 server.onlyReplicationServerArg = 624 BooleanArgument.builder("onlyReplicationServer2") 625 .description(INFO_DESCRIPTION_ENABLE_REPLICATION_ONLY_REPLICATION_SERVER2.get()) 626 .buildArgument(); 627 } 628 629 /** 630 * Creates the disable replication subcommand and all the specific options 631 * for the subcommand. Note: this method assumes that 632 * initializeGlobalArguments has already been called and that hostNameArg and 633 * portArg have been created. 634 */ 635 private void createDisableReplicationSubCommand() 636 throws ArgumentException 637 { 638 disableReplicationSubCmd = new SubCommand(this, 639 DISABLE_REPLICATION_SUBCMD_NAME, 640 INFO_DESCRIPTION_SUBCMD_DISABLE_REPLICATION.get()); 641 secureArgsList.setBindDnArgDescription(INFO_DESCRIPTION_DISABLE_REPLICATION_BINDDN.get()); 642 disableReplicationServerArg = 643 BooleanArgument.builder("disableReplicationServer") 644 .shortIdentifier('a') 645 .description(INFO_DESCRIPTION_DISABLE_REPLICATION_SERVER.get()) 646 .buildArgument(); 647 disableAllArg = 648 BooleanArgument.builder("disableAll") 649 .description(INFO_DESCRIPTION_DISABLE_ALL.get()) 650 .buildArgument(); 651 652 Argument[] argsToAdd = { secureArgsList.getHostNameArg(), 653 secureArgsList.getPortArg(), secureArgsList.getBindDnArg(), 654 disableReplicationServerArg, disableAllArg}; 655 for (Argument arg : argsToAdd) 656 { 657 disableReplicationSubCmd.addArgument(arg); 658 } 659 } 660 661 /** 662 * Creates the initialize replication subcommand and all the specific options 663 * for the subcommand. 664 */ 665 private void createInitializeReplicationSubCommand() throws ArgumentException 666 { 667 initializeReplicationSubCmd = new SubCommand(this, INITIALIZE_REPLICATION_SUBCMD_NAME, 668 INFO_DESCRIPTION_SUBCMD_INITIALIZE_REPLICATION.get(INITIALIZE_ALL_REPLICATION_SUBCMD_NAME)); 669 addArgumentsToSubCommand(initializeReplicationSubCmd, 670 hostNameSourceArg, portSourceArg, hostNameDestinationArg, portDestinationArg); 671 } 672 673 private void createRelatedServersOptions() throws ArgumentException 674 { 675 final String defaultHostName = secureArgsList.getDefaultHostName(); 676 hostNameSourceArg = 677 StringArgument.builder("hostSource") 678 .shortIdentifier(OPTION_SHORT_HOST) 679 .description(INFO_DESCRIPTION_INITIALIZE_REPLICATION_HOST_SOURCE.get()) 680 .defaultValue(defaultHostName) 681 .valuePlaceholder(INFO_HOST_PLACEHOLDER.get()) 682 .buildArgument(); 683 portSourceArg = 684 IntegerArgument.builder("portSource") 685 .shortIdentifier(OPTION_SHORT_PORT) 686 .description(INFO_DESCRIPTION_INITIALIZE_REPLICATION_SERVER_PORT_SOURCE.get()) 687 .range(1, 65336) 688 .defaultValue(defaultAdminPort) 689 .valuePlaceholder(INFO_PORT_PLACEHOLDER.get()) 690 .buildArgument(); 691 hostNameDestinationArg = 692 StringArgument.builder("hostDestination") 693 .shortIdentifier('O') 694 .description(INFO_DESCRIPTION_INITIALIZE_REPLICATION_HOST_DESTINATION.get()) 695 .defaultValue(defaultHostName) 696 .valuePlaceholder(INFO_HOST_PLACEHOLDER.get()) 697 .buildArgument(); 698 portDestinationArg = 699 IntegerArgument.builder("portDestination") 700 .description(INFO_DESCRIPTION_INITIALIZE_REPLICATION_SERVER_PORT_DESTINATION.get()) 701 .range(1, 65336) 702 .defaultValue(defaultAdminPort) 703 .valuePlaceholder(INFO_PORT_PLACEHOLDER.get()) 704 .buildArgument(); 705 } 706 707 /** 708 * Creates the initialize all replication subcommand and all the specific 709 * options for the subcommand. Note: this method assumes that 710 * initializeGlobalArguments has already been called and that hostNameArg and 711 * portArg have been created. 712 */ 713 private void createInitializeAllReplicationSubCommand() 714 throws ArgumentException 715 { 716 initializeAllReplicationSubCmd = new SubCommand(this, 717 INITIALIZE_ALL_REPLICATION_SUBCMD_NAME, 718 INFO_DESCRIPTION_SUBCMD_INITIALIZE_ALL_REPLICATION.get( 719 INITIALIZE_REPLICATION_SUBCMD_NAME)); 720 Argument[] argsToAdd = { secureArgsList.getHostNameArg(), 721 secureArgsList.getPortArg() }; 722 for (Argument arg : argsToAdd) 723 { 724 initializeAllReplicationSubCmd.addArgument(arg); 725 } 726 } 727 728 /** 729 * Creates the subcommand that the user must launch before doing an external 730 * initialization of the topology ( and all the specific 731 * options for the subcommand. Note: this method assumes that 732 * initializeGlobalArguments has already been called and that hostNameArg and 733 * portArg have been created. 734 */ 735 private void createPreExternalInitializationSubCommand() 736 throws ArgumentException 737 { 738 preExternalInitializationSubCmd = new SubCommand(this, 739 PRE_EXTERNAL_INITIALIZATION_SUBCMD_NAME, 740 INFO_DESCRIPTION_SUBCMD_PRE_EXTERNAL_INITIALIZATION.get( 741 POST_EXTERNAL_INITIALIZATION_SUBCMD_NAME)); 742 BooleanArgument externalInitializationLocalOnlyArg = 743 BooleanArgument.builder("local-only") 744 .shortIdentifier('l') 745 .description(LocalizableMessage.EMPTY) 746 .hidden() 747 .buildArgument(); 748 749 Argument[] argsToAdd = { secureArgsList.getHostNameArg(), 750 secureArgsList.getPortArg(), 751 externalInitializationLocalOnlyArg}; 752 753 for (Argument arg : argsToAdd) 754 { 755 preExternalInitializationSubCmd.addArgument(arg); 756 } 757 } 758 759 /** 760 * Creates the subcommand that the user must launch after doing an external 761 * initialization of the topology ( and all the specific 762 * options for the subcommand. Note: this method assumes that 763 * initializeGlobalArguments has already been called and that hostNameArg and 764 * portArg have been created. 765 */ 766 private void createPostExternalInitializationSubCommand() 767 throws ArgumentException 768 { 769 postExternalInitializationSubCmd = new SubCommand(this, 770 POST_EXTERNAL_INITIALIZATION_SUBCMD_NAME, 771 INFO_DESCRIPTION_SUBCMD_POST_EXTERNAL_INITIALIZATION.get( 772 PRE_EXTERNAL_INITIALIZATION_SUBCMD_NAME)); 773 Argument[] argsToAdd = { secureArgsList.getHostNameArg(), 774 secureArgsList.getPortArg() }; 775 for (Argument arg : argsToAdd) 776 { 777 postExternalInitializationSubCmd.addArgument(arg); 778 } 779 } 780 781 private void createResetChangeNumberSubCommand() throws ArgumentException 782 { 783 resetChangelogNumber = new SubCommand(this, RESET_CHANGE_NUMBER_SUBCMD_NAME, 784 INFO_DESCRIPTION_RESET_CHANGE_NUMBER.get()); 785 resetChangeNumber = newChangeNumberArgument(); 786 addArgumentsToSubCommand(resetChangelogNumber, 787 hostNameSourceArg, portSourceArg, hostNameDestinationArg, portDestinationArg, resetChangeNumber); 788 } 789 790 private IntegerArgument newChangeNumberArgument() throws ArgumentException 791 { 792 return IntegerArgument.builder("change-number") 793 .description(INFO_DESCRIPTION_START_CHANGE_NUMBER.get()) 794 .valuePlaceholder(INFO_CHANGE_NUMBER_PLACEHOLDER.get()) 795 .buildArgument(); 796 } 797 798 /** 799 * Creates the status replication subcommand and all the specific options 800 * for the subcommand. Note: this method assumes that 801 * initializeGlobalArguments has already been called and that hostNameArg and 802 * portArg have been created. 803 */ 804 private void createStatusReplicationSubCommand() throws ArgumentException 805 { 806 statusReplicationSubCmd = new SubCommand(this, 807 STATUS_REPLICATION_SUBCMD_NAME, 808 INFO_DESCRIPTION_SUBCMD_STATUS_REPLICATION.get()); 809 scriptFriendlyArg = 810 BooleanArgument.builder("script-friendly") 811 .shortIdentifier('s') 812 .description(INFO_DESCRIPTION_SCRIPT_FRIENDLY.get()) 813 .buildArgument(); 814 addArgumentsToSubCommand( 815 statusReplicationSubCmd, secureArgsList.getHostNameArg(), secureArgsList.getPortArg(), scriptFriendlyArg); 816 } 817 818 /** 819 * Creates the purge historical subcommand and all the specific options 820 * for the subcommand. Note: this method assumes that 821 * initializeGlobalArguments has already been called and that hostNameArg and 822 * portArg have been created. 823 */ 824 private void createPurgeHistoricalSubCommand() throws ArgumentException 825 { 826 maximumDurationArg = 827 IntegerArgument.builder("maximumDuration") 828 .description(INFO_DESCRIPTION_PURGE_HISTORICAL_MAXIMUM_DURATION.get()) 829 .required() 830 .lowerBound(0) 831 .defaultValue(PurgeConflictsHistoricalTask.DEFAULT_MAX_DURATION) 832 .valuePlaceholder(INFO_MAXIMUM_DURATION_PLACEHOLDER.get()) 833 .buildArgument(); 834 835 purgeHistoricalSubCmd = new SubCommand( 836 this, 837 PURGE_HISTORICAL_SUBCMD_NAME, 838 INFO_DESCRIPTION_SUBCMD_PURGE_HISTORICAL.get()); 839 840 addArgumentsToSubCommand(purgeHistoricalSubCmd, 841 secureArgsList.getHostNameArg(), secureArgsList.getPortArg(), maximumDurationArg); 842 addArgumentsToSubCommand(purgeHistoricalSubCmd, taskArgs.getArguments()); 843 } 844 845 private void addArgumentsToSubCommand(final SubCommand subCommand, final Argument... args) throws ArgumentException 846 { 847 for (final Argument arg : args) 848 { 849 subCommand.addArgument(arg); 850 } 851 } 852 853 /** 854 * Tells whether the user specified to have an interactive operation or not. 855 * This method must be called after calling parseArguments. 856 * @return {@code true} if the user specified to have an interactive 857 * operation and {@code false} otherwise. 858 */ 859 public boolean isInteractive() 860 { 861 return !noPromptArg.isPresent(); 862 } 863 864 /** 865 * Tells whether the user specified to have a quite operation or not. 866 * This method must be called after calling parseArguments. 867 * @return {@code true} if the user specified to have a quite operation 868 * and {@code false} otherwise. 869 */ 870 public boolean isQuiet() 871 { 872 return quietArg.isPresent(); 873 } 874 875 /** 876 * Tells whether the user specified to have a script-friendly output or not. 877 * This method must be called after calling parseArguments. 878 * @return {@code true} if the user specified to have a script-friendly 879 * output and {@code false} otherwise. 880 */ 881 public boolean isScriptFriendly() 882 { 883 return scriptFriendlyArg.isPresent(); 884 } 885 886 /** 887 * Get the global administrator password which has to be used for the command 888 * to connect to the server(s) without prompting the user. If no password was 889 * specified, return null. 890 * 891 * @return the global administrator password which has to be used for the 892 * command to connect to the server(s) without prompting the user. If no 893 * password was specified, return null. 894 */ 895 public String getBindPasswordAdmin() 896 { 897 return getBindPassword(secureArgsList.getBindPasswordArg(), secureArgsList.getBindPasswordFileArg()); 898 } 899 900 /** 901 * Returns the Administrator UID explicitly provided in the command-line. 902 * @return the Administrator UID explicitly provided in the command-line. 903 */ 904 @Override 905 public String getAdministratorUID() 906 { 907 return getValue(getAdminUidArg()); 908 } 909 910 /** 911 * Returns the default Administrator UID value. 912 * @return the default Administrator UID value. 913 */ 914 public String getAdministratorUIDOrDefault() 915 { 916 return getValueOrDefault(getAdminUidArg()); 917 } 918 919 /** 920 * Returns the Administrator UID argument. 921 * @return the Administrator UID argument. 922 */ 923 StringArgument getAdminUidArg() 924 { 925 return secureArgsList.getAdminUidArg(); 926 } 927 928 /** 929 * Returns the first server replication port explicitly provided in the enable 930 * replication subcommand. 931 * @return the first server replication port explicitly provided in the enable 932 * replication subcommand. Returns -1 if no port was explicitly provided. 933 */ 934 public int getReplicationPort1() 935 { 936 return getValue(server1.replicationPortArg); 937 } 938 939 /** 940 * Returns the second server replication port explicitly provided in the 941 * enable replication subcommand. 942 * @return the second server replication port explicitly provided in the 943 * enable replication subcommand. Returns -1 if no port was explicitly 944 * provided. 945 */ 946 public int getReplicationPort2() 947 { 948 return getValue(server2.replicationPortArg); 949 } 950 951 /** 952 * Returns whether the user asked to skip the replication port checks (if the 953 * ports are free) or not. 954 * @return {@code true} the user asked to skip the replication port 955 * checks (if the ports are free) and {@code false} otherwise. 956 */ 957 boolean skipReplicationPortCheck() 958 { 959 return skipPortCheckArg.isPresent(); 960 } 961 962 /** 963 * Returns whether the user asked to not replicate the schema between servers. 964 * @return {@code true} if the user asked to not replicate schema and 965 * {@code false} otherwise. 966 */ 967 boolean noSchemaReplication() 968 { 969 return noSchemaReplicationArg.isPresent(); 970 } 971 972 /** 973 * Returns whether the user asked to use the second server to initialize the 974 * schema of the first server. 975 * @return {@code true} if the user asked to use the second server to 976 * initialize the schema of the first server and {@code false} otherwise. 977 */ 978 boolean useSecondServerAsSchemaSource() 979 { 980 return useSecondServerAsSchemaSourceArg.isPresent(); 981 } 982 983 /** 984 * Returns the host name explicitly provided in the disable replication 985 * subcommand. 986 * @return the host name explicitly provided in the disable replication 987 * subcommand. 988 */ 989 public String getHostNameToDisable() 990 { 991 return getValue(secureArgsList.getHostNameArg()); 992 } 993 994 /** 995 * Returns the host name default value in the disable replication 996 * subcommand. 997 * @return the host name default value in the disable replication 998 * subcommand. 999 */ 1000 public String getHostNameToDisableOrDefault() 1001 { 1002 return getValueOrDefault(secureArgsList.getHostNameArg()); 1003 } 1004 1005 /** 1006 * Returns the server bind dn explicitly provided in the disable replication 1007 * subcommand. 1008 * @return the server bind dn explicitly provided in the disable replication 1009 * subcommand. 1010 */ 1011 public String getBindDNToDisable() 1012 { 1013 return getValue(secureArgsList.getBindDnArg()); 1014 } 1015 1016 /** 1017 * Returns the host name default value in the status replication subcommand. 1018 * @return the host name default value in the status replication subcommand. 1019 */ 1020 public String getHostNameToStatusOrDefault() 1021 { 1022 return getValueOrDefault(secureArgsList.getHostNameArg()); 1023 } 1024 1025 /** 1026 * Returns the host name default value in the initialize all replication 1027 * subcommand. 1028 * @return the host name default value in the initialize all replication 1029 * subcommand. 1030 */ 1031 public String getHostNameToInitializeAllOrDefault() 1032 { 1033 return getValueOrDefault(secureArgsList.getHostNameArg()); 1034 } 1035 1036 /** 1037 * Returns the source host name explicitly provided in the initialize 1038 * replication subcommand. 1039 * @return the source host name explicitly provided in the initialize 1040 * replication subcommand. 1041 */ 1042 public String getHostNameSource() 1043 { 1044 return getValue(hostNameSourceArg); 1045 } 1046 1047 /** 1048 * Returns the first host name default value in the initialize replication 1049 * subcommand. 1050 * @return the first host name default value in the initialize replication 1051 * subcommand. 1052 */ 1053 public String getHostNameSourceOrDefault() 1054 { 1055 return getValueOrDefault(hostNameSourceArg); 1056 } 1057 1058 /** 1059 * Returns the destination host name explicitly provided in the initialize 1060 * replication subcommand. 1061 * @return the destination host name explicitly provided in the initialize 1062 * replication subcommand. 1063 */ 1064 public String getHostNameDestination() 1065 { 1066 return getValue(hostNameDestinationArg); 1067 } 1068 1069 /** 1070 * Returns the destination host name default value in the initialize 1071 * replication subcommand. 1072 * @return the destination host name default value in the initialize 1073 * replication subcommand. 1074 */ 1075 public String getHostNameDestinationOrDefault() 1076 { 1077 return getValueOrDefault(hostNameDestinationArg); 1078 } 1079 1080 /** 1081 * Returns the source server port explicitly provided in the initialize 1082 * replication subcommand. 1083 * @return the source server port explicitly provided in the initialize 1084 * replication subcommand. Returns -1 if no port was explicitly provided. 1085 */ 1086 public int getPortSource() 1087 { 1088 return getValue(portSourceArg); 1089 } 1090 1091 /** 1092 * Returns the source server port default value in the initialize replication 1093 * subcommand. 1094 * @return the source server port default value in the initialize replication 1095 * subcommand. 1096 */ 1097 public int getPortSourceOrDefault() 1098 { 1099 return getValueOrDefault(portSourceArg); 1100 } 1101 1102 /** 1103 * Returns the destination server port explicitly provided in the initialize 1104 * replication subcommand. 1105 * @return the destination server port explicitly provided in the initialize 1106 * replication subcommand. Returns -1 if no port was explicitly provided. 1107 */ 1108 public int getPortDestination() 1109 { 1110 return getValue(portDestinationArg); 1111 } 1112 1113 /** 1114 * Returns the destination server port default value in the initialize 1115 * replication subcommand. 1116 * @return the destination server port default value in the initialize 1117 * replication subcommand. 1118 */ 1119 public int getPortDestinationOrDefault() 1120 { 1121 return getValueOrDefault(portDestinationArg); 1122 } 1123 1124 /** 1125 * Returns the server port explicitly provided in the disable replication 1126 * subcommand. 1127 * @return the server port explicitly provided in the disable replication 1128 * subcommand. Returns -1 if no port was explicitly provided. 1129 */ 1130 public int getPortToDisable() 1131 { 1132 return getValue(secureArgsList.getPortArg()); 1133 } 1134 1135 /** 1136 * Returns the server port default value in the disable replication 1137 * subcommand. 1138 * @return the server port default value in the disable replication 1139 * subcommand. 1140 */ 1141 public int getPortToDisableOrDefault() 1142 { 1143 return getValueOrDefault(secureArgsList.getPortArg()); 1144 } 1145 1146 /** 1147 * Returns the server port default value in the initialize all replication 1148 * subcommand. 1149 * @return the server port default value in the initialize all replication 1150 * subcommand. 1151 */ 1152 public int getPortToInitializeAllOrDefault() 1153 { 1154 return getValueOrDefault(secureArgsList.getPortArg()); 1155 } 1156 1157 /** 1158 * Returns the server port default value in the status replication subcommand. 1159 * @return the server port default value in the status replication subcommand. 1160 */ 1161 public int getPortToStatusOrDefault() 1162 { 1163 return getValueOrDefault(secureArgsList.getPortArg()); 1164 } 1165 1166 /** 1167 * Returns the list of base DNs provided by the user. 1168 * @return the list of base DNs provided by the user. 1169 */ 1170 public List<String> getBaseDNs() 1171 { 1172 return baseDNsArg.getValues(); 1173 } 1174 1175 /** 1176 * Returns the config file value provided in the hidden argument of the 1177 * command-line. 1178 * @return the config file value provided in the hidden argument of the 1179 * command-line. 1180 */ 1181 public String getConfigFile() 1182 { 1183 return getValue(configFileArg); 1184 } 1185 1186 /** 1187 * Returns the argument's value if present or else return the argument's default value. 1188 * 1189 * @param arg the argument 1190 * @return the argument's value if present, the argument's default value if not present 1191 */ 1192 static String getValueOrDefault(StringArgument arg) 1193 { 1194 String v = getValue(arg); 1195 String defaultValue = getDefaultValue(arg); 1196 return v != null ? v : defaultValue; 1197 } 1198 1199 /** 1200 * Returns the argument's value if present or else return the argument's default value. 1201 * 1202 * @param arg the argument 1203 * @return the argument's value if present, the argument's default value if not present 1204 */ 1205 static int getValueOrDefault(IntegerArgument arg) 1206 { 1207 int v = getValue(arg); 1208 int defaultValue = getDefaultValue(arg); 1209 return v != -1 ? v : defaultValue; 1210 } 1211 1212 /** 1213 * Returns the value of the provided argument only if the user provided it 1214 * explicitly. 1215 * @param arg the StringArgument to be handled. 1216 * @return the value of the provided argument only if the user provided it 1217 * explicitly. 1218 */ 1219 static String getValue(StringArgument arg) 1220 { 1221 return arg.isPresent() ? arg.getValue() : null; 1222 } 1223 1224 /** 1225 * Returns the default value of the provided argument. 1226 * @param arg the StringArgument to be handled. 1227 * @return the default value of the provided argument. 1228 */ 1229 static String getDefaultValue(StringArgument arg) 1230 { 1231 return arg.getDefaultValue(); 1232 } 1233 1234 /** 1235 * Returns the value of the provided argument only if the user provided it 1236 * explicitly. 1237 * @param arg the StringArgument to be handled. 1238 * @return the value of the provided argument only if the user provided it 1239 * explicitly. 1240 */ 1241 static int getValue(IntegerArgument arg) 1242 { 1243 if (arg.isPresent()) 1244 { 1245 try 1246 { 1247 return arg.getIntValue(); 1248 } 1249 catch (ArgumentException ae) 1250 { 1251 // This is a bug 1252 throw new IllegalStateException( 1253 "There was an argument exception calling "+ 1254 "ReplicationCliParser.getValue(). This appears to be a bug "+ 1255 "because this method should be called after calling "+ 1256 "parseArguments which should result in an error.", ae); 1257 } 1258 } 1259 return -1; 1260 } 1261 1262 /** 1263 * Returns the default value of the provided argument. 1264 * @param arg the StringArgument to be handled. 1265 * @return the default value of the provided argument. 1266 */ 1267 static int getDefaultValue(IntegerArgument arg) 1268 { 1269 String v = arg.getDefaultValue(); 1270 return v != null ? Integer.parseInt(v) : -1; 1271 } 1272 1273 /** 1274 * Checks the subcommand options and updates the provided LocalizableMessageBuilder 1275 * with the errors that were encountered with the subcommand options. 1276 * 1277 * This method assumes that the method parseArguments for the parser has 1278 * already been called. 1279 * @param buf the LocalizableMessageBuilder object where we add the error messages 1280 * describing the errors encountered. 1281 */ 1282 private void validateSubcommandOptions(LocalizableMessageBuilder buf) 1283 { 1284 if (isEnableReplicationSubcommand()) 1285 { 1286 validateEnableReplicationOptions(buf); 1287 } 1288 else if (isDisableReplicationSubcommand()) 1289 { 1290 validateDisableReplicationOptions(buf); 1291 } 1292 else if (isStatusReplicationSubcommand()) 1293 { 1294 validateStatusReplicationOptions(buf); 1295 } 1296 else if (isInitializeReplicationSubcommand()) 1297 { 1298 validateSourceAndDestinationServersOptions(buf); 1299 } 1300 else if (isPurgeHistoricalSubcommand()) 1301 { 1302 validatePurgeHistoricalOptions(buf); 1303 } 1304 else if (isResetChangeNumber()) 1305 { 1306 validateSourceAndDestinationServersOptions(buf); 1307 } 1308 } 1309 1310 /** 1311 * Checks the purge historical subcommand options and updates the 1312 * provided LocalizableMessageBuilder with the errors that were encountered with the 1313 * subcommand options. 1314 * 1315 * This method assumes that the method parseArguments for the parser has 1316 * already been called. 1317 * @param buf the LocalizableMessageBuilder object where we add the error messages 1318 * describing the errors encountered. 1319 */ 1320 private void validatePurgeHistoricalOptions(LocalizableMessageBuilder buf) 1321 { 1322 try 1323 { 1324 if (!isInteractive() && !connectionArgumentsPresent()) 1325 { 1326 taskArgs.validateArgsIfOffline(); 1327 } 1328 else 1329 { 1330 taskArgs.validateArgs(); 1331 } 1332 } 1333 catch (ClientException | ArgumentException e) 1334 { 1335 addMessage(buf, e.getMessageObject()); 1336 } 1337 } 1338 1339 /** 1340 * Returns whether the user provided subcommand is the enable replication 1341 * or not. 1342 * @return {@code true} if the user provided subcommand is the 1343 * enable replication and {@code false} otherwise. 1344 */ 1345 public boolean isEnableReplicationSubcommand() 1346 { 1347 return isSubcommand(ENABLE_REPLICATION_SUBCMD_NAME); 1348 } 1349 1350 /** 1351 * Returns whether the user provided subcommand is the disable replication 1352 * or not. 1353 * @return {@code true} if the user provided subcommand is the 1354 * disable replication and {@code false} otherwise. 1355 */ 1356 public boolean isDisableReplicationSubcommand() 1357 { 1358 return isSubcommand(DISABLE_REPLICATION_SUBCMD_NAME); 1359 } 1360 1361 /** 1362 * Returns whether the user specified the reset changelog numbering subcommand. 1363 * @return {@code true} if the user wanted to reset change number 1364 */ 1365 public boolean isResetChangeNumber() 1366 { 1367 return isSubcommand(RESET_CHANGE_NUMBER_SUBCMD_NAME); 1368 } 1369 1370 /** 1371 * Returns whether the user provided subcommand is the status replication 1372 * or not. 1373 * @return {@code true} if the user provided subcommand is the 1374 * status replication and {@code false} otherwise. 1375 */ 1376 public boolean isStatusReplicationSubcommand() 1377 { 1378 return isSubcommand(STATUS_REPLICATION_SUBCMD_NAME); 1379 } 1380 1381 /** 1382 * Returns whether the user provided subcommand is the purge historical 1383 * or not. 1384 * @return {@code true} if the user provided subcommand is the 1385 * purge historical and {@code false} otherwise. 1386 */ 1387 public boolean isPurgeHistoricalSubcommand() 1388 { 1389 return isSubcommand(PURGE_HISTORICAL_SUBCMD_NAME); 1390 } 1391 1392 /** 1393 * Returns whether the user provided subcommand is the initialize all 1394 * replication or not. 1395 * @return {@code true} if the user provided subcommand is the 1396 * initialize all replication and {@code false} otherwise. 1397 */ 1398 public boolean isInitializeAllReplicationSubcommand() 1399 { 1400 return isSubcommand(INITIALIZE_ALL_REPLICATION_SUBCMD_NAME); 1401 } 1402 1403 /** 1404 * Returns whether the user provided subcommand is the pre external 1405 * initialization or not. 1406 * @return {@code true} if the user provided subcommand is the 1407 * pre external initialization and {@code false} otherwise. 1408 */ 1409 public boolean isPreExternalInitializationSubcommand() 1410 { 1411 return isSubcommand(PRE_EXTERNAL_INITIALIZATION_SUBCMD_NAME); 1412 } 1413 1414 /** 1415 * Returns whether the user provided subcommand is the post external 1416 * initialization or not. 1417 * @return {@code true} if the user provided subcommand is the 1418 * post external initialization and {@code false} otherwise. 1419 */ 1420 public boolean isPostExternalInitializationSubcommand() 1421 { 1422 return isSubcommand(POST_EXTERNAL_INITIALIZATION_SUBCMD_NAME); 1423 } 1424 1425 /** 1426 * Returns whether the user provided subcommand is the initialize replication 1427 * or not. 1428 * @return {@code true} if the user provided subcommand is the 1429 * initialize replication and {@code false} otherwise. 1430 */ 1431 public boolean isInitializeReplicationSubcommand() 1432 { 1433 return isSubcommand(INITIALIZE_REPLICATION_SUBCMD_NAME); 1434 } 1435 1436 /** 1437 * Returns whether the command-line subcommand has the name provided 1438 * or not. 1439 * @param name the name of the subcommand. 1440 * @return {@code true} if command-line subcommand has the name provided 1441 * and {@code false} otherwise. 1442 */ 1443 private boolean isSubcommand(String name) 1444 { 1445 SubCommand subCommand = getSubCommand(); 1446 return subCommand != null && subCommand.getName().equalsIgnoreCase(name); 1447 } 1448 1449 /** 1450 * Checks the enable replication subcommand options and updates the provided 1451 * LocalizableMessageBuilder with the errors that were encountered with the subcommand 1452 * options. 1453 * 1454 * This method assumes that the method parseArguments for the parser has 1455 * already been called. 1456 * @param buf the LocalizableMessageBuilder object where we add the error messages 1457 * describing the errors encountered. 1458 */ 1459 private void validateEnableReplicationOptions(LocalizableMessageBuilder buf) 1460 { 1461 appendErrorMessageIfArgumentsConflict(buf, server1.bindPasswordArg, server1.bindPasswordFileArg ); 1462 appendErrorMessageIfArgumentsConflict(buf, server2.bindPasswordArg, server2.bindPasswordFileArg ); 1463 appendErrorMessageIfArgumentsConflict(buf, server1.replicationPortArg, server1.noReplicationServerArg ); 1464 appendErrorMessageIfArgumentsConflict(buf, server1.noReplicationServerArg, server1.onlyReplicationServerArg ); 1465 appendErrorMessageIfArgumentsConflict(buf, server2.replicationPortArg, server2.noReplicationServerArg ); 1466 appendErrorMessageIfArgumentsConflict(buf, server2.noReplicationServerArg, server2.onlyReplicationServerArg ); 1467 appendErrorMessageIfArgumentsConflict(buf,noSchemaReplicationArg, useSecondServerAsSchemaSourceArg); 1468 1469 if (server1.hostNameArg.getValue().equalsIgnoreCase(server2.hostNameArg.getValue()) 1470 && !isInteractive() 1471 && server1.portArg.getValue().equals(server2.portArg.getValue())) 1472 { 1473 LocalizableMessage message = ERR_REPLICATION_ENABLE_SAME_SERVER_PORT.get( 1474 server1.hostNameArg.getValue(), server1.portArg.getValue()); 1475 addMessage(buf, message); 1476 } 1477 } 1478 1479 /** 1480 * Checks the disable replication subcommand options and updates the provided 1481 * LocalizableMessageBuilder with the errors that were encountered with the subcommand 1482 * options. 1483 * 1484 * This method assumes that the method parseArguments for the parser has 1485 * already been called. 1486 * @param buf the LocalizableMessageBuilder object where we add the error messages 1487 * describing the errors encountered. 1488 */ 1489 private void validateDisableReplicationOptions(LocalizableMessageBuilder buf) 1490 { 1491 appendErrorMessageIfArgumentsConflict(buf, getAdminUidArg(), secureArgsList.getBindDnArg()); 1492 appendErrorMessageIfArgumentsConflict(buf, disableAllArg, disableReplicationServerArg); 1493 appendErrorMessageIfArgumentsConflict(buf, disableAllArg, baseDNsArg); 1494 } 1495 1496 /** 1497 * Checks the status replication subcommand options and updates the provided 1498 * LocalizableMessageBuilder with the errors that were encountered with the subcommand 1499 * options. 1500 * 1501 * This method assumes that the method parseArguments for the parser has 1502 * already been called. 1503 * @param buf the LocalizableMessageBuilder object where we add the error messages 1504 * describing the errors encountered. 1505 */ 1506 private void validateStatusReplicationOptions(LocalizableMessageBuilder buf) 1507 { 1508 if (quietArg.isPresent()) 1509 { 1510 LocalizableMessage message = ERR_REPLICATION_STATUS_QUIET.get( 1511 STATUS_REPLICATION_SUBCMD_NAME, "--"+quietArg.getLongIdentifier()); 1512 addMessage(buf, message); 1513 } 1514 } 1515 1516 /** 1517 * Checks the initialize replication subcommand options and updates the 1518 * provided LocalizableMessageBuilder with the errors that were encountered with the 1519 * subcommand options. 1520 * 1521 * This method assumes that the method parseArguments for the parser has 1522 * already been called. 1523 * @param buf the LocalizableMessageBuilder object where we add the error messages 1524 * describing the errors encountered. 1525 */ 1526 private void validateSourceAndDestinationServersOptions(LocalizableMessageBuilder buf) 1527 { 1528 if (hostNameSourceArg.getValue().equalsIgnoreCase(hostNameDestinationArg.getValue()) 1529 && !isInteractive() 1530 && portSourceArg.getValue().equals(portDestinationArg.getValue())) 1531 { 1532 LocalizableMessage message = ERR_SOURCE_DESTINATION_INITIALIZE_SAME_SERVER_PORT.get( 1533 hostNameSourceArg.getValue(), portSourceArg.getValue()); 1534 addMessage(buf, message); 1535 } 1536 } 1537 1538 /** 1539 * Adds a message to the provided LocalizableMessageBuilder. 1540 * @param buf the LocalizableMessageBuilder. 1541 * @param message the message to be added. 1542 */ 1543 private void addMessage(LocalizableMessageBuilder buf, LocalizableMessage message) 1544 { 1545 if (buf.length() > 0) 1546 { 1547 buf.append(LINE_SEPARATOR); 1548 } 1549 buf.append(message); 1550 } 1551 1552 /** 1553 * Returns the SecureConnectionCliArgs object containing the arguments 1554 * of this parser. 1555 * @return the SecureConnectionCliArgs object containing the arguments 1556 * of this parser. 1557 */ 1558 public SecureConnectionCliArgs getSecureArgsList() 1559 { 1560 return secureArgsList; 1561 } 1562 1563 /** 1564 * Returns the TaskScheduleArgs object containing the arguments 1565 * of this parser. 1566 * @return the TaskScheduleArgs object containing the arguments 1567 * of this parser. 1568 */ 1569 public TaskScheduleArgs getTaskArgsList() 1570 { 1571 return taskArgs; 1572 } 1573 1574 /** 1575 * Returns whether the user specified connection arguments or not. 1576 * @return {@code true} if the user specified connection arguments and 1577 * {@code false} otherwise. 1578 */ 1579 boolean connectionArgumentsPresent() 1580 { 1581 if (isPurgeHistoricalSubcommand()) { 1582 boolean secureArgsPresent = getSecureArgsList() != null && 1583 getSecureArgsList().argumentsPresent(); 1584 // This have to be explicitly specified because their original definition 1585 // has been replaced. 1586 boolean adminArgsPresent = getAdminUidArg().isPresent() || 1587 secureArgsList.getBindPasswordArg().isPresent() || 1588 secureArgsList.getBindPasswordFileArg().isPresent(); 1589 return secureArgsPresent || adminArgsPresent; 1590 } 1591 return true; 1592 } 1593 1594 /** 1595 * Returns the maximum duration explicitly provided in the purge historical 1596 * replication subcommand. 1597 * @return the maximum duration explicitly provided in the purge historical 1598 * replication subcommand. Returns -1 if no port was explicitly provided. 1599 */ 1600 public int getMaximumDuration() 1601 { 1602 return getValue(maximumDurationArg); 1603 } 1604 1605 /** 1606 * Returns the maximum duration default value in the purge historical 1607 * replication subcommand. 1608 * @return the maximum duration default value in the purge historical 1609 * replication subcommand. 1610 */ 1611 public int getMaximumDurationOrDefault() 1612 { 1613 return getValueOrDefault(maximumDurationArg); 1614 } 1615 1616 /** 1617 * Returns the changenumber specified as argument. 1618 * @return the changenumber specified as argument 1619 */ 1620 public int getResetChangeNumber() 1621 { 1622 return getValue(resetChangeNumber); 1623 } 1624 1625 /** 1626 * Sets the start change number value. 1627 * @param changeNumber the new value of the option 1628 */ 1629 public void setResetChangeNumber(String changeNumber) 1630 { 1631 resetChangeNumber.setPresent(true); 1632 resetChangeNumber.addValue(changeNumber); 1633 } 1634}