mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

jvergara
26.16.2007 59b4905a66a5db370e6d0de5f7cb6dcd314ef443
This commit includes all the code for the first version of the replication tools.  As they require further testing the command line associated with them has not been committed.

Appart from the code particular for the replication tools, some refactoring has been done and some new methods have been added to the Utilities classes. Some typos have also been fixed.
9 files added
17 files modified
7159 ■■■■■ changed files
opends/src/ads/org/opends/admin/ads/ADSContext.java 14 ●●●●● patch | view | raw | blame | history
opends/src/ads/org/opends/admin/ads/ServerDescriptor.java 101 ●●●● patch | view | raw | blame | history
opends/src/ads/org/opends/admin/ads/TopologyCache.java 29 ●●●●● patch | view | raw | blame | history
opends/src/ads/org/opends/admin/ads/TopologyCacheException.java 13 ●●●●● patch | view | raw | blame | history
opends/src/ads/org/opends/admin/ads/util/ConnectionUtils.java 233 ●●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/replicationcli/DisableReplicationUserData.java 117 ●●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/replicationcli/EnableReplicationUserData.java 325 ●●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/replicationcli/InitializeReplicationUserData.java 203 ●●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/replicationcli/ReplicationCliException.java 63 ●●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/replicationcli/ReplicationCliMain.java 3780 ●●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/replicationcli/ReplicationCliParser.java 1462 ●●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/replicationcli/ReplicationCliReturnCode.java 188 ●●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/replicationcli/ReplicationUserData.java 98 ●●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/replicationcli/package-info.java 40 ●●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/statuspanel/StatusCli.java 2 ●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/uninstaller/UninstallCliHelper.java 53 ●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/uninstaller/Uninstaller.java 15 ●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/uninstaller/UninstallerArgumentParser.java 2 ●●● patch | view | raw | blame | history
opends/src/messages/messages/admin_tool.properties 149 ●●●●● patch | view | raw | blame | history
opends/src/quicksetup/org/opends/quicksetup/Application.java 4 ●●●● patch | view | raw | blame | history
opends/src/quicksetup/org/opends/quicksetup/CliApplicationHelper.java 105 ●●●●● patch | view | raw | blame | history
opends/src/quicksetup/org/opends/quicksetup/installer/Installer.java 109 ●●●● patch | view | raw | blame | history
opends/src/quicksetup/org/opends/quicksetup/installer/InstallerHelper.java 15 ●●●● patch | view | raw | blame | history
opends/src/quicksetup/org/opends/quicksetup/util/Utils.java 17 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/client/cli/DsFrameworkCliGlobalAdmin.java 2 ●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/client/cli/SecureConnectionCliParser.java 20 ●●●● patch | view | raw | blame | history
opends/src/ads/org/opends/admin/ads/ADSContext.java
@@ -338,7 +338,7 @@
  }
  private static HashMap<String, AdministratorProperty>
    nameToAdminUSerProperty = null;
    nameToAdminUserProperty = null;
  /**
   * Get a AdministratorProperty associated to a name.
@@ -347,17 +347,17 @@
   * @return The corresponding AdministratorProperty or null if name
   * doesn't match with an existing property.
   */
  public static AdministratorProperty getAdminUSerPropFromName(String name)
  public static AdministratorProperty getAdminUserPropFromName(String name)
  {
    if (nameToAdminUSerProperty == null)
    if (nameToAdminUserProperty == null)
    {
      nameToAdminUSerProperty = new HashMap<String, AdministratorProperty>();
      nameToAdminUserProperty = new HashMap<String, AdministratorProperty>();
      for (AdministratorProperty u : AdministratorProperty.values())
      {
        nameToAdminUSerProperty.put(u.getAttributeName(), u);
        nameToAdminUserProperty.put(u.getAttributeName(), u);
      }
    }
    return nameToAdminUSerProperty.get(name);
    return nameToAdminUserProperty.get(name);
  }
  // The context used to retrieve information
@@ -898,6 +898,8 @@
   * So this should not be called by the Java Web Start before being sure that
   * this jar is loaded.
   * @param backendName the backend name which will handle admin information.
   * <CODE>null</CODE> to use the default backend name for the admin
   * information.
   * @throws ADSContextException if something goes wrong.
   */
  public void createAdminData(String backendName) throws ADSContextException
opends/src/ads/org/opends/admin/ads/ServerDescriptor.java
@@ -27,17 +27,14 @@
package org.opends.admin.ads;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.naming.Context;
import javax.naming.NameNotFoundException;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
@@ -181,6 +178,69 @@
  }
  /**
   * Tells whether this server is a replication server or not.
   * @return <CODE>true</CODE> if the server is a replication server and
   * <CODE>false</CODE> otherwise.
   */
  public boolean isReplicationServer()
  {
    return Boolean.TRUE.equals(
        serverProperties.get(ServerProperty.IS_REPLICATION_SERVER));
  }
  /**
   * Returns the String representation of this replication server based
   * on the information we have ("hostname":"replication port") and
   * <CODE>null</CODE> if this is not a replication server.
   * @return the String representation of this replication server based
   * on the information we have ("hostname":"replication port") and
   * <CODE>null</CODE> if this is not a replication server.
   */
  public String getReplicationServerHostPort()
  {
    String hostPort = null;
    if (isReplicationServer())
    {
      hostPort = getHostName().toLowerCase()+ ":" + getReplicationServerPort();
    }
    return hostPort;
  }
  /**
   * Returns the replication server ID of this server and -1 if this is not a
   * replications server.
   * @return the replication server ID of this server and -1 if this is not a
   * replications server.
   */
  public int getReplicationServerId()
  {
    int port = -1;
    if (isReplicationServer())
    {
      port = (Integer)serverProperties.get(
          ServerProperty.REPLICATION_SERVER_ID);
    }
    return port;
  }
  /**
   * Returns the replication port of this server and -1 if this is not a
   * replications server.
   * @return the replication port of this server and -1 if this is not a
   * replications server.
   */
  public int getReplicationServerPort()
  {
    int port = -1;
    if (isReplicationServer())
    {
      port = (Integer)serverProperties.get(
          ServerProperty.REPLICATION_SERVER_PORT);
    }
    return port;
  }
  /**
   * Sets the ADS properties of the server.
   * @param adsProperties a Map containing the ADS properties of the server.
   */
@@ -405,6 +465,7 @@
        adsProperties.put(adsProps[i][1], String.valueOf(port));
      }
    }
    adsProperties.put(ADSContext.ServerProperty.ID, getHostPort(true));
  }
  /**
@@ -442,17 +503,9 @@
    updateReplicas(desc, ctx);
    updateReplication(desc, ctx);
    String s = (String)ctx.getEnvironment().get(Context.PROVIDER_URL);
    try
    {
      URI ldapURL = new URI(s);
      desc.serverProperties.put(ServerProperty.HOST_NAME, ldapURL.getHost());
    }
    catch (URISyntaxException use)
    {
      // This is really strange.  Seems like a bug somewhere.
      LOG.log(Level.WARNING, "Error parsing ldap URL "+s, use);
    }
    desc.serverProperties.put(ServerProperty.HOST_NAME,
        ConnectionUtils.getHostName(ctx));
    return desc;
  }
@@ -683,7 +736,14 @@
            if (areDnsEqual(replica.getSuffix().getDN(), dn))
            {
              replica.setReplicationId(id);
              replica.setReplicationServers(replicationServers);
              // Keep the values of the replication servers in lower case
              // to make use of Sets as String simpler.
              LinkedHashSet<String> repServers = new LinkedHashSet<String>();
              for (String s: replicationServers)
              {
                repServers.add(s.toLowerCase());
              }
              replica.setReplicationServers(repServers);
            }
          }
        }
@@ -724,8 +784,15 @@
        desc.serverProperties.put(ServerProperty.REPLICATION_SERVER_ID,
            Integer.parseInt(v));
        Set<String> values = getValues(sr, "ds-cfg-replication-server");
        // Keep the values of the replication servers in lower case
        // to make use of Sets as String simpler.
        LinkedHashSet<String> repServers = new LinkedHashSet<String>();
        for (String s: values)
        {
          repServers.add(s.toLowerCase());
        }
        desc.serverProperties.put(ServerProperty.EXTERNAL_REPLICATION_SERVERS,
            values);
            repServers);
      }
    }
    catch (NameNotFoundException nse)
opends/src/ads/org/opends/admin/ads/TopologyCache.java
@@ -36,12 +36,11 @@
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.ldap.LdapName;
import org.opends.admin.ads.ADSContext.ServerProperty;
import org.opends.admin.ads.util.ApplicationTrustManager;
import org.opends.admin.ads.util.ConnectionUtils;
import org.opends.admin.ads.util.ServerLoader;
/**
@@ -72,27 +71,14 @@
   * @param trustManager the ApplicationTrustManager that must be used to trust
   * certificates when we create connections to the registered servers to read
   * their configuration.
   * @throws TopologyCacheException if an error occurred reading the
   * authentication data in the DirContext associated with the provided
   * ADSContext.
   */
  public TopologyCache(ADSContext adsContext,
      ApplicationTrustManager trustManager)
  throws TopologyCacheException
  {
    this.adsContext = adsContext;
    this.trustManager = trustManager;
    try
    {
      dn = (String)adsContext.getDirContext().getEnvironment().get(
          Context.SECURITY_PRINCIPAL);
      pwd = (String)adsContext.getDirContext().getEnvironment().get(
          Context.SECURITY_CREDENTIALS);
    }
    catch (NamingException ne)
    {
      throw new TopologyCacheException(TopologyCacheException.Type.BUG, ne);
    }
    dn = ConnectionUtils.getBindDN(adsContext.getDirContext());
    pwd = ConnectionUtils.getBindPassword(adsContext.getDirContext());
  }
  /**
@@ -256,4 +242,13 @@
    return new ServerLoader(serverProperties, dn, pwd,
        trustManager.createCopy());
  }
  /**
   * Returns the adsContext used by this TopologyCache.
   * @return the adsContext used by this TopologyCache.
   */
  public ADSContext getAdsContext()
  {
    return adsContext;
  }
}
opends/src/ads/org/opends/admin/ads/TopologyCacheException.java
@@ -141,6 +141,19 @@
  }
  /**
   * Returns the host port representation of the server we where connected to
   * (or trying to connect) when this exception was generated.
   * @return the host port representation of the server we where connected to
   * (or trying to connect) when this exception was generated.
   */
  public String getHostPort()
  {
    int index = ldapUrl.indexOf("//");
    String hostPort = ldapUrl.substring(index + 2);
    return hostPort;
  }
  /**
   * Returns the ApplicationTrustManager that we were using when this exception
   * was generated.
   * @return the ApplicationTrustManager that we were using when this exception
opends/src/ads/org/opends/admin/ads/util/ConnectionUtils.java
@@ -29,10 +29,13 @@
import java.io.IOException;
import java.net.ConnectException;
import java.net.URI;
import java.security.GeneralSecurityException;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.naming.CommunicationException;
import javax.naming.Context;
@@ -58,6 +61,12 @@
{
  private static final int DEFAULT_LDAP_CONNECT_TIMEOUT = 10000;
  private static final String STARTTLS_PROPERTY =
    "org.opends.connectionutils.isstarttls";
  static private final Logger LOG =
    Logger.getLogger(ConnectionUtils.class.getName());
  /**
   * Private constructor: this class cannot be instantiated.
   */
@@ -313,8 +322,10 @@
            throw xx;
          }
          result.addToEnvironment(STARTTLS_PROPERTY, "true");
          if (fDn != null)
          {
            result.addToEnvironment(Context.SECURITY_AUTHENTICATION , "simple");
            result.addToEnvironment(Context.SECURITY_PRINCIPAL, fDn);
            if (fPwd != null)
@@ -338,6 +349,168 @@
    return getInitialLdapContext(t, pair, timeout);
  }
  /**
   * Returns the LDAP URL used in the provided InitialLdapContext.
   * @param ctx the context to analyze.
   * @return the LDAP URL used in the provided InitialLdapContext.
   */
  public static String getLdapUrl(InitialLdapContext ctx)
  {
    String s = null;
    try
    {
      s = (String)ctx.getEnvironment().get(Context.PROVIDER_URL);
    }
    catch (NamingException ne)
    {
      // This is really strange.  Seems like a bug somewhere.
      LOG.log(Level.WARNING, "Naming exception getting environment of "+ctx,
          ne);
    }
    return s;
  }
  /**
   * Returns the host name used in the provided InitialLdapContext.
   * @param ctx the context to analyze.
   * @return the host name used in the provided InitialLdapContext.
   */
  public static String getHostName(InitialLdapContext ctx)
  {
    String s = null;
    try
    {
      URI ldapURL = new URI(getLdapUrl(ctx));
      s = ldapURL.getHost();
    }
    catch (Throwable t)
    {
      // This is really strange.  Seems like a bug somewhere.
      LOG.log(Level.WARNING, "Error getting host: "+t, t);
    }
    return s;
  }
  /**
   * Returns the port number used in the provided InitialLdapContext.
   * @param ctx the context to analyze.
   * @return the port number used in the provided InitialLdapContext.
   */
  public static int getPort(InitialLdapContext ctx)
  {
    int port = -1;
    try
    {
      URI ldapURL = new URI(getLdapUrl(ctx));
      port = ldapURL.getPort();
    }
    catch (Throwable t)
    {
      // This is really strange.  Seems like a bug somewhere.
      LOG.log(Level.WARNING, "Error getting port: "+t, t);
    }
    return port;
  }
  /**
   * Returns the host port representation of the server to which this
   * context is connected.
   * @param ctx the context to analyze.
   * @return the host port representation of the server to which this
   * context is connected.
   */
  public static String getHostPort(InitialLdapContext ctx)
  {
    return getHostName(ctx)+":"+getPort(ctx);
  }
  /**
   * Returns the bind DN used in the provided InitialLdapContext.
   * @param ctx the context to analyze.
   * @return the bind DN used in the provided InitialLdapContext.
   */
  public static String getBindDN(InitialLdapContext ctx)
  {
    String bindDN = null;
    try
    {
      bindDN = (String)ctx.getEnvironment().get(Context.SECURITY_PRINCIPAL);
    }
    catch (NamingException ne)
    {
      // This is really strange.  Seems like a bug somewhere.
      LOG.log(Level.WARNING, "Naming exception getting environment of "+ctx,
          ne);
    }
    return bindDN;
  }
  /**
   * Returns the password used in the provided InitialLdapContext.
   * @param ctx the context to analyze.
   * @return the password used in the provided InitialLdapContext.
   */
  public static String getBindPassword(InitialLdapContext ctx)
  {
    String bindPwd = null;
    try
    {
      bindPwd = (String)ctx.getEnvironment().get(Context.SECURITY_CREDENTIALS);
    }
    catch (NamingException ne)
    {
      // This is really strange.  Seems like a bug somewhere.
      LOG.log(Level.WARNING, "Naming exception getting environment of "+ctx,
          ne);
    }
    return bindPwd;
  }
  /**
   * Tells whether we are using SSL in the provided InitialLdapContext.
   * @param ctx the context to analyze.
   * @return <CODE>true</CODE> if we are using SSL and <CODE>false</CODE>
   * otherwise.
   */
  public static boolean isSSL(InitialLdapContext ctx)
  {
    boolean isSSL = false;
    String s = null;
    try
    {
      s = getLdapUrl(ctx);
      isSSL = s.toLowerCase().startsWith("ldaps");
    }
    catch (Throwable t)
    {
      // This is really strange.  Seems like a bug somewhere.
      LOG.log(Level.WARNING, "Error getting if is SSL "+t, t);
    }
    return isSSL;
  }
  /**
   * Tells whether we are using StartTLS in the provided InitialLdapContext.
   * @param ctx the context to analyze.
   * @return <CODE>true</CODE> if we are using StartTLS and <CODE>false</CODE>
   * otherwise.
   */
  public static boolean isStartTLS(InitialLdapContext ctx)
  {
    boolean isStartTLS = false;
    try
    {
      isStartTLS = "true".equalsIgnoreCase((String)ctx.getEnvironment().get(
            STARTTLS_PROPERTY));
    }
    catch (NamingException ne)
    {
      // This is really strange.  Seems like a bug somewhere.
      LOG.log(Level.WARNING, "Naming exception getting environment of "+ctx,
          ne);
    }
    return isStartTLS;
  }
  /**
   * Method used to know if we can connect as administrator in a server with a
@@ -354,21 +527,19 @@
    boolean canConnectAsAdministrativeUser = false;
    try
    {
      InitialLdapContext ctx =
        createLdapContext(ldapUrl, dn, pwd, getDefaultLDAPTimeout(), null);
      InitialLdapContext ctx;
      if (ldapUrl.toLowerCase().startsWith("ldap:"))
      {
        ctx = createLdapContext(ldapUrl, dn, pwd, getDefaultLDAPTimeout(),
            null);
      }
      else
      {
        ctx = createLdapsContext(ldapUrl, dn, pwd, getDefaultLDAPTimeout(),
            null, null, null);
      }
      /*
       * Search for the config to check that it is the directory manager.
       */
      SearchControls searchControls = new SearchControls();
      searchControls.setCountLimit(1);
      searchControls.setSearchScope(
      SearchControls. OBJECT_SCOPE);
      searchControls.setReturningAttributes(
      new String[] {"dn"});
      ctx.search("cn=config", "objectclass=*", searchControls);
      canConnectAsAdministrativeUser = true;
      canConnectAsAdministrativeUser = connectedAsAdministrativeUser(ctx);
    } catch (NamingException ne)
    {
      // Nothing to do.
@@ -380,6 +551,40 @@
  }
  /**
   * Method used to know if we are connected as administrator in a server with a
   * given InitialLdapContext.
   * @param ctx the context.
   * @return <CODE>true</CODE> if we are connected and read the configuration
   * and <CODE>false</CODE> otherwise.
   */
  public static boolean connectedAsAdministrativeUser(InitialLdapContext ctx)
  {
    boolean connectedAsAdministrativeUser = false;
    try
    {
      /*
       * Search for the config to check that it is the directory manager.
       */
      SearchControls searchControls = new SearchControls();
      searchControls.setCountLimit(1);
      searchControls.setSearchScope(
          SearchControls. OBJECT_SCOPE);
      searchControls.setReturningAttributes(
          new String[] {"dn"});
      ctx.search("cn=config", "objectclass=*", searchControls);
      connectedAsAdministrativeUser = true;
    } catch (NamingException ne)
    {
      // Nothing to do.
    } catch (Throwable t)
    {
      throw new IllegalStateException("Unexpected throwable.", t);
    }
    return connectedAsAdministrativeUser;
  }
  /**
   * This is just a commodity method used to try to get an InitialLdapContext.
   * @param t the Thread to be used to create the InitialLdapContext.
   * @param pair an Object[] array that contains the InitialLdapContext and the
opends/src/guitools/org/opends/guitools/replicationcli/DisableReplicationUserData.java
New file
@@ -0,0 +1,117 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 */
package org.opends.guitools.replicationcli;
/**
 * This class is used to store the information provided by the user to
 * disable replication.  It is required because when we are in interactive
 * mode the ReplicationCliArgumentParser is not enough.
 *
 */
class DisableReplicationUserData extends ReplicationUserData
{
  private String hostName;
  private int port;
  private boolean useStartTLS;
  private boolean useSSL;
  /**
   * Returns the host name of the server.
   * @return the host name of the server.
   */
  String getHostName()
  {
    return hostName;
  }
  /**
   * Sets the host name of the server.
   * @param hostName the host name of the server.
   */
  void setHostName(String hostName)
  {
    this.hostName = hostName;
  }
  /**
   * Returns the port of the server.
   * @return the port of the server.
   */
  int getPort()
  {
    return port;
  }
  /**
   * Sets the port of the server.
   * @param port the port of the server.
   */
  void setPort(int port)
  {
    this.port = port;
  }
  /**
   * Returns <CODE>true</CODE> if we must use SSL to connect to the server and
   * <CODE>false</CODE> otherwise.
   * @return <CODE>true</CODE> if we must use SSL to connect to the server and
   * <CODE>false</CODE> otherwise.
   */
  boolean useSSL()
  {
    return useSSL;
  }
  /**
   * Sets whether we must use SSL to connect to the server or not.
   * @param useSSL whether we must use SSL to connect to the server or not.
   */
  void setUseSSL(boolean useSSL)
  {
    this.useSSL = useSSL;
  }
  /**
   * Returns <CODE>true</CODE> if we must use StartTLS to connect to the server
   * and <CODE>false</CODE> otherwise.
   * @return <CODE>true</CODE> if we must use StartTLS to connect to the server
   * and <CODE>false</CODE> otherwise.
   */
  boolean useStartTLS()
  {
    return useStartTLS;
  }
  /**
   * Sets whether we must use StartTLS to connect to the server or not.
   * @param useStartTLS whether we must use SSL to connect to the server or not.
   */
  void setUseStartTLS(boolean useStartTLS)
  {
    this.useStartTLS = useStartTLS;
  }
}
opends/src/guitools/org/opends/guitools/replicationcli/EnableReplicationUserData.java
New file
@@ -0,0 +1,325 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 */
package org.opends.guitools.replicationcli;
/**
 * This class is used to store the information provided by the user to enable
 * replication.  It is required because when we are in interactive mode the
 * ReplicationCliArgumentParser is not enough.
 *
 */
class EnableReplicationUserData extends ReplicationUserData
{
  private String hostName1;
  private int port1;
  private String bindDn1;
  private String pwd1;
  private boolean useStartTLS1;
  private boolean useSSL1;
  private int replicationPort1;
  private String hostName2;
  private int port2;
  private String pwd2;
  private String bindDn2;
  private boolean useStartTLS2;
  private boolean useSSL2;
  private int replicationPort2;
  /**
   * Returns the host name of the first server.
   * @return the host name of the first server.
   */
  String getHostName1()
  {
    return hostName1;
  }
  /**
   * Sets the host name of the first server.
   * @param hostName1 the host name of the first server.
   */
  void setHostName1(String hostName1)
  {
    this.hostName1 = hostName1;
  }
  /**
   * Returns the port of the first server.
   * @return the port of the first server.
   */
  int getPort1()
  {
    return port1;
  }
  /**
   * Sets the port of the first server.
   * @param port1 the port of the first server.
   */
  void setPort1(int port1)
  {
    this.port1 = port1;
  }
  /**
   * Returns the password for the first server.
   * @return the password for the first server.
   */
  String getPwd1()
  {
    return pwd1;
  }
  /**
   * Sets the password for the first server.
   * @param pwd1 the password for the first server.
   */
  void setPwd1(String pwd1)
  {
    this.pwd1 = pwd1;
  }
  /**
   * Returns <CODE>true</CODE> if we must use SSL to connect to the first
   * server and <CODE>false</CODE> otherwise.
   * @return <CODE>true</CODE> if we must use SSL to connect to the first
   * server and <CODE>false</CODE> otherwise.
   */
  boolean useSSL1()
  {
    return useSSL1;
  }
  /**
   * Sets whether we must use SSL to connect to the first server or not.
   * @param useSSL1 whether we must use SSL to connect to the first server or
   * not.
   */
  void setUseSSL1(boolean useSSL1)
  {
    this.useSSL1 = useSSL1;
  }
  /**
   * Returns <CODE>true</CODE> if we must use StartTLS to connect to the first
   * server and <CODE>false</CODE> otherwise.
   * @return <CODE>true</CODE> if we must use StartTLS to connect to the first
   * server and <CODE>false</CODE> otherwise.
   */
  boolean useStartTLS1()
  {
    return useStartTLS1;
  }
  /**
   * Sets whether we must use StartTLS to connect to the first server or not.
   * @param useStartTLS1 whether we must use SSL to connect to the first server
   * or not.
   */
  void setUseStartTLS1(boolean useStartTLS1)
  {
    this.useStartTLS1 = useStartTLS1;
  }
  /**
   * Returns the host name of the second server.
   * @return the host name of the second server.
   */
  String getHostName2()
  {
    return hostName2;
  }
  /**
   * Sets the host name of the second server.
   * @param host2Name the host name of the second server.
   */
  void setHostName2(String host2Name)
  {
    this.hostName2 = host2Name;
  }
  /**
   * Returns the port of the second server.
   * @return the port of the second server.
   */
  int getPort2()
  {
    return port2;
  }
  /**
   * Sets the port of the second server.
   * @param port2 the port of the second server.
   */
  void setPort2(int port2)
  {
    this.port2 = port2;
  }
  /**
   * Returns the password for the second server.
   * @return the password for the second server.
   */
  String getPwd2()
  {
    return pwd2;
  }
  /**
   * Sets the password for the second server.
   * @param pwd2 the password for the second server.
   */
  void setPwd2(String pwd2)
  {
    this.pwd2 = pwd2;
  }
  /**
   * Returns <CODE>true</CODE> if we must use SSL to connect to the second
   * server and <CODE>false</CODE> otherwise.
   * @return <CODE>true</CODE> if we must use SSL to connect to the second
   * server and <CODE>false</CODE> otherwise.
   */
  boolean useSSL2()
  {
    return useSSL2;
  }
  /**
   * Sets whether we must use SSL to connect to the second server or not.
   * @param useSSL2 whether we must use SSL to connect to the second server or
   * not.
   */
  void setUseSSL2(boolean useSSL2)
  {
    this.useSSL2 = useSSL2;
  }
  /**
   * Returns <CODE>true</CODE> if we must use StartTLS to connect to the second
   * server and <CODE>false</CODE> otherwise.
   * @return <CODE>true</CODE> if we must use StartTLS to connect to the second
   * server and <CODE>false</CODE> otherwise.
   */
  boolean useStartTLS2()
  {
    return useStartTLS2;
  }
  /**
   * Sets whether we must use StartTLS to connect to the second server or not.
   * @param useStartTLS2 whether we must use SSL to connect to the second server
   * or not.
   */
  void setUseStartTLS2(boolean useStartTLS2)
  {
    this.useStartTLS2 = useStartTLS2;
  }
  /**
   * Returns the dn to be used to bind to the first server.
   * @return the dn to be used to bind to the first server.
   */
  String getBindDn1()
  {
    return bindDn1;
  }
  /**
   * Sets the dn to be used to bind to the first server.
   * @param bindDn1 the dn to be used to bind to the first server.
   */
  void setBindDn1(String bindDn1)
  {
    this.bindDn1 = bindDn1;
  }
  /**
   * Returns the dn to be used to bind to the second server.
   * @return the dn to be used to bind to the second server.
   */
  String getBindDn2()
  {
    return bindDn2;
  }
  /**
   * Sets the dn to be used to bind to the second server.
   * @param bindDn2 the dn to be used to bind to the second server.
   */
  void setBindDn2(String bindDn2)
  {
    this.bindDn2 = bindDn2;
  }
  /**
   * Returns the replication port to be used on the first server if it is not
   * defined yet.
   * @return the replication port to be used on the first server if it is not
   * defined yet.
   */
  int getReplicationPort1()
  {
    return replicationPort1;
  }
  /**
   * Sets the replication port to be used on the first server if it is not
   * defined yet.
   * @param replicationPort1 the replication port to be used on the first server
   * if it is not defined yet.
   */
  void setReplicationPort1(int replicationPort1)
  {
    this.replicationPort1 = replicationPort1;
  }
  /**
   * Returns the replication port to be used on the second server if it is not
   * defined yet.
   * @return the replication port to be used on the second server if it is not
   * defined yet.
   */
  int getReplicationPort2()
  {
    return replicationPort2;
  }
  /**
   * Sets the replication port to be used on the second server if it is not
   * defined yet.
   * @param replicationPort2 the replication port to be used on the second
   * server if it is not defined yet.
   */
  void setReplicationPort2(int replicationPort2)
  {
    this.replicationPort2 = replicationPort2;
  }
}
opends/src/guitools/org/opends/guitools/replicationcli/InitializeReplicationUserData.java
New file
@@ -0,0 +1,203 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 */
package org.opends.guitools.replicationcli;
/**
 * This class is used to store the information provided by the user to
 * initialize replication.  It is required because when we are in interactive
 * mode the ReplicationCliArgumentParser is not enough.
 *
 */
class InitializeReplicationUserData extends ReplicationUserData
{
  private String hostNameSource;
  private int portSource;
  private boolean useStartTLSSource;
  private boolean useSSLSource;
  private String hostNameDestination;
  private int portDestination;
  private boolean useStartTLSDestination;
  private boolean useSSLDestination;
  /**
   * Returns the host name of the source server.
   * @return the host name of the source server.
   */
  String getHostNameSource()
  {
    return hostNameSource;
  }
  /**
   * Sets the host name of the source server.
   * @param hostNameSource the host name of the source server.
   */
  void setHostNameSource(String hostNameSource)
  {
    this.hostNameSource = hostNameSource;
  }
  /**
   * Returns the port of the source server.
   * @return the port of the source server.
   */
  int getPortSource()
  {
    return portSource;
  }
  /**
   * Sets the port of the source server.
   * @param portSource the port of the source server.
   */
  void setPortSource(int portSource)
  {
    this.portSource = portSource;
  }
  /**
   * Returns <CODE>true</CODE> if we must use SSL to connect to the source
   * server and <CODE>false</CODE> otherwise.
   * @return <CODE>true</CODE> if we must use SSL to connect to the source
   * server and <CODE>false</CODE> otherwise.
   */
  boolean useSSLSource()
  {
    return useSSLSource;
  }
  /**
   * Sets whether we must use SSL to connect to the source server or not.
   * @param useSSLSource whether we must use SSL to connect to the source server
   * or not.
   */
  void setUseSSLSource(boolean useSSLSource)
  {
    this.useSSLSource = useSSLSource;
  }
  /**
   * Returns <CODE>true</CODE> if we must use StartTLS to connect to the source
   * server and <CODE>false</CODE> otherwise.
   * @return <CODE>true</CODE> if we must use StartTLS to connect to the source
   * server and <CODE>false</CODE> otherwise.
   */
  boolean useStartTLSSource()
  {
    return useStartTLSSource;
  }
  /**
   * Sets whether we must use StartTLS to connect to the source server or not.
   * @param useStartTLSSource whether we must use SSL to connect to the source
   * server or not.
   */
  void setUseStartTLSSource(boolean useStartTLSSource)
  {
    this.useStartTLSSource = useStartTLSSource;
  }
  /**
   * Returns the host name of the destination server.
   * @return the host name of the destination server.
   */
  String getHostNameDestination()
  {
    return hostNameDestination;
  }
  /**
   * Sets the host name of the destination server.
   * @param hostNameDestination the host name of the destination server.
   */
  void setHostNameDestination(String hostNameDestination)
  {
    this.hostNameDestination = hostNameDestination;
  }
  /**
   * Returns the port of the destination server.
   * @return the port of the destination server.
   */
  int getPortDestination()
  {
    return portDestination;
  }
  /**
   * Sets the port of the destination server.
   * @param portDestination the port of the destination server.
   */
  void setPortDestination(int portDestination)
  {
    this.portDestination = portDestination;
  }
  /**
   * Returns <CODE>true</CODE> if we must use SSL to connect to the destination
   * server and <CODE>false</CODE> otherwise.
   * @return <CODE>true</CODE> if we must use SSL to connect to the destination
   * server and <CODE>false</CODE> otherwise.
   */
  boolean useSSLDestination()
  {
    return useSSLDestination;
  }
  /**
   * Sets whether we must use SSL to connect to the destination server or not.
   * @param useSSLDestination whether we must use SSL to connect to the
   * destination server or not.
   */
  void setUseSSLDestination(boolean useSSLDestination)
  {
    this.useSSLDestination = useSSLDestination;
  }
  /**
   * Returns <CODE>true</CODE> if we must use StartTLS to connect to the
   * destination server and <CODE>false</CODE> otherwise.
   * @return <CODE>true</CODE> if we must use StartTLS to connect to the
   * destination server and <CODE>false</CODE> otherwise.
   */
  boolean useStartTLSDestination()
  {
    return useStartTLSDestination;
  }
  /**
   * Sets whether we must use StartTLS to connect to the destination server or
   * not.
   * @param useStartTLSDestination whether we must use SSL to connect to the
   * destination server or not.
   */
  void setUseStartTLSDestination(boolean useStartTLSDestination)
  {
    this.useStartTLSDestination = useStartTLSDestination;
  }
}
opends/src/guitools/org/opends/guitools/replicationcli/ReplicationCliException.java
New file
@@ -0,0 +1,63 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 */
package org.opends.guitools.replicationcli;
import org.opends.messages.Message;
import org.opends.server.types.OpenDsException;
/**
 * The exception that is thrown during the replication command-line execution.
 *
 */
public class ReplicationCliException extends OpenDsException {
  private static final long serialVersionUID = -8085682356609610678L;
  private ReplicationCliReturnCode errorCode;
  /**
   * The constructor for the exception.
   * @param message the localized message.
   * @param errorCode the error code associated with this exception.
   * @param cause the cause that generated this exception.
   */
  ReplicationCliException(Message message, ReplicationCliReturnCode errorCode,
      Throwable cause)
  {
    super(message, cause);
    this.errorCode = errorCode;
  }
  /**
   * Returns the error code associated with this exception.
   * @return the error code associated with this exception.
   */
  public ReplicationCliReturnCode getErrorCode()
  {
    return errorCode;
  }
}
opends/src/guitools/org/opends/guitools/replicationcli/ReplicationCliMain.java
New file
@@ -0,0 +1,3780 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 */
package org.opends.guitools.replicationcli;
import static org.opends.guitools.replicationcli.ReplicationCliReturnCode.*;
import static org.opends.messages.AdminToolMessages.*;
import static org.opends.messages.QuickSetupMessages.*;
import static org.opends.messages.ToolMessages.*;
import static org.opends.server.util.ServerConstants.MAX_LINE_WIDTH;
import static org.opends.server.util.StaticUtils.wrapText;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.naming.NamingException;
import javax.naming.NoPermissionException;
import javax.naming.ldap.InitialLdapContext;
import org.opends.admin.ads.ADSContext;
import org.opends.admin.ads.ADSContextException;
import org.opends.admin.ads.ReplicaDescriptor;
import org.opends.admin.ads.ServerDescriptor;
import org.opends.admin.ads.SuffixDescriptor;
import org.opends.admin.ads.TopologyCache;
import org.opends.admin.ads.TopologyCacheException;
import org.opends.admin.ads.util.ApplicationTrustManager;
import org.opends.admin.ads.util.ConnectionUtils;
import org.opends.admin.ads.util.ServerLoader;
import org.opends.messages.Message;
import org.opends.messages.MessageBuilder;
import org.opends.quicksetup.ApplicationException;
import org.opends.quicksetup.CliApplicationHelper;
import org.opends.quicksetup.Constants;
import org.opends.quicksetup.event.ProgressUpdateEvent;
import org.opends.quicksetup.event.ProgressUpdateListener;
import org.opends.quicksetup.installer.InstallerHelper;
import org.opends.quicksetup.installer.PeerNotFoundException;
import org.opends.quicksetup.installer.offline.OfflineInstaller;
import org.opends.quicksetup.util.PlainTextProgressMessageFormatter;
import org.opends.quicksetup.util.Utils;
import org.opends.server.admin.DefaultBehaviorException;
import org.opends.server.admin.ManagedObjectNotFoundException;
import org.opends.server.admin.client.ManagementContext;
import org.opends.server.admin.client.ldap.JNDIDirContextAdaptor;
import org.opends.server.admin.client.ldap.LDAPManagementContext;
import org.opends.server.admin.std.client.*;
import org.opends.server.admin.std.meta.*;
import org.opends.server.types.DN;
import org.opends.server.types.NullOutputStream;
import org.opends.server.types.OpenDsException;
import org.opends.server.util.args.ArgumentException;
/**
 * This class provides a tool that can be used to enable and disable replication
 * and also to initialize the contents of a replicated suffix with the contents
 * of another suffix.
 */
public class ReplicationCliMain extends CliApplicationHelper
{
  /**
   * The fully-qualified name of this class.
   */
  private static final String CLASS_NAME = ReplicationCliMain.class.getName();
  private static final Logger LOG =
    Logger.getLogger(CliApplicationHelper.class.getName());
  // The print stream to use for standard error.
  private PrintStream err;
  // The print stream to use for standard output.
  private PrintStream out;
  // The argument parser to be used.
  private ReplicationCliParser argParser;
  // The message formatter
  PlainTextProgressMessageFormatter formatter =
      new PlainTextProgressMessageFormatter();
  /**
   * Constructor for the ReplicationCliMain object.
   *
   * @param  out the print stream to use for standard output.
   * @param  err the print stream to use for standard error.
   */
  public ReplicationCliMain(PrintStream out, PrintStream err)
  {
    this.out = out;
    this.err = err;
  }
  /**
   * The main method for the replication tool.
   *
   * @param args the command-line arguments provided to this program.
   */
  public static void main(String[] args)
  {
    int retCode = mainCLI(args, true, System.out, System.err);
    if(retCode != 0)
    {
      System.exit(retCode);
    }
  }
  /**
   * Parses the provided command-line arguments and uses that information to
   * run the replication tool.
   *
   * @param args the command-line arguments provided to this program.
   *
   * @return The error code.
   */
  public static int mainCLI(String[] args)
  {
    return mainCLI(args, true, System.out, System.err);
  }
  /**
   * Parses the provided command-line arguments and uses that information to
   * run the replication tool.
   *
   * @param  args              The command-line arguments provided to this
   *                           program.
   * @param initializeServer   Indicates whether to initialize the server.
   * @param  outStream         The output stream to use for standard output, or
   *                           <CODE>null</CODE> if standard output is not
   *                           needed.
   * @param  errStream         The output stream to use for standard error, or
   *                           <CODE>null</CODE> if standard error is not
   *                           needed.
   * @return The error code.
   */
  public static int mainCLI(String[] args, boolean initializeServer,
      OutputStream outStream, OutputStream errStream)
  {
    PrintStream out;
    if (outStream == null)
    {
      out = NullOutputStream.printStream();
    }
    else
    {
      out = new PrintStream(outStream);
    }
    PrintStream err;
    if (errStream == null)
    {
      err = NullOutputStream.printStream();
    }
    else
    {
      err = new PrintStream(errStream);
    }
    ReplicationCliMain replicationCli = new ReplicationCliMain(out, err);
    return replicationCli.execute(args, initializeServer);
  }
  /**
   * Parses the provided command-line arguments and uses that information to
   * run the replication tool.
   *
   * @param args the command-line arguments provided to this program.
   * @param  initializeServer  Indicates whether to initialize the server.
   *
   * @return The error code.
   */
  public int execute(String[] args, boolean initializeServer)
  {
    ReplicationCliReturnCode returnValue = SUCCESSFUL_NOP;
    // Create the command-line argument parser for use with this
    // program.
    try
    {
      argParser = new ReplicationCliParser(CLASS_NAME);
      argParser.initializeParser(out);
    }
    catch (ArgumentException ae)
    {
      Message message = ERR_CANNOT_INITIALIZE_ARGS.get(ae.getMessage());
      printErrorMessage(message);
      LOG.log(Level.SEVERE, "Complete error stack:", ae);
      returnValue = CANNOT_INITIALIZE_ARGS;
    }
    if (returnValue == SUCCESSFUL_NOP)
    {
      //  Parse the command-line arguments provided to this program.
      try
      {
        argParser.parseArguments(args);
      }
      catch (ArgumentException ae)
      {
        Message message = ERR_ERROR_PARSING_ARGS.get(ae.getMessage());
        printErrorMessage(message);
        err.println(argParser.getUsage());
        LOG.log(Level.SEVERE, "Complete error stack:", ae);
        returnValue = ERROR_PARSING_ARGS;
      }
    }
    if (returnValue == SUCCESSFUL_NOP)
    {
      /* Check that the provided parameters are compatible.
       */
      MessageBuilder buf = new MessageBuilder();
      argParser.validateOptions(buf);
      if (buf.length() > 0)
      {
        err.println(wrapText(buf.toMessage(), MAX_LINE_WIDTH));
        err.println(argParser.getUsage());
        returnValue = ERROR_PARSING_ARGS;
      }
    }
    if (returnValue == SUCCESSFUL_NOP)
    {
      if (argParser.isEnableReplicationSubcommand())
      {
        returnValue = enableReplication();
      }
      else if (argParser.isDisableReplicationSubcommand())
      {
        returnValue = disableReplication();
      }
      else if (argParser.isInitializeReplicationSubcommand())
      {
        returnValue = initializeReplication();
      }
      else
      {
        err.println(wrapText(ERR_REPLICATION_VALID_SUBCOMMAND_NOT_FOUND.get(),
            MAX_LINE_WIDTH));
        err.println(argParser.getUsage());
        returnValue = ERROR_PARSING_ARGS;
      }
    }
    return returnValue.getReturnCode();
  }
  /**
   * Displays an error message in the error output (wrapping it if necessary).
   * @param msg the error message to be displayed.
   */
  protected void printErrorMessage(Message msg)
  {
    err.println(org.opends.server.util.StaticUtils.wrapText(msg,
        Utils.getCommandLineMaxLineWidth()));
    LOG.log(Level.SEVERE, msg.toString());
  }
  /**
   * Displays a progress message in the error output (wrapping it if necessary).
   * @param msg the error message to be displayed.
   */
  protected void printProgressMessage(Message msg)
  {
    if (!argParser.isQuiet())
    {
      out.print(org.opends.server.util.StaticUtils.wrapText(msg,
          Utils.getCommandLineMaxLineWidth()));
      out.flush();
    }
    LOG.log(Level.INFO, msg.toString());
  }
  /**
   * Prints a line break in the standard output if we are not in quite mode.
   */
  protected void printProgressLineBreak()
  {
    if (!argParser.isQuiet())
    {
      out.println();
    }
  }
  /**
   * Displays a warning message in the error output (wrapping it if necessary).
   * @param msg the warning message to be displayed.
   */
  protected void printWarningMessage(Message msg)
  {
    if (!argParser.isQuiet())
    {
      // TODO: decide if even in quiet mode we must display this message or not.
      out.print(org.opends.server.util.StaticUtils.wrapText(msg,
          Utils.getCommandLineMaxLineWidth()));
      out.flush();
    }
    LOG.log(Level.WARNING, msg.toString());
  }
  /**
   * Prints a line break in the standard output.
   */
  protected void printLineBreak()
  {
    out.println();
  }
  /**
   * Based on the data provided in the command-line it enables replication
   * between two servers.
   * @return the error code if the operation failed and 0 if it was successful.
   */
  private ReplicationCliReturnCode enableReplication()
  {
    ReplicationCliReturnCode returnValue = SUCCESSFUL_NOP;
    EnableReplicationUserData uData = new EnableReplicationUserData();
    if (argParser.isInteractive())
    {
      if (promptIfRequired(uData))
      {
        returnValue = enableReplication(uData);
      }
      else
      {
        returnValue = USER_CANCELLED;
      }
    }
    else
    {
      initializeWithArgParser(uData);
      returnValue = enableReplication(uData);
    }
    return returnValue;
  }
  /**
   * Based on the data provided in the command-line it disables replication
   * in the server.
   * @return the error code if the operation failed and SUCCESSFUL if it was
   * successful.
   */
  private ReplicationCliReturnCode disableReplication()
  {
    ReplicationCliReturnCode returnValue = SUCCESSFUL_NOP;
    DisableReplicationUserData uData = new DisableReplicationUserData();
    if (argParser.isInteractive())
    {
      if (promptIfRequired(uData))
      {
        returnValue = disableReplication(uData);
      }
      else
      {
        returnValue = USER_CANCELLED;
      }
    }
    else
    {
      initializeWithArgParser(uData);
      returnValue = disableReplication(uData);
    }
    return returnValue;
  }
  /**
   * Based on the data provided in the command-line it initializes replication
   * between two servers.
   * @return the error code if the operation failed and SUCCESSFUL if it was
   * successful.
   */
  private ReplicationCliReturnCode initializeReplication()
  {
    ReplicationCliReturnCode returnValue = SUCCESSFUL_NOP;
    InitializeReplicationUserData uData = new InitializeReplicationUserData();
    if (argParser.isInteractive())
    {
      if (promptIfRequired(uData))
      {
        returnValue = initializeReplication(uData);
      }
      else
      {
        returnValue = USER_CANCELLED;
      }
    }
    else
    {
      initializeWithArgParser(uData);
      returnValue = initializeReplication(uData);
    }
    return returnValue;
  }
  /**
   * Updates the contents of the provided EnableReplicationUserData object
   * with the information provided in the command-line.  If some information
   * is missing, ask the user to provide valid data.
   * We assume that if this method is called we are in interactive mode.
   * @param uData the object to be updated.
   * @return <CODE>true</CODE> if the object was successfully updated and
   * <CODE>false</CODE> if the user cancelled the operation.
   */
  private boolean promptIfRequired(EnableReplicationUserData uData)
  {
    boolean cancelled = false;
    String adminPwd = argParser.getBindPasswordAdmin();
    String adminUid = argParser.getAdministratorUID();
    /*
     * Try to connect to the first server.
     */
    String host1 = getValue(argParser.getHostName1(),
        argParser.getDefaultHostName1());
    int port1 = getValue(argParser.getPort1(),
        argParser.getDefaultPort1());
    String bindDn1 = getValue(argParser.getBindDn1(),
        argParser.getDefaultBindDn1());
    String pwd1 = argParser.getBindPassword1();
    if ((pwd1 == null) && (adminPwd != null) && (adminUid != null))
    {
      // No information provided to connect to the first server.  Try
      // to use global administrator.
      bindDn1 = ADSContext.getAdministratorDN(adminUid);
      pwd1 = adminPwd;
    }
    boolean useSSL1 = argParser.useSSL1();
    boolean useStartTLS1 = argParser.useStartTLS1();
    InitialLdapContext ctx1 = null;
    // Boolean used to only ask for the information that was not explicitly
    // provided the first time we ask.  After we ask for all the information.
    boolean firstTimeAsked =
      (argParser.getHostName1() == null) ||
      (argParser.getPort1() == -1) ||
      (argParser.getBindDn1() == null) ||
      (argParser.getBindPassword1() == null);
    while ((ctx1 == null) && !cancelled)
    {
      try
      {
        ctx1 = createContext(host1, port1, useSSL1, useStartTLS1, bindDn1,
            pwd1, getTrustManager());
      }
      catch (NamingException ne)
      {
        LOG.log(Level.WARNING, "Error connecting to "+host1+":"+port1, ne);
        if (Utils.isCertificateException(ne))
        {
          String usedUrl = getLDAPUrl(host1, port1, useSSL1);
          if (!promptForCertificateConfirmation(ne, getTrustManager(), usedUrl))
          {
            cancelled = true;
          }
        }
        else
        {
          if (pwd1 != null)
          {
            printLineBreak();
            printErrorMessage(ERR_ERROR_CONNECTING_TO_SERVER_PROMPT_AGAIN.get(
                host1+":"+port1));
          }
          printLineBreak();
          if (!firstTimeAsked || (argParser.getHostName1() == null))
          {
            host1 = promptForString(
              INFO_REPLICATION_ENABLE_HOSTNAME1_PROMPT.get(),
              getValue(host1, argParser.getDefaultHostName1()));
          }
          if (!firstTimeAsked || (argParser.getPort1() == -1))
          {
            port1 = promptForPort(INFO_REPLICATION_ENABLE_PORT1_PROMPT.get(),
              getValue(port1, argParser.getDefaultPort1()));
          }
          if (!firstTimeAsked || (argParser.getBindDn1() == null))
          {
            bindDn1 = promptForString(
              INFO_REPLICATION_BINDDN_PROMPT.get(),
              getValue(bindDn1, argParser.getDefaultBindDn1()));
          }
          if (!firstTimeAsked || (argParser.getBindPassword1() == null))
          {
            pwd1 = promptForPassword(INFO_REPLICATION_PASSWORD_PROMPT.get());
          }
          if (!firstTimeAsked || (!useSSL1 && !useStartTLS1))
          {
            useSSL1 = confirm(INFO_REPLICATION_USESSL_PROMPT.get(),
                useSSL1);
            if (!useSSL1)
            {
              useStartTLS1 = confirm(INFO_REPLICATION_USESTARTTLS_PROMPT.get(),
                  useStartTLS1);
            }
          }
          firstTimeAsked = false;
        }
      }
    }
    if (!cancelled)
    {
      uData.setHostName1(host1);
      uData.setPort1(port1);
      uData.setBindDn1(bindDn1);
      uData.setPwd1(pwd1);
      uData.setUseSSL1(useSSL1);
      uData.setUseStartTLS1(useStartTLS1);
    }
    if (ctx1 != null)
    {
      // Try to get the replication port for server 1 only if the user did
      // not explicitly provide it and if it is required.
      int replicationPort1 = argParser.getReplicationPort1();
      if (replicationPort1 == -1)
      {
        if (!hasReplicationPort(ctx1))
        {
          while (replicationPort1 == -1)
          {
            replicationPort1 = promptForPort(
                INFO_REPLICATION_ENABLE_REPLICATIONPORT1_PROMPT.get(),
                argParser.getDefaultReplicationPort1());
            if (replicationPort1 == port1)
            {
              replicationPort1 = -1;
              printLineBreak();
              printErrorMessage(
                  ERR_REPLICATION_PORT_AND_REPLICATION_PORT_EQUAL.get(
                      String.valueOf(port1)));
            }
          }
          uData.setReplicationPort1(replicationPort1);
        }
      }
      else
      {
        uData.setReplicationPort1(replicationPort1);
      }
      // If the server contains an ADS. Try to load it and only load it: if
      // there are issues with the ADS they will be encountered in the
      // enableReplication(EnableReplicationUserData) method.  Here we have
      // to load the ADS to ask the user to accept the certificates and
      // eventually admin authentication data.
      cancelled = loadADSAndAcceptCertificates(ctx1, uData, true);
    }
    /*
     * Try to connect to the second server.
     */
    String host2 = getValue(argParser.getHostName2(),
        argParser.getDefaultHostName2());
    int port2 = getValue(argParser.getPort2(),
        argParser.getDefaultPort2());
    String bindDn2 = getValue(argParser.getBindDn2(),
        argParser.getDefaultBindDn2());
    String pwd2 = argParser.getBindPassword2();
    if ((pwd2 == null) && (adminPwd != null) && (adminUid != null))
    {
      // No information provided to connect to the second server.  Try
      // to use global administrator.
      bindDn2 = ADSContext.getAdministratorDN(adminUid);
      pwd2 = adminPwd;
    }
    boolean useSSL2 = argParser.useSSL2();
    boolean useStartTLS2 = argParser.useStartTLS2();
    InitialLdapContext ctx2 = null;
    firstTimeAsked =
      (argParser.getHostName2() == null) ||
      (argParser.getPort2() == -1) ||
      (argParser.getBindDn2() == null) ||
      (argParser.getBindPassword2() == null);
    while ((ctx2 == null) && !cancelled)
    {
      try
      {
        ctx2 = createContext(host2, port2, useSSL2, useStartTLS2, bindDn2,
            pwd2, getTrustManager());
      }
      catch (NamingException ne)
      {
        LOG.log(Level.WARNING, "Error connecting to "+host2+":"+port2, ne);
        if (Utils.isCertificateException(ne))
        {
          String usedUrl = getLDAPUrl(host2, port2, useSSL2);
          if (!promptForCertificateConfirmation(ne, getTrustManager(), usedUrl))
          {
            cancelled = true;
          }
        }
        else
        {
          if (pwd2 != null)
          {
            printLineBreak();
            printErrorMessage(ERR_ERROR_CONNECTING_TO_SERVER_PROMPT_AGAIN.get(
                host2+":"+port2));
          }
          printLineBreak();
          if (!firstTimeAsked || (argParser.getHostName2() == null))
          {
            host2 = promptForString(
              INFO_REPLICATION_ENABLE_HOSTNAME2_PROMPT.get(),
              getValue(host2, argParser.getDefaultHostName2()));
          }
          if (!firstTimeAsked || (argParser.getPort2() == -1))
          {
            port2 = promptForPort(INFO_REPLICATION_ENABLE_PORT2_PROMPT.get(),
              getValue(port2, argParser.getDefaultPort2()));
          }
          if (!firstTimeAsked || (argParser.getBindDn2() == null))
          {
            bindDn2 = promptForString(
              INFO_REPLICATION_BINDDN_PROMPT.get(),
              getValue(bindDn2, argParser.getDefaultBindDn2()));
          }
          if (!firstTimeAsked || (argParser.getBindPassword2() == null))
          {
            pwd2 = promptForPassword(INFO_REPLICATION_PASSWORD_PROMPT.get());
          }
          if (!firstTimeAsked || !useSSL2 || !useStartTLS2)
          {
            useSSL2 = confirm(INFO_REPLICATION_USESSL_PROMPT.get(),
                useSSL2);
            if (!useSSL2)
            {
              useStartTLS2 = confirm(INFO_REPLICATION_USESTARTTLS_PROMPT.get(),
                  useStartTLS2);
            }
          }
          firstTimeAsked = false;
        }
      }
    }
    if (!cancelled)
    {
      uData.setHostName2(host2);
      uData.setPort2(port2);
      uData.setBindDn2(bindDn2);
      uData.setPwd2(pwd2);
      uData.setUseSSL2(useSSL2);
      uData.setUseStartTLS2(useStartTLS2);
    }
    if (ctx2 != null)
    {
      int replicationPort2 = argParser.getReplicationPort2();
      if (replicationPort2 == -1)
      {
        if (!hasReplicationPort(ctx2))
        {
          while (replicationPort2 == -1)
          {
            replicationPort2 = promptForPort(
                INFO_REPLICATION_ENABLE_REPLICATIONPORT2_PROMPT.get(),
                argParser.getDefaultReplicationPort2());
            if (replicationPort2 == port2)
            {
              replicationPort2 = -1;
              printLineBreak();
              printErrorMessage(
                  ERR_REPLICATION_PORT_AND_REPLICATION_PORT_EQUAL.get(
                      String.valueOf(port2)));
            }
          }
          uData.setReplicationPort2(replicationPort2);
        }
      }
      else
      {
        uData.setReplicationPort2(replicationPort2);
      }
      // If the server contains an ADS. Try to load it and only load it: if
      // there are issues with the ADS they will be encountered in the
      // enableReplication(EnableReplicationUserData) method.  Here we have
      // to load the ADS to ask the user to accept the certificates.
      cancelled = loadADSAndAcceptCertificates(ctx2, uData, false);
    }
    // If the adminUid and adminPwd are not set in the EnableReplicationUserData
    // object, that means that there are no administrators and that they
    // must be created. The adminUId and adminPwd are updated inside
    // loadADSAndAcceptCertificates.
    if (!cancelled && (uData.getAdminUid() == null))
    {
      if (adminUid == null)
      {
        adminUid= askForAdministratorUID(
            argParser.getDefaultAdministratorUID());
      }
      uData.setAdminUid(adminUid);
    }
    if (!cancelled && (uData.getAdminPwd() == null))
    {
      boolean adminDefined = hasAdministrator(ctx1) || hasAdministrator(ctx2);
      while ((adminPwd == null) && !adminDefined)
      {
        adminPwd = askForAdministratorPwd();
        String adminPwdConfirm =
          promptForPassword(INFO_ADMINISTRATOR_PWD_CONFIRM_PROMPT.get());
        if (!adminPwd.equals(adminPwdConfirm))
        {
          printErrorMessage(ERR_ADMINISTRATOR_PWD_DO_NOT_MATCH.get());
          printLineBreak();
          adminPwd = null;
        }
      }
      uData.setAdminPwd(adminPwd);
    }
    if (!cancelled)
    {
      LinkedList<String> suffixes = argParser.getBaseDNs();
      checkSuffixesForEnableReplication(suffixes, ctx1, ctx2, true);
      cancelled = suffixes.isEmpty();
      uData.setBaseDNs(suffixes);
    }
    if (ctx1 != null)
    {
      try
      {
        ctx1.close();
      }
      catch (Throwable t)
      {
      }
    }
    if (ctx2 != null)
    {
      try
      {
        ctx2.close();
      }
      catch (Throwable t)
      {
      }
    }
    return cancelled;
  }
  /**
   * Updates the contents of the provided DisableReplicationUserData object
   * with the information provided in the command-line.  If some information
   * is missing, ask the user to provide valid data.
   * We assume that if this method is called we are in interactive mode.
   * @param uData the object to be updated.
   * @return <CODE>true</CODE> if the object was successfully updated and
   * <CODE>false</CODE> if the user cancelled the operation.
   */
  private boolean promptIfRequired(DisableReplicationUserData uData)
  {
    boolean cancelled = false;
    String adminPwd = argParser.getBindPasswordAdmin();
    String adminUid = argParser.getAdministratorUID();
    if (adminPwd == null)
    {
      adminPwd = askForAdministratorPwd();
    }
    /*
     * Try to connect to the server.
     */
    String host = getValue(argParser.getHostNameToDisable(),
        argParser.getDefaultHostNameToDisable());
    int port = getValue(argParser.getPortToDisable(),
        argParser.getDefaultPortToDisable());
    boolean useSSL = argParser.useSSLToDisable();
    boolean useStartTLS = argParser.useStartTLSToDisable();
    InitialLdapContext ctx = null;
    boolean firstTimeAsked =
      (argParser.getHostNameToDisable() == null) ||
      (argParser.getPortToDisable() == -1) ||
      (argParser.getAdministratorUID() == null) ||
      (argParser.getBindPasswordAdmin() == null);
    while ((ctx == null) && !cancelled)
    {
      try
      {
        ctx = createContext(host, port, useSSL, useStartTLS,
            ADSContext.getAdministratorDN(adminUid), adminPwd,
            getTrustManager());
      }
      catch (NamingException ne)
      {
        LOG.log(Level.WARNING, "Error connecting to "+host+":"+port, ne);
        if (Utils.isCertificateException(ne))
        {
          String usedUrl = getLDAPUrl(host, port, useSSL);
          if (!promptForCertificateConfirmation(ne, getTrustManager(), usedUrl))
          {
            cancelled = true;
          }
        }
        else
        {
          printLineBreak();
          printErrorMessage(ERR_ERROR_CONNECTING_TO_SERVER_PROMPT_AGAIN.get(
              host+":"+port));
          printLineBreak();
          if (!firstTimeAsked || (argParser.getHostNameToDisable() == null))
          {
            host = promptForString(
                INFO_REPLICATION_DISABLE_HOSTNAME_PROMPT.get(),
                getValue(host, argParser.getDefaultHostNameToDisable()));
          }
          if (!firstTimeAsked || (argParser.getPortToDisable() == -1))
          {
            port = promptForPort(
                INFO_REPLICATION_DISABLE_PORT_PROMPT.get(),
              getValue(port, argParser.getDefaultPortToDisable()));
          }
          if (!firstTimeAsked || (argParser.getAdministratorUID() == null))
          {
            adminUid = askForAdministratorUID(adminUid);
          }
          if (!firstTimeAsked || (argParser.getBindPasswordAdmin() == null))
          {
            adminPwd = askForAdministratorPwd();
          }
          if (!firstTimeAsked || useSSL)
          {
            useSSL = confirm(INFO_REPLICATION_USESSL_PROMPT.get(), useSSL);
            if (!useSSL)
            {
              useStartTLS =
                confirm(INFO_REPLICATION_USESTARTTLS_PROMPT.get(), useStartTLS);
            }
          }
          firstTimeAsked = false;
        }
      }
    }
    if (!cancelled)
    {
      uData.setHostName(host);
      uData.setPort(port);
      uData.setUseSSL(useSSL);
      uData.setUseStartTLS(useStartTLS);
      uData.setAdminUid(adminUid);
      uData.setAdminPwd(adminPwd);
    }
    if (ctx != null)
    {
      // If the server contains an ADS, try to load it and only load it: if
      // there are issues with the ADS they will be encountered in the
      // disableReplication(DisableReplicationUserData) method.  Here we have
      // to load the ADS to ask the user to accept the certificates and
      // eventually admin authentication data.
      cancelled = loadADSAndAcceptCertificates(ctx, uData, false);
    }
    if (!cancelled)
    {
      LinkedList<String> suffixes = argParser.getBaseDNs();
      checkSuffixesForDisableReplication(suffixes, ctx, true);
      cancelled = suffixes.isEmpty();
      uData.setBaseDNs(suffixes);
    }
    if (!cancelled)
    {
      // Ask for confirmation to disable.
      boolean disableADS = false;
      for (String dn : uData.getBaseDNs())
      {
        if (Utils.areDnsEqual(ADSContext.getAdministrationSuffixDN(), dn))
        {
          disableADS = true;
          break;
        }
      }
      if (disableADS)
      {
        cancelled = !confirm(INFO_REPLICATION_CONFIRM_DISABLE_ADS.get(
            ADSContext.getAdministrationSuffixDN()));
      }
      else
      {
        cancelled = !confirm(INFO_REPLICATION_CONFIRM_DISABLE_GENERIC.get());
      }
    }
    if (ctx != null)
    {
      try
      {
        ctx.close();
      }
      catch (Throwable t)
      {
      }
    }
    return cancelled;
  }
  /**
   * Updates the contents of the provided InitializeReplicationUserData object
   * with the information provided in the command-line.  If some information
   * is missing, ask the user to provide valid data.
   * We assume that if this method is called we are in interactive mode.
   * @param uData the object to be updated.
   * @return <CODE>true</CODE> if the object was successfully updated and
   * <CODE>false</CODE> if the user cancelled the operation.
   */
  private boolean promptIfRequired(InitializeReplicationUserData uData)
  {
    boolean cancelled = false;
    String adminPwd = argParser.getBindPasswordAdmin();
    String adminUid = argParser.getAdministratorUID();
    if (adminPwd == null)
    {
      adminPwd = askForAdministratorPwd();
    }
    /*
     * Try to connect to the source server.
     */
    String hostSource = getValue(argParser.getHostNameSource(),
        argParser.getDefaultHostNameSource());
    int portSource = getValue(argParser.getPortSource(),
        argParser.getDefaultPortSource());
    boolean useSSLSource = argParser.useSSLSource();
    boolean useStartTLSSource = argParser.useStartTLSSource();
    InitialLdapContext ctxSource = null;
    boolean firstTimeAsked =
      (argParser.getHostNameSource() == null) ||
      (argParser.getPortSource() == -1) ||
      (argParser.getAdministratorUID() == null) ||
      (argParser.getBindPasswordAdmin() == null);
    while ((ctxSource == null) && !cancelled)
    {
      try
      {
        ctxSource = createContext(hostSource, portSource, useSSLSource,
              useStartTLSSource, ADSContext.getAdministratorDN(adminUid),
              adminPwd, getTrustManager());
      }
      catch (NamingException ne)
      {
        LOG.log(Level.WARNING, "Error connecting to "+hostSource+":"+portSource,
            ne);
        if (Utils.isCertificateException(ne))
        {
          String usedUrl = getLDAPUrl(hostSource, portSource, useSSLSource);
          if (!promptForCertificateConfirmation(ne, getTrustManager(), usedUrl))
          {
            cancelled = true;
          }
        }
        else
        {
          printLineBreak();
          printErrorMessage(ERR_ERROR_CONNECTING_TO_SERVER_PROMPT_AGAIN.get(
              hostSource+":"+portSource));
          printLineBreak();
          if (!firstTimeAsked || (argParser.getHostNameSource() == null))
          {
            hostSource = promptForString(
                INFO_REPLICATION_INITIALIZE_HOSTNAMESOURCE_PROMPT.get(),
                getValue(hostSource, argParser.getDefaultHostNameSource()));
          }
          if (!firstTimeAsked || (argParser.getPortSource() == -1))
          {
            portSource = promptForPort(
              INFO_REPLICATION_INITIALIZE_PORTSOURCE_PROMPT.get(),
              getValue(portSource, argParser.getDefaultPortSource()));
          }
          if (!firstTimeAsked || (argParser.getAdministratorUID() == null))
          {
            adminUid = askForAdministratorUID(adminUid);
          }
          if (!firstTimeAsked || (argParser.getBindPasswordAdmin() == null))
          {
            adminPwd = askForAdministratorPwd();
          }
          if (!firstTimeAsked || useSSLSource)
          {
            useSSLSource = confirm(INFO_REPLICATION_USESSL_PROMPT.get(),
                useSSLSource);
            if (!useSSLSource)
            {
              useStartTLSSource =
                confirm(INFO_REPLICATION_USESTARTTLS_PROMPT.get(),
                    useStartTLSSource);
            }
          }
          firstTimeAsked = false;
        }
      }
    }
    if (!cancelled)
    {
      uData.setHostNameSource(hostSource);
      uData.setPortSource(portSource);
      uData.setUseSSLSource(useSSLSource);
      uData.setUseStartTLSSource(useStartTLSSource);
      uData.setAdminUid(adminUid);
      uData.setAdminPwd(adminPwd);
    }
    /*
     * Try to connect to the destination server.
     */
    String hostDestination = getValue(argParser.getHostNameDestination(),
        argParser.getDefaultHostNameDestination());
    int portDestination = getValue(argParser.getPortDestination(),
        argParser.getDefaultPortDestination());
    boolean useSSLDestination = argParser.useSSLDestination();
    boolean useStartTLSDestination = argParser.useStartTLSDestination();
    InitialLdapContext ctxDestination = null;
    firstTimeAsked =
      (argParser.getHostNameDestination() == null) ||
      (argParser.getPortDestination() == -1);
    while ((ctxDestination == null) && !cancelled)
    {
      try
      {
        ctxDestination = createContext(hostDestination, portDestination,
            useSSLDestination, useStartTLSDestination,
            ADSContext.getAdministratorDN(adminUid),
            adminPwd, getTrustManager());
      }
      catch (NamingException ne)
      {
        LOG.log(Level.WARNING, "Error connecting to "+hostDestination+":"+
            portDestination, ne);
        if (Utils.isCertificateException(ne))
        {
          String usedUrl = getLDAPUrl(hostDestination, portDestination,
              useSSLDestination);
          if (!promptForCertificateConfirmation(ne, getTrustManager(), usedUrl))
          {
            cancelled = true;
          }
        }
        else
        {
          printLineBreak();
          printErrorMessage(ERR_ERROR_CONNECTING_TO_SERVER_PROMPT_AGAIN.get(
              hostDestination+":"+portDestination));
          printLineBreak();
          if (!firstTimeAsked || (argParser.getHostNameDestination() == null))
          {
            hostDestination = promptForString(
                INFO_REPLICATION_INITIALIZE_HOSTNAMEDESTINATION_PROMPT.get(),
                getValue(hostDestination,
                    argParser.getDefaultHostNameDestination()));
          }
          if (!firstTimeAsked || (argParser.getPortDestination() == -1))
          {
            portDestination = promptForPort(
                INFO_REPLICATION_INITIALIZE_PORTDESTINATION_PROMPT.get(),
                getValue(portDestination,
                    argParser.getDefaultPortDestination()));
          }
          if (!firstTimeAsked || useSSLDestination)
          {
            useSSLDestination = confirm(INFO_REPLICATION_USESSL_PROMPT.get(),
                useSSLDestination);
            if (!useSSLDestination)
            {
              useStartTLSDestination =
                confirm(INFO_REPLICATION_USESTARTTLS_PROMPT.get(),
                    useStartTLSDestination);
            }
          }
        }
      }
    }
    if (!cancelled)
    {
      uData.setHostNameDestination(hostDestination);
      uData.setPortDestination(portDestination);
      uData.setUseSSLDestination(useSSLDestination);
      uData.setUseStartTLSDestination(useStartTLSDestination);
    }
    if (!cancelled)
    {
      LinkedList<String> suffixes = argParser.getBaseDNs();
      checkSuffixesForInitializeReplication(suffixes, ctxSource, ctxDestination,
          true);
      cancelled = suffixes.isEmpty();
      uData.setBaseDNs(suffixes);
    }
    if (!cancelled)
    {
      // Ask for confirmation to disable.
      boolean initializeADS = false;
      for (String dn : uData.getBaseDNs())
      {
        if (Utils.areDnsEqual(ADSContext.getAdministrationSuffixDN(), dn))
        {
          initializeADS = true;
          break;
        }
      }
      String hostPortSource = ConnectionUtils.getHostPort(ctxSource);
      String hostPortDestination = ConnectionUtils.getHostPort(ctxDestination);
      if (initializeADS)
      {
        cancelled = !confirm(INFO_REPLICATION_CONFIRM_INITIALIZE_ADS.get(
            ADSContext.getAdministrationSuffixDN(), hostPortDestination,
            hostPortSource));
      }
      else
      {
        cancelled = !confirm(INFO_REPLICATION_CONFIRM_INITIALIZE_GENERIC.get(
            hostPortDestination, hostPortSource));
      }
    }
    if (ctxSource != null)
    {
      try
      {
        ctxSource.close();
      }
      catch (Throwable t)
      {
      }
    }
    if (ctxDestination != null)
    {
      try
      {
        ctxDestination.close();
      }
      catch (Throwable t)
      {
      }
    }
    return cancelled;
  }
  /**
   * Commodity method that simply checks if a provided value is null or not,
   * if it is not <CODE>null</CODE> returns it and if it is <CODE>null</CODE>
   * returns the provided default value.
   * @param v the value to analyze.
   * @param defaultValue the default value.
   * @return if the provided value is not <CODE>null</CODE> returns it and if it
   * is <CODE>null</CODE> returns the provided default value.
   */
  private String getValue(String v, String defaultValue)
  {
    if (v != null)
    {
      return v;
    }
    else
    {
      return defaultValue;
    }
  }
  /**
   * Commodity method that simply checks if a provided value is -1 or not,
   * if it is not -1 returns it and if it is -1 returns the provided default
   * value.
   * @param v the value to analyze.
   * @param defaultValue the default value.
   * @return if the provided value is not -1 returns it and if it is -1 returns
   * the provided default value.
   */
  private int getValue(int v, int defaultValue)
  {
    if (v != -1)
    {
      return v;
    }
    else
    {
      return defaultValue;
    }
  }
  /**
   * Returns the trust manager to be used by this application.
   * @return the trust manager to be used by this application.
   */
  private ApplicationTrustManager getTrustManager()
  {
    return argParser.getTrustManager();
  }
  /**
   * Initializes the contents of the provided enable replication user data
   * object with what was provided in the command-line without prompting to the
   * user.
   * @param uData the enable replication user data object to be initialized.
   */
  private void initializeWithArgParser(EnableReplicationUserData uData)
  {
    uData.setBaseDNs(new LinkedList<String>(argParser.getBaseDNs()));
    String adminUid = getValue(argParser.getAdministratorUID(),
        argParser.getDefaultAdministratorUID());
    uData.setAdminUid(adminUid);
    String adminPwd = argParser.getBindPasswordAdmin();
    uData.setAdminPwd(adminPwd);
    String host1Name = getValue(argParser.getHostName1(),
        argParser.getDefaultHostName1());
    uData.setHostName1(host1Name);
    int port1 = getValue(argParser.getPort1(),
        argParser.getDefaultPort1());
    uData.setPort1(port1);
    uData.setUseSSL1(argParser.useSSL1());
    uData.setUseStartTLS1(argParser.useStartTLS1());
    String pwd1 = argParser.getBindPassword1();
    if (pwd1 == null)
    {
      uData.setBindDn1(ADSContext.getAdministratorDN(adminUid));
      uData.setPwd1(adminPwd);
    }
    else
    {
      String bindDn = getValue(argParser.getBindDn1(),
          argParser.getDefaultBindDn1());
      uData.setBindDn1(bindDn);
      uData.setPwd1(pwd1);
    }
    int replicationPort1 = getValue(argParser.getReplicationPort1(),
        argParser.getDefaultReplicationPort1());
    uData.setReplicationPort1(replicationPort1);
    String host2Name = getValue(argParser.getHostName2(),
        argParser.getDefaultHostName2());
    uData.setHostName2(host2Name);
    int port2 = getValue(argParser.getPort2(),
        argParser.getDefaultPort2());
    uData.setPort2(port2);
    uData.setUseSSL2(argParser.useSSL2());
    uData.setUseStartTLS2(argParser.useStartTLS2());
    String pwd2 = argParser.getBindPassword2();
    if (pwd2 == null)
    {
      uData.setBindDn2(ADSContext.getAdministratorDN(adminUid));
      uData.setPwd2(adminPwd);
    }
    else
    {
      String bindDn = getValue(argParser.getBindDn2(),
          argParser.getDefaultBindDn2());
      uData.setBindDn2(bindDn);
      uData.setPwd2(pwd2);
    }
    uData.setReplicationPort1(replicationPort1);
  }
  /**
   * Initializes the contents of the provided initialize replication user data
   * object with what was provided in the command-line without prompting to the
   * user.
   * @param uData the initialize replication user data object to be initialized.
   */
  private void initializeWithArgParser(InitializeReplicationUserData uData)
  {
    uData.setBaseDNs(new LinkedList<String>(argParser.getBaseDNs()));
    String adminUid = getValue(argParser.getAdministratorUID(),
        argParser.getDefaultAdministratorUID());
    uData.setAdminUid(adminUid);
    String adminPwd = argParser.getBindPasswordAdmin();
    uData.setAdminPwd(adminPwd);
    String hostNameSource = getValue(argParser.getHostNameSource(),
        argParser.getDefaultHostNameSource());
    uData.setHostNameSource(hostNameSource);
    int portSource = getValue(argParser.getPortSource(),
        argParser.getDefaultPortSource());
    uData.setPortSource(portSource);
    uData.setUseSSLSource(argParser.useSSLSource());
    uData.setUseStartTLSSource(argParser.useStartTLSSource());
    String hostNameDestination = getValue(
        argParser.getHostNameDestination(),
        argParser.getDefaultHostNameDestination());
    uData.setHostNameDestination(hostNameDestination);
    int portDestination = getValue(argParser.getPortSource(),
        argParser.getDefaultPortDestination());
    uData.setPortDestination(portDestination);
    uData.setUseSSLDestination(argParser.useSSLDestination());
    uData.setUseStartTLSDestination(argParser.useStartTLSDestination());
  }
  /**
   * Initializes the contents of the provided disable replication user data
   * object with what was provided in the command-line without prompting to the
   * user.
   * @param uData the disable replication user data object to be initialized.
   */
  private void initializeWithArgParser(DisableReplicationUserData uData)
  {
    uData.setBaseDNs(new LinkedList<String>(argParser.getBaseDNs()));
    String adminUid = getValue(argParser.getAdministratorUID(),
        argParser.getDefaultAdministratorUID());
    uData.setAdminUid(adminUid);
    String adminPwd = argParser.getBindPasswordAdmin();
    uData.setAdminPwd(adminPwd);
    String hostName = getValue(argParser.getHostNameToDisable(),
        argParser.getDefaultHostNameToDisable());
    uData.setHostName(hostName);
    int port = getValue(argParser.getPortToDisable(),
        argParser.getDefaultPortToDisable());
    uData.setPort(port);
    uData.setUseSSL(argParser.useSSLToDisable());
    uData.setUseStartTLS(argParser.useStartTLSToDisable());
  }
  /**
   * Returns an InitialLdapContext using the provided parameters.  We try
   * to guarantee that the connection is able to read the configuration.
   * @param host the host name.
   * @param port the port to connect.
   * @param useSSL whether to use SSL or not.
   * @param useStartTLS whether to use StartTLS or not.
   * @param bindDn the bind dn to be used.
   * @param pwd the password.
   * @param trustManager the trust manager.
   * @return an InitialLdapContext connected.
   * @throws NamingException if there was an error establishing the connection.
   */
  private InitialLdapContext createContext(String host, int port,
      boolean useSSL, boolean useStartTLS, String bindDn, String pwd,
      ApplicationTrustManager trustManager)
  throws NamingException
  {
    InitialLdapContext ctx;
    String ldapUrl = getLDAPUrl(host, port, useSSL);
    if (useSSL)
    {
      ctx = Utils.createLdapsContext(ldapUrl, bindDn, pwd,
          Utils.getDefaultLDAPTimeout(), null, trustManager);
    }
    else if (useStartTLS)
    {
      ctx = Utils.createStartTLSContext(ldapUrl, bindDn, pwd,
          Utils.getDefaultLDAPTimeout(), null, trustManager,
          null);
    }
    else
    {
      ctx = Utils.createLdapContext(ldapUrl, bindDn, pwd,
          Utils.getDefaultLDAPTimeout(), null);
    }
    if (!ConnectionUtils.connectedAsAdministrativeUser(ctx))
    {
      throw new NoPermissionException(
          ERR_NOT_ADMINISTRATIVE_USER.get().toString());
    }
    return ctx;
  }
  /**
   * Returns the LDAP URL for the provided parameters.
   * @param host the host name.
   * @param port the LDAP port.
   * @param useSSL whether to use SSL or not.
   * @return the LDAP URL for the provided parameters.
   */
  private String getLDAPUrl(String host, int port, boolean useSSL)
  {
    String ldapUrl;
    host = Utils.getHostNameForLdapUrl(host);
    if (useSSL)
    {
      ldapUrl = "ldaps://"+host+":"+port;
    }
    else
    {
      ldapUrl = "ldap://"+host+":"+port;
    }
    return ldapUrl;
  }
  /**
   * Tells whether the server to which the LdapContext is connected has a
   * replication port or not.
   * @param ctx the InitialLdapContext to be used.
   * @return <CODE>true</CODE> if the replication port for the server could
   * be found and <CODE>false</CODE> otherwise.
   */
  private boolean hasReplicationPort(InitialLdapContext ctx)
  {
    return getReplicationPort(ctx) != -1;
  }
  /**
   * Returns the replication port of server to which the LdapContext is
   * connected and -1 if the replication port could not be found.
   * @param ctx the InitialLdapContext to be used.
   * @return the replication port of server to which the LdapContext is
   * connected and -1 if the replication port could not be found.
   */
  private int getReplicationPort(InitialLdapContext ctx)
  {
    int replicationPort = -1;
    try
    {
      ManagementContext mCtx = LDAPManagementContext.createFromContext(
          JNDIDirContextAdaptor.adapt(ctx));
      RootCfgClient root = mCtx.getRootConfiguration();
      MultimasterSynchronizationProviderCfgClient sync = null;
      sync = (MultimasterSynchronizationProviderCfgClient)
      root.getSynchronizationProvider("Multimaster Synchronization");
      /*
       * Configure the replication server.
       */
      if (sync.hasReplicationServer())
      {
        ReplicationServerCfgClient replicationServer =
          sync.getReplicationServer();
        replicationPort = replicationServer.getReplicationPort();
      }
    }
    catch (Throwable t)
    {
      LOG.log(Level.WARNING,
          "Unexpected error retrieving the replication port: "+t, t);
    }
    return replicationPort;
  }
  /**
   * Loads the ADS with the provided context.  If there are certificates to
   * be accepted we prompt them to the user.  If there are errors loading the
   * servers we display them to the user and we ask for confirmation.  If the
   * provided ctx is not using Global Administrator credentials, we prompt the
   * user to provide them and update the provide ReplicationUserData
   * accordingly.
   * @param ctx the Ldap context to be used.
   * @param uData the ReplicationUserData to be udpated.
   * @param isFirstOrSourceServer whether this is the first server in the
   * enable replication subcommand or the source server in the initialize server
   * subcommand.
   * @return <CODE>true</CODE> if everything went fine and the user accepted
   * all the certificates and confirmed everything.  Returns <CODE>false</CODE>
   * if a critical error occurred or the user did not accept a certificate or
   * any of the confirmation messages.
   */
  private boolean loadADSAndAcceptCertificates(InitialLdapContext ctx,
      ReplicationUserData uData, boolean isFirstOrSourceServer)
  {
    boolean cancelled = false;
    boolean triedWithUserProvidedAdmin = false;
    String host = ConnectionUtils.getHostName(ctx);
    int port = ConnectionUtils.getPort(ctx);
    boolean isSSL = ConnectionUtils.isSSL(ctx);
    boolean isStartTLS = ConnectionUtils.isStartTLS(ctx);
    try
    {
      ADSContext adsContext = new ADSContext(ctx);
      if (adsContext.hasAdminData())
      {
        TopologyCache cache = new TopologyCache(adsContext, getTrustManager());
        boolean reloadTopology = true;
        LinkedList<Message> exceptionMsgs = new LinkedList<Message>();
        while (reloadTopology && !cancelled)
        {
          cache.reloadTopology();
          reloadTopology = false;
          exceptionMsgs.clear();
          /* Analyze if we had any exception while loading servers.  For the
           * moment only throw the exception found if the user did not provide
           * the Administrator DN and this caused a problem authenticating in
           * one server or if there is a certificate problem.
           */
          Set<TopologyCacheException> exceptions =
            new HashSet<TopologyCacheException>();
          Set<ServerDescriptor> servers = cache.getServers();
          for (ServerDescriptor server : servers)
          {
            TopologyCacheException e = server.getLastException();
            if (e != null)
            {
              exceptions.add(e);
            }
          }
          /* Check the exceptions and see if we throw them or not. */
          for (TopologyCacheException e : exceptions)
          {
            switch (e.getType())
            {
              case NOT_GLOBAL_ADMINISTRATOR:
                printLineBreak();
                printErrorMessage(INFO_NOT_GLOBAL_ADMINISTRATOR_PROVIDED.get());
                boolean connected = false;
                String adminUid = uData.getAdminUid();
                String adminPwd = uData.getAdminPwd();
                while (!connected)
                {
                  if ((!triedWithUserProvidedAdmin) && (adminPwd == null))
                  {
                    adminUid = getValue(argParser.getAdministratorUID(),
                        argParser.getDefaultAdministratorUID());
                    adminPwd = argParser.getBindPasswordAdmin();
                    triedWithUserProvidedAdmin = true;
                  }
                  if (adminPwd == null)
                  {
                    adminUid = askForAdministratorUID(
                        argParser.getDefaultAdministratorUID());
                    adminPwd = askForAdministratorPwd();
                  }
                  try
                  {
                    ctx.close();
                  }
                  catch (Throwable t)
                  {
                  }
                  try
                  {
                    ctx = createContext(host, port, isSSL, isStartTLS,
                        ADSContext.getAdministratorDN(adminUid), adminPwd,
                        getTrustManager());
                    adsContext = new ADSContext(ctx);
                    cache = new TopologyCache(adsContext, getTrustManager());
                  }
                  catch (Throwable t)
                  {
                    printLineBreak();
                    printErrorMessage(
                        ERR_ERROR_CONNECTING_TO_SERVER_PROMPT_AGAIN.get(
                        host+":"+port));
                    LOG.log(Level.WARNING, "Complete error stack:", t);
                    printLineBreak();
                  }
                }
                uData.setAdminUid(adminUid);
                uData.setAdminPwd(adminPwd);
                if (uData instanceof EnableReplicationUserData)
                {
                  EnableReplicationUserData enableData =
                    (EnableReplicationUserData)uData;
                  if (isFirstOrSourceServer)
                  {
                    enableData.setBindDn1(
                        ADSContext.getAdministratorDN(adminUid));
                    enableData.setPwd1(adminPwd);
                  }
                  else
                  {
                    enableData.setBindDn2(
                        ADSContext.getAdministratorDN(adminUid));
                    enableData.setPwd2(adminPwd);
                  }
                }
                reloadTopology = true;
              break;
            case GENERIC_CREATING_CONNECTION:
              if ((e.getCause() != null) &&
                  Utils.isCertificateException(e.getCause()))
              {
                reloadTopology = true;
                cancelled = !promptForCertificateConfirmation(e.getCause(),
                      getTrustManager(), e.getLdapUrl());
              }
              else
              {
                exceptionMsgs.add(Utils.getMessage(e));
              }
              break;
            default:
              exceptionMsgs.add(Utils.getMessage(e));
            }
          }
        }
        if ((exceptionMsgs.size() > 0) && !cancelled)
        {
          cancelled = !confirm(
              ERR_REPLICATION_READING_REGISTERED_SERVERS_CONFIRM_UPDATE_REMOTE.
              get(Utils.getMessageFromCollection(exceptionMsgs,
                    Constants.LINE_SEPARATOR).toString()));
        }
      }
    }
    catch (ADSContextException ace)
    {
      printLineBreak();
      printErrorMessage(Utils.getThrowableMsg(INFO_BUG_MSG.get(), ace));
      LOG.log(Level.SEVERE, "Complete error stack:", ace);
      cancelled = true;
    }
    catch (TopologyCacheException tce)
    {
      printLineBreak();
      printErrorMessage(Utils.getMessage(tce));
      LOG.log(Level.SEVERE, "Complete error stack:", tce);
      cancelled = true;
    }
    return !cancelled;
  }
  /**
   * Tells whether there is a Global Administrator defined in the server
   * to which the InitialLdapContext is connected.
   * @param ctx the InitialLdapContext.
   * @return <CODE>true</CODE> if we could find an administrator and
   * <CODE>false</CODE> otherwise.
   */
  private boolean hasAdministrator(InitialLdapContext ctx)
  {
    boolean isAdminDefined = false;
    try
    {
      ADSContext adsContext = new ADSContext(ctx);
      if (adsContext.hasAdminData())
      {
        Set administrators = adsContext.readAdministratorRegistry();
        isAdminDefined = administrators.size() > 0;
      }
    }
    catch (Throwable t)
    {
      LOG.log(Level.WARNING,
          "Unexpected error retrieving the ADS data: "+t, t);
    }
    return isAdminDefined;
  }
  /**
   * Returns a Collection containing a list of suffixes that are defined in
   * two servers at the same time (depending on the value of the argument
   * replicated this list contains only the suffixes that are replicated
   * between the servers or the list of suffixes that are not replicated
   * between the servers).
   * @param ctx1 the connection to the first server.
   * @param ctx2 the connection to the second server.
   * @param type whether to return a list with the suffixes that are
   * replicated, fully replicated (replicas have exactly the same list of
   * replication servers), not replicated or all the common suffixes.
   * @return a Collection containing a list of suffixes that are replicated
   * (or those that can be replicated) in two servers.
   */
  private enum SuffixRelationType
  {
    NOT_REPLICATED, FULLY_REPLICATED, REPLICATED, NOT_FULLY_REPLICATED, ALL
  };
  private Collection<String> getCommonSuffixes(
      InitialLdapContext ctx1, InitialLdapContext ctx2, SuffixRelationType type)
  {
    LinkedList<String> suffixes = new LinkedList<String>();
    try
    {
      ServerDescriptor server1 = ServerDescriptor.createStandalone(ctx1);
      ServerDescriptor server2 = ServerDescriptor.createStandalone(ctx2);
      Set<ReplicaDescriptor> replicas1 = server1.getReplicas();
      Set<ReplicaDescriptor> replicas2 = server2.getReplicas();
      for (ReplicaDescriptor rep1 : replicas1)
      {
        for (ReplicaDescriptor rep2 : replicas2)
        {
          switch (type)
          {
          case NOT_REPLICATED:
            if (!areReplicated(rep1, rep2))
            {
              suffixes.add(rep1.getSuffix().getDN());
            }
            break;
          case FULLY_REPLICATED:
            if (areFullyReplicated(rep1, rep2))
            {
              suffixes.add(rep1.getSuffix().getDN());
            }
            break;
          case REPLICATED:
            if (areReplicated(rep1, rep2))
            {
              suffixes.add(rep1.getSuffix().getDN());
            }
            break;
          case NOT_FULLY_REPLICATED:
            if (!areFullyReplicated(rep1, rep2))
            {
              suffixes.add(rep1.getSuffix().getDN());
            }
            break;
          case ALL:
            if (Utils.areDnsEqual(rep1.getSuffix().getDN(),
                rep2.getSuffix().getDN()))
            {
              suffixes.add(rep1.getSuffix().getDN());
            }
            break;
            default:
              throw new IllegalStateException("Unknown type: "+type);
          }
        }
      }
    }
    catch (Throwable t)
    {
      LOG.log(Level.WARNING,
          "Unexpected error retrieving the server configuration: "+t, t);
    }
    return suffixes;
  }
  /**
   * Tells whether the two provided replicas are fully replicated or not.  The
   * code in fact checks that both replicas have the same DN that they are
   * replicated if both servers are replication servers and that both replicas
   * make reference to the other replication server.
   * @param rep1 the first replica.
   * @param rep2 the second replica.
   * @return <CODE>true</CODE> if we can assure that the two replicas are
   * replicated using the replication server and replication port information
   * and <CODE>false</CODE> otherwise.
   */
  private boolean areFullyReplicated(ReplicaDescriptor rep1,
      ReplicaDescriptor rep2)
  {
    boolean areFullyReplicated = false;
    if (Utils.areDnsEqual(rep1.getSuffix().getDN(), rep2.getSuffix().getDN()) &&
        rep1.isReplicated() && rep2.isReplicated() &&
        rep1.getServer().isReplicationServer() &&
        rep2.getServer().isReplicationServer())
    {
     Set<String> servers1 = rep1.getReplicationServers();
     Set<String> servers2 = rep2.getReplicationServers();
     String server1 = rep1.getServer().getReplicationServerHostPort();
     String server2 = rep2.getServer().getReplicationServerHostPort();
     areFullyReplicated = servers1.contains(server2) &&
     servers2.contains(server1);
    }
    return areFullyReplicated;
  }
  /**
   * Tells whether the two provided replicas are replicated or not.  The
   * code in fact checks that both replicas have the same DN and that they
   * have at least one common replication server referenced.
   * @param rep1 the first replica.
   * @param rep2 the second replica.
   * @return <CODE>true</CODE> if we can assure that the two replicas are
   * replicated and <CODE>false</CODE> otherwise.
   */
  private boolean areReplicated(ReplicaDescriptor rep1, ReplicaDescriptor rep2)
  {
    boolean areReplicated = false;
    if (Utils.areDnsEqual(rep1.getSuffix().getDN(), rep2.getSuffix().getDN()) &&
        rep1.isReplicated() && rep2.isReplicated())
    {
      Set<String> servers1 = rep1.getReplicationServers();
      Set<String> servers2 = rep2.getReplicationServers();
      servers1.retainAll(servers2);
      areReplicated = !servers1.isEmpty();
    }
    return areReplicated;
  }
  /**
   * Returns a Collection containing a list of replicas in a server.
   * @param ctx the connection to the server.
   * @return a Collection containing a list of replicas in a server.
   */
  private Collection<ReplicaDescriptor> getReplicas(InitialLdapContext ctx)
  {
    LinkedList<ReplicaDescriptor> suffixes =
      new LinkedList<ReplicaDescriptor>();
    try
    {
      ServerDescriptor server = ServerDescriptor.createStandalone(ctx);
      suffixes.addAll(server.getReplicas());
    }
    catch (Throwable t)
    {
      LOG.log(Level.WARNING,
          "Unexpected error retrieving the server configuration: "+t, t);
    }
    return suffixes;
  }
  /**
   * Enables the replication between two servers using the parameters in the
   * provided EnableReplicationUserData.  This method does not prompt to the
   * user for information if something is missing.
   * @param uData the EnableReplicationUserData object.
   * @return ReplicationCliReturnCode.SUCCESSFUL if the operation was
   * successful.
   * and the replication could be enabled and an error code otherwise.
   */
  private ReplicationCliReturnCode enableReplication(
      EnableReplicationUserData uData)
  {
    ReplicationCliReturnCode returnValue = SUCCESSFUL_NOP;
    InitialLdapContext ctx1 = null;
    InitialLdapContext ctx2 = null;
    printProgressMessage(
        formatter.getFormattedWithPoints(INFO_REPLICATION_CONNECTING.get()));
    try
    {
      ctx1 = createContext(uData.getHostName1(), uData.getPort1(),
          uData.useSSL1(), uData.useStartTLS1(), uData.getBindDn1(),
          uData.getPwd1(), getTrustManager());
    }
    catch (NamingException ne)
    {
      String hostPort = uData.getHostName1()+":"+uData.getPort1();
      printLineBreak();
      printErrorMessage(getMessageForException(ne, hostPort));
      LOG.log(Level.SEVERE, "Complete error stack:", ne);
    }
    try
    {
      ctx2 = createContext(uData.getHostName2(), uData.getPort2(),
          uData.useSSL2(), uData.useStartTLS2(), uData.getBindDn2(),
          uData.getPwd2(), getTrustManager());
    }
    catch (NamingException ne)
    {
      String hostPort = uData.getHostName2()+":"+uData.getPort2();
      printLineBreak();
      printErrorMessage(getMessageForException(ne, hostPort));
      LOG.log(Level.SEVERE, "Complete error stack:", ne);
    }
    if ((ctx1 != null) && (ctx2 != null))
    {
      // This done is for the message informing that we are connecting.
      printProgressMessage(formatter.getFormattedDone());
      printProgressMessage(formatter.getLineBreak());
      LinkedList<String> suffixes = uData.getBaseDNs();
      checkSuffixesForEnableReplication(suffixes, ctx1, ctx2, false);
      if (!suffixes.isEmpty())
      {
        uData.setBaseDNs(suffixes);
        try
        {
          updateConfiguration(ctx1, ctx2, uData);
          returnValue = SUCCESSFUL;
        }
        catch (ReplicationCliException rce)
        {
          returnValue = rce.getErrorCode();
          printLineBreak();
          printErrorMessage(rce.getMessageObject());
          LOG.log(Level.SEVERE, "Complete error stack:", rce);
        }
      }
      else
      {
        // The error messages are already displayed in the method
        // checkSuffixesForEnableReplication.
        returnValue = REPLICATION_CANNOT_BE_ENABLED_ON_BASEDN;
      }
    }
    else
    {
      returnValue = ERROR_CONNECTING;
    }
    if (ctx1 != null)
    {
      try
      {
        ctx1.close();
      }
      catch (Throwable t)
      {
      }
    }
    if (ctx2 != null)
    {
      try
      {
        ctx2.close();
      }
      catch (Throwable t)
      {
      }
    }
    return returnValue;
  }
  /**
   * Disbles the replication in the server for the provided suffixes using the
   * data in the DisableReplicationUserData object.  This method does not prompt
   * to the user for information if something is missing.
   * @param uData the DisableReplicationUserData object.
   * @return ReplicationCliReturnCode.SUCCESSFUL if the operation was
   * successful.
   * and the replication could be enabled and an error code otherwise.
   */
  private ReplicationCliReturnCode disableReplication(
      DisableReplicationUserData uData)
  {
    ReplicationCliReturnCode returnValue = SUCCESSFUL_NOP;
    InitialLdapContext ctx = null;
    printProgressMessage(
        formatter.getFormattedWithPoints(INFO_REPLICATION_CONNECTING.get()));
    try
    {
      ctx = createContext(uData.getHostName(), uData.getPort(),
          uData.useSSL(), uData.useStartTLS(),
          ADSContext.getAdministratorDN(uData.getAdminUid()),
          uData.getAdminPwd(), getTrustManager());
    }
    catch (NamingException ne)
    {
      String hostPort = uData.getHostName()+":"+uData.getPort();
      printLineBreak();
      printErrorMessage(getMessageForException(ne, hostPort));
      LOG.log(Level.SEVERE, "Complete error stack:", ne);
    }
    if (ctx != null)
    {
      // This done is for the message informing that we are connecting.
      printProgressMessage(formatter.getFormattedDone());
      printProgressMessage(formatter.getLineBreak());
      LinkedList<String> suffixes = uData.getBaseDNs();
      checkSuffixesForDisableReplication(suffixes, ctx, false);
      if (!suffixes.isEmpty())
      {
        uData.setBaseDNs(suffixes);
        try
        {
          updateConfiguration(ctx, uData);
          returnValue = SUCCESSFUL;
        }
        catch (ReplicationCliException rce)
        {
          returnValue = rce.getErrorCode();
          printLineBreak();
          printErrorMessage(rce.getMessageObject());
          LOG.log(Level.SEVERE, "Complete error stack:", rce);
        }
      }
      else
      {
        returnValue = REPLICATION_CANNOT_BE_DISABLED_ON_BASEDN;
      }
    }
    else
    {
      returnValue = ERROR_CONNECTING;
    }
    if (ctx != null)
    {
      try
      {
        ctx.close();
      }
      catch (Throwable t)
      {
      }
    }
    return returnValue;
  }
  /**
   * Initializes the contents of one server with the contents of the other
   * using the parameters in the provided InitializeReplicationUserData.
   * This method does not prompt to the user for information if something is
   * missing.
   * @param uData the InitializeReplicationUserData object.
   * @return ReplicationCliReturnCode.SUCCESSFUL if the operation was
   * successful.
   * and the replication could be enabled and an error code otherwise.
   */
  private ReplicationCliReturnCode initializeReplication(
      InitializeReplicationUserData uData)
  {
    ReplicationCliReturnCode returnValue = SUCCESSFUL_NOP;
    InitialLdapContext ctxSource = null;
    InitialLdapContext ctxDestination = null;
    try
    {
      ctxSource = createContext(uData.getHostNameSource(),
          uData.getPortSource(), uData.useSSLSource(),
          uData.useStartTLSSource(),
          ADSContext.getAdministratorDN(uData.getAdminUid()),
          uData.getAdminPwd(), getTrustManager());
    }
    catch (NamingException ne)
    {
      String hostPort = uData.getHostNameSource()+":"+uData.getPortSource();
      printLineBreak();
      printErrorMessage(getMessageForException(ne, hostPort));
      LOG.log(Level.SEVERE, "Complete error stack:", ne);
    }
    try
    {
      ctxDestination = createContext(uData.getHostNameDestination(),
          uData.getPortDestination(), uData.useSSLDestination(),
          uData.useStartTLSDestination(),
          ADSContext.getAdministratorDN(uData.getAdminUid()),
          uData.getAdminPwd(), getTrustManager());
    }
    catch (NamingException ne)
    {
      String hostPort = uData.getHostNameDestination()+":"+
      uData.getPortDestination();
      printLineBreak();
      printErrorMessage(getMessageForException(ne, hostPort));
      LOG.log(Level.SEVERE, "Complete error stack:", ne);
    }
    if ((ctxSource != null) && (ctxDestination != null))
    {
      LinkedList<String> baseDNs = uData.getBaseDNs();
      checkSuffixesForInitializeReplication(baseDNs, ctxSource, ctxDestination,
          false);
      if (!baseDNs.isEmpty())
      {
        for (String baseDN : baseDNs)
        {
          try
          {
            Message msg = formatter.getFormattedProgress(
                INFO_PROGRESS_INITIALIZING_SUFFIX.get(baseDN,
                    ConnectionUtils.getHostPort(ctxDestination)));
            printProgressMessage(msg);
            printProgressLineBreak();
            initializeSuffix(baseDN, ctxSource, ctxDestination, true);
          }
          catch (ReplicationCliException rce)
          {
            printLineBreak();
            printErrorMessage(rce.getMessageObject());
            returnValue = rce.getErrorCode();
            LOG.log(Level.SEVERE, "Complete error stack:", rce);
          }
        }
      }
      else
      {
        returnValue = REPLICATION_CANNOT_BE_INITIALIZED_ON_BASEDN;
      }
    }
    else
    {
      returnValue = ERROR_CONNECTING;
    }
    if (ctxSource != null)
    {
      try
      {
        ctxSource.close();
      }
      catch (Throwable t)
      {
      }
    }
    if (ctxDestination != null)
    {
      try
      {
        ctxDestination.close();
      }
      catch (Throwable t)
      {
      }
    }
    return returnValue;
  }
  /**
   * Checks that replication can actually be enabled in the provided baseDNs
   * for the two servers.
   * @param suffixes the suffixes provided by the user.  This Collection is
   * updated by removing the base DNs that cannot be enabled and with the
   * base DNs that the user provided interactively.
   * @param ctx1 connection to the first server.
   * @param ctx2 connection to the second server.
   * @param interactive whether to ask the user to provide interactively
   * base DNs if none of the provided base DNs can be enabled.
   */
  private void checkSuffixesForEnableReplication(Collection<String> suffixes,
      InitialLdapContext ctx1, InitialLdapContext ctx2,
      boolean interactive)
  {
    boolean cancelled = false;
    TreeSet<String> availableSuffixes =
      new TreeSet<String>(getCommonSuffixes(ctx1, ctx2,
          SuffixRelationType.NOT_FULLY_REPLICATED));
    TreeSet<String> alreadyReplicatedSuffixes =
      new TreeSet<String>(getCommonSuffixes(ctx1, ctx2,
          SuffixRelationType.FULLY_REPLICATED));
    if (availableSuffixes.size() == 0)
    {
      printLineBreak();
      printErrorMessage(
          ERR_NO_SUFFIXES_AVAILABLE_TO_ENABLE_REPLICATION.get());
      LinkedList<String> userProvidedSuffixes = argParser.getBaseDNs();
      TreeSet<String> userProvidedReplicatedSuffixes = new TreeSet<String>();
      for (String s1 : userProvidedSuffixes)
      {
        for (String s2 : alreadyReplicatedSuffixes)
        {
          if (Utils.areDnsEqual(s1, s2))
          {
            userProvidedReplicatedSuffixes.add(s1);
          }
        }
      }
      if (userProvidedReplicatedSuffixes.size() > 0)
      {
        printErrorMessage(
            INFO_ALREADY_REPLICATED_SUFFIXES.get(
                Utils.getStringFromCollection(userProvidedReplicatedSuffixes,
                    Constants.LINE_SEPARATOR)));
      }
      cancelled = true;
    }
    //  Verify that the provided suffixes are configured in the servers.
    if (!cancelled)
    {
      TreeSet<String> notFound = new TreeSet<String>();
      TreeSet<String> alreadyReplicated = new TreeSet<String>();
      for (String dn : suffixes)
      {
        boolean found = false;
        for (String dn1 : availableSuffixes)
        {
          if (Utils.areDnsEqual(dn, dn1))
          {
            found = true;
            break;
          }
        }
        if (!found)
        {
          boolean isReplicated = false;
          for (String s : alreadyReplicatedSuffixes)
          {
            if (Utils.areDnsEqual(s, dn))
            {
              isReplicated = true;
              break;
            }
          }
          if (isReplicated)
          {
            alreadyReplicated.add(dn);
          }
          else
          {
            notFound.add(dn);
          }
        }
      }
      suffixes.removeAll(notFound);
      suffixes.removeAll(alreadyReplicated);
      if (notFound.size() > 0)
      {
        printLineBreak();
        printErrorMessage(ERR_REPLICATION_ENABLE_SUFFIXES_NOT_FOUND.get(
              Utils.getStringFromCollection(notFound,
                  Constants.LINE_SEPARATOR)));
      }
      if (alreadyReplicated.size() > 0)
      {
        printLineBreak();
        printErrorMessage(INFO_ALREADY_REPLICATED_SUFFIXES.get(
            Utils.getStringFromCollection(alreadyReplicated,
                Constants.LINE_SEPARATOR)));
      }
      if (interactive)
      {
        while (suffixes.isEmpty())
        {
          printLineBreak();
          printErrorMessage(ERR_NO_SUFFIXES_SELECTED_TO_REPLICATE.get());
          for (String dn : availableSuffixes)
          {
            if (confirm(INFO_REPLICATION_ENABLE_SUFFIX_PROMPT.get(dn)))
            {
              suffixes.add(dn);
            }
          }
        }
      }
      else if (suffixes.isEmpty())
      {
        cancelled = true;
      }
    }
  }
  /**
   * Checks that replication can actually be disabled in the provided baseDNs
   * for the server.
   * @param suffixes the suffixes provided by the user.  This Collection is
   * updated by removing the base DNs that cannot be enabled and with the
   * base DNs that the user provided interactively.
   * @param ctx connection to the server.
   * @param interactive whether to ask the user to provide interactively
   * base DNs if none of the provided base DNs can be disabled.
   */
  private void checkSuffixesForDisableReplication(Collection<String> suffixes,
      InitialLdapContext ctx, boolean interactive)
  {
    boolean cancelled = false;
    TreeSet<String> availableSuffixes = new TreeSet<String>();
    TreeSet<String> notReplicatedSuffixes = new TreeSet<String>();
    Collection<ReplicaDescriptor> replicas = getReplicas(ctx);
    for (ReplicaDescriptor rep : replicas)
    {
      String dn = rep.getSuffix().getDN();
      if (rep.isReplicated())
      {
        availableSuffixes.add(dn);
      }
      else
      {
        notReplicatedSuffixes.add(dn);
      }
    }
    if (availableSuffixes.size() == 0)
    {
      printLineBreak();
      printErrorMessage(
          ERR_NO_SUFFIXES_AVAILABLE_TO_DISABLE_REPLICATION.get());
      LinkedList<String> userProvidedSuffixes = argParser.getBaseDNs();
      TreeSet<String> userProvidedNotReplicatedSuffixes =
        new TreeSet<String>();
      for (String s1 : userProvidedSuffixes)
      {
        for (String s2 : notReplicatedSuffixes)
        {
          if (Utils.areDnsEqual(s1, s2))
          {
            userProvidedNotReplicatedSuffixes.add(s1);
          }
        }
      }
      if (userProvidedNotReplicatedSuffixes.size() > 0)
      {
        printErrorMessage(
            INFO_ALREADY_NOT_REPLICATED_SUFFIXES.get(
                Utils.getStringFromCollection(
                    userProvidedNotReplicatedSuffixes,
                    Constants.LINE_SEPARATOR)));
      }
      cancelled = true;
    }
    if (!cancelled)
    {
      // Verify that the provided suffixes are configured in the servers.
      TreeSet<String> notFound = new TreeSet<String>();
      TreeSet<String> alreadyNotReplicated = new TreeSet<String>();
      for (String dn : suffixes)
      {
        boolean found = false;
        for (String dn1 : availableSuffixes)
        {
          if (Utils.areDnsEqual(dn, dn1))
          {
            found = true;
            break;
          }
        }
        if (!found)
        {
          boolean notReplicated = false;
          for (String s : notReplicatedSuffixes)
          {
            if (Utils.areDnsEqual(s, dn))
            {
              notReplicated = true;
              break;
            }
          }
          if (notReplicated)
          {
            alreadyNotReplicated.add(dn);
          }
          else
          {
            notFound.add(dn);
          }
        }
      }
      suffixes.removeAll(notFound);
      suffixes.removeAll(alreadyNotReplicated);
      if (notFound.size() > 0)
      {
        printLineBreak();
        printErrorMessage(ERR_REPLICATION_DISABLE_SUFFIXES_NOT_FOUND.get(
                Utils.getStringFromCollection(notFound,
                    Constants.LINE_SEPARATOR)));
      }
      if (alreadyNotReplicated.size() > 0)
      {
        printLineBreak();
        printErrorMessage(INFO_ALREADY_NOT_REPLICATED_SUFFIXES.get(
                Utils.getStringFromCollection(alreadyNotReplicated,
                    Constants.LINE_SEPARATOR)));
      }
      if (interactive)
      {
        while (suffixes.isEmpty())
        {
          printLineBreak();
          printErrorMessage(ERR_NO_SUFFIXES_SELECTED_TO_DISABLE.get());
          for (String dn : availableSuffixes)
          {
            if (confirm(INFO_REPLICATION_DISABLE_SUFFIX_PROMPT.get(dn)))
            {
              suffixes.add(dn);
            }
          }
        }
      }
    }
  }
  /**
   * Checks that we can initialize the provided baseDNs between the two servers.
   * @param suffixes the suffixes provided by the user.  This Collection is
   * updated by removing the base DNs that cannot be enabled and with the
   * base DNs that the user provided interactively.
   * @param ctxSource connection to the source server.
   * @param ctxDestination connection to the destination server.
   * @param interactive whether to ask the user to provide interactively
   * base DNs if none of the provided base DNs can be initialized.
   */
  private void checkSuffixesForInitializeReplication(
      Collection<String> suffixes, InitialLdapContext ctxSource,
      InitialLdapContext ctxDestination, boolean interactive)
  {
    boolean cancelled = false;
    TreeSet<String> availableSuffixes = new TreeSet<String>(
        getCommonSuffixes(ctxSource, ctxDestination,
            SuffixRelationType.REPLICATED));
    if (availableSuffixes.size() == 0)
    {
      printLineBreak();
      printErrorMessage(
          ERR_NO_SUFFIXES_AVAILABLE_TO_INITIALIZE_REPLICATION.get());
      cancelled = true;
    }
    if (!cancelled)
    {
      // Verify that the provided suffixes are configured in the servers.
      LinkedList<String> notFound = new LinkedList<String>();
      for (String dn : suffixes)
      {
        boolean found = false;
        for (String dn1 : availableSuffixes)
        {
          if (Utils.areDnsEqual(dn, dn1))
          {
            found = true;
            break;
          }
        }
        if (!found)
        {
          notFound.add(dn);
        }
      }
      suffixes.removeAll(notFound);
      if (notFound.size() > 0)
      {
        printLineBreak();
        printErrorMessage(ERR_SUFFIXES_CANNOT_BE_INITIALIZED.get(
                Utils.getStringFromCollection(notFound,
                    Constants.LINE_SEPARATOR)));
      }
      if (interactive)
      {
        while (suffixes.isEmpty())
        {
          printLineBreak();
          printErrorMessage(ERR_NO_SUFFIXES_SELECTED_TO_INITIALIZE.get());
          for (String dn : availableSuffixes)
          {
            if (confirm(INFO_REPLICATION_INITIALIZE_SUFFIX_PROMPT.get(dn)))
            {
              suffixes.add(dn);
            }
          }
        }
      }
    }
  }
  /**
   * Updates the configuration in the two servers (and in other servers if
   * they are referenced) to enable replication.
   * @param ctx1 the connection to the first server.
   * @param ctx2 the connection to the second server.
   * @param uData the EnableReplicationUserData object containing the required
   * parameters to update the confgiuration.
   * @throws ReplicationCliException if there is an error.
   */
  private void updateConfiguration(InitialLdapContext ctx1,
      InitialLdapContext ctx2, EnableReplicationUserData uData)
  throws ReplicationCliException
  {
    LinkedHashSet<String> twoReplServers = new LinkedHashSet<String>();
    LinkedHashSet<String> allRepServers = new LinkedHashSet<String>();
    HashMap<String, LinkedHashSet<String>> hmRepServers =
      new HashMap<String, LinkedHashSet<String>>();
    Set<Integer> usedReplicationServerIds = new HashSet<Integer>();
    HashMap<String, HashSet<Integer>> hmUsedReplicationDomainIds =
      new HashMap<String, HashSet<Integer>>();
    ServerDescriptor server1;
    try
    {
      server1 = ServerDescriptor.createStandalone(ctx1);
    }
    catch (NamingException ne)
    {
      throw new ReplicationCliException(
          getMessageForException(ne, ConnectionUtils.getHostPort(ctx1)),
          ERROR_READING_CONFIGURATION, ne);
    }
    ServerDescriptor server2;
    try
    {
      server2 = ServerDescriptor.createStandalone(ctx2);
    }
    catch (NamingException ne)
    {
      throw new ReplicationCliException(
          getMessageForException(ne, ConnectionUtils.getHostPort(ctx2)),
          ERROR_READING_CONFIGURATION, ne);
    }
    ADSContext adsCtx1 = new ADSContext(ctx1);
    ADSContext adsCtx2 = new ADSContext(ctx2);
    // These are used to identify which server we use to initialize
    // the contents of the other server (if any).
    InitialLdapContext ctxAdsSource = null;
    InitialLdapContext ctxAdsDestination = null;
    printProgressMessage(formatter.getFormattedWithPoints(
        INFO_REPLICATION_ENABLE_UPDATING_ADS_CONTENTS.get()));
    try
    {
      if (adsCtx1.hasAdminData() && adsCtx2.hasAdminData())
      {
        Set<Map<ADSContext.ServerProperty, Object>> registry1 =
          adsCtx1.readServerRegistry();
        Set<Map<ADSContext.ServerProperty, Object>> registry2 =
          adsCtx2.readServerRegistry();
        if (registry2.size() <= 1)
        {
          // Only the server itself registered.
          if (!hasAdministrator(adsCtx1.getDirContext()))
          {
            adsCtx1.createAdministrator(getAdministratorProperties(uData));
          }
          if (registry2.size() == 0)
          {
            server2.updateAdsPropertiesWithServerProperties();
            adsCtx1.registerServer(server2.getAdsProperties());
          }
          else
          {
            adsCtx1.registerServer(registry2.iterator().next());
          }
          ctxAdsSource = ctx1;
          ctxAdsDestination = ctx2;
        }
        else if (registry1.size() <= 1)
        {
          // Only the server itself registered.
          if (!hasAdministrator(adsCtx2.getDirContext()))
          {
            adsCtx2.createAdministrator(getAdministratorProperties(uData));
          }
          if (registry1.size() == 0)
          {
            server1.updateAdsPropertiesWithServerProperties();
            adsCtx2.registerServer(server1.getAdsProperties());
          }
          else
          {
            adsCtx2.registerServer(registry1.iterator().next());
          }
          ctxAdsSource = ctx2;
          ctxAdsDestination = ctx1;
        }
        else if (!registry1.equals(registry2))
        {
          // TO COMPLETE: we may want to merge the ADS but for the moment
          // just say this is not supported.
          throw new ReplicationCliException(
              ERR_REPLICATION_ADS_MERGE_NOT_SUPPORTED.get(
                  ConnectionUtils.getHostPort(ctx1),
                  ConnectionUtils.getHostPort(ctx2)),
                  REPLICATION_ADS_MERGE_NOT_SUPPORTED, null);
        }
        else
        {
          // They are already replicated: nothing to do in terms of ADS
          // initialization or ADS update data
        }
      }
      else if (!adsCtx1.hasAdminData() && adsCtx2.hasAdminData())
      {
        adsCtx1.createAdministrationSuffix(null);
        if (!hasAdministrator(adsCtx2.getDirContext()))
        {
          adsCtx2.createAdministrator(getAdministratorProperties(uData));
        }
        server1.updateAdsPropertiesWithServerProperties();
        adsCtx2.registerServer(server1.getAdsProperties());
        ctxAdsSource = ctx2;
        ctxAdsDestination = ctx1;
      }
      else if (adsCtx1.hasAdminData() && !adsCtx2.hasAdminData())
      {
        adsCtx2.createAdministrationSuffix(null);
        if (!hasAdministrator(adsCtx1.getDirContext()))
        {
          adsCtx1.createAdministrator(getAdministratorProperties(uData));
        }
        server2.updateAdsPropertiesWithServerProperties();
        adsCtx1.registerServer(server2.getAdsProperties());
        ctxAdsSource = ctx1;
        ctxAdsDestination = ctx2;
      }
      else
      {
        adsCtx1.createAdminData(null);
        adsCtx1.createAdministrator(getAdministratorProperties(uData));
        server1.updateAdsPropertiesWithServerProperties();
        adsCtx1.registerServer(server1.getAdsProperties());
        server2.updateAdsPropertiesWithServerProperties();
        adsCtx1.registerServer(server2.getAdsProperties());
        adsCtx2.createAdministrationSuffix(null);
        ctxAdsSource = ctx1;
        ctxAdsDestination = ctx2;
      }
    }
    catch (ADSContextException adce)
    {
      throw new ReplicationCliException(
          ERR_REPLICATION_UPDATING_ADS.get(adce.getMessage()),
          ERROR_UPDATING_ADS, adce);
    }
    printProgressMessage(formatter.getFormattedDone());
    printProgressMessage(formatter.getLineBreak());
    LinkedList<String> baseDNs = uData.getBaseDNs();
    boolean found = false;
    for (String dn : baseDNs)
    {
      if (Utils.areDnsEqual(dn, ADSContext.getAdministrationSuffixDN()))
      {
        found = true;
        break;
      }
    }
    if (!found)
    {
      baseDNs.add(ADSContext.getAdministrationSuffixDN());
      uData.setBaseDNs(baseDNs);
    }
    TopologyCache cache1 = null;
    TopologyCache cache2 = null;
    try
    {
      if (adsCtx1.hasAdminData())
      {
        cache1 = new TopologyCache(adsCtx1, getTrustManager());
        cache1.reloadTopology();
        usedReplicationServerIds.addAll(getReplicationServerIds(cache1));
      }
      if (adsCtx2.hasAdminData())
      {
        cache2 = new TopologyCache(adsCtx2, getTrustManager());
        cache2.reloadTopology();
        usedReplicationServerIds.addAll(getReplicationServerIds(cache2));
      }
    }
    catch (ADSContextException adce)
    {
      throw new ReplicationCliException(
          ERR_REPLICATION_READING_ADS.get(adce.getMessage()),
          ERROR_READING_ADS, adce);
    }
    catch (TopologyCacheException tce)
    {
      throw new ReplicationCliException(
          ERR_REPLICATION_READING_ADS.get(tce.getMessage()),
          ERROR_READING_TOPOLOGY_CACHE, tce);
    }
    if (!argParser.isInteractive())
    {
      // Inform the user of the potential errors that we found.
      LinkedHashSet<Message> messages = new LinkedHashSet<Message>();
      if (cache1 != null)
      {
        messages.addAll(getErrorMessages(cache1));
      }
      if (cache2 != null)
      {
        messages.addAll(getErrorMessages(cache2));
      }
      if (!messages.isEmpty())
      {
        printWarningMessage(
            ERR_REPLICATION_READING_REGISTERED_SERVERS_WARNING.get(
                Utils.getMessageFromCollection(messages,
                    Constants.LINE_SEPARATOR).toString()));
      }
    }
    if (server1.isReplicationServer())
    {
      twoReplServers.add(server1.getReplicationServerHostPort());
      usedReplicationServerIds.add(server1.getReplicationServerId());
    }
    else
    {
      twoReplServers.add(
          ConnectionUtils.getHostName(ctx1)+":"+uData.getReplicationPort1());
    }
    if (server2.isReplicationServer())
    {
      twoReplServers.add(server2.getReplicationServerHostPort());
      usedReplicationServerIds.add(server2.getReplicationServerId());
    }
    else
    {
      twoReplServers.add(
          ConnectionUtils.getHostName(ctx2)+":"+uData.getReplicationPort2());
    }
    for (String baseDN : uData.getBaseDNs())
    {
      LinkedHashSet<String> repServersForBaseDN = new LinkedHashSet<String>();
      repServersForBaseDN.addAll(getReplicationServers(baseDN, cache1,
          server1));
      repServersForBaseDN.addAll(getReplicationServers(baseDN, cache2,
          server2));
      repServersForBaseDN.addAll(twoReplServers);
      hmRepServers.put(baseDN, repServersForBaseDN);
      Set<Integer> ids = new HashSet<Integer>();
      ids.addAll(getReplicationDomainIds(baseDN, server1));
      ids.addAll(getReplicationDomainIds(baseDN, server2));
      if (cache1 != null)
      {
        for (ServerDescriptor server : cache1.getServers())
        {
          ids.addAll(getReplicationDomainIds(baseDN, server));
        }
      }
      if (cache2 != null)
      {
        for (ServerDescriptor server : cache2.getServers())
        {
          ids.addAll(getReplicationDomainIds(baseDN, server));
        }
      }
    }
    for (LinkedHashSet<String> v : hmRepServers.values())
    {
      allRepServers.addAll(v);
    }
    if (!server1.isReplicationServer())
    {
      try
      {
        configureAsReplicationServer(ctx1, uData.getReplicationPort1(),
          allRepServers, usedReplicationServerIds);
      }
      catch (OpenDsException ode)
      {
        throw new ReplicationCliException(
            getMessageForReplicationServerException(ode,
            ConnectionUtils.getHostPort(ctx1)),
            ERROR_CONFIGURING_REPLICATIONSERVER, ode);
      }
    }
    if (!server2.isReplicationServer())
    {
      try
      {
        configureAsReplicationServer(ctx2, uData.getReplicationPort2(),
            allRepServers, usedReplicationServerIds);
      }
      catch (OpenDsException ode)
      {
        throw new ReplicationCliException(
            getMessageForReplicationServerException(ode,
            ConnectionUtils.getHostPort(ctx1)),
            ERROR_CONFIGURING_REPLICATIONSERVER, ode);
      }
    }
    for (String baseDN : uData.getBaseDNs())
    {
      LinkedHashSet<String> repServers = hmRepServers.get(baseDN);
      Set<Integer> usedIds = hmUsedReplicationDomainIds.get(baseDN);
      Set<String> alreadyConfiguredServers = new HashSet<String>();
      try
      {
        configureToReplicateBaseDN(ctx1, baseDN, repServers, usedIds);
      }
      catch (OpenDsException ode)
      {
        Message msg = getMessageForEnableException(ode,
            ConnectionUtils.getHostPort(ctx1), baseDN);
        throw new ReplicationCliException(msg,
            ERROR_ENABLING_REPLICATION_ON_BASEDN, ode);
      }
      alreadyConfiguredServers.add(server1.getId());
      try
      {
        configureToReplicateBaseDN(ctx2, baseDN, repServers, usedIds);
      }
      catch (OpenDsException ode)
      {
        Message msg = getMessageForEnableException(ode,
            ConnectionUtils.getHostPort(ctx2), baseDN);
        throw new ReplicationCliException(msg,
            ERROR_ENABLING_REPLICATION_ON_BASEDN, ode);
      }
      alreadyConfiguredServers.add(server2.getId());
      if (cache1 != null)
      {
        configureToReplicateBaseDN(baseDN, repServers, usedIds, cache1, server1,
            alreadyConfiguredServers);
      }
      if (cache2 != null)
      {
        configureToReplicateBaseDN(baseDN, repServers, usedIds, cache2, server2,
            alreadyConfiguredServers);
      }
    }
    // Now that replication is configured in all servers, simply try to
    // initialize the contents of one ADS with the other (in the case where
    // already both servers were replicating the same ADS there is nothing to be
    // done).
    if ((ctxAdsSource != null) && (ctxAdsDestination != null))
    {
      printProgressMessage(formatter.getFormattedWithPoints(
          INFO_ENABLE_REPLICATION_INITIALIZING_ADS.get(
              ConnectionUtils.getHostPort(ctxAdsDestination),
              ConnectionUtils.getHostPort(ctxAdsSource))));
      initializeSuffix(ADSContext.getAdministrationSuffixDN(), ctxAdsSource,
          ctxAdsDestination, false);
      printProgressMessage(formatter.getFormattedDone());
      printProgressMessage(formatter.getLineBreak());
    }
  }
  /**
   * Updates the configuration in the server (and in other servers if
   * they are referenced) to disable replication.
   * @param ctx the connection to the server.
   * @param uData the DisableReplicationUserData object containing the required
   * parameters to update the confgiuration.
   * @throws ReplicationCliException if there is an error.
   */
  private void updateConfiguration(InitialLdapContext ctx,
      DisableReplicationUserData uData) throws ReplicationCliException
  {
    ServerDescriptor server;
    try
    {
      server = ServerDescriptor.createStandalone(ctx);
    }
    catch (NamingException ne)
    {
      throw new ReplicationCliException(
          getMessageForException(ne, ConnectionUtils.getHostPort(ctx)),
          ERROR_READING_CONFIGURATION, ne);
    }
    ADSContext adsCtx = new ADSContext(ctx);
    TopologyCache cache = null;
    try
    {
      if (adsCtx.hasAdminData())
      {
        cache = new TopologyCache(adsCtx, getTrustManager());
        cache.reloadTopology();
      }
    }
    catch (ADSContextException adce)
    {
      throw new ReplicationCliException(
          ERR_REPLICATION_READING_ADS.get(adce.getMessage()),
          ERROR_READING_ADS, adce);
    }
    catch (TopologyCacheException tce)
    {
      throw new ReplicationCliException(
          ERR_REPLICATION_READING_ADS.get(tce.getMessage()),
          ERROR_READING_TOPOLOGY_CACHE, tce);
    }
    if (!argParser.isInteractive())
    {
      // Inform the user of the potential errors that we found.
      LinkedHashSet<Message> messages = new LinkedHashSet<Message>();
      if (cache != null)
      {
        messages.addAll(getErrorMessages(cache));
      }
      if (!messages.isEmpty())
      {
        printWarningMessage(
            ERR_REPLICATION_READING_REGISTERED_SERVERS_WARNING.get(
                Utils.getMessageFromCollection(messages,
                    Constants.LINE_SEPARATOR).toString()));
      }
    }
    String replicationServerHostPort = server.getReplicationServerHostPort();
    for (String baseDN : uData.getBaseDNs())
    {
      try
      {
        deleteReplicationDomain(ctx, baseDN);
      }
      catch (OpenDsException ode)
      {
        Message msg = getMessageForDisableException(ode,
            ConnectionUtils.getHostPort(ctx), baseDN);
        throw new ReplicationCliException(msg,
            ERROR_DISABLING_REPLICATION_ON_BASEDN, ode);
      }
    }
    if ((replicationServerHostPort != null) && (cache != null))
    {
      Set<ServerDescriptor> serversToUpdate =
        new LinkedHashSet<ServerDescriptor>();
      for (String baseDN : uData.getBaseDNs())
      {
        SuffixDescriptor suffix = getSuffix(baseDN, cache, server);
        if (suffix != null)
        {
          for (ReplicaDescriptor replica : suffix.getReplicas())
          {
            serversToUpdate.add(replica.getServer());
          }
        }
      }
      String bindDn = ConnectionUtils.getBindDN(ctx);
      String pwd = ConnectionUtils.getBindPassword(ctx);
      for (ServerDescriptor s : serversToUpdate)
      {
        removeReferencesInServer(s, replicationServerHostPort, bindDn, pwd,
            uData.getBaseDNs());
      }
    }
  }
  /**
   * Retrieves all the replication servers for a given baseDN.  The
   * ServerDescriptor is used to identify the server where the suffix is
   * defined and it cannot be null.  The TopologyCache is used to retrieve
   * replication servers defined in other replicas but not in the one we
   * get in the ServerDescriptor.
   * @param baseDN the base DN.
   * @param cache the TopologyCache (might be null).
   * @param server the ServerDescriptor.
   * @return a Set containing the replication servers currently being used
   * to replicate the baseDN defined in the server described by the
   * ServerDescriptor.
   */
  private LinkedHashSet<String> getReplicationServers(String baseDN,
      TopologyCache cache, ServerDescriptor server)
  {
    LinkedHashSet<String> servers = new LinkedHashSet<String>();
    for (ReplicaDescriptor replica : server.getReplicas())
    {
      if (Utils.areDnsEqual(replica.getSuffix().getDN(), baseDN))
      {
        servers.addAll(replica.getReplicationServers());
        break;
      }
    }
    if (cache != null)
    {
      Set<SuffixDescriptor> suffixes = cache.getSuffixes();
      for (SuffixDescriptor suffix : suffixes)
      {
        if (Utils.areDnsEqual(suffix.getDN(), baseDN))
        {
          Set<String> s = suffix.getReplicationServers();
          // Test that at least we share one of the replication servers.
          // If we do: we are dealing with the same replication topology
          // (we must consider the case of disjoint replication topologies
          // replicating the same base DN).
          HashSet<String> copy = new HashSet<String>(s);
          copy.retainAll(servers);
          if (!copy.isEmpty())
          {
            servers.addAll(s);
            break;
          }
        }
      }
    }
    return servers;
  }
  /**
   * Retrieves the suffix in the TopologyCache for a given baseDN.  The
   * ServerDescriptor is used to identify the server where the suffix is
   * defined.
   * @param baseDN the base DN.
   * @param cache the TopologyCache.
   * @param server the ServerDescriptor.
   * @return the suffix in the TopologyCache for a given baseDN.
   */
  private SuffixDescriptor getSuffix(String baseDN, TopologyCache cache,
      ServerDescriptor server)
  {
    SuffixDescriptor returnValue = null;
    Set<String> servers = new LinkedHashSet<String>();
    for (ReplicaDescriptor replica : server.getReplicas())
    {
      if (Utils.areDnsEqual(replica.getSuffix().getDN(), baseDN))
      {
        servers.addAll(replica.getReplicationServers());
        break;
      }
    }
    Set<SuffixDescriptor> suffixes = cache.getSuffixes();
    for (SuffixDescriptor suffix : suffixes)
    {
      if (Utils.areDnsEqual(suffix.getDN(), baseDN))
      {
        Set<String> s = suffix.getReplicationServers();
        // Test that at least we share one of the replication servers.
        // If we do: we are dealing with the same replication topology
        // (we must consider the case of disjoint replication topologies
        // replicating the same base DN).
        HashSet<String> copy = new HashSet<String>(s);
        copy.retainAll(servers);
        if (!copy.isEmpty())
        {
          returnValue = suffix;
          break;
        }
      }
    }
    return returnValue;
  }
  /**
   * Retrieves all the replication domain IDs for a given baseDN in the
   * ServerDescriptor.
   * @param baseDN the base DN.
   * @param server the ServerDescriptor.
   * @return a Set containing the replication domain IDs for a given baseDN in
   * the ServerDescriptor.
   */
  private Set<Integer> getReplicationDomainIds(String baseDN,
      ServerDescriptor server)
  {
    Set<Integer> ids = new HashSet<Integer>();
    for (ReplicaDescriptor replica : server.getReplicas())
    {
      if ((replica.isReplicated()) &&
      Utils.areDnsEqual(replica.getSuffix().getDN(), baseDN))
      {
        ids.add(replica.getReplicationId());
        break;
      }
    }
    return ids;
  }
  /**
   * Configures the server to which the provided InitialLdapContext is connected
   * as a replication server.  The replication server listens in the provided
   * port.
   * @param ctx the context connected to the server that we want to configure.
   * @param replicationPort the replication port of the replication server.
   * @param replicationServers the list of replication servers to which the
   * replication server will communicate with.
   * @param usedReplicationServerIds the set of replication server IDs that
   * are already in use.  The set will be updated with the replication ID
   * that will be used by the newly configured replication server.
   * @throws OpenDsException if there is an error updating the configuration.
   */
  private void configureAsReplicationServer(InitialLdapContext ctx,
      int replicationPort, LinkedHashSet<String> replicationServers,
      Set<Integer> usedReplicationServerIds) throws OpenDsException
  {
    printProgressMessage(formatter.getFormattedWithPoints(
        INFO_REPLICATION_ENABLE_CONFIGURING_REPLICATION_SERVER.get(
            ConnectionUtils.getHostPort(ctx))));
    ManagementContext mCtx = LDAPManagementContext.createFromContext(
        JNDIDirContextAdaptor.adapt(ctx));
    RootCfgClient root = mCtx.getRootConfiguration();
    /*
     * Configure Synchronization plugin.
     */
    MultimasterSynchronizationProviderCfgClient sync = null;
    try
    {
      sync = (MultimasterSynchronizationProviderCfgClient)
      root.getSynchronizationProvider("Multimaster Synchronization");
    }
    catch (ManagedObjectNotFoundException monfe)
    {
      LOG.log(Level.INFO, "Synchronization server does not exist in "+
          ConnectionUtils.getHostPort(ctx));
    }
    if (sync == null)
    {
      MultimasterSynchronizationProviderCfgDefn provider =
        MultimasterSynchronizationProviderCfgDefn.getInstance();
      sync = root.createSynchronizationProvider(provider,
          "Multimaster Synchronization",
          new ArrayList<DefaultBehaviorException>());
      sync.setJavaImplementationClass(
          org.opends.server.replication.plugin.MultimasterReplication.class.
          getName());
      sync.setEnabled(Boolean.TRUE);
    }
    else
    {
      if (!sync.isEnabled())
      {
        sync.setEnabled(Boolean.TRUE);
      }
    }
    sync.commit();
    /*
     * Configure the replication server.
     */
    ReplicationServerCfgClient replicationServer = null;
    boolean mustCommit = false;
    if (!sync.hasReplicationServer())
    {
      int id = InstallerHelper.getReplicationId(usedReplicationServerIds);
      usedReplicationServerIds.add(id);
      replicationServer = sync.createReplicationServer(
          ReplicationServerCfgDefn.getInstance(),
          new ArrayList<DefaultBehaviorException>());
      replicationServer.setReplicationServerId(id);
      replicationServer.setReplicationPort(replicationPort);
      replicationServer.setReplicationServer(replicationServers);
      mustCommit = true;
    }
    else
    {
      replicationServer = sync.getReplicationServer();
      usedReplicationServerIds.add(
          replicationServer.getReplicationServerId());
      Set<String> servers = replicationServer.getReplicationServer();
      if (servers == null)
      {
        replicationServer.setReplicationServer(servers);
        mustCommit = true;
      }
      else if (!servers.equals(replicationServers))
      {
        replicationServers.addAll(servers);
        replicationServer.setReplicationServer(replicationServers);
        mustCommit = true;
      }
    }
    if (mustCommit)
    {
      replicationServer.commit();
    }
    printProgressMessage(formatter.getFormattedDone());
    printProgressMessage(formatter.getLineBreak());
  }
  /**
   * Returns a Set containing all the replication server ids found in the
   * servers of a given TopologyCache object.
   * @param cache the TopologyCache object to use.
   * @return a Set containing all the replication server ids found in a given
   * TopologyCache object.
   */
  private Set<Integer> getReplicationServerIds(TopologyCache cache)
  {
    Set<Integer> ids = new HashSet<Integer>();
    for (ServerDescriptor server : cache.getServers())
    {
      if (server.isReplicationServer())
      {
        ids.add(server.getReplicationServerId());
      }
    }
    return ids;
  }
  /**
   * Configures a replication domain for a given base DN in the server to which
   * the provided InitialLdapContext is connected.
   * @param ctx the context connected to the server that we want to configure.
   * @param baseDN the base DN of the replication domain to configure.
   * @param replicationServers the list of replication servers to which the
   * replication domain will communicate with.
   * @param usedReplicationDomainIds the set of replication domain IDs that
   * are already in use.  The set will be updated with the replication ID
   * that will be used by the newly configured replication server.
   * @throws OpenDsException if there is an error updating the configuration.
   */
  private void configureToReplicateBaseDN(InitialLdapContext ctx,
      String baseDN,
      LinkedHashSet<String> replicationServers,
      Set<Integer> usedReplicationDomainIds) throws OpenDsException
  {
    printProgressMessage(formatter.getFormattedWithPoints(
        INFO_REPLICATION_ENABLE_CONFIGURING_BASEDN.get(baseDN,
            ConnectionUtils.getHostPort(ctx))));
    ManagementContext mCtx = LDAPManagementContext.createFromContext(
        JNDIDirContextAdaptor.adapt(ctx));
    RootCfgClient root = mCtx.getRootConfiguration();
    MultimasterSynchronizationProviderCfgClient sync =
      (MultimasterSynchronizationProviderCfgClient)
      root.getSynchronizationProvider("Multimaster Synchronization");
    String[] domainNames = sync.listMultimasterDomains();
    if (domainNames == null)
    {
      domainNames = new String[]{};
    }
    MultimasterDomainCfgClient[] domains =
      new MultimasterDomainCfgClient[domainNames.length];
    for (int i=0; i<domains.length; i++)
    {
      domains[i] = sync.getMultimasterDomain(domainNames[i]);
    }
    MultimasterDomainCfgClient domain = null;
    String domainName = null;
    for (int i=0; i<domains.length && (domain == null); i++)
    {
      if (Utils.areDnsEqual(baseDN, domains[i].getReplicationDN().toString()))
      {
        domain = domains[i];
        domainName = domainNames[i];
      }
    }
    boolean mustCommit = false;
    if (domain == null)
    {
      int domainId = InstallerHelper.getReplicationId(usedReplicationDomainIds);
      usedReplicationDomainIds.add(domainId);
      domainName = InstallerHelper.getDomainName(domainNames, domainId);
      domain = sync.createMultimasterDomain(
          MultimasterDomainCfgDefn.getInstance(), domainName,
          new ArrayList<DefaultBehaviorException>());
      domain.setServerId(domainId);
      domain.setReplicationDN(DN.decode(baseDN));
      domain.setReplicationServer(replicationServers);
      mustCommit = true;
    }
    else
    {
      Set<String> servers = domain.getReplicationServer();
      if (servers == null)
      {
        domain.setReplicationServer(servers);
        mustCommit = true;
      }
      else if (!servers.equals(replicationServers))
      {
        replicationServers.addAll(servers);
        domain.setReplicationServer(replicationServers);
        mustCommit = true;
      }
    }
    if (mustCommit)
    {
      domain.commit();
    }
    printProgressMessage(formatter.getFormattedDone());
    printProgressMessage(formatter.getLineBreak());
  }
  /**
   * Configures the baseDN to replicate in all the Replicas found in a Topology
   * Cache that are replicated with the Replica of the same base DN in the
   * provided ServerDescriptor object.
   * @param baseDN the base DN to replicate.
   * @param repServers the replication servers to be defined in the domain.
   * @param usedIds the replication domain Ids already used.  This Set is
   * updated with the new domains that are used.
   * @param cache the TopologyCache used to retrieve the different defined
   * replicas.
   * @param server the ServerDescriptor that is used to identify the
   * replication topology that we are interested at (we only update the replicas
   * that are already replicated with this server).
   * @param alreadyConfiguredServers the list of already configured servers.  If
   * a server is in this list no updates are performed.
   * @throws ReplicationCliException if something goes wrong.
   */
  private void configureToReplicateBaseDN(String baseDN,
      LinkedHashSet<String> repServers, Set<Integer> usedIds,
      TopologyCache cache, ServerDescriptor server,
      Set<String>alreadyConfiguredServers) throws ReplicationCliException
  {
    SuffixDescriptor suffix = getSuffix(baseDN, cache, server);
    if (suffix != null)
    {
      for (ReplicaDescriptor replica: suffix.getReplicas())
      {
        ServerDescriptor s = replica.getServer();
        if (!alreadyConfiguredServers.contains(s.getId()))
        {
          String dn = ConnectionUtils.getBindDN(
              cache.getAdsContext().getDirContext());
          String pwd = ConnectionUtils.getBindPassword(
              cache.getAdsContext().getDirContext());
          ServerLoader loader = new ServerLoader(server.getAdsProperties(),
              dn, pwd, getTrustManager());
          InitialLdapContext ctx = null;
          try
          {
            ctx = loader.createContext();
            configureToReplicateBaseDN(ctx, baseDN, repServers, usedIds);
          }
          catch (NamingException ne)
          {
            String hostPort = server.getHostPort(true);
            Message msg = getMessageForException(ne, hostPort);
            throw new ReplicationCliException(msg, ERROR_CONNECTING, ne);
          }
          catch (OpenDsException ode)
          {
            String hostPort = server.getHostPort(true);
            Message msg = getMessageForEnableException(ode, hostPort, baseDN);
            throw new ReplicationCliException(msg,
                ERROR_ENABLING_REPLICATION_ON_BASEDN, ode);
          }
          finally
          {
            if (ctx != null)
            {
              try
              {
                ctx.close();
              }
              catch (Throwable t)
              {
              }
            }
          }
          alreadyConfiguredServers.add(s.getId());
        }
      }
    }
  }
  /**
   * Returns the Map of properties to be used to update the ADS.
   * This map uses the data provided by the user.
   * @return the Map of properties to be used to update the ADS.
   * This map uses the data provided by the user
   */
  private Map<ADSContext.AdministratorProperty, Object>
  getAdministratorProperties(ReplicationUserData uData)
  {
    Map<ADSContext.AdministratorProperty, Object> adminProperties =
      new HashMap<ADSContext.AdministratorProperty, Object>();
    adminProperties.put(ADSContext.AdministratorProperty.UID,
        uData.getAdminUid());
    adminProperties.put(ADSContext.AdministratorProperty.PASSWORD,
        uData.getAdminPwd());
    adminProperties.put(ADSContext.AdministratorProperty.DESCRIPTION,
        INFO_GLOBAL_ADMINISTRATOR_DESCRIPTION.get().toString());
    return adminProperties;
  }
  private void initializeSuffix(String baseDN, InitialLdapContext ctxSource,
      InitialLdapContext ctxDestination, boolean displayProgress)
  throws ReplicationCliException
  {
    int replicationId = -1;
    try
    {
      ServerDescriptor source = ServerDescriptor.createStandalone(
          ctxSource);
      for (ReplicaDescriptor replica : source.getReplicas())
      {
        if (Utils.areDnsEqual(replica.getSuffix().getDN(), baseDN))
        {
          replicationId = replica.getReplicationId();
          break;
        }
      }
    }
    catch (NamingException ne)
    {
      String hostPort = ConnectionUtils.getHostPort(ctxSource);
      Message msg = getMessageForException(ne, hostPort);
      throw new ReplicationCliException(msg, ERROR_READING_CONFIGURATION, ne);
    }
    if (replicationId == -1)
    {
      throw new ReplicationCliException(
          ERR_INITIALIZING_REPLICATIONID_NOT_FOUND.get(
              ConnectionUtils.getHostPort(ctxSource), baseDN),
          REPLICATIONID_NOT_FOUND, null);
    }
    OfflineInstaller installer = new OfflineInstaller();
    installer.setProgressMessageFormatter(formatter);
    installer.addProgressUpdateListener(new ProgressUpdateListener()
    {
      public void progressUpdate(ProgressUpdateEvent ev)
      {
        Message newLogDetails = ev.getNewLogs();
        if (newLogDetails != null)
        {
          printProgressMessage(newLogDetails);
          printProgressLineBreak();
        }
      }
    });
    int nTries = 5;
    boolean initDone = false;
    while (!initDone)
    {
      try
      {
        installer.initializeSuffix(ctxDestination, replicationId, baseDN,
            displayProgress, ConnectionUtils.getHostPort(ctxSource));
        initDone = true;
      }
      catch (PeerNotFoundException pnfe)
      {
        LOG.log(Level.INFO, "Peer could not be found");
        if (nTries == 1)
        {
          throw new ReplicationCliException(
              ERR_REPLICATION_INITIALIZING_TRIES_COMPLETED.get(
                  pnfe.getMessageObject().toString()),
              INITIALIZING_TRIES_COMPLETED, pnfe);
        }
        try
        {
          Thread.sleep((5 - nTries) * 3000);
        }
        catch (Throwable t)
        {
        }
      }
      catch (ApplicationException ae)
      {
        throw new ReplicationCliException(ae.getMessageObject(),
            ERROR_INITIALIZING_BASEDN_GENERIC, ae);
      }
      nTries--;
    }
  }
  /**
   * Returns a set of error messages encountered in the provided TopologyCache.
   * @param cache the topology cache.
   * @return a set of error messages encountered in the provided TopologyCache.
   */
  private LinkedHashSet<Message> getErrorMessages(TopologyCache cache)
  {
    Set<TopologyCacheException> exceptions =
      new HashSet<TopologyCacheException>();
    Set<ServerDescriptor> servers = cache.getServers();
    LinkedHashSet<Message> exceptionMsgs = new LinkedHashSet<Message>();
    for (ServerDescriptor server : servers)
    {
      TopologyCacheException e = server.getLastException();
      if (e != null)
      {
        exceptions.add(e);
      }
    }
    /* Check the exceptions and see if we throw them or not. */
    for (TopologyCacheException e : exceptions)
    {
      switch (e.getType())
      {
        case NOT_GLOBAL_ADMINISTRATOR:
          exceptionMsgs.add(INFO_NOT_GLOBAL_ADMINISTRATOR_PROVIDED.get());
        break;
      case GENERIC_CREATING_CONNECTION:
        if ((e.getCause() != null) &&
            Utils.isCertificateException(e.getCause()))
        {
          exceptionMsgs.add(
              INFO_ERROR_READING_CONFIG_LDAP_CERTIFICATE_SERVER.get(
              e.getHostPort(), e.getCause().getMessage()));
        }
        else
        {
          exceptionMsgs.add(Utils.getMessage(e));
        }
        break;
      default:
        exceptionMsgs.add(Utils.getMessage(e));
      }
    }
    return exceptionMsgs;
  }
  /**
   * Removes the references to a replication server in the base DNs of a
   * given server.
   * @param server the server that we want to update.
   * @param replicationServer the replication server whose references we want
   * to remove.
   * @param bindDn the bindDn that must be used to log to the server.
   * @param pwd the password that must be used to log to the server.
   * @param baseDNs the list of base DNs where we want to remove the references
   * to the provided replication server.
   * @throws ReplicationCliException if there is an error updating the
   * configuration.
   */
  private void removeReferencesInServer(ServerDescriptor server,
      String replicationServer, String bindDn, String pwd,
      Collection<String> baseDNs)
  throws ReplicationCliException
  {
    ServerLoader loader = new ServerLoader(server.getAdsProperties(), bindDn,
        pwd, getTrustManager());
    InitialLdapContext ctx = null;
    String lastBaseDN = null;
    String hostPort = null;
    try
    {
      ctx = loader.createContext();
      hostPort = ConnectionUtils.getHostPort(ctx);
      ManagementContext mCtx = LDAPManagementContext.createFromContext(
          JNDIDirContextAdaptor.adapt(ctx));
      RootCfgClient root = mCtx.getRootConfiguration();
      MultimasterSynchronizationProviderCfgClient sync = null;
      try
      {
        sync = (MultimasterSynchronizationProviderCfgClient)
        root.getSynchronizationProvider("Multimaster Synchronization");
      }
      catch (ManagedObjectNotFoundException monfe)
      {
        // It does not exist.
        LOG.log(Level.INFO, "No synchronization found on "+ hostPort +".",
            monfe);
      }
      if (sync != null)
      {
        String[] domainNames = sync.listMultimasterDomains();
        if (domainNames != null)
        {
          for (int i=0; i<domainNames.length; i++)
          {
            MultimasterDomainCfgClient domain =
              sync.getMultimasterDomain(domainNames[i]);
            for (String baseDN : baseDNs)
            {
              lastBaseDN = baseDN;
              if (Utils.areDnsEqual(domain.getReplicationDN().toString(),
                  baseDN))
              {
                printProgressMessage(formatter.getFormattedWithPoints(
                    INFO_REPLICATION_REMOVING_REFERENCES_ON_REMOTE.get(baseDN,
                        hostPort)));
                Set<String> replServers = domain.getReplicationServer();
                if (replServers != null)
                {
                  String replServer = null;
                  for (String o : replServers)
                  {
                    if (replicationServer.equalsIgnoreCase(o))
                    {
                      replServer = o;
                      break;
                    }
                  }
                  if (replServer != null)
                  {
                    LOG.log(Level.INFO, "Updating references in domain " +
                        domain.getReplicationDN()+" on " + hostPort + ".");
                    replServers.remove(replServer);
                    if (replServers.size() > 0)
                    {
                      domain.setReplicationServer(replServers);
                      domain.commit();
                    }
                    else
                    {
                      sync.removeMultimasterDomain(domainNames[i]);
                      sync.commit();
                    }
                  }
                }
                printProgressMessage(formatter.getFormattedDone());
                printProgressMessage(formatter.getLineBreak());
              }
            }
          }
        }
      }
    }
    catch (NamingException ne)
    {
      hostPort = server.getHostPort(true);
      Message msg = getMessageForException(ne, hostPort);
      throw new ReplicationCliException(msg, ERROR_CONNECTING, ne);
    }
    catch (OpenDsException ode)
    {
      if (lastBaseDN != null)
      {
        Message msg = getMessageForDisableException(ode, hostPort, lastBaseDN);
        throw new ReplicationCliException(msg,
          ERROR_DISABLING_REPLICATION_REMOVE_REFERENCE_ON_BASEDN, ode);
      }
      else
      {
        Message msg = ERR_REPLICATION_ERROR_READING_CONFIGURATION.get(hostPort,
            ode.getMessage());
        throw new ReplicationCliException(msg, ERROR_CONNECTING, ode);
      }
    }
    finally
    {
      if (ctx != null)
      {
        try
        {
          ctx.close();
        }
        catch (Throwable t)
        {
        }
      }
    }
  }
  /**
   * Deletes a replication domain in a server for a given base DN (disable
   * replication of the base DN).
   * @param ctx the connection to the server.
   * @param baseDN the base DN of the replication domain that we want to
   * delete.
   * @throws ReplicationCliException if there is an error updating the
   * configuration of the server.
   */
  private void deleteReplicationDomain(InitialLdapContext ctx,
      String baseDN) throws ReplicationCliException
  {
    String hostPort = ConnectionUtils.getHostPort(ctx);
    try
    {
      ManagementContext mCtx = LDAPManagementContext.createFromContext(
          JNDIDirContextAdaptor.adapt(ctx));
      RootCfgClient root = mCtx.getRootConfiguration();
      MultimasterSynchronizationProviderCfgClient sync = null;
      try
      {
        sync = (MultimasterSynchronizationProviderCfgClient)
        root.getSynchronizationProvider("Multimaster Synchronization");
      }
      catch (ManagedObjectNotFoundException monfe)
      {
        // It does not exist.
        LOG.log(Level.INFO, "No synchronization found on "+ hostPort +".",
            monfe);
      }
      if (sync != null)
      {
        String[] domainNames = sync.listMultimasterDomains();
        if (domainNames != null)
        {
          for (int i=0; i<domainNames.length; i++)
          {
            MultimasterDomainCfgClient domain =
              sync.getMultimasterDomain(domainNames[i]);
            if (Utils.areDnsEqual(domain.getReplicationDN().toString(), baseDN))
            {
              printProgressMessage(formatter.getFormattedWithPoints(
                  INFO_REPLICATION_DISABLING_BASEDN.get(baseDN,
                      hostPort)));
              sync.removeMultimasterDomain(domainNames[i]);
              sync.commit();
              printProgressMessage(formatter.getFormattedDone());
              printProgressMessage(formatter.getLineBreak());
            }
          }
        }
      }
    }
    catch (OpenDsException ode)
    {
      Message msg = getMessageForDisableException(ode, hostPort, baseDN);
        throw new ReplicationCliException(msg,
          ERROR_DISABLING_REPLICATION_REMOVE_REFERENCE_ON_BASEDN, ode);
    }
  }
  /**
   * Returns a message object for the given NamingException.
   * @param ne the NamingException.
   * @param hostPort the hostPort representation of the server we were
   * contacting when the NamingException occurred.
   * @return a message object for the given NamingException.
   */
  private Message getMessageForException(NamingException ne, String hostPort)
  {
    Message msg;
    if (Utils.isCertificateException(ne))
    {
      msg = INFO_ERROR_READING_CONFIG_LDAP_CERTIFICATE_SERVER.get(
              hostPort, ne.getMessage());
    }
    else
    {
       msg = INFO_CANNOT_CONNECT_TO_REMOTE_GENERIC.get(
          hostPort, ne.getMessage());
    }
    return msg;
  }
  /**
   * Returns a message for a given OpenDsException (we assume that was an
   * exception generated updating the configuration of the server) that
   * occurred when we were configuring the replication server.
   * @param ode the OpenDsException.
   * @param hostPort the hostPort representation of the server we were
   * contacting when the OpenDsException occurred.
   * @return a message for a given OpenDsException (we assume that was an
   * exception generated updating the configuration of the server) that
   * occurred when we were configuring the replication server.
   */
  private Message getMessageForReplicationServerException(OpenDsException ode,
      String hostPort)
  {
    return ERR_REPLICATION_CONFIGURING_REPLICATIONSERVER.get(hostPort);
  }
  /**
   * Returns a message for a given OpenDsException (we assume that was an
   * exception generated updating the configuration of the server) that
   * occurred when we were configuring some replication domain (creating
   * the replication domain or updating the list of replication servers of
   * the replication domain).
   * @param ode the OpenDsException.
   * @param hostPort the hostPort representation of the server we were
   * contacting when the OpenDsException occurred.
   * @return a message for a given OpenDsException (we assume that was an
   * exception generated updating the configuration of the server) that
   * occurred when we were configuring some replication domain (creating
   * the replication domain or updating the list of replication servers of
   * the replication domain).
   */
  private Message getMessageForEnableException(OpenDsException ode,
      String hostPort, String baseDN)
  {
    return ERR_REPLICATION_CONFIGURING_BASEDN.get(baseDN, hostPort);
  }
  /**
   * Returns a message for a given OpenDsException (we assume that was an
   * exception generated updating the configuration of the server) that
   * occurred when we were configuring some replication domain (deleting
   * the replication domain or updating the list of replication servers of
   * the replication domain).
   * @param ode the OpenDsException.
   * @param hostPort the hostPort representation of the server we were
   * contacting when the OpenDsException occurred.
   * @return a message for a given OpenDsException (we assume that was an
   * exception generated updating the configuration of the server) that
   * occurred when we were configuring some replication domain (deleting
   * the replication domain or updating the list of replication servers of
   * the replication domain).
   */
  private Message getMessageForDisableException(OpenDsException ode,
      String hostPort, String baseDN)
  {
    return ERR_REPLICATION_CONFIGURING_BASEDN.get(baseDN, hostPort);
  }
}
opends/src/guitools/org/opends/guitools/replicationcli/ReplicationCliParser.java
New file
@@ -0,0 +1,1462 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 */
package org.opends.guitools.replicationcli;
import static org.opends.messages.AdminToolMessages.*;
import static org.opends.messages.ToolMessages.*;
import static org.opends.server.tools.ToolConstants.*;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.LinkedList;
import org.opends.messages.Message;
import org.opends.messages.MessageBuilder;
import org.opends.quicksetup.Constants;
import org.opends.quicksetup.util.Utils;
import org.opends.server.admin.client.cli.SecureConnectionCliParser;
import org.opends.server.util.args.Argument;
import org.opends.server.util.args.ArgumentException;
import org.opends.server.util.args.BooleanArgument;
import org.opends.server.util.args.FileBasedArgument;
import org.opends.server.util.args.IntegerArgument;
import org.opends.server.util.args.StringArgument;
import org.opends.server.util.args.SubCommand;
/**
 * This class is used to parse the arguments passed to the replication CLI.
 * It also checks the compatibility between the values and that all the
 * required information has been provided.  However it does not do any
 * verification that require connection to any server.
 */
public class ReplicationCliParser extends SecureConnectionCliParser
{
  private SubCommand enableReplicationSubCmd;
  private SubCommand disableReplicationSubCmd;
  private SubCommand initializeReplicationSubCmd;
  private BooleanArgument interactive;
  /**
   * The 'hostName' global argument for the first server.
   */
  private StringArgument hostName1Arg = null;
  /**
   * The 'port' global argument for the first server.
   */
  private IntegerArgument port1Arg = null;
  /**
   * The 'binDN' global argument for the first server.
   */
  private StringArgument bindDn1Arg = null;
  /**
   * The 'bindPasswordFile' global argument for the first server.
   */
  private FileBasedArgument bindPasswordFile1Arg = null;
  /**
   * The 'bindPassword' global argument for the first server.
   */
  private StringArgument bindPassword1Arg = null;
  /**
   * The 'useSSLArg' argument for the first server.
   */
  protected BooleanArgument useSSL1Arg = null;
  /**
   * The 'useStartTLS1Arg' argument for the first server.
   */
  protected BooleanArgument useStartTLS1Arg = null;
  /**
   * The 'replicationPort' global argument for the first server.
   */
  private IntegerArgument replicationPort1Arg = null;
  /**
   * The 'hostName' global argument for the second server.
   */
  private StringArgument hostName2Arg = null;
  /**
   * The 'port' global argument for the second server.
   */
  private IntegerArgument port2Arg = null;
  /**
   * The 'binDN' global argument for the second server.
   */
  private StringArgument bindDn2Arg = null;
  /**
   * The 'bindPasswordFile' global argument for the second server.
   */
  private FileBasedArgument bindPasswordFile2Arg = null;
  /**
   * The 'bindPassword' global argument for the second server.
   */
  private StringArgument bindPassword2Arg = null;
  /**
   * The 'useSSLArg' argument for the second server.
   */
  protected BooleanArgument useSSL2Arg = null;
  /**
   * The 'useStartTLS2Arg' argument for the second server.
   */
  protected BooleanArgument useStartTLS2Arg = null;
  /**
   * The 'replicationPort' global argument for the second server.
   */
  private IntegerArgument replicationPort2Arg = null;
  /**
   * The 'hostName' global argument for the source server.
   */
  private StringArgument hostNameSourceArg = null;
  /**
   * The 'port' global argument for the source server.
   */
  private IntegerArgument portSourceArg = null;
  /**
   * The 'useSSLArg' argument for the source server.
   */
  protected BooleanArgument useSSLSourceArg = null;
  /**
   * The 'useStartTLSSourceArg' argument for the source server.
   */
  protected BooleanArgument useStartTLSSourceArg = null;
  /**
   * The 'hostName' global argument for the destination server.
   */
  private StringArgument hostNameDestinationArg = null;
  /**
   * The 'port' global argument for the destination server.
   */
  private IntegerArgument portDestinationArg = null;
  /**
   * The 'useSSLArg' argument for the destination server.
   */
  protected BooleanArgument useSSLDestinationArg = null;
  /**
   * The 'useStartTLSDestinationArg' argument for the destination server.
   */
  protected BooleanArgument useStartTLSDestinationArg = null;
  /**
   * The 'suffixes' global argument.
   */
  private StringArgument baseDNsArg = null;
  /**
   * The 'admin UID' global argument.
   */
  private StringArgument adminUidArg;
  /**
   * The 'admin Password' global argument.
   */
  private StringArgument adminPasswordArg;
  /**
   * The 'admin Password File' global argument.
   */
  private FileBasedArgument adminPasswordFileArg;
  /**
   * The 'quiet' argument.
   */
  private BooleanArgument quietArg;
  /**
   * The text of the enable replication subcommand.
   */
  public static final String ENABLE_REPLICATION_SUBCMD_NAME = "enable";
  /**
   * The text of the disable replication subcommand.
   */
  public static final String DISABLE_REPLICATION_SUBCMD_NAME = "disable";
  /**
   * The text of the initialize replication subcommand.
   */
  public static final String INITIALIZE_REPLICATION_SUBCMD_NAME = "initialize";
  /**
   * Creates a new instance of this argument parser with no arguments.
   *
   * @param mainClassName
   *          The fully-qualified name of the Java class that should
   *          be invoked to launch the program with which this
   *          argument parser is associated.
   */
  public ReplicationCliParser(String mainClassName)
  {
    super(mainClassName,
        INFO_REPLICATION_TOOL_DESCRIPTION.get(ENABLE_REPLICATION_SUBCMD_NAME,
            INITIALIZE_REPLICATION_SUBCMD_NAME),
            false);
  }
  /**
   * Initialize the parser with the Global options and subcommands.
   *
   * @param outStream
   *          The output stream to use for standard output, or <CODE>null</CODE>
   *          if standard output is not needed.
   * @throws ArgumentException
   *           If there is a problem with any of the parameters used
   *           to create this argument.
   */
  public void initializeParser(OutputStream outStream)
      throws ArgumentException
  {
    initializeGlobalArguments(outStream);
    createEnableReplicationSubCommand();
    createDisableReplicationSubCommand();
    createInitializeReplicationSubCommand();
  }
  /**
   * Checks all the options parameters and updates the provided MessageBuilder
   * with the errors that where encountered.
   *
   * This method assumes that the method parseArguments for the parser has
   * already been called.
   * @param buf the MessageBuilder object where we add the error messages
   * describing the errors encountered.
   */
  public void validateOptions(MessageBuilder buf)
  {
    validateGlobalOptions(buf);
    validateSubcommandOptions(buf);
  }
  /**
   * {@inheritDoc}
   */
  public int validateGlobalOptions(MessageBuilder buf)
  {
    int returnValue;
    super.validateGlobalOptions(buf);
    ArrayList<Message> errors = new ArrayList<Message>();
    if (adminPasswordArg.isPresent() && adminPasswordFileArg.isPresent()) {
      Message message = ERR_TOOL_CONFLICTING_ARGS.get(
          adminPasswordArg.getLongIdentifier(),
          adminPasswordFileArg.getLongIdentifier());
      errors.add(message);
    }
    if (!isInteractive())
    {
      // Check that we have the required data
      if (!baseDNsArg.isPresent())
      {
        errors.add(ERR_REPLICATION_NO_BASE_DN_PROVIDED.get());
      }
      if (getBindPasswordAdmin() == null)
      {
        errors.add(ERR_REPLICATION_NO_ADMINISTRATOR_PASSWORD_PROVIDED.get(
                adminPasswordArg.getLongIdentifier(),
                adminPasswordFileArg.getLongIdentifier()));
      }
    }
    if (baseDNsArg.isPresent())
    {
      LinkedList<String> baseDNs = baseDNsArg.getValues();
      for (String dn : baseDNs)
      {
        if (!Utils.isDn(dn))
        {
          errors.add(ERR_REPLICATION_NOT_A_VALID_BASEDN.get(dn));
        }
      }
    }
    if (errors.size() > 0)
    {
      for (Message error : errors)
      {
        addMessage(buf, error);
      }
    }
    if (buf.length() > 0)
    {
      returnValue = ReplicationCliReturnCode.CONFLICTING_ARGS.getReturnCode();
    }
    else
    {
      returnValue = ReplicationCliReturnCode.SUCCESSFUL_NOP.getReturnCode();
    }
    return returnValue;
  }
  /**
   * Initialize Global option.
   *
   * @param outStream
   *          The output stream used for the usage.
   * @throws ArgumentException
   *           If there is a problem with any of the parameters used
   *           to create this argument.
   */
  private void initializeGlobalArguments(OutputStream outStream)
  throws ArgumentException
  {
    ArrayList<Argument> defaultArgs =
      new ArrayList<Argument>(createGlobalArguments(outStream));
    Argument[] argsToRemove = {
      hostNameArg,
      portArg,
      bindDnArg,
      bindPasswordFileArg,
      bindPasswordArg,
      useSSLArg,
      useStartTLSArg
    };
    for (int i=0; i<argsToRemove.length; i++)
    {
      defaultArgs.remove(argsToRemove[i]);
    }
    baseDNsArg = new StringArgument("baseDNs", 'b',
        "baseDNs", false, true, true, OPTION_VALUE_BASEDN, null,
        null, INFO_DESCRIPTION_REPLICATION_BASEDNS.get());
    defaultArgs.add(baseDNsArg);
    adminUidArg = new StringArgument("adminUID", 'I',
        "adminUID", false, false, true, "adminUID",
        Constants.GLOBAL_ADMIN_UID, null,
        INFO_DESCRIPTION_REPLICATION_ADMIN_UID.get(
            ENABLE_REPLICATION_SUBCMD_NAME));
    defaultArgs.add(adminUidArg);
    adminPasswordArg = new StringArgument("adminPassword",
        OPTION_SHORT_BINDPWD, "adminPassword", false, false, true,
        OPTION_VALUE_BINDPWD, null, null,
        INFO_DESCRIPTION_REPLICATION_ADMIN_BINDPASSWORD.get());
    defaultArgs.add(adminPasswordArg);
    adminPasswordFileArg = new FileBasedArgument("adminPasswordFile",
        OPTION_SHORT_BINDPWD_FILE, "adminPasswordFile", false, false,
        OPTION_VALUE_BINDPWD_FILE, null, null,
        INFO_DESCRIPTION_REPLICATION_ADMIN_BINDPASSWORDFILE.get());
    defaultArgs.add(adminPasswordFileArg);
    defaultArgs.remove(verboseArg);
    interactive = new BooleanArgument(
        INTERACTIVE_OPTION_LONG,
        INTERACTIVE_OPTION_SHORT,
        INTERACTIVE_OPTION_LONG,
        INFO_DESCRIPTION_INTERACTIVE.get());
    defaultArgs.add(interactive);
    quietArg = new BooleanArgument(
        SecureConnectionCliParser.QUIET_OPTION_LONG,
        SecureConnectionCliParser.QUIET_OPTION_SHORT,
        SecureConnectionCliParser.QUIET_OPTION_LONG,
        INFO_REPLICATION_DESCRIPTION_QUIET.get());
    defaultArgs.add(quietArg);
    initializeGlobalArguments(defaultArgs);
  }
  /**
   * Creates the enable replication subcommand and all the specific options
   * for the subcommand.
   */
  private void createEnableReplicationSubCommand()
  throws ArgumentException
  {
    hostName1Arg = new StringArgument("host1", 'h',
        "host1", false, false, true, OPTION_VALUE_HOST, "localhost",
        null, INFO_DESCRIPTION_ENABLE_REPLICATION_HOST1.get());
    port1Arg = new IntegerArgument("port1", 'p', "port1",
        false, false, true, OPTION_VALUE_PORT, 389, null,
        INFO_DESCRIPTION_ENABLE_REPLICATION_SERVER_PORT1.get());
    bindDn1Arg = new StringArgument("bindDN1", 'D',
        "bindDN1", false, false, true, OPTION_VALUE_BINDDN,
        "cn=Directory Manager", null,
        INFO_DESCRIPTION_ENABLE_REPLICATION_BINDDN1.get());
    bindPassword1Arg = new StringArgument("bindPassword1",
        'w', "bindPassword1", false, false, true,
        OPTION_VALUE_BINDPWD, null, null,
        INFO_DESCRIPTION_ENABLE_REPLICATION_BINDPASSWORD1.get());
    bindPasswordFile1Arg = new FileBasedArgument("bindPasswordFile1",
        'j', "bindPasswordFile1", false, false,
        OPTION_VALUE_BINDPWD_FILE, null, null,
        INFO_DESCRIPTION_ENABLE_REPLICATION_BINDPASSWORDFILE1.get());
    useSSL1Arg = new BooleanArgument("useSSL1", 'Z',
        "useSSL1", INFO_DESCRIPTION_ENABLE_REPLICATION_USE_SSL1.get());
    useStartTLS1Arg = new BooleanArgument("startTLS1", 'q',
        "startTLS1",
        INFO_DESCRIPTION_ENABLE_REPLICATION_STARTTLS1.get());
    replicationPort1Arg = new IntegerArgument("replicationPort1", 'r',
        "replicationPort1", false, false, true, OPTION_VALUE_PORT, 8989, null,
        INFO_DESCRIPTION_ENABLE_REPLICATION_PORT1.get());
    hostName2Arg = new StringArgument("host2", 'H',
        "host2", false, false, true, OPTION_VALUE_HOST, "localhost",
        null, INFO_DESCRIPTION_ENABLE_REPLICATION_HOST2.get());
    port2Arg = new IntegerArgument("port2", 'P', "port2",
        false, false, true, OPTION_VALUE_PORT, 389, null,
        INFO_DESCRIPTION_ENABLE_REPLICATION_SERVER_PORT2.get());
    bindDn2Arg = new StringArgument("bindDN2", 'N',
        "bindDN2", false, false, true, OPTION_VALUE_BINDDN,
        "cn=Directory Manager", null,
        INFO_DESCRIPTION_ENABLE_REPLICATION_BINDDN2.get());
    bindPassword2Arg = new StringArgument("bindPassword2",
        'W', "bindPassword2", false, false, true,
        OPTION_VALUE_BINDPWD, null, null,
        INFO_DESCRIPTION_ENABLE_REPLICATION_BINDPASSWORD2.get());
    bindPasswordFile2Arg = new FileBasedArgument("bindPasswordFile2",
        'F', "bindPasswordFile2", false, false,
        OPTION_VALUE_BINDPWD_FILE, null, null,
        INFO_DESCRIPTION_ENABLE_REPLICATION_BINDPASSWORDFILE2.get());
    useSSL2Arg = new BooleanArgument("useSSL2", 'S',
        "useSSL2", INFO_DESCRIPTION_ENABLE_REPLICATION_USE_SSL2.get());
    useStartTLS2Arg = new BooleanArgument("startTLS2", 'Q',
        "startTLS2",
        INFO_DESCRIPTION_ENABLE_REPLICATION_STARTTLS2.get());
    replicationPort2Arg = new IntegerArgument("replicationPort2", 'R',
        "replicationPort2", false, false, true, OPTION_VALUE_PORT, 8989, null,
        INFO_DESCRIPTION_ENABLE_REPLICATION_PORT2.get());
    enableReplicationSubCmd = new SubCommand(this,
        ENABLE_REPLICATION_SUBCMD_NAME,
        INFO_DESCRIPTION_SUBCMD_ENABLE_REPLICATION.get());
    Argument[] argsToAdd = {
        hostName1Arg, port1Arg, bindDn1Arg, bindPassword1Arg,
        bindPasswordFile1Arg, useStartTLS1Arg, useSSL1Arg, replicationPort1Arg,
        hostName2Arg, port2Arg, bindDn2Arg, bindPassword2Arg,
        bindPasswordFile2Arg, useStartTLS2Arg, useSSL2Arg, replicationPort2Arg,
    };
    for (int i=0; i<argsToAdd.length; i++)
    {
      enableReplicationSubCmd.addArgument(argsToAdd[i]);
    }
  }
  /**
   * Creates the disable replication subcommand and all the specific options
   * for the subcommand.  Note: this method assumes that
   * initializeGlobalArguments has already been called and that hostNameArg,
   * portArg, startTLSArg and useSSLArg have been created.
   */
  private void createDisableReplicationSubCommand()
  throws ArgumentException
  {
    disableReplicationSubCmd = new SubCommand(this,
        DISABLE_REPLICATION_SUBCMD_NAME,
        INFO_DESCRIPTION_SUBCMD_DISABLE_REPLICATION.get());
    Argument[] argsToAdd = {
        hostNameArg, portArg,
        useSSLArg, useStartTLSArg
    };
    for (int i=0; i<argsToAdd.length; i++)
    {
      disableReplicationSubCmd.addArgument(argsToAdd[i]);
    }
  }
  /**
   * Creates the initialize replication subcommand and all the specific options
   * for the subcommand.
   */
  private void createInitializeReplicationSubCommand()
  throws ArgumentException
  {
    hostNameSourceArg = new StringArgument("hostSource", 'h',
        "hostSource", false, false, true, OPTION_VALUE_HOST, "localhost",
        null, INFO_DESCRIPTION_INITIALIZE_REPLICATION_HOST_SOURCE.get());
    portSourceArg = new IntegerArgument("portSource", 'p', "portSource",
        false, false, true, OPTION_VALUE_PORT, 389, null,
        INFO_DESCRIPTION_INITIALIZE_REPLICATION_SERVER_PORT_SOURCE.get());
    useSSLSourceArg = new BooleanArgument("useSSLSource", 'Z',
        "useSSLSource",
        INFO_DESCRIPTION_INITIALIZE_REPLICATION_USE_SSL_SOURCE.get());
    useStartTLSSourceArg = new BooleanArgument("startTLSSource", 'q',
        "startTLSSource",
        INFO_DESCRIPTION_INITIALIZE_REPLICATION_STARTTLS_SOURCE.get());
    hostNameDestinationArg = new StringArgument("hostDestination", 'H',
        "hostDestination", false, false, true, OPTION_VALUE_HOST, "localhost",
        null, INFO_DESCRIPTION_INITIALIZE_REPLICATION_HOST_DESTINATION.get());
    portDestinationArg = new IntegerArgument("portDestination", 'P',
        "portDestination", false, false, true, OPTION_VALUE_PORT, 389, null,
        INFO_DESCRIPTION_INITIALIZE_REPLICATION_SERVER_PORT_DESTINATION.get());
    useSSLDestinationArg = new BooleanArgument("useSSLDestination", 'S',
        "useSSLDestination",
        INFO_DESCRIPTION_INITIALIZE_REPLICATION_USE_SSL_DESTINATION.get());
    useStartTLSDestinationArg = new BooleanArgument("startTLSDestination", 'Q',
        "startTLSDestination",
        INFO_DESCRIPTION_INITIALIZE_REPLICATION_STARTTLS_DESTINATION.get());
    initializeReplicationSubCmd = new SubCommand(this,
        INITIALIZE_REPLICATION_SUBCMD_NAME,
        INFO_DESCRIPTION_SUBCMD_INITIALIZE_REPLICATION.get());
    Argument[] argsToAdd = {
        hostNameSourceArg, portSourceArg, useSSLSourceArg, useStartTLSSourceArg,
        hostNameDestinationArg, portDestinationArg, useSSLDestinationArg,
        useStartTLSDestinationArg
    };
    for (int i=0; i<argsToAdd.length; i++)
    {
      initializeReplicationSubCmd.addArgument(argsToAdd[i]);
    }
  }
  /**
   * Tells whether the user specified to have an interactive operation or not.
   * This method must be called after calling parseArguments.
   * @return <CODE>true</CODE> if the user specified to have an interactive
   * operation and <CODE>false</CODE> otherwise.
   */
  public boolean isInteractive()
  {
    return interactive.isPresent();
  }
  /**
   * Tells whether the user specified to have a quite operation or not.
   * This method must be called after calling parseArguments.
   * @return <CODE>true</CODE> if the user specified to have a quite operation
   * and <CODE>false</CODE> otherwise.
   */
  public boolean isQuiet()
  {
    return quietArg.isPresent();
  }
  /**
   * Get the password which has to be used for the command to connect to the
   * first server without prompting the user in the enable replication
   * subcommand.  If no password was specified return null.
   *
   * @return the password which has to be used for the command to connect to the
   * first server without prompting the user in the enable replication
   * subcommand.  If no password was specified return null.
   */
  public String getBindPassword1()
  {
    return getBindPassword(bindPassword1Arg, bindPasswordFile1Arg);
  }
  /**
   * Get the password which has to be used for the command to connect to the
   * second server without prompting the user in the enable replication
   * subcommand.  If no password was specified return null.
   *
   * @return the password which has to be used for the command to connect to the
   * second server without prompting the user in the enable replication
   * subcommand.  If no password was specified return null.
   */
  public String getBindPassword2()
  {
    return getBindPassword(bindPassword2Arg, bindPasswordFile2Arg);
  }
  /**
   * Get the global administrator password which has to be used for the command
   * to connect to the server(s) without prompting the user.  If no password was
   * specified, return null.
   *
   * @return the global administrator password which has to be used for the
   * command to connect to the server(s) without prompting the user.  If no
   * password was specified, return null.
   */
  public String getBindPasswordAdmin()
  {
    return getBindPassword(adminPasswordArg, adminPasswordFileArg);
  }
  /**
   * Get the password of the first server which has to be used in the
   * enable replication subcommand.
   *
   * @param dn
   *          The user DN for which to password could be asked.
   * @param out
   *          The input stream to used if we have to prompt to the
   *          user.
   * @param err
   *          The error stream to used if we have to prompt to the
   *          user.
   * @return the password of the first server which has to be used n the
   *          enable replication subcommand.
   */
  public String getBindPassword1(
      String dn, OutputStream out, OutputStream err)
  {
    return getBindPassword(dn, out, err, bindPassword1Arg,
        bindPasswordFile1Arg);
  }
  /**
   * Get the password of the second server which has to be used in the
   * enable replication subcommand.
   *
   * @param dn
   *          The user DN for which to password could be asked.
   * @param out
   *          The input stream to used if we have to prompt to the
   *          user.
   * @param err
   *          The error stream to used if we have to prompt to the
   *          user.
   * @return the password of the second server which has to be used in the
   *          enable replication subcommand.
   */
  public String getBindPassword2(
      String dn, OutputStream out, OutputStream err)
  {
    return getBindPassword(dn, out, err, bindPassword2Arg,
        bindPasswordFile2Arg);
  }
  /**
   * Get the password of the global administrator which has to be used for the
   * command.
   *
   * @param dn
   *          The user DN for which to password could be asked.
   * @param out
   *          The input stream to used if we have to prompt to the
   *          user.
   * @param err
   *          The error stream to used if we have to prompt to the
   *          user.
   * @return the password of the global administrator which has to be used for
   *          the command.
   */
  public String getBindPasswordAdmin(
      String dn, OutputStream out, OutputStream err)
  {
    return getBindPassword(dn, out, err, adminPasswordArg,
        adminPasswordFileArg);
  }
  /**
   * Indicate if the SSL mode is required for the first server in the enable
   * replication subcommand.
   *
   * @return <CODE>true</CODE> if SSL mode is required for the first server in
   * the enable replication subcommand and <CODE>false</CODE> otherwise.
   */
  public boolean useSSL1()
  {
    return useSSL1Arg.isPresent();
  }
  /**
   * Indicate if the startTLS mode is required for the first server in the
   * enable replication subcommand.
   *
   * @return <CODE>true</CODE> if startTLS mode is required for the first server
   * in the enable replication subcommand and <CODE>false</CODE> otherwise.
   */
  public boolean useStartTLS1()
  {
    return useStartTLS1Arg.isPresent();
  }
  /**
   * Indicate if the SSL mode is required for the second server in the enable
   * replication subcommand.
   *
   * @return <CODE>true</CODE> if SSL mode is required for the second server in
   * the enable replication subcommand and <CODE>false</CODE> otherwise.
   */
  public boolean useSSL2()
  {
    return useSSL2Arg.isPresent();
  }
  /**
   * Indicate if the startTLS mode is required for the second server in the
   * enable replication subcommand.
   *
   * @return <CODE>true</CODE> if startTLS mode is required for the second
   * server in the enable replication subcommand and <CODE>false</CODE>
   * otherwise.
   */
  public boolean useStartTLS2()
  {
    return useStartTLS2Arg.isPresent();
  }
  /**
   * Indicate if the SSL mode is required for the source server in the
   * initialize replication subcommand.
   *
   * @return <CODE>true</CODE> if SSL mode is required for the source server
   * in the initialize replication subcommand and <CODE>false</CODE> otherwise.
   */
  public boolean useSSLSource()
  {
    return useSSLSourceArg.isPresent();
  }
  /**
   * Indicate if the StartTLS mode is required for the source server in the
   * initialize replication subcommand.
   *
   * @return <CODE>true</CODE> if StartTLS mode is required for the source
   * server in the initialize replication subcommand and <CODE>false</CODE>
   * otherwise.
   */
  public boolean useStartTLSSource()
  {
    return useStartTLSSourceArg.isPresent();
  }
  /**
   * Indicate if the SSL mode is required for the destinaton server in the
   * initialize replication subcommand.
   *
   * @return <CODE>true</CODE> if SSL mode is required for the destination
   * server in the initialize replication subcommand and <CODE>false</CODE>
   * otherwise.
   */
  public boolean useSSLDestination()
  {
    return useSSLDestinationArg.isPresent();
  }
  /**
   * Indicate if the SSL mode is required for the destination server in the
   * initialize replication subcommand.
   *
   * @return <CODE>true</CODE> if StartTLS mode is required for the destination
   * server in the initialize replication subcommand and <CODE>false</CODE>
   * otherwise.
   */
  public boolean useStartTLSDestination()
  {
    return useStartTLSDestinationArg.isPresent();
  }
  /**
   * Indicate if the SSL mode is required for the server in the disable
   * replication subcommand.
   *
   * @return <CODE>true</CODE> if SSL mode is required for the server in the
   * disable replication subcommand and <CODE>false</CODE> otherwise.
   */
  public boolean useSSLToDisable()
  {
    return useSSLArg.isPresent();
  }
  /**
   * Indicate if the SSL mode is required for the server in the disable
   * replication subcommand.
   *
   * @return <CODE>true</CODE> if StartTLS mode is required for the server in
   * the disable replication subcommand and <CODE>false</CODE> otherwise.
   */
  public boolean useStartTLSToDisable()
  {
    return useStartTLSArg.isPresent();
  }
  /**
   * Returns the Administrator UID explicitly provided in the command-line.
   * @return the Administrator UID explicitly provided in the command-line.
   */
  public String getAdministratorUID()
  {
    return getValue(adminUidArg);
  }
  /**
   * Returns the default Administrator UID value.
   * @return the default Administrator UID value.
   */
  public String getDefaultAdministratorUID()
  {
    return getDefaultValue(adminUidArg);
  }
  /**
   * Returns the first host name explicitly provided in the enable replication
   * subcommand.
   * @return the first host name explicitly provided in the enable replication
   * subcommand.
   */
  public String getHostName1()
  {
    return getValue(hostName1Arg);
  }
  /**
   * Returns the first host name default value in the enable replication
   * subcommand.
   * @return the first host name default value in the enable replication
   * subcommand.
   */
  public String getDefaultHostName1()
  {
    return getDefaultValue(hostName1Arg);
  }
  /**
   * Returns the first server port explicitly provided in the enable replication
   * subcommand.
   * @return the first server port explicitly provided in the enable replication
   * subcommand.  Returns -1 if no port was explicitly provided.
   */
  public int getPort1()
  {
    return getValue(port1Arg);
  }
  /**
   * Returns the first server port default value in the enable replication
   * subcommand.
   * @return the first server port default value in the enable replication
   * subcommand.
   */
  public int getDefaultPort1()
  {
    return getDefaultValue(port1Arg);
  }
  /**
   * Returns the first server bind dn explicitly provided in the enable
   * replication subcommand.
   * @return the first server bind dn explicitly provided in the enable
   * replication subcommand.  Returns -1 if no port was explicitly provided.
   */
  public String getBindDn1()
  {
    return getValue(bindDn1Arg);
  }
  /**
   * Returns the first server bind dn default value in the enable replication
   * subcommand.
   * @return the first server bind dn default value in the enable replication
   * subcommand.
   */
  public String getDefaultBindDn1()
  {
    return getDefaultValue(bindDn1Arg);
  }
  /**
   * Returns the first server replication port explicitly provided in the enable
   * replication subcommand.
   * @return the first server replication port explicitly provided in the enable
   * replication subcommand.  Returns -1 if no port was explicitly provided.
   */
  public int getReplicationPort1()
  {
    return getValue(replicationPort1Arg);
  }
  /**
   * Returns the first server replication port default value in the enable
   * replication subcommand.
   * @return the first server replication port default value in the enable
   * replication subcommand.
   */
  public int getDefaultReplicationPort1()
  {
    return getDefaultValue(replicationPort1Arg);
  }
  /**
   * Returns the second host name explicitly provided in the enable replication
   * subcommand.
   * @return the second host name explicitly provided in the enable replication
   * subcommand.
   */
  public String getHostName2()
  {
    return getValue(hostName2Arg);
  }
  /**
   * Returns the second host name default value in the enable replication
   * subcommand.
   * @return the second host name default value in the enable replication
   * subcommand.
   */
  public String getDefaultHostName2()
  {
    return getDefaultValue(hostName2Arg);
  }
  /**
   * Returns the second server port explicitly provided in the enable
   * replication subcommand.
   * @return the second server port explicitly provided in the enable
   * replication subcommand.  Returns -1 if no port was explicitly provided.
   */
  public int getPort2()
  {
    return getValue(port2Arg);
  }
  /**
   * Returns the second server port default value in the enable replication
   * subcommand.
   * @return the second server port default value in the enable replication
   * subcommand.
   */
  public int getDefaultPort2()
  {
    return getDefaultValue(port2Arg);
  }
  /**
   * Returns the second server bind dn explicitly provided in the enable
   * replication subcommand.
   * @return the second server bind dn explicitly provided in the enable
   * replication subcommand.  Returns -1 if no port was explicitly provided.
   */
  public String getBindDn2()
  {
    return getValue(bindDn2Arg);
  }
  /**
   * Returns the second server bind dn default value in the enable replication
   * subcommand.
   * @return the second server bind dn default value in the enable replication
   * subcommand.
   */
  public String getDefaultBindDn2()
  {
    return getDefaultValue(bindDn2Arg);
  }
  /**
   * Returns the second server replication port explicitly provided in the
   * enable replication subcommand.
   * @return the second server replication port explicitly provided in the
   * enable replication subcommand.  Returns -1 if no port was explicitly
   * provided.
   */
  public int getReplicationPort2()
  {
    return getValue(replicationPort2Arg);
  }
  /**
   * Returns the second server replication port default value in the enable
   * replication subcommand.
   * @return the second server replication port default value in the enable
   * replication subcommand.
   */
  public int getDefaultReplicationPort2()
  {
    return getDefaultValue(replicationPort2Arg);
  }
  /**
   * Returns the host name explicitly provided in the disable replication
   * subcommand.
   * @return the host name explicitly provided in the disable replication
   * subcommand.
   */
  public String getHostNameToDisable()
  {
    return getValue(hostNameArg);
  }
  /**
   * Returns the host name default value in the disable replication
   * subcommand.
   * @return the host name default value in the disable replication
   * subcommand.
   */
  public String getDefaultHostNameToDisable()
  {
    return getDefaultValue(hostNameArg);
  }
  /**
   * Returns the source host name explicitly provided in the initialize
   * replication subcommand.
   * @return the source host name explicitly provided in the initialize
   * replication subcommand.
   */
  public String getHostNameSource()
  {
    return getValue(hostNameSourceArg);
  }
  /**
   * Returns the first host name default value in the initialize replication
   * subcommand.
   * @return the first host name default value in the initialize replication
   * subcommand.
   */
  public String getDefaultHostNameSource()
  {
    return getDefaultValue(hostNameSourceArg);
  }
  /**
   * Returns the destination host name explicitly provided in the initialize
   * replication subcommand.
   * @return the destination host name explicitly provided in the initialize
   * replication subcommand.
   */
  public String getHostNameDestination()
  {
    return getValue(hostNameDestinationArg);
  }
  /**
   * Returns the destination host name default value in the initialize
   * replication subcommand.
   * @return the destination host name default value in the initialize
   * replication subcommand.
   */
  public String getDefaultHostNameDestination()
  {
    return getDefaultValue(hostNameDestinationArg);
  }
  /**
   * Returns the source server port explicitly provided in the initialize
   * replication subcommand.
   * @return the source server port explicitly provided in the initialize
   * replication subcommand.  Returns -1 if no port was explicitly provided.
   */
  public int getPortSource()
  {
    return getValue(portSourceArg);
  }
  /**
   * Returns the source server port default value in the initialize replication
   * subcommand.
   * @return the source server port default value in the initialize replication
   * subcommand.
   */
  public int getDefaultPortSource()
  {
    return getDefaultValue(portSourceArg);
  }
  /**
   * Returns the destination server port explicitly provided in the initialize
   * replication subcommand.
   * @return the destination server port explicitly provided in the initialize
   * replication subcommand.  Returns -1 if no port was explicitly provided.
   */
  public int getPortDestination()
  {
    return getValue(portDestinationArg);
  }
  /**
   * Returns the destination server port default value in the initialize
   * replication subcommand.
   * @return the destination server port default value in the initialize
   * replication subcommand.
   */
  public int getDefaultPortDestination()
  {
    return getDefaultValue(portDestinationArg);
  }
  /**
   * Returns the server port explicitly provided in the disable replication
   * subcommand.
   * @return the server port explicitly provided in the disable replication
   * subcommand.  Returns -1 if no port was explicitly provided.
   */
  public int getPortToDisable()
  {
    return getValue(portArg);
  }
  /**
   * Returns the server port default value in the disable replication
   * subcommand.
   * @return the server port default value in the disable replication
   * subcommand.
   */
  public int getDefaultPortToDisable()
  {
    return getDefaultValue(portArg);
  }
  /**
   * Returns the list of base DNs provided by the user.
   * @return the list of base DNs provided by the user.
   */
  public LinkedList<String> getBaseDNs()
  {
    return baseDNsArg.getValues();
  }
  /**
   * Returns the value of the provided argument only if the user provided it
   * explicitly.
   * @param arg the StringArgument to be handled.
   * @return the value of the provided argument only if the user provided it
   * explicitly.
   */
  private String getValue(StringArgument arg)
  {
    String v = null;
    if (arg.isPresent())
    {
      v = arg.getValue();
    }
    return v;
  }
  /**
   * Returns the default value of the provided argument.
   * @param arg the StringArgument to be handled.
   * @return the default value of the provided argument.
   */
  private String getDefaultValue(StringArgument arg)
  {
    return arg.getDefaultValue();
  }
  /**
   * Returns the value of the provided argument only if the user provided it
   * explicitly.
   * @param arg the StringArgument to be handled.
   * @return the value of the provided argument only if the user provided it
   * explicitly.
   */
  private int getValue(IntegerArgument arg)
  {
    int v = -1;
    if (arg.isPresent())
    {
      try
      {
        v = arg.getIntValue();
      }
      catch (ArgumentException ae)
      {
        // This is a bug
        throw new IllegalStateException(
            "There was an argument exception calling "+
            "ReplicationCliParser.getValue().  This appears to be a bug "+
            "because this method should be called after calling "+
            "parseArguments which should result in an error.", ae);
      }
    }
    return v;
  }
  /**
   * Returns the default value of the provided argument.
   * @param arg the StringArgument to be handled.
   * @return the default value of the provided argument.
   */
  private int getDefaultValue(IntegerArgument arg)
  {
    int returnValue = -1;
    String defaultValue = arg.getDefaultValue();
    if (defaultValue != null)
    {
      returnValue = Integer.parseInt(arg.getDefaultValue());
    }
    return returnValue;
  }
  /**
   * Checks the subcommand options and updates the provided MessageBuilder
   * with the errors that were encountered with the subcommand options.
   *
   * This method assumes that the method parseArguments for the parser has
   * already been called.
   * @param buf the MessageBuilder object where we add the error messages
   * describing the errors encountered.
   */
  public void validateSubcommandOptions(MessageBuilder buf)
  {
    if (isEnableReplicationSubcommand())
    {
      validateEnableReplicationOptions(buf);
    }
    else if (isDisableReplicationSubcommand())
    {
      validateDisableReplicationOptions(buf);
    }
    else  if (isInitializeReplicationSubcommand())
    {
      validateInitializeReplicationOptions(buf);
    }
    else
    {
      // This can occur if the user did not provide any subcommand.  We assume
      // that the error informing of this will be generated in
      // validateGlobalOptions.
    }
  }
  /**
   * Returns whether the user provided subcommand is the enable replication
   * or not.
   * @return <CODE>true</CODE> if the user provided subcommand is the
   * enable replication and <CODE>false</CODE> otherwise.
   */
  public boolean isEnableReplicationSubcommand()
  {
    return isSubcommand(ENABLE_REPLICATION_SUBCMD_NAME);
  }
  /**
   * Returns whether the user provided subcommand is the disable replication
   * or not.
   * @return <CODE>true</CODE> if the user provided subcommand is the
   * disable replication and <CODE>false</CODE> otherwise.
   */
  public boolean isDisableReplicationSubcommand()
  {
    return isSubcommand(DISABLE_REPLICATION_SUBCMD_NAME);
  }
  /**
   * Returns whether the user provided subcommand is the initialize replication
   * or not.
   * @return <CODE>true</CODE> if the user provided subcommand is the
   * initialize replication and <CODE>false</CODE> otherwise.
   */
  public boolean isInitializeReplicationSubcommand()
  {
    return isSubcommand(INITIALIZE_REPLICATION_SUBCMD_NAME);
  }
  /**
   * Returns whether the command-line subcommand has the name provided
   * or not.
   * @param name the name of the subcommand.
   * @return <CODE>true</CODE> if command-line subcommand has the name provided
   * and <CODE>false</CODE> otherwise.
   */
  private boolean isSubcommand(String name)
  {
    boolean isSubcommand = false;
    SubCommand subCommand = getSubCommand();
    if (subCommand != null)
    {
      isSubcommand = subCommand.getName().equalsIgnoreCase(name);
    }
    return isSubcommand;
  }
  /**
   * Checks the enable replication subcommand options and updates the provided
   * MessageBuilder with the errors that were encountered with the subcommand
   * options.
   *
   * This method assumes that the method parseArguments for the parser has
   * already been called.
   * @param buf the MessageBuilder object where we add the error messages
   * describing the errors encountered.
   */
  private void validateEnableReplicationOptions(MessageBuilder buf)
  {
    Argument[][] conflictingPairs =
    {
        {bindPassword1Arg, bindPasswordFile1Arg},
        {useStartTLS1Arg, useSSL1Arg},
        {bindPassword2Arg, bindPasswordFile2Arg},
        {useStartTLS2Arg, useSSL2Arg}
    };
    for (int i=0; i< conflictingPairs.length; i++)
    {
      Argument arg1 = conflictingPairs[i][0];
      Argument arg2 = conflictingPairs[i][1];
      if (arg1.isPresent() && arg2.isPresent())
      {
        Message message = ERR_TOOL_CONFLICTING_ARGS.get(
            arg1.getLongIdentifier(), arg2.getLongIdentifier());
        addMessage(buf, message);
      }
    }
    if (hostName1Arg.getValue().equalsIgnoreCase(hostName2Arg.getValue()))
    {
      if (port1Arg.getValue() == port2Arg.getValue())
      {
        Message message = ERR_REPLICATION_SAME_SERVER_PORT.get(
            hostName1Arg.getValue(), port1Arg.getValue());
        addMessage(buf, message);
      }
      // If the user explicitly provides the same port in the same host,
      // reject it.
      if (getValue(replicationPort1Arg) == getValue(replicationPort2Arg))
      {
        Message message = ERR_REPLICATION_SAME_REPLICATION_PORT.get(
            replicationPort1Arg.getValue(), hostName1Arg.getValue());
        addMessage(buf, message);
      }
      try
      {
        if (replicationPort1Arg.getIntValue() == port1Arg.getIntValue())
        {
          Message message = ERR_REPLICATION_SAME_REPLICATION_PORT.get(
              replicationPort1Arg.getValue(), hostName1Arg.getValue());
          addMessage(buf, message);
        }
      } catch (ArgumentException ae)
      {
        // This is a bug
        throw new IllegalStateException(
            "There was an argument exception calling "+
            "ReplicationCliParser.validateEnableReplicationOptions().  "+
            "This appears to be a bug "+
            "because this method should be called after calling "+
            "parseArguments which should result in an error.", ae);
      }
    }
  }
  /**
   * Checks the disable replication subcommand options and updates the provided
   * MessageBuilder with the errors that were encountered with the subcommand
   * options.
   *
   * This method assumes that the method parseArguments for the parser has
   * already been called.
   * @param buf the MessageBuilder object where we add the error messages
   * describing the errors encountered.
   */
  private void validateDisableReplicationOptions(MessageBuilder buf)
  {
    Argument[][] conflictingPairs =
    {
        {useStartTLSSourceArg, useSSLSourceArg},
        {useStartTLSDestinationArg, useSSLDestinationArg}
    };
    for (int i=0; i< conflictingPairs.length; i++)
    {
      Argument arg1 = conflictingPairs[i][0];
      Argument arg2 = conflictingPairs[i][1];
      if (arg1.isPresent() && arg2.isPresent())
      {
        Message message = ERR_TOOL_CONFLICTING_ARGS.get(
            arg1.getLongIdentifier(), arg2.getLongIdentifier());
        addMessage(buf, message);
      }
    }
    if (hostNameSourceArg.getValue().equalsIgnoreCase(
        hostNameDestinationArg.getValue()))
    {
      if (portSourceArg.getValue() == portDestinationArg.getValue())
      {
        Message message = ERR_REPLICATION_SAME_SERVER_PORT.get(
            hostNameSourceArg.getValue(), portSourceArg.getValue());
        addMessage(buf, message);
      }
    }
  }
  /**
   * Checks the initialize replication subcommand options and updates the
   * provided MessageBuilder with the errors that were encountered with the
   * subcommand options.
   *
   * This method assumes that the method parseArguments for the parser has
   * already been called.
   * @param buf the MessageBuilder object where we add the error messages
   * describing the errors encountered.
   */
  private void validateInitializeReplicationOptions(MessageBuilder buf)
  {
    // The startTLS and useSSL arguments are already validated in
    // SecureConnectionCliParser.validateGlobalOptions.
  }
  /**
   * Adds a message to the provided MessageBuilder.
   * @param buf the MessageBuilder.
   * @param message the message to be added.
   */
  private void addMessage(MessageBuilder buf, Message message)
  {
    if (buf.length() > 0)
    {
      buf.append(EOL);
    }
    buf.append(message);
  }
}
opends/src/guitools/org/opends/guitools/replicationcli/ReplicationCliReturnCode.java
New file
@@ -0,0 +1,188 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 */
package org.opends.guitools.replicationcli;
import static org.opends.messages.AdminToolMessages.*;
import org.opends.messages.Message;
/**
 *
 * The enumeration which defines the return code.
 *
 */
public enum ReplicationCliReturnCode
{
  /**
   * successful.
   */
  SUCCESSFUL(0, INFO_REPLICATION_SUCCESSFUL.get()),
  /**
   * successful but no operation was performed.
   */
  SUCCESSFUL_NOP(SUCCESSFUL.getReturnCode(),
      INFO_REPLICATION_SUCCESSFUL_NOP.get()),
  /**
   * Unable to initialize arguments.
   */
  CANNOT_INITIALIZE_ARGS(1, ERR_REPLICATION_NO_MESSAGE.get()),
  /**
   * Cannot parse argument.
   */
  ERROR_PARSING_ARGS(2, ERR_REPLICATION_NO_MESSAGE.get()),
  /**
   * The user cancelled the operation in interactive mode.
   */
  USER_CANCELLED(3, ERR_REPLICATION_USER_CANCELLED.get()),
  /**
   * Unexpected error (potential bug).
   */
  CONFLICTING_ARGS(4, ERR_REPLICATION_NO_MESSAGE.get()),
  /**
   * The provided base DNs cannot be used to enable replication.
   */
  REPLICATION_CANNOT_BE_ENABLED_ON_BASEDN(5, ERR_REPLICATION_NO_MESSAGE.get()),
  /**
   * The provided base DNs cannot be used to disable replication.
   */
  REPLICATION_CANNOT_BE_DISABLED_ON_BASEDN(6, ERR_REPLICATION_NO_MESSAGE.get()),
  /**
   * The provided base DNs cannot be used to initialize the contents of the
   * replicas.
   */
  REPLICATION_CANNOT_BE_INITIALIZED_ON_BASEDN(7,
      ERR_REPLICATION_NO_MESSAGE.get()),
  /**
   * Error connecting with the provided credentials.
   */
  ERROR_CONNECTING(8, ERR_REPLICATION_NO_MESSAGE.get()),
  /**
   * Could not find the replication ID of the domain to be used to initialize
   * the replica.
   */
  REPLICATIONID_NOT_FOUND(9, ERR_REPLICATION_NO_MESSAGE.get()),
  /**
   * The number of tries we perform to start the initialization are over.
   * We systematically receive a peer not found error.
   */
  INITIALIZING_TRIES_COMPLETED(10, ERR_REPLICATION_NO_MESSAGE.get()),
  /**
   * Error enabling replication on a base DN.
   */
  ERROR_ENABLING_REPLICATION_ON_BASEDN(11, ERR_REPLICATION_NO_MESSAGE.get()),
  /**
   * Error initializing base DN.
   */
  ERROR_INITIALIZING_BASEDN_GENERIC(12, ERR_REPLICATION_NO_MESSAGE.get()),
  /**
   * Error reading configuration.
   */
  ERROR_READING_CONFIGURATION(13, ERR_REPLICATION_NO_MESSAGE.get()),
  /**
   * Error updating ADS.
   */
  ERROR_UPDATING_ADS(14, ERR_REPLICATION_NO_MESSAGE.get()),
  /**
   * Error reading ADS.
   */
  ERROR_READING_ADS(15, ERR_REPLICATION_NO_MESSAGE.get()),
  /**
   * Error reading TopologyCache.
   */
  ERROR_READING_TOPOLOGY_CACHE(16, ERR_REPLICATION_NO_MESSAGE.get()),
  /**
   * Error configuring replication server.
   */
  ERROR_CONFIGURING_REPLICATIONSERVER(17, ERR_REPLICATION_NO_MESSAGE.get()),
  /**
   * Unsupported ADS scenario.
   */
  REPLICATION_ADS_MERGE_NOT_SUPPORTED(18, ERR_REPLICATION_NO_MESSAGE.get()),
  /**
   * Error disabling replication on base DN.
   */
  ERROR_DISABLING_REPLICATION_ON_BASEDN(19, ERR_REPLICATION_NO_MESSAGE.get()),
  /**
   * Error removing replication port reference on base DN.
   */
  ERROR_DISABLING_REPLICATION_REMOVE_REFERENCE_ON_BASEDN(20,
      ERR_REPLICATION_NO_MESSAGE.get());
  private Message message;
  private int returnCode;
  // Private constructor.
  private ReplicationCliReturnCode(int returnCode, Message message)
  {
    this.returnCode = returnCode;
    this.message = message;
  }
  /**
   * Get the corresponding message.
   *
   * @return The corresponding message.
   */
  public Message getMessage()
  {
    return message;
  }
  /**
   * Get the corresponding return code value.
   *
   * @return The corresponding return code value.
   */
  public int getReturnCode()
  {
    return returnCode;
  }
}
opends/src/guitools/org/opends/guitools/replicationcli/ReplicationUserData.java
New file
@@ -0,0 +1,98 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 */
package org.opends.guitools.replicationcli;
import java.util.LinkedList;
/**
 * This class is used to store the information provided by the user in the
 * replication command line.  It is required because when we are in interactive
 * mode the ReplicationCliArgumentParser is not enough.
 *
 */
abstract class ReplicationUserData
{
  private LinkedList<String> baseDNs = new LinkedList<String>();
  private String adminUid;
  private String adminPwd;
  /**
   * Returns the Global Administrator password.
   * @return the Global Administrator password.
   */
  String getAdminPwd()
  {
    return adminPwd;
  }
  /**
   * Sets the Global Administrator password.
   * @param adminPwd the Global Administrator password.
   */
  void setAdminPwd(String adminPwd)
  {
    this.adminPwd = adminPwd;
  }
  /**
   * Returns the Global Administrator UID.
   * @return the Global Administrator UID.
   */
  String getAdminUid()
  {
    return adminUid;
  }
  /**
   * Sets the Global Administrator UID.
   * @param adminUid the Global Administrator UID.
   */
  void setAdminUid(String adminUid)
  {
    this.adminUid = adminUid;
  }
  /**
   * Returns the Base DNs to replicate.
   * @return the Base DNs to replicate.
   */
  LinkedList<String> getBaseDNs()
  {
    return new LinkedList<String>(baseDNs);
  }
  /**
   * Sets the Base DNs to replicate.
   * @param baseDNs the Base DNs to replicate.
   */
  void setBaseDNs(LinkedList<String> baseDNs)
  {
    this.baseDNs.clear();
    this.baseDNs.addAll(baseDNs);
  }
}
opends/src/guitools/org/opends/guitools/replicationcli/package-info.java
New file
@@ -0,0 +1,40 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 */
/**
 * Defines the  classes that are you used by the replication
 * command lines.  This includes the command line parsers
 * (ReplicationCliParser), the classes that actually execute the configuration
 * operations (ReplicationCliMain), the enumeration that defines the return
 * codes of the command-line (ReplicationCliReturnCode), a particular exception
 * used only for the package (ReplicationCliException) and the different data
 * models that represent the data provided by the user directly as command-line
 * parameters and also interactively.
 * */
package org.opends.guitools.replicationcli;
opends/src/guitools/org/opends/guitools/statuspanel/StatusCli.java
@@ -178,7 +178,7 @@
              directoryManagerDn, directoryManagerPwd);
          ConfigFromLDAP onLineConf = new ConfigFromLDAP();
          ConnectionProtocolPolicy policy;
          if (startTLSArg.isPresent())
          if (useStartTLSArg.isPresent())
          {
            policy = ConnectionProtocolPolicy.USE_STARTTLS;
          }
opends/src/guitools/org/opends/guitools/uninstaller/UninstallCliHelper.java
@@ -555,25 +555,6 @@
    return confirm(INFO_CLI_UNINSTALL_CONFIRM_DELETE_FILES.get());
  }
  private boolean confirm(Message msg) {
    boolean confirm = true;
    Message[] validValues = {
        INFO_CLI_YES_SHORT.get(),
        INFO_CLI_NO_SHORT.get(),
        INFO_CLI_YES_LONG.get(),
        INFO_CLI_NO_LONG.get(),
    };
    Message answer = promptConfirm(msg, validValues[2], validValues);
    if (INFO_CLI_NO_SHORT.get().toString()
            .equalsIgnoreCase(answer.toString()) ||
        INFO_CLI_NO_LONG.get().toString()
                .equalsIgnoreCase(answer.toString()))
    {
      confirm = false;
    }
    return confirm;
  }
  /**
   *  Ask for confirmation to update configuration on remote servers.
   *  @return <CODE>true</CODE> if the user wants to continue and stop the
@@ -626,7 +607,7 @@
    {
      while (uid == null)
      {
        uid = askForAdministratorUID();
        uid = askForAdministratorUID(parser.getDefaultAdministratorUID());
      }
      while (pwd == null)
      {
@@ -727,17 +708,6 @@
    return accepted;
  }
  private String askForAdministratorUID()
  {
    return promptForString(INFO_UNINSTALL_CLI_ADMINISTRATOR_UID_PROMPT.get(),
        Constants.GLOBAL_ADMIN_UID);
  }
  private String askForAdministratorPwd()
  {
    return promptForPassword(INFO_UNINSTALL_CLI_ADMINISTRATOR_PWD_PROMPT.get());
  }
  private String askForReferencedHostName(String defaultHostName)
  {
    return promptForString(INFO_UNINSTALL_CLI_REFERENCED_HOSTNAME_PROMPT.get(),
@@ -916,7 +886,7 @@
    } catch (TopologyCacheException te)
    {
      LOG.log(Level.WARNING, "Error connecting to server: "+te, te);
      printErrorMessage(Utils.getStringRepresentation(te));
      printErrorMessage(Utils.getMessage(te));
    } catch (Throwable t)
    {
@@ -973,7 +943,7 @@
        exceptions.add(e);
      }
    }
    Set<String> exceptionMsgs = new LinkedHashSet<String>();
    Set<Message> exceptionMsgs = new LinkedHashSet<Message>();
    /* Check the exceptions and see if we throw them or not. */
    for (TopologyCacheException e : exceptions)
    {
@@ -1007,21 +977,18 @@
          else
          {
            stopProcessing = true;
            String url = e.getLdapUrl();
            int index = url.indexOf("//");
            String hostPort = url.substring(index + 2);
            printErrorMessage(
                INFO_ERROR_READING_CONFIG_LDAP_CERTIFICATE_SERVER.get(
                hostPort, e.getCause().getMessage()));
                e.getHostPort(), e.getCause().getMessage()));
          }
        }
        else
        {
          exceptionMsgs.add(Utils.getStringRepresentation(e));
          exceptionMsgs.add(Utils.getMessage(e));
        }
        break;
      default:
        exceptionMsgs.add(Utils.getStringRepresentation(e));
        exceptionMsgs.add(Utils.getMessage(e));
      }
    }
    if (interactive)
@@ -1029,9 +996,9 @@
      if (!stopProcessing && (exceptionMsgs.size() > 0))
      {
        returnValue = confirm(
            ERR_READING_REGISTERED_SERVERS_CONFIRM_UPDATE_REMOTE.get(
                Utils.getStringFromCollection(exceptionMsgs,
                  Constants.LINE_SEPARATOR)));
            ERR_UNINSTALL_READING_REGISTERED_SERVERS_CONFIRM_UPDATE_REMOTE.get(
                Utils.getMessageFromCollection(exceptionMsgs,
                  Constants.LINE_SEPARATOR).toString()));
      }
      else if (reloadTopologyCache)
      {
@@ -1047,7 +1014,7 @@
    {
      if (exceptionMsgs.size() > 0)
      {
        printErrorMessage(Utils.getStringFromCollection(exceptionMsgs,
        printErrorMessage(Utils.getMessageFromCollection(exceptionMsgs,
            Constants.LINE_SEPARATOR));
        returnValue = false;
      }
opends/src/guitools/org/opends/guitools/uninstaller/Uninstaller.java
@@ -1374,8 +1374,8 @@
            if (throwable instanceof TopologyCacheException)
            {
              qs.displayError(
                      Message.raw(getStringRepresentation(
                              (TopologyCacheException)throwable)),
                      getMessage(
                              (TopologyCacheException)throwable),
                      INFO_ERROR_TITLE.get());
            }
            else
@@ -1438,7 +1438,7 @@
        exceptions.add(e);
      }
    }
    Set<String> exceptionMsgs = new LinkedHashSet<String>();
    Set<Message> exceptionMsgs = new LinkedHashSet<Message>();
    /* Check the exceptions and see if we throw them or not. */
    for (TopologyCacheException e : exceptions)
    {
@@ -1504,13 +1504,13 @@
          }
        }
      }
      exceptionMsgs.add(getStringRepresentation(e));
      exceptionMsgs.add(getMessage(e));
    }
    if (!stopProcessing && (exceptionMsgs.size() > 0))
    {
      Message confirmationMsg =
        ERR_READING_REGISTERED_SERVERS_CONFIRM_UPDATE_REMOTE.get(
                getStringFromCollection(exceptionMsgs, "n"));
        ERR_UNINSTALL_READING_REGISTERED_SERVERS_CONFIRM_UPDATE_REMOTE.get(
                getMessageFromCollection(exceptionMsgs, "\n").toString());
      stopProcessing = !qs.displayConfirmation(confirmationMsg,
          INFO_CONFIRMATION_TITLE.get());
    }
@@ -1568,8 +1568,7 @@
            {
              if (throwable instanceof TopologyCacheException)
              {
                qs.displayError(Message.raw(
                    getStringRepresentation((TopologyCacheException)throwable)),
                qs.displayError(getMessage((TopologyCacheException)throwable),
                    INFO_ERROR_TITLE.get());
              }
              else
opends/src/guitools/org/opends/guitools/uninstaller/UninstallerArgumentParser.java
@@ -167,7 +167,7 @@
        SecureConnectionCliParser.QUIET_OPTION_LONG,
        SecureConnectionCliParser.QUIET_OPTION_SHORT,
        SecureConnectionCliParser.QUIET_OPTION_LONG,
        INFO_UNINSTALLDS_DESCRIPTION_SILENT.get());
        INFO_UNINSTALLDS_DESCRIPTION_QUIET.get());
    args.add(quiet);
    adminUidArg = new StringArgument("adminUID", 'I',
opends/src/messages/messages/admin_tool.properties
@@ -103,8 +103,6 @@
OpenDS servers the server must be started and then you must provide \
administrator authentication.  Do you want to start the server and then \
provide authentication to remove the remote references?
INFO_UNINSTALL_CLI_ADMINISTRATOR_UID_PROMPT=Global Administrator User ID
INFO_UNINSTALL_CLI_ADMINISTRATOR_PWD_PROMPT=Global Administrator Password:
INFO_UNINSTALL_CLI_REFERENCED_HOSTNAME_PROMPT=The name of this host (or IP \
address) as it is referenced in remote servers for replication
INFO_UNINSTALL_CONFIRM_PROVIDE_AUTHENTICATION_AGAIN=Do you want to provide \
@@ -159,8 +157,8 @@
 continue. Do you want the uninstaller to stop the server for you and continue \
 with the uninstall? If you click No, you will need to stop the server \
 manually to continue.
MILD_ERR_READING_REGISTERED_SERVERS_CONFIRM_UPDATE_REMOTE=The following \
 errors were encountered reading the configuration of the existing \
MILD_ERR_UNINSTALL_READING_REGISTERED_SERVERS_CONFIRM_UPDATE_REMOTE=The \
 following errors were encountered reading the configuration of the existing \
 servers:\n%s\nDo you want the uninstaller to try to remove the references to \
 this server in a best-effort mode?
INFO_CONFIRM_UNINSTALL_SERVER_RUNNING_TITLE=Server is Running
@@ -347,7 +345,7 @@
 install.  If not specified the graphical interface will be launched.  The \
 rest of the options (excluding help and version) will only be taken into \
 account if this option is specified
INFO_UNINSTALLDS_DESCRIPTION_SILENT=Perform a quiet uninstall (no \
INFO_UNINSTALLDS_DESCRIPTION_QUIET=Perform a quiet uninstall (no \
 progress information is written to the standard output)
INFO_UNINSTALLDS_DESCRIPTION_REMOVE_ALL=Remove all components of \
 OpenDS (this option is not compatible with the rest of remove options)
@@ -441,15 +439,21 @@
 StartTLS to secure communication with the source server
INFO_REPLICATION_TOOL_DESCRIPTION=This utility may be used to configure \
 replication between servers so that the data of the servers is synchronized.\
 In order replication to work you have first to enable replication between two \
 servers using the {%s} subcommand and then initialize the contents of one of \
 In order replication to work you have first to enable replication using the \
 {%s} subcommand and then initialize the contents of one of \
 servers with the contents of the other using the {%s} subcommand.
INFO_REPLICATION_DESCRIPTION_QUIET=Perform a quiet operation (no \
 progress information is written to the standard output)
INFO_DESCRIPTION_SUBCMD_INITIALIZE_REPLICATION=Initialize the contents of the \
 data under the specified Bind DN on the destination server with the contents \
 on the source server.  This operation is required after enabling replication \
 in order replication to work.
INFO_DESCRIPTION_SUBCMD_ENABLE_REPLICATION=Configures the two specified \
 servers to replicate the data under the specified Bind DN.
INFO_DESCRIPTION_SUBCMD_ENABLE_REPLICATION=Updates the configuration of the \
 servers to replicate the data under the specified Base DN.  If one of the \
 specified servers is already replicating the data under the Base DN with \
 other servers, executing this subcommand will update the configuration of all \
 the servers (so it is sufficient to execute the command line once for each \
 server we add to the replication topology).
INFO_DESCRIPTION_SUBCMD_DISABLE_REPLICATION=Disables replication on the \
 specified server for the provided Base DN and removes references in the other \
 servers with which it is replicating data.
@@ -460,3 +464,130 @@
 provide it using the {%s} or the {%s} options.
SEVERE_ERR_REPLICATION_NOT_A_VALID_BASEDN=The provided value %s is not a valid \
 base DN.
SEVERE_ERR_REPLICATION_SAME_SERVER_PORT=You have to provide two different \
 servers to replicate.  You have provided twice the server %s:%s
SEVERE_ERR_REPLICATION_SAME_REPLICATION_PORT=You have provided the same \
 replication port (%s) for two servers located on the same machine (%s).
SEVERE_ERR_REPLICATION_VALID_SUBCOMMAND_NOT_FOUND=Could not find a valid \
 subcommand.
INFO_REPLICATION_SUCCESSFUL=The operation has been successfully completed
INFO_REPLICATION_SUCCESSFUL_NOP=The operation has been successfully completed, \
 but no action was required
MILD_ERR_REPLICATION_USER_CANCELLED=User cancelled the operation
SEVERE_ERR_REPLICATION_NO_MESSAGE=
INFO_ADMINISTRATOR_UID_PROMPT=Global Administrator User ID:
INFO_ADMINISTRATOR_PWD_PROMPT=Global Administrator Password:
INFO_ADMINISTRATOR_PWD_CONFIRM_PROMPT=Confirm Password:
MILD_ERR_ADMINISTRATOR_PWD_DO_NOT_MATCH=The provided passwords do not match.
MILD_ERR_ERROR_CONNECTING_TO_SERVER_PROMPT_AGAIN=Could not connect to the \
 Directory Server %s with the provided credentials.%nProvide again the \
 required information to connect to the server:
INFO_REPLICATION_ENABLE_HOSTNAME1_PROMPT=Host name of the first server:
INFO_REPLICATION_ENABLE_PORT1_PROMPT=LDAP port of the first server:
INFO_REPLICATION_ENABLE_REPLICATIONPORT1_PROMPT=Replication port for the first \
server (the port must be free):
INFO_REPLICATION_ENABLE_HOSTNAME2_PROMPT=Host name of the second server:
INFO_REPLICATION_ENABLE_PORT2_PROMPT=LDAP port of the second server:
INFO_REPLICATION_ENABLE_REPLICATIONPORT2_PROMPT=Replication port for the \
second server (the port must be free):
INFO_REPLICATION_INITIALIZE_HOSTNAMESOURCE_PROMPT=Host name of the source \
server:
INFO_REPLICATION_INITIALIZE_PORTSOURCE_PROMPT=LDAP port of the source server:
INFO_REPLICATION_DISABLE_HOSTNAME_PROMPT=Host name of the server:
INFO_REPLICATION_DISABLE_PORT_PROMPT=LDAP port of the server:
INFO_REPLICATION_INITIALIZE_HOSTNAMEDESTINATION_PROMPT=Host name of the \
destination server:
INFO_REPLICATION_INITIALIZE_PORTDESTINATION_PROMPT=LDAP port of the \
destination server:
INFO_REPLICATION_BINDDN_PROMPT=Bind DN
INFO_REPLICATION_PASSWORD_PROMPT=Password
INFO_REPLICATION_USESSL_PROMPT=Use SSL to connect
INFO_CLI_INVALID_PORT=The provided value is not a valid port
INFO_REPLICATION_USESTARTTLS_PROMPT=Use StartTLS to connect
SEVERE_ERR_REPLICATION_PORT_AND_REPLICATION_PORT_EQUAL=The server LDAP port \
 and the replication port cannot have the same value.  You provided %s for both.
SEVERE_ERR_NO_SUFFIXES_AVAILABLE_TO_ENABLE_REPLICATION=There are no base DNs \
 available to enable replication between the two servers.
INFO_ALREADY_REPLICATED_SUFFIXES=The following base DNs are already replicated \
 between the two servers:%n%s
INFO_ALREADY_NOT_REPLICATED_SUFFIXES=The following base DNs are not replicated \
 between the two servers:%n%s
MILD_ERR_REPLICATION_ENABLE_SUFFIXES_NOT_FOUND=The following base DNs cannot \
 be replicated between the two servers because they could not be found in at \
 least one of the servers:%n%s
MILD_ERR_NO_SUFFIXES_SELECTED_TO_REPLICATE=You must choose at least one base \
 DN to be replicated.
INFO_REPLICATION_ENABLE_SUFFIX_PROMPT=Replicate base DN %s?
SEVERE_ERR_NO_SUFFIXES_AVAILABLE_TO_INITIALIZE_REPLICATION=There are no base \
 DNs replicated between the two servers.
MILD_ERR_SUFFIXES_CANNOT_BE_INITIALIZED=The following base DNs cannot be \
 initialized because they are not replicated or they are not configured on \
 both servers:%n%s
MILD_ERR_NO_SUFFIXES_SELECTED_TO_INITIALIZE=You must choose at least one \
 base DN to be initialized.
INFO_REPLICATION_INITIALIZE_SUFFIX_PROMPT=Initialize base DN %s?
SEVERE_ERR_NO_SUFFIXES_AVAILABLE_TO_DISABLE_REPLICATION=There are no base \
 DNs replicated in the server.
MILD_ERR_REPLICATION_DISABLE_SUFFIXES_NOT_FOUND=The following base DNs could \
 not be found on the server:%n%s
MILD_ERR_NO_SUFFIXES_SELECTED_TO_DISABLE=You must choose at least one \
 base DN to be disabled.
INFO_REPLICATION_DISABLE_SUFFIX_PROMPT=Disable replication on base DN %s?
MILD_ERR_REPLICATION_READING_REGISTERED_SERVERS_CONFIRM_UPDATE_REMOTE=The \
 following errors were encountered reading the configuration of the existing \
 servers:\n%s\nIf you continue the replication tool will to try to update the \
 configuration of all the servers in a best-effort mode.  However it cannot \
 guarantee that the servers that are generating errors will be updated.  Do \
 you want to continue?
MILD_ERR_NOT_ADMINISTRATIVE_USER=You do not have access rights to the \
 configuration of the server.
INFO_REPLICATION_CONFIRM_DISABLE_ADS=You chose to disable replication on \
 base DN %s.  This base DN is used by the replication mechanism and by some \
 administrative tools and it is not recommended to configure it directly.  Do \
 you want to continue?
INFO_REPLICATION_CONFIRM_DISABLE_GENERIC=Disabling replication will make the \
 data under the selected base DNs not to be synchronized with other servers \
 any more.  Do you want to continue?
INFO_REPLICATION_CONFIRM_INITIALIZE_ADS=You chose to initialize the contents \
 of base DN %s on server %s with the contents in server %s.  This base DN is \
 used by the replication mechanism and by some administrative tools and it is \
 not recommended to configure it directly.  Do you want to continue?
INFO_REPLICATION_CONFIRM_INITIALIZE_GENERIC=Initializing the contents of a \
 base DN removes all the existing contents of that base DN.  Do you want to \
 remove the contents of the selected base DNs on server %s and replace them \
 with the contents of server %s?
MILD_ERR_REPLICATION_READING_REGISTERED_SERVERS_WARNING=The following errors \
 were encountered reading the configuration of the existing servers:\n%s\nThe \
 replication tool will to try to update the configuration of all the servers \
 in a best-effort mode.  However it cannot guarantee that the servers that are \
 generating errors will be updated.
INFO_REPLICATION_CONNECTING=Establishing connections
INFO_REPLICATION_ENABLE_UPDATING_ADS_CONTENTS=Checking Registration information
INFO_REPLICATION_ENABLE_CONFIGURING_REPLICATION_SERVER=Configuring Replication \
 port on server %s
INFO_REPLICATION_ENABLE_CONFIGURING_BASEDN=Enabling Replication for baseDN %s \
 on server %s
INFO_ENABLE_REPLICATION_INITIALIZING_ADS=Initializing Registration information \
 on server %s with the contents of server %s
SEVERE_ERR_INITIALIZING_REPLICATIONID_NOT_FOUND=Error initializing.  Could not \
 find replication ID in the server %s for base DN %s.
SEVERE_ERR_REPLICATION_INITIALIZING_TRIES_COMPLETED=Error initializing.  Could \
 not find a peer to start the initialization after several tries.  Details: %s
SEVERE_ERR_REPLICATION_CONFIGURING_REPLICATIONSERVER=Error configuring \
 replication port on server %s.
SEVERE_ERR_REPLICATION_CONFIGURING_BASEDN=Error updating replication \
 configuration on base DN %s of server %s.
SEVERE_ERR_REPLICATION_UPDATING_ADS=Error updating Registration information.  \
 Details: %s
SEVERE_ERR_REPLICATION_READING_ADS=Error reading Registration information.  \
 Details: %s
SEVERE_ERR_REPLICATION_ADS_MERGE_NOT_SUPPORTED=The registry information found \
in servers %s and %s is different.  This tool does not allow to handle this \
scenario.
SEVERE_ERR_REPLICATION_ERROR_READING_CONFIGURATION=Error reading replication \
configuration of server %s.  Details: %s
INFO_REPLICATION_REMOVING_REFERENCES_ON_REMOTE=Removing references on base DN \
%s of server %s
INFO_REPLICATION_DISABLING_BASEDN=Disabling replication on base DN %s of \
server %s
opends/src/quicksetup/org/opends/quicksetup/Application.java
@@ -682,9 +682,9 @@
   * @param e the exception we want to obtain the representation from.
   * @return a localized representation of a TopologyCacheException object.
   */
  protected String getStringRepresentation(TopologyCacheException e)
  protected Message getMessage(TopologyCacheException e)
  {
    return Utils.getStringRepresentation(e);
    return Utils.getMessage(e);
  }
  /**
opends/src/quicksetup/org/opends/quicksetup/CliApplicationHelper.java
@@ -195,6 +195,43 @@
  }
  /**
   * Prompts the user to provide a port.
   * @param msg the message to be displayed.
   * @param defaultValue the default value to be proposed.
   * @return the user to provide a port.
   */
  protected int promptForPort(Message msg, int defaultValue)
  {
    int port = -1;
    while (port == -1)
    {
      String s = promptForString(msg, String.valueOf(defaultValue));
      if ((s != null) && (s.trim().length() > 0))
      {
        try
        {
          port = Integer.parseInt(s);
          if ((port < 0) || (port > 65535))
          {
            port = -1;
          }
        }
        catch (Throwable t)
        {
          port = -1;
        }
        if (port == -1)
        {
          Message message = INFO_CLI_INVALID_PORT.get();
          System.err.println(StaticUtils.wrapText(message,
                  Utils.getCommandLineMaxLineWidth()));
        }
      }
    }
    return port;
  }
  /**
   * Reads a line of text from standard input.
   * @return  The line of text read from standard input, or <CODE>null</CODE>
   *          if the end of the stream is reached or an error occurs while
@@ -406,6 +443,74 @@
  }
  /**
   * Prompts the user to give the Global Administrator UID.
   * @param defaultValue the default value that will be proposed in the prompt
   * message.
   * @return the Global Administrator UID as provided by the user.
   */
  protected String askForAdministratorUID(String defaultValue)
  {
    return promptForString(INFO_ADMINISTRATOR_UID_PROMPT.get(), defaultValue);
  }
  /**
   * Prompts the user to give the Global Administrator password.
   * @return the Global Administrator password as provided by the user.
   */
  protected String askForAdministratorPwd()
  {
    return promptForPassword(INFO_ADMINISTRATOR_PWD_PROMPT.get());
  }
  /**
   * Prompts the user to confirm a question.  The default proposed value as
   * answer is to confirm the question.
   * @param msg the message to be displayed to the user.
   * @return <CODE>true</CODE> if the user accepted the message and
   * <CODE>false</CODE> otherwise.
   */
  protected boolean confirm(Message msg)
  {
    return confirm(msg, true);
  }
  /**
   * Prompts the user to confirm a question.
   * @param msg the message to be displayed to the user.
   * @param defaultTrue whether the default proposed value as answer is to
   * accept the message or not.
   * @return <CODE>true</CODE> if the user accepted the message and
   * <CODE>false</CODE> otherwise.
   */
  protected boolean confirm(Message msg, boolean defaultTrue) {
    boolean confirm = true;
    Message[] validValues = {
        INFO_CLI_YES_SHORT.get(),
        INFO_CLI_NO_SHORT.get(),
        INFO_CLI_YES_LONG.get(),
        INFO_CLI_NO_LONG.get(),
    };
    Message defaultMessage;
    if (defaultTrue)
    {
      defaultMessage = validValues[2];
    }
    else
    {
      defaultMessage = validValues[3];
    }
    Message answer = promptConfirm(msg, defaultMessage, validValues);
    if (INFO_CLI_NO_SHORT.get().toString()
            .equalsIgnoreCase(answer.toString()) ||
        INFO_CLI_NO_LONG.get().toString()
                .equalsIgnoreCase(answer.toString()))
    {
      confirm = false;
    }
    return confirm;
  }
  /**
   * Prompts the user to accept the certificate.
   * @param t the throwable that was generated because the certificate was
   * not trusted.
opends/src/quicksetup/org/opends/quicksetup/installer/Installer.java
@@ -74,7 +74,6 @@
import org.opends.quicksetup.installer.ui.ServerSettingsPanel;
import org.opends.quicksetup.installer.ui.SuffixesToReplicatePanel;
import org.opends.server.util.SetupUtils;
import org.opends.server.types.OpenDsException;
import org.opends.messages.Message;
import org.opends.messages.MessageBuilder;
import static org.opends.messages.QuickSetupMessages.*;
@@ -1927,8 +1926,7 @@
          adsContext.createAdminData(null);
          adsContext.createAdministrator(getAdministratorProperties());
          adsContext.registerServer(
              getRemoteServerProperties(auth.getHostName(),
                  adsContext.getDirContext()));
              getRemoteServerProperties(adsContext.getDirContext()));
          createdRemoteAds = true;
          notifyListeners(getFormattedDone());
          notifyListeners(getLineBreak());
@@ -2841,7 +2839,7 @@
        }
        Set<TopologyCacheException> exceptions =
        updateUserDataWithSuffixesInADS(adsContext, trustManager);
        Set<String> exceptionMsgs = new LinkedHashSet<String>();
        Set<Message> exceptionMsgs = new LinkedHashSet<Message>();
        /* Check the exceptions and see if we throw them or not. */
        for (TopologyCacheException e : exceptions)
        {
@@ -2901,13 +2899,13 @@
              }
            }
          }
          exceptionMsgs.add(getStringRepresentation(e));
          exceptionMsgs.add(getMessage(e));
        }
        if (exceptionMsgs.size() > 0)
        {
          Message confirmationMsg =
            INFO_ERROR_READING_REGISTERED_SERVERS_CONFIRM.get(
                    getStringFromCollection(exceptionMsgs, "n"));
                    getMessageFromCollection(exceptionMsgs, "\n"));
          throw new UserDataConfirmationException(Step.REPLICATION_OPTIONS,
              confirmationMsg);
        }
@@ -2984,7 +2982,6 @@
      }
      else if (t instanceof ADSContextException)
      {
        String[] args = {host+":"+port, t.toString()};
        errorMsgs.add(INFO_REMOTE_ADS_EXCEPTION.get(
                host+":"+port, t.toString()));
      }
@@ -3365,66 +3362,11 @@
  }
  private Map<ADSContext.ServerProperty, Object> getRemoteServerProperties(
      String hostName, InitialLdapContext ctx) throws NamingException
      InitialLdapContext ctx) throws NamingException
  {
    ServerDescriptor server = ServerDescriptor.createStandalone(ctx);
    Map<ADSContext.ServerProperty, Object> serverProperties =
      new HashMap<ADSContext.ServerProperty, Object>();
    serverProperties.put(ADSContext.ServerProperty.HOST_NAME, hostName);
    ADSContext.ServerProperty[][] adsProperties =
    {
        {ADSContext.ServerProperty.LDAP_PORT,
        ADSContext.ServerProperty.LDAP_ENABLED},
        {ADSContext.ServerProperty.LDAPS_PORT,
        ADSContext.ServerProperty.LDAPS_ENABLED},
        {ADSContext.ServerProperty.JMX_PORT,
        ADSContext.ServerProperty.JMX_ENABLED},
        {ADSContext.ServerProperty.JMXS_PORT,
        ADSContext.ServerProperty.JMXS_ENABLED}
    };
    ServerDescriptor.ServerProperty[][] properties =
    {
        {ServerDescriptor.ServerProperty.LDAP_PORT,
         ServerDescriptor.ServerProperty.LDAP_ENABLED},
        {ServerDescriptor.ServerProperty.LDAPS_PORT,
         ServerDescriptor.ServerProperty.LDAPS_ENABLED},
        {ServerDescriptor.ServerProperty.JMX_PORT,
         ServerDescriptor.ServerProperty.JMX_ENABLED},
        {ServerDescriptor.ServerProperty.JMXS_PORT,
         ServerDescriptor.ServerProperty.JMXS_ENABLED}
    };
    for (int i=0; i<properties.length; i++)
    {
      ArrayList portNumbers =
        (ArrayList)server.getServerProperties().get(properties[i][0]);
      if (portNumbers != null)
      {
        ArrayList enabled =
          (ArrayList)server.getServerProperties().get(properties[i][1]);
        boolean enabledFound = false;
        for (int j=0; j<enabled.size() && !enabledFound; j++)
        {
          if (Boolean.TRUE.equals(enabled.get(j)))
          {
            enabledFound = true;
            serverProperties.put(adsProperties[i][0],
                String.valueOf(portNumbers.get(j)));
          }
        }
        if (!enabledFound && (portNumbers.size() > 0))
        {
          serverProperties.put(adsProperties[i][0],
              String.valueOf(portNumbers.get(0)));
        }
        serverProperties.put(adsProperties[i][1], enabledFound?"true":"false");
      }
    }
    serverProperties.put(ADSContext.ServerProperty.ID,
        server.getHostPort(true));
    return serverProperties;
    server.updateAdsPropertiesWithServerProperties();
    return server.getAdsProperties();
  }
  /**
@@ -3739,7 +3681,21 @@
        trustManager);
  }
  private void initializeSuffix(InitialLdapContext ctx, int replicaId,
  /**
   * Initializes a suffix with the contents of a replica that has a given
   * replication id.
   * @param ctx the connection to the server whose suffix we want to initialize.
   * @param replicaId the replication ID of the replica we want to use to
   * initialize the contents of the suffix.
   * @param suffixDn the dn of the suffix.
   * @param displayProgress whether we want to display progress or not.
   * @param sourceServerDisplay the string to be used to represent the server
   * that contains the data that will be used to initialize the suffix.
   * @throws ApplicationException if an unexpected error occurs.
   * @throws PeerNotFoundException if the replication mechanism cannot find
   * a peer.
   */
  public void initializeSuffix(InitialLdapContext ctx, int replicaId,
      String suffixDn, boolean displayProgress, String sourceServerDisplay)
  throws ApplicationException, PeerNotFoundException
  {
@@ -3983,23 +3939,4 @@
    value = (random.nextInt() & modulo);
    return value;
  }
}
/**
 * The exception that is thrown during initialization if the peer specified
 * could not be found.
 *
 */
class PeerNotFoundException extends OpenDsException {
  private static final long serialVersionUID = -362726764261560341L;
  /**
   * The constructor for the exception.
   * @param message the localized message.
   */
  PeerNotFoundException(Message message)
  {
    super(message);
  }
}
}
opends/src/quicksetup/org/opends/quicksetup/installer/InstallerHelper.java
@@ -572,7 +572,12 @@
                ERR_NO_REACHABLE_PEER_IN_THE_DOMAIN.getId()) != -1;
  }
  private int getReplicationId(Set<Integer> usedIds)
  /**
   * Returns the ID to be used for a new replication server or domain.
   * @param usedIds the list of already used ids.
   * @return the ID to be used for a new replication server or domain.
   */
  public static int getReplicationId(Set<Integer> usedIds)
  {
    Random r = new Random();
    int id = 0;
@@ -583,7 +588,13 @@
    return id;
  }
  private String getDomainName(String[] existingDomains, int newDomainId)
  /**
   * Returns the name to be used for a new replication domain.
   * @param existingDomains the existing domains names.
   * @param newDomainId the new domain replication id.
   * @return the name to be used for a new replication domain.
   */
  public static String getDomainName(String[] existingDomains, int newDomainId)
  {
    String domainName = DOMAIN_BASE_NAME+newDomainId;
    boolean nameExists = true;
opends/src/quicksetup/org/opends/quicksetup/util/Utils.java
@@ -517,18 +517,17 @@
  public static String getStringFromCollection(Collection<String> col,
      String separator)
  {
    String msg = null;
    StringBuffer msg = new StringBuffer();
    for (String m : col)
    {
      if (msg == null)
      if (msg.length() > 0)
      {
        msg = m;
      } else
      {
        msg += separator + m;
        msg.append(separator);
      }
      msg.append(m);
    }
    return msg;
    return msg.toString();
  }
  /**
@@ -669,7 +668,7 @@
   * @param te the exception.
   * @return a localized representation of the provide TopologyCacheException.
   */
  public static String getStringRepresentation(TopologyCacheException te)
  public static Message getMessage(TopologyCacheException te)
  {
    MessageBuilder buf = new MessageBuilder();
@@ -690,7 +689,7 @@
      // This is unexpected.
      buf.append(getThrowableMsg(INFO_BUG_MSG.get(), te.getCause()));
    }
    return buf.toString();
    return buf.toMessage();
  }
  /**
opends/src/server/org/opends/server/admin/client/cli/DsFrameworkCliGlobalAdmin.java
@@ -690,7 +690,7 @@
      // Check that propName is a known prop.
      AdministratorProperty adminUserProperty = ADSContext
          .getAdminUSerPropFromName(propertyName);
          .getAdminUserPropFromName(propertyName);
      if (adminUserProperty == null)
      {
        Message message = ERR_CLI_ERROR_PROPERTY_UNRECOGNIZED.get(propertyName);
opends/src/server/org/opends/server/admin/client/cli/SecureConnectionCliParser.java
@@ -157,20 +157,20 @@
  protected BooleanArgument useSSLArg = null;
  /**
   * The 'startTLSArg' global argument.
   * The 'useStartTLSArg' global argument.
   */
  protected BooleanArgument startTLSArg = null;
  protected BooleanArgument useStartTLSArg = null;
  /** Short form of the option for specifying a noninteractive session. */
  static public final Character INTERACTIVE_OPTION_SHORT = 'i';
  /** Long form of the option for specifying a noninteractive session. */
  /** Long form of the option for specifying a quiet session. */
  static public final String QUIET_OPTION_LONG = "quiet";
  /** Long form of the option for specifying a noninteractive session. */
  static public final String INTERACTIVE_OPTION_LONG = "interactive";
  /** Short form of the option for specifying a noninteractive session. */
  /** Short form of the option for specifying a quiet session. */
  static public final Character QUIET_OPTION_SHORT = 'Q';
  /**
@@ -181,7 +181,7 @@
  /**
   * End Of Line.
   */
  protected static String EOL = System.getProperty("line.separator");
  public static String EOL = System.getProperty("line.separator");
  /**
   * The Logger.
@@ -400,10 +400,10 @@
        OPTION_LONG_USE_SSL, INFO_DESCRIPTION_USE_SSL.get());
    set.add(useSSLArg);
    startTLSArg = new BooleanArgument("startTLS", OPTION_SHORT_START_TLS,
    useStartTLSArg = new BooleanArgument("startTLS", OPTION_SHORT_START_TLS,
        OPTION_LONG_START_TLS,
        INFO_DESCRIPTION_START_TLS.get());
    set.add(startTLSArg);
    set.add(useStartTLSArg);
    hostNameArg = new StringArgument("host", OPTION_SHORT_HOST,
        OPTION_LONG_HOST, false, false, true, OPTION_VALUE_HOST, "localhost",
@@ -584,10 +584,10 @@
    // Couldn't have at the same time startTLSArg and
    // useSSLArg
    if (startTLSArg.isPresent()
    if (useStartTLSArg.isPresent()
            && useSSLArg.isPresent()) {
      Message message = ERR_TOOL_CONFLICTING_ARGS.get(
              startTLSArg
              useStartTLSArg
                      .getLongIdentifier(), useSSLArg.getLongIdentifier());
      errors.add(message);
    }
@@ -666,7 +666,7 @@
   */
  public boolean startTLS()
  {
    if (startTLSArg.isPresent())
    if (useStartTLSArg.isPresent())
    {
      return true;
    }