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