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