From a837c0600e8855892427c493e164147a8f68d6f4 Mon Sep 17 00:00:00 2001
From: jvergara <jvergara@localhost>
Date: Mon, 13 Jul 2009 09:20:24 +0000
Subject: [PATCH] Fix for issue 4106 (dsreplication should allow to merge disjoint replication topologies) dsreplication allows to merge disjoint topologies.  The limitations on the topologies that can be merged are described in the issue report.

---
 opends/src/server/org/opends/server/tools/dsreplication/ReplicationCliMain.java |  702 ++++++++++++++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 606 insertions(+), 96 deletions(-)

diff --git a/opends/src/server/org/opends/server/tools/dsreplication/ReplicationCliMain.java b/opends/src/server/org/opends/server/tools/dsreplication/ReplicationCliMain.java
index 590bc65..a8fafa3 100644
--- a/opends/src/server/org/opends/server/tools/dsreplication/ReplicationCliMain.java
+++ b/opends/src/server/org/opends/server/tools/dsreplication/ReplicationCliMain.java
@@ -2488,9 +2488,6 @@
         uData.setPwd1(pwd1);
       }
     }
-    int replicationPort1 = getValue(argParser.getReplicationPort1(),
-        argParser.getDefaultReplicationPort1());
-    uData.setReplicationPort1(replicationPort1);
     uData.setSecureReplication1(argParser.isSecureReplication1());
 
     String host2Name = getValue(argParser.getHostName2(),
@@ -2526,9 +2523,6 @@
         uData.setPwd2(pwd2);
       }
     }
-    int replicationPort2 = getValue(argParser.getReplicationPort2(),
-        argParser.getDefaultReplicationPort2());
-    uData.setReplicationPort2(replicationPort2);
     uData.setSecureReplication2(argParser.isSecureReplication2());
     uData.setReplicateSchema(!argParser.noSchemaReplication());
     uData.setConfigureReplicationDomain1(
@@ -2539,6 +2533,20 @@
         !argParser.noReplicationServer1Arg.isPresent());
     uData.setConfigureReplicationServer2(
         !argParser.noReplicationServer2Arg.isPresent());
+
+    int replicationPort1 = getValue(argParser.getReplicationPort1(),
+        argParser.getDefaultReplicationPort1());
+    if (uData.configureReplicationServer1())
+    {
+      uData.setReplicationPort1(replicationPort1);
+    }
+
+    int replicationPort2 = getValue(argParser.getReplicationPort2(),
+        argParser.getDefaultReplicationPort2());
+    if (uData.configureReplicationServer2())
+    {
+      uData.setReplicationPort2(replicationPort2);
+    }
   }
 
   /**
@@ -3286,12 +3294,21 @@
 //    If we are not in interactive mode do some checks...
       if (!argParser.isInteractive())
       {
-        boolean hasReplicationPort1 = hasReplicationPort(ctx1);
-        boolean hasReplicationPort2 = hasReplicationPort(ctx2);
-        int replPort1 = uData.getReplicationPort1();
-        int replPort2 = uData.getReplicationPort2();
-
-        if (!hasReplicationPort1)
+        int replPort1 = getReplicationPort(ctx1);
+        boolean hasReplicationPort1 = replPort1 > 0;
+        if (replPort1 < 0 && uData.configureReplicationServer1())
+        {
+          replPort1 = uData.getReplicationPort1();
+        }
+        int replPort2 = getReplicationPort(ctx2);
+        boolean hasReplicationPort2 = replPort2 > 0;
+        if (replPort2 < 0 && uData.configureReplicationServer2())
+        {
+          replPort2 = uData.getReplicationPort2();
+        }
+        boolean checkReplicationPort1 = replPort1 > 0;
+        boolean checkReplicationPort2 = replPort2 > 0;
+        if (!hasReplicationPort1 && checkReplicationPort1)
         {
           if (!argParser.skipReplicationPortCheck() &&
               uData.configureReplicationServer1() &&
@@ -3301,7 +3318,7 @@
             errorMessages.add(getCannotBindToPortError(replPort1));
           }
         }
-        if (!hasReplicationPort2)
+        if (!hasReplicationPort2 && checkReplicationPort2)
         {
           if (!argParser.skipReplicationPortCheck() &&
               uData.configureReplicationServer2() &&
@@ -3311,7 +3328,7 @@
             errorMessages.add(getCannotBindToPortError(replPort2));
           }
         }
-        if (!hasReplicationPort1 && !hasReplicationPort2 &&
+        if (checkReplicationPort1 && checkReplicationPort2 &&
             (replPort1 == replPort2) &&
             (host1.equalsIgnoreCase(host2)))
         {
@@ -3323,14 +3340,14 @@
         {
           // This is something that we must do in any case... this test is
           // already included when we call SetupUtils.canUseAsPort
-          if (replPort1 == port1)
+          if (checkReplicationPort1 && replPort1 == port1)
           {
             errorMessages.add(
                 ERR_REPLICATION_PORT_AND_REPLICATION_PORT_EQUAL.get(
                 host1, String.valueOf(replPort1)));
           }
 
-          if (replPort2 == port2)
+          if (checkReplicationPort2 && replPort2 == port2)
           {
             errorMessages.add(
                 ERR_REPLICATION_PORT_AND_REPLICATION_PORT_EQUAL.get(
@@ -4112,7 +4129,6 @@
 
     TreeSet<String> availableSuffixes;
     TreeSet<String> alreadyReplicatedSuffixes;
-
     if (uData.configureReplicationDomain1() &&
         uData.configureReplicationDomain2())
     {
@@ -4850,6 +4866,7 @@
     TopologyCacheFilter filter = new TopologyCacheFilter();
     filter.setSearchMonitoringInformation(false);
     filter.addBaseDNToSearch(ADSContext.getAdministrationSuffixDN());
+    filter.addBaseDNToSearch(Constants.SCHEMA_DN);
     for (String dn : uData.getBaseDNs())
     {
       filter.addBaseDNToSearch(dn);
@@ -4994,6 +5011,7 @@
     ADSContext adsCtxSource = null;
 
     boolean adsAlreadyReplicated = false;
+    boolean adsMergeDone = false;
 
     printProgress(formatter.getFormattedWithPoints(
         INFO_REPLICATION_ENABLE_UPDATING_ADS_CONTENTS.get()));
@@ -5059,13 +5077,19 @@
         }
         else if (!areEqual(registry1, 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);
+          printProgress(formatter.getFormattedDone());
+          printlnProgress();
+
+          boolean isFirstSource = mergeRegistries(adsCtx1, adsCtx2);
+          if (isFirstSource)
+          {
+            ctxSource = ctx1;
+          }
+          else
+          {
+            ctxSource = ctx2;
+          }
+          adsMergeDone = true;
         }
         else
         {
@@ -5142,7 +5166,7 @@
           ERR_REPLICATION_UPDATING_ADS.get(adce.getMessageObject()),
           ERROR_UPDATING_ADS, adce);
     }
-    if (!adsAlreadyReplicated)
+    if (!adsAlreadyReplicated && !adsMergeDone)
     {
       try
       {
@@ -5152,14 +5176,21 @@
       catch (Throwable t)
       {
         LOG.log(Level.SEVERE, "Error seeding truststores: "+t, t);
+        String arg = (t instanceof OpenDsException) ?
+            ((OpenDsException)t).getMessageObject().toString() : t.toString();
         throw new ReplicationCliException(
-            ERR_REPLICATION_ENABLE_SEEDING_TRUSTSTORE.get(t.toString()),
+            ERR_REPLICATION_ENABLE_SEEDING_TRUSTSTORE.get(
+                ConnectionUtils.getHostPort(ctxDestination),
+                ConnectionUtils.getHostPort(adsCtxSource.getDirContext()),
+               arg),
             ERROR_SEEDING_TRUSTORE, t);
       }
     }
-    printProgress(formatter.getFormattedDone());
-    printlnProgress();
-
+    if (!adsMergeDone)
+    {
+      printProgress(formatter.getFormattedDone());
+      printlnProgress();
+    }
     LinkedList<String> baseDNs = uData.getBaseDNs();
     if (!adsAlreadyReplicated)
     {
@@ -5187,6 +5218,7 @@
     }
     TopologyCache cache1 = null;
     TopologyCache cache2 = null;
+
     try
     {
       LinkedHashSet<PreferredConnection> cnx =
@@ -5435,7 +5467,27 @@
     // 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 ((ctxSource != null) && (ctxDestination != null))
+    if (adsMergeDone)
+    {
+      PointAdder pointAdder = new PointAdder();
+      printProgress(
+          INFO_ENABLE_REPLICATION_INITIALIZING_ADS_ALL.get(
+              ConnectionUtils.getHostPort(ctxSource)));
+      pointAdder.start();
+      try
+      {
+        initializeAllSuffix(ADSContext.getAdministrationSuffixDN(),
+          ctxSource, false);
+      }
+      finally
+      {
+        pointAdder.stop();
+      }
+      printProgress(formatter.getSpace());
+      printProgress(formatter.getFormattedDone());
+      printlnProgress();
+    }
+    else if ((ctxSource != null) && (ctxDestination != null))
     {
       printProgress(formatter.getFormattedWithPoints(
           INFO_ENABLE_REPLICATION_INITIALIZING_ADS.get(
@@ -5461,12 +5513,33 @@
         ctxSource = ctx1;
         ctxDestination = ctx2;
       }
-      printProgress(formatter.getFormattedWithPoints(
-          INFO_ENABLE_REPLICATION_INITIALIZING_SCHEMA.get(
-              ConnectionUtils.getHostPort(ctxDestination),
-              ConnectionUtils.getHostPort(ctxSource))));
-      initializeSuffix(Constants.SCHEMA_DN, ctxSource,
+      if (adsMergeDone)
+      {
+        PointAdder pointAdder = new PointAdder();
+        printProgress(
+            INFO_ENABLE_REPLICATION_INITIALIZING_SCHEMA.get(
+                ConnectionUtils.getHostPort(ctxDestination),
+                ConnectionUtils.getHostPort(ctxSource)));
+        pointAdder.start();
+        try
+        {
+          initializeAllSuffix(Constants.SCHEMA_DN, ctxSource, false);
+        }
+        finally
+        {
+          pointAdder.stop();
+        }
+        printProgress(formatter.getSpace());
+      }
+      else
+      {
+        printProgress(formatter.getFormattedWithPoints(
+            INFO_ENABLE_REPLICATION_INITIALIZING_SCHEMA.get(
+                ConnectionUtils.getHostPort(ctxDestination),
+                ConnectionUtils.getHostPort(ctxSource))));
+        initializeSuffix(Constants.SCHEMA_DN, ctxSource,
           ctxDestination, false);
+      }
       printProgress(formatter.getFormattedDone());
       printlnProgress();
     }
@@ -5970,7 +6043,7 @@
       {
         // Delete all contents from ADSContext.
         printProgress(formatter.getFormattedWithPoints(
-            INFO_REPLICATION_DISABLE_ADS_CONTENTS.get()));
+            INFO_REPLICATION_REMOVE_ADS_CONTENTS.get()));
         adsCtx.removeAdminData();
         String adminBackendName = null;
         for (ReplicaDescriptor replica : server.getReplicas())
@@ -5988,11 +6061,27 @@
       }
       catch (ADSContextException adce)
       {
-        LOG.log(Level.SEVERE, "Error resetting contents of cn=admin data: "+
+        LOG.log(Level.SEVERE, "Error removing contents of cn=admin data: "+
             adce, adce);
         throw new ReplicationCliException(
             ERR_REPLICATION_UPDATING_ADS.get(adce.getMessageObject()),
-            ERROR_READING_ADS, adce);
+            ERROR_UPDATING_ADS, adce);
+      }
+      try
+      {
+        // Delete all contents from truststore.
+        printProgress(formatter.getFormattedWithPoints(
+            INFO_REPLICATION_REMOVE_TRUSTSTORE_CONTENTS.get()));
+        ServerDescriptor.cleanAdsTrustStore(adsCtx.getDirContext());
+        printProgress(formatter.getFormattedDone());
+        printlnProgress();
+      }
+      catch (Throwable t)
+      {
+        LOG.log(Level.SEVERE, "Error removing contents of truststore: "+t, t);
+        throw new ReplicationCliException(
+            ERR_REPLICATION_UPDATING_ADS.get(t.toString()),
+            ERROR_UPDATING_ADS, t);
       }
     }
   }
@@ -6010,6 +6099,7 @@
   {
     ADSContext adsCtx = new ADSContext(ctx);
 
+    boolean somethingDisplayed = false;
     TopologyCache cache = null;
     try
     {
@@ -6142,13 +6232,9 @@
         {
           displayStatus(rServers, uData.isScriptFriendly(),
               getPreferredConnections(ctx));
+          somethingDisplayed = true;
         }
       }
-      else
-      {
-        printProgress(INFO_REPLICATION_STATUS_NO_BASEDNS.get());
-        printlnProgress();
-      }
     }
 
     if (!replicaLists.isEmpty())
@@ -6184,6 +6270,7 @@
         displayStatus(replicas, uData.isScriptFriendly(),
             getPreferredConnections(ctx), cache.getServers(),
             replicasWithNoReplicationServer, serversWithNoReplica);
+        somethingDisplayed = true;
       }
       if (oneReplicated && !uData.isScriptFriendly())
       {
@@ -6202,6 +6289,20 @@
               INFO_REPLICATION_STATUS_NOT_A_REPLICATION_DOMAIN_LEGEND.get());
         }
         printlnProgress();
+        somethingDisplayed = true;
+      }
+    }
+    if (!somethingDisplayed)
+    {
+      if (displayAll)
+      {
+        printProgress(INFO_REPLICATION_STATUS_NO_REPLICATION_INFORMATION.get());
+        printlnProgress();
+      }
+      else
+      {
+        printProgress(INFO_REPLICATION_STATUS_NO_BASEDNS.get());
+        printlnProgress();
       }
     }
   }
@@ -6706,6 +6807,17 @@
         break;
       }
     }
+    if (servers.isEmpty())
+    {
+      boolean found = false;
+      for (ReplicaDescriptor replica : server.getReplicas())
+      {
+        if (Utils.areDnsEqual(replica.getSuffix().getDN(), baseDN))
+        {
+          found = true;
+        }
+      }
+    }
     if (cache != null)
     {
       Set<SuffixDescriptor> suffixes = cache.getSuffixes();
@@ -6744,6 +6856,11 @@
       ServerDescriptor server)
   {
     SuffixDescriptor returnValue = null;
+    String replicationServer = null;
+    if (server.isReplicationServer())
+    {
+      replicationServer = server.getReplicationServerHostPort();
+    }
     Set<String> servers = new LinkedHashSet<String>();
     for (ReplicaDescriptor replica : server.getReplicas())
     {
@@ -6771,6 +6888,18 @@
           returnValue = suffix;
           break;
         }
+        else if (replicationServer != null)
+        {
+          // Check if the server is only a replication server.
+          for (String repServer : s)
+          {
+            if (repServer.equalsIgnoreCase(replicationServer))
+            {
+              returnValue = suffix;
+              break;
+            }
+          }
+        }
       }
     }
     return returnValue;
@@ -7120,6 +7249,8 @@
       Set<String> alreadyConfiguredReplicationServers)
   throws ReplicationCliException
   {
+    LOG.log(Level.INFO, "Configuring base DN '"+baseDN+
+        "' the replication servers are "+repServers);
     Set<ServerDescriptor> serversToConfigureDomain =
       new HashSet<ServerDescriptor>();
     Set<ServerDescriptor> replicationServersToConfigure =
@@ -7140,7 +7271,7 @@
     for (ServerDescriptor s : cache.getServers())
     {
       if (s.isReplicationServer() &&
-          !alreadyConfiguredReplicationServers.contains(server.getId()))
+          !alreadyConfiguredReplicationServers.contains(s.getId()))
       {
         // Check if it is part of the replication topology
         boolean isInTopology = false;
@@ -7155,7 +7286,7 @@
         }
         if (isInTopology)
         {
-          replicationServersToConfigure.add(server);
+          replicationServersToConfigure.add(s);
         }
       }
     }
@@ -7166,40 +7297,29 @@
 
     for (ServerDescriptor s : allServers)
     {
-      String dn = ConnectionUtils.getBindDN(
-          cache.getAdsContext().getDirContext());
-      String pwd = ConnectionUtils.getBindPassword(
-          cache.getAdsContext().getDirContext());
-      TopologyCacheFilter filter = new TopologyCacheFilter();
-      filter.setSearchMonitoringInformation(false);
-      filter.setSearchBaseDNInformation(false);
-      ServerLoader loader = new ServerLoader(s.getAdsProperties(),
-          dn, pwd, getTrustManager(), cache.getPreferredConnections(),
-          filter);
+      LOG.log(Level.INFO,"Configuring server "+server.getHostPort(true));
       InitialLdapContext ctx = null;
       try
       {
-        ctx = loader.createContext();
-        if (serversToConfigureDomain.contains(server))
+        ctx = getDirContextForServer(cache, s);
+        if (serversToConfigureDomain.contains(s))
         {
           configureToReplicateBaseDN(ctx, baseDN, repServers, usedIds);
         }
-        if (replicationServersToConfigure.contains(server))
+        if (replicationServersToConfigure.contains(s))
         {
           updateReplicationServer(ctx, allRepServers);
         }
       }
       catch (NamingException ne)
       {
-        String hostPort = getHostPort(server,
-            cache.getPreferredConnections());
+        String hostPort = getHostPort(s, cache.getPreferredConnections());
         Message msg = getMessageForException(ne, hostPort);
         throw new ReplicationCliException(msg, ERROR_CONNECTING, ne);
       }
       catch (OpenDsException ode)
       {
-        String hostPort = getHostPort(server,
-            cache.getPreferredConnections());
+        String hostPort = getHostPort(s, cache.getPreferredConnections());
         Message msg = getMessageForEnableException(ode, hostPort, baseDN);
         throw new ReplicationCliException(msg,
             ERROR_ENABLING_REPLICATION_ON_BASEDN, ode);
@@ -7607,7 +7727,7 @@
     attrs.put("ds-task-initialize-replica-server-id", "all");
     while (!taskCreated)
     {
-      String id = "quicksetup-initialize"+i;
+      String id = "dsreplication-initialize"+i;
       dn = "ds-task-id="+id+",cn=Scheduled Tasks,cn=Tasks";
       attrs.put("ds-task-id", id);
       try
@@ -9835,6 +9955,9 @@
         if (adsContext.hasAdminData())
         {
           cache1 = new TopologyCache(adsContext, getTrustManager());
+          cache1.getFilter().setSearchMonitoringInformation(false);
+          cache1.setPreferredConnections(getPreferredConnections(ctx1));
+          cache1.reloadTopology();
         }
       }
       catch (Throwable t)
@@ -9852,6 +9975,9 @@
         if (adsContext.hasAdminData())
         {
           cache2 = new TopologyCache(adsContext, getTrustManager());
+          cache2.getFilter().setSearchMonitoringInformation(false);
+          cache2.setPreferredConnections(getPreferredConnections(ctx2));
+          cache2.reloadTopology();
         }
       }
       catch (Throwable t)
@@ -9863,39 +9989,12 @@
 
     if (cache1 != null && cache2 != null)
     {
-      // Check common suffixes
-      Set<String> dns1 = new HashSet<String>();
-      Set<String> dns2 = new HashSet<String>();
-
-      Set<SuffixDescriptor> suffixes = cache1.getSuffixes();
-      for (SuffixDescriptor suffix : suffixes)
-      {
-        for (String rServer : suffix.getReplicationServers())
-        {
-          if (rServer.equalsIgnoreCase(replicationServer1))
-          {
-            dns1.add(suffix.getDN());
-          }
-        }
-      }
-
-      suffixes = cache2.getSuffixes();
-      for (SuffixDescriptor suffix : suffixes)
-      {
-        for (String rServer : suffix.getReplicationServers())
-        {
-          if (rServer.equalsIgnoreCase(replicationServer2))
-          {
-            dns2.add(suffix.getDN());
-          }
-        }
-      }
-
-      availableSuffixes.addAll(dns1);
-      availableSuffixes.removeAll(dns2);
-
-      alreadyReplicatedSuffixes.addAll(dns1);
-      alreadyReplicatedSuffixes.retainAll(dns2);
+      updateAvailableAndReplicatedSuffixesForNoDomainOneSense(cache1, cache2,
+          replicationServer1, replicationServer2, availableSuffixes,
+          alreadyReplicatedSuffixes);
+      updateAvailableAndReplicatedSuffixesForNoDomainOneSense(cache2, cache1,
+          replicationServer2, replicationServer1, availableSuffixes,
+          alreadyReplicatedSuffixes);
     }
     else if (cache1 != null)
     {
@@ -9927,6 +10026,59 @@
     }
   }
 
+  private void updateAvailableAndReplicatedSuffixesForNoDomainOneSense(
+      TopologyCache cache1, TopologyCache cache2, String replicationServer1,
+      String replicationServer2,
+      Collection<String> availableSuffixes,
+      Collection<String> alreadyReplicatedSuffixes)
+  {
+    Set<SuffixDescriptor> suffixes = cache1.getSuffixes();
+    for (SuffixDescriptor suffix : suffixes)
+    {
+      for (String rServer : suffix.getReplicationServers())
+      {
+        if (rServer.equalsIgnoreCase(replicationServer1))
+        {
+          boolean isSecondReplicatedInSameTopology = false;
+          boolean isSecondReplicated = false;
+          boolean isFirstReplicated = false;
+          for (SuffixDescriptor suffix2 : cache2.getSuffixes())
+          {
+            if (Utils.areDnsEqual(suffix.getDN(), suffix2.getDN()))
+            {
+              for (String rServer2 : suffix2.getReplicationServers())
+              {
+                if (rServer2.equalsIgnoreCase(replicationServer2))
+                {
+                  isSecondReplicated = true;
+                }
+                if (rServer.equalsIgnoreCase(replicationServer2))
+                {
+                  isFirstReplicated = true;
+                }
+                if (isFirstReplicated && isSecondReplicated)
+                {
+                  isSecondReplicatedInSameTopology = true;
+                  break;
+                }
+              }
+              break;
+            }
+          }
+          if (!isSecondReplicatedInSameTopology)
+          {
+            availableSuffixes.add(suffix.getDN());
+          }
+          else
+          {
+            alreadyReplicatedSuffixes.add(suffix.getDN());
+          }
+          break;
+        }
+      }
+    }
+  }
+
   private void updateBaseDnsWithNotEnoughReplicationServer(ADSContext adsCtx1,
       ADSContext adsCtx2, EnableReplicationUserData uData,
       Set<String> baseDNsWithNoReplicationServer,
@@ -10054,9 +10206,367 @@
   {
     return server1.getId().equals(server2.getId());
   }
+
+  /**
+   * Merge the contents of the two registries but only does it partially.
+   * Only one of the two ADSContext will be updated (in terms of data in
+   * cn=admin data), while the other registry's replication servers will have
+   * their truststore updated to be able to initialize all the contents.
+   *
+   * This method does NOT configure replication between topologies or initialize
+   * replication.
+   *
+   * @param adsCtx1 the ADSContext of the first registry.
+   * @param adsCtx2 the ADSContext of the second registry.
+   * @return <CODE>true</CODE> if the registry containing all the data is
+   * the first registry and <CODE>false</CODE> otherwise.
+   * @throws ReplicationCliException if there is a problem reading or updating
+   * the registries.
+   */
+  private boolean mergeRegistries(ADSContext adsCtx1, ADSContext adsCtx2)
+  throws ReplicationCliException
+  {
+
+    PointAdder pointAdder = new PointAdder();
+    try
+    {
+      LinkedHashSet<PreferredConnection> cnx =
+        new LinkedHashSet<PreferredConnection>();
+      cnx.addAll(getPreferredConnections(adsCtx1.getDirContext()));
+      cnx.addAll(getPreferredConnections(adsCtx2.getDirContext()));
+      // Check that there are no errors.  We do not allow to do the merge with
+      // errors.
+      TopologyCache cache1 = new TopologyCache(adsCtx1, getTrustManager());
+      cache1.setPreferredConnections(cnx);
+      cache1.getFilter().setSearchBaseDNInformation(false);
+      try
+      {
+        cache1.reloadTopology();
+      }
+      catch (TopologyCacheException te)
+      {
+        LOG.log(Level.SEVERE, "Error reading topology cache of "+
+            ConnectionUtils.getHostPort(adsCtx1.getDirContext())+ " "+te, te);
+        throw new ReplicationCliException(
+            ERR_REPLICATION_READING_ADS.get(te.getMessageObject()),
+            ERROR_UPDATING_ADS, te);
+      }
+      TopologyCache cache2 = new TopologyCache(adsCtx2, getTrustManager());
+      cache2.setPreferredConnections(cnx);
+      cache2.getFilter().setSearchBaseDNInformation(false);
+      try
+      {
+        cache2.reloadTopology();
+      }
+      catch (TopologyCacheException te)
+      {
+        LOG.log(Level.SEVERE, "Error reading topology cache of "+
+            ConnectionUtils.getHostPort(adsCtx2.getDirContext())+ " "+te, te);
+        throw new ReplicationCliException(
+            ERR_REPLICATION_READING_ADS.get(te.getMessageObject()),
+            ERROR_UPDATING_ADS, te);
+      }
+
+      // Look for the cache with biggest number of replication servers:
+      // that one is going to be source.
+      int nRepServers1 = 0;
+      for (ServerDescriptor server : cache1.getServers())
+      {
+        if (server.isReplicationServer())
+        {
+          nRepServers1 ++;
+        }
+      }
+
+      int nRepServers2 = 0;
+      for (ServerDescriptor server : cache2.getServers())
+      {
+        if (server.isReplicationServer())
+        {
+          nRepServers2 ++;
+        }
+      }
+
+      InitialLdapContext ctxSource;
+      InitialLdapContext ctxDestination;
+      if (nRepServers1 >= nRepServers2)
+      {
+        ctxSource = adsCtx1.getDirContext();
+        ctxDestination = adsCtx2.getDirContext();
+      }
+      else
+      {
+        ctxSource = adsCtx2.getDirContext();
+        ctxDestination = adsCtx1.getDirContext();
+      }
+
+      if (isInteractive())
+      {
+        Message msg = INFO_REPLICATION_MERGING_REGISTRIES_CONFIRMATION.get(
+            ConnectionUtils.getHostPort(ctxSource),
+            ConnectionUtils.getHostPort(ctxDestination),
+            ConnectionUtils.getHostPort(ctxSource),
+            ConnectionUtils.getHostPort(ctxDestination));
+        try
+        {
+          if (!askConfirmation(msg, true, LOG))
+          {
+            throw new ReplicationCliException(
+                ERR_REPLICATION_USER_CANCELLED.get(),
+                ReplicationCliReturnCode.USER_CANCELLED, null);
+          }
+        }
+        catch (CLIException ce)
+        {
+          println(ce.getMessageObject());
+          throw new ReplicationCliException(
+              ERR_REPLICATION_USER_CANCELLED.get(),
+              ReplicationCliReturnCode.USER_CANCELLED, null);
+        }
+      }
+      else
+      {
+        Message msg = INFO_REPLICATION_MERGING_REGISTRIES_DESCRIPTION.get(
+            ConnectionUtils.getHostPort(ctxSource),
+            ConnectionUtils.getHostPort(ctxDestination),
+            ConnectionUtils.getHostPort(ctxSource),
+            ConnectionUtils.getHostPort(ctxDestination));
+      }
+
+      printProgress(INFO_REPLICATION_MERGING_REGISTRIES_PROGRESS.get());
+      pointAdder.start();
+
+      Collection<Message> cache1Errors = getErrorMessages(cache1);
+      if (!cache1Errors.isEmpty())
+      {
+        throw new ReplicationCliException(
+            ERR_REPLICATION_CANNOT_MERGE_WITH_ERRORS.get(
+                ConnectionUtils.getHostPort(adsCtx1.getDirContext()),
+                Utils.getMessageFromCollection(cache1Errors,
+                    Constants.LINE_SEPARATOR)),
+                    ERROR_READING_ADS, null);
+      }
+
+      Collection<Message> cache2Errors = getErrorMessages(cache2);
+      if (!cache2Errors.isEmpty())
+      {
+        throw new ReplicationCliException(
+            ERR_REPLICATION_CANNOT_MERGE_WITH_ERRORS.get(
+                ConnectionUtils.getHostPort(adsCtx2.getDirContext()),
+                Utils.getMessageFromCollection(cache2Errors,
+                    Constants.LINE_SEPARATOR)),
+                    ERROR_READING_ADS, null);
+      }
+
+      Set<Message> commonRepServerIDErrors = new HashSet<Message>();
+      for (ServerDescriptor server1 : cache1.getServers())
+      {
+        if (server1.isReplicationServer())
+        {
+          int replicationID1 = server1.getReplicationServerId();
+          boolean found = false;
+          for (ServerDescriptor server2 : cache2.getServers())
+          {
+            if (server2.isReplicationServer())
+            {
+              int replicationID2 = server2.getReplicationServerId();
+              found = replicationID2 == replicationID1;
+              if (found)
+              {
+                commonRepServerIDErrors.add(
+                    ERR_REPLICATION_ENABLE_COMMON_REPLICATION_SERVER_ID_ARG.get(
+                        server1.getHostPort(true),
+                        server2.getHostPort(true),
+                        replicationID1));
+                found = true;
+                break;
+              }
+            }
+          }
+          if (found)
+          {
+            break;
+          }
+        }
+      }
+      Set<Message> commonDomainIDErrors = new HashSet<Message>();
+      for (SuffixDescriptor suffix1 : cache1.getSuffixes())
+      {
+        for (ReplicaDescriptor replica1 : suffix1.getReplicas())
+        {
+          if (replica1.isReplicated())
+          {
+            int domain1 = replica1.getReplicationId();
+            boolean found = false;
+            for (SuffixDescriptor suffix2 : cache2.getSuffixes())
+            {
+              if (!Utils.areDnsEqual(suffix2.getDN(),
+                  replica1.getSuffix().getDN()))
+              {
+                // Conflicting domain names must apply to same suffix.
+                continue;
+              }
+              for (ReplicaDescriptor replica2 : suffix2.getReplicas())
+              {
+                if (replica2.isReplicated())
+                {
+                  int domain2 = replica2.getReplicationId();
+                  if (domain1 == domain2)
+                  {
+                    commonDomainIDErrors.add(
+                        ERR_REPLICATION_ENABLE_COMMON_DOMAIN_ID_ARG.get(
+                            replica1.getServer().getHostPort(true),
+                            suffix1.getDN(),
+                            replica2.getServer().getHostPort(true),
+                            suffix2.getDN(),
+                            domain1));
+                    found = true;
+                    break;
+                  }
+                }
+              }
+              if (found)
+              {
+                break;
+              }
+            }
+          }
+        }
+      }
+      if (!commonRepServerIDErrors.isEmpty() || !commonDomainIDErrors.isEmpty())
+      {
+        MessageBuilder mb = new MessageBuilder();
+        if (!commonRepServerIDErrors.isEmpty())
+        {
+          mb.append(ERR_REPLICATION_ENABLE_COMMON_REPLICATION_SERVER_ID.get(
+            Utils.getMessageFromCollection(commonRepServerIDErrors,
+                Constants.LINE_SEPARATOR)));
+        }
+        if (!commonDomainIDErrors.isEmpty())
+        {
+          if (mb.length() > 0)
+          {
+            mb.append(Constants.LINE_SEPARATOR);
+          }
+          mb.append(ERR_REPLICATION_ENABLE_COMMON_DOMAIN_ID.get(
+            Utils.getMessageFromCollection(commonDomainIDErrors,
+                Constants.LINE_SEPARATOR)));
+        }
+        throw new ReplicationCliException(mb.toMessage(),
+            ReplicationCliReturnCode.REPLICATION_ADS_MERGE_NOT_SUPPORTED,
+            null);
+      }
+
+      ADSContext adsCtxSource;
+      ADSContext adsCtxDestination;
+      TopologyCache cacheDestination;
+      if (nRepServers1 >= nRepServers2)
+      {
+        adsCtxSource = adsCtx1;
+        adsCtxDestination = adsCtx2;
+        cacheDestination = cache2;
+      }
+      else
+      {
+        adsCtxSource = adsCtx2;
+        adsCtxDestination = adsCtx1;
+        cacheDestination = cache1;
+      }
+
+      try
+      {
+        adsCtxSource.mergeWithRegistry(adsCtxDestination);
+      }
+      catch (ADSContextException adce)
+      {
+        LOG.log(Level.SEVERE, "Error merging registry of "+
+            ConnectionUtils.getHostPort(adsCtxSource.getDirContext())+
+            " with registry of "+
+            ConnectionUtils.getHostPort(adsCtxDestination.getDirContext())+" "+
+            adce, adce);
+        if (adce.getError() == ADSContextException.ErrorType.ERROR_MERGING)
+        {
+          throw new ReplicationCliException(adce.getMessageObject(),
+          REPLICATION_ADS_MERGE_NOT_SUPPORTED, adce);
+        }
+        else
+        {
+          throw new ReplicationCliException(
+              ERR_REPLICATION_UPDATING_ADS.get(adce.getMessageObject()),
+              ERROR_UPDATING_ADS, adce);
+        }
+      }
+
+      try
+      {
+        for (ServerDescriptor server : cacheDestination.getServers())
+        {
+          if (server.isReplicationServer())
+          {
+            LOG.log(Level.INFO, "Seeding to replication server on "+
+                server.getHostPort(true)+" with certificates of "+
+                ConnectionUtils.getHostPort(adsCtxSource.getDirContext()));
+            InitialLdapContext ctx = null;
+            try
+            {
+              ctx = getDirContextForServer(cacheDestination, server);
+              ServerDescriptor.seedAdsTrustStore(ctx,
+                  adsCtxSource.getTrustedCertificates());
+            }
+            finally
+            {
+              if (ctx != null)
+              {
+                ctx.close();
+              }
+            }
+          }
+        }
+      }
+      catch (Throwable t)
+      {
+        LOG.log(Level.SEVERE, "Error seeding truststore: "+t, t);
+        String arg = (t instanceof OpenDsException) ?
+            ((OpenDsException)t).getMessageObject().toString() : t.toString();
+            throw new ReplicationCliException(
+                ERR_REPLICATION_ENABLE_SEEDING_TRUSTSTORE.get(
+                    ConnectionUtils.getHostPort(adsCtx2.getDirContext()),
+                    ConnectionUtils.getHostPort(adsCtx1.getDirContext()),
+                    arg),
+                    ERROR_SEEDING_TRUSTORE, t);
+      }
+      pointAdder.stop();
+      printProgress(formatter.getSpace());
+      printProgress(formatter.getFormattedDone());
+      printlnProgress();
+
+      return adsCtxSource == adsCtx1;
+    }
+    finally
+    {
+      pointAdder.stop();
+    }
+  }
+
+  private InitialLdapContext getDirContextForServer(TopologyCache cache,
+      ServerDescriptor server) throws NamingException
+  {
+    String dn = ConnectionUtils.getBindDN(
+        cache.getAdsContext().getDirContext());
+    String pwd = ConnectionUtils.getBindPassword(
+        cache.getAdsContext().getDirContext());
+    TopologyCacheFilter filter = new TopologyCacheFilter();
+    filter.setSearchMonitoringInformation(false);
+    filter.setSearchBaseDNInformation(false);
+    ServerLoader loader = new ServerLoader(server.getAdsProperties(),
+        dn, pwd, getTrustManager(), cache.getPreferredConnections(),
+        filter);
+    return loader.createContext();
+  }
 }
 
 
+
 /**
  * Class used to compare replication servers.
  *

--
Gitblit v1.10.0