From 018234e6ccd27c399d0d1aa17981c8b4f7abbc39 Mon Sep 17 00:00:00 2001
From: ludovicp <ludovicp@localhost>
Date: Mon, 07 Jun 2010 09:55:29 +0000
Subject: [PATCH] Fix issue #3404. Conflicting entries are now indexed by ds-sync-conflict attribute. This index is only updated when conflicts are detected and searched on for all deletes and modDN operations. Tested successfully against performance regression.

---
 opends/resource/schema/02-config.ldif                                                                  |    3 
 opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/NamingConflictTest.java |  201 +++++++++++++++++++++++++++-
 opends/src/server/org/opends/server/replication/plugin/Historical.java                                 |   21 ++
 opends/src/admin/defn/org/opends/server/admin/std/LocalDBBackendConfiguration.xml                      |    8 +
 opends/resource/config/config.ldif                                                                     |    6 
 opends/src/messages/messages/replication.properties                                                    |    4 
 opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java                      |  163 ++++++++++++++++++++++-
 7 files changed, 385 insertions(+), 21 deletions(-)

diff --git a/opends/resource/config/config.ldif b/opends/resource/config/config.ldif
index 574a82d..c370f27 100644
--- a/opends/resource/config/config.ldif
+++ b/opends/resource/config/config.ldif
@@ -223,6 +223,12 @@
 ds-cfg-attribute: ds-sync-hist
 ds-cfg-index-type: ordering
 
+dn: ds-cfg-attribute=ds-sync-conflict,cn=Index,ds-cfg-backend-id=userRoot,cn=Backends,cn=config
+objectClass: top
+objectClass: ds-cfg-local-db-index
+ds-cfg-attribute: ds-sync-conflict
+ds-cfg-index-type: equality
+
 dn: ds-cfg-attribute=entryUUID,cn=Index,ds-cfg-backend-id=userRoot,cn=Backends,cn=config
 objectClass: top
 objectClass: ds-cfg-local-db-index
diff --git a/opends/resource/schema/02-config.ldif b/opends/resource/schema/02-config.ldif
index 6322ce2..2bd9523 100644
--- a/opends/resource/schema/02-config.ldif
+++ b/opends/resource/schema/02-config.ldif
@@ -1552,7 +1552,8 @@
   X-ORIGIN 'OpenDS Directory Server' )
 attributeTypes: ( 1.3.6.1.4.1.26027.1.1.317
   NAME 'ds-sync-conflict'
-  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+  EQUALITY distinguishedNameMatch
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
   USAGE directoryOperation
   X-ORIGIN 'OpenDS Directory Server' )
 attributeTypes: ( 1.3.6.1.4.1.26027.1.1.319
diff --git a/opends/src/admin/defn/org/opends/server/admin/std/LocalDBBackendConfiguration.xml b/opends/src/admin/defn/org/opends/server/admin/std/LocalDBBackendConfiguration.xml
index d0ae3fc..052e353 100644
--- a/opends/src/admin/defn/org/opends/server/admin/std/LocalDBBackendConfiguration.xml
+++ b/opends/src/admin/defn/org/opends/server/admin/std/LocalDBBackendConfiguration.xml
@@ -84,6 +84,14 @@
           <adm:value>ds-sync-hist</adm:value>
         </adm:property>
       </adm:default-managed-object>
+      <adm:default-managed-object name="ds-sync-conflict">
+        <adm:property name="index-type">
+          <adm:value>equality</adm:value>
+        </adm:property>
+        <adm:property name="attribute">
+          <adm:value>ds-sync-conflict</adm:value>
+        </adm:property>
+      </adm:default-managed-object>
     </adm:one-to-many>
     <adm:profile name="ldap">
       <ldap:rdn-sequence>cn=Index</ldap:rdn-sequence>
diff --git a/opends/src/messages/messages/replication.properties b/opends/src/messages/messages/replication.properties
index 25e4416..0189c92 100644
--- a/opends/src/messages/messages/replication.properties
+++ b/opends/src/messages/messages/replication.properties
@@ -494,4 +494,6 @@
 NOTICE_ERR_WHILE_TRYING_TO_DECODE_RUV_IN_STATE_200=Error while trying to \
  translate RUV into state for suffix %s
 SEVERE_ERR_RSQUEUE_DIFFERENT_MSGS_WITH_SAME_CN_201=Processing two different \
- changes with same changeNumber=%s. Previous msg=<%s>, New msg=<%s>
\ No newline at end of file
+ changes with same changeNumber=%s. Previous msg=<%s>, New msg=<%s>
+SEVERE_ERR_COULD_NOT_SOLVE_CONFLICT_202=Error while trying to solve conflict \
+ with DN : %s ERROR : %s
diff --git a/opends/src/server/org/opends/server/replication/plugin/Historical.java b/opends/src/server/org/opends/server/replication/plugin/Historical.java
index 0d269fd..11ef740 100644
--- a/opends/src/server/org/opends/server/replication/plugin/Historical.java
+++ b/opends/src/server/org/opends/server/replication/plugin/Historical.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2009 Sun Microsystems, Inc.
+ *      Copyright 2006-2010 Sun Microsystems, Inc.
  */
 package org.opends.server.replication.plugin;
 
@@ -449,6 +449,25 @@
 
 
   /**
+   * Returns the lastChangeNumber when the entry DN was modified.
+   *
+   * @return The lastChangeNumber when the entry DN was modified.
+   */
+  public ChangeNumber getDNDate()
+  {
+    if (ADDDate == null)
+      return MODDNDate;
+
+    if (MODDNDate == null)
+      return ADDDate;
+
+    if (MODDNDate.older(ADDDate))
+      return MODDNDate;
+    else
+      return ADDDate;
+  }
+
+  /**
    * read the historical information from the entry attribute and
    * load it into the Historical object attached to the entry.
    * @param entry The entry which historical information must be loaded
diff --git a/opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java b/opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java
index 04094a0..3b45c55 100644
--- a/opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java
+++ b/opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java
@@ -2411,6 +2411,148 @@
         pendingChanges.pushCommittedChanges();
       }
     }
+
+    checkForClearedConflict(op);
+  }
+
+  /**
+   * Check if the operation that just happened has cleared a conflict :
+   * Clearing a conflict happens if the operation has free a DN that
+   * for which an other entry was in conflict.
+   */
+   private void checkForClearedConflict(PostOperationOperation op)
+   {
+     OperationType type = op.getOperationType();
+     if (op.getResultCode() != ResultCode.SUCCESS)
+     {
+       // those operations cannot have cleared a conflict
+       return;
+     }
+
+     DN targetDN;
+     if (type == OperationType.DELETE)
+     {
+       targetDN = ((PostOperationDeleteOperation) op).getEntryDN();
+     }
+     else if (type == OperationType.MODIFY_DN)
+     {
+       targetDN = ((PostOperationModifyDNOperation) op).getEntryDN();
+     }
+     else
+     {
+       return;
+     }
+
+    LDAPFilter filter = null;
+    try
+    {
+      filter = LDAPFilter.decode(
+          DS_SYNC_CONFLICT + "=" + targetDN.toNormalizedString());
+    } catch (LDAPException e)
+    {
+      // Not possible. We know the filter just above is correct.
+    }
+
+     LinkedHashSet<String> attrs = new LinkedHashSet<String>(1);
+     attrs.add(Historical.HISTORICALATTRIBUTENAME);
+     attrs.add(Historical.ENTRYUIDNAME);
+     attrs.add("*");
+     InternalSearchOperation searchOp =  conn.processSearch(
+       ByteString.valueOf(baseDn.toString()),
+       SearchScope.WHOLE_SUBTREE,
+       DereferencePolicy.NEVER_DEREF_ALIASES,
+       0, 0, false, filter,
+       attrs, null);
+
+     LinkedList<SearchResultEntry> entries = searchOp.getSearchEntries();
+     Entry entrytoRename = null;
+     ChangeNumber entrytoRenameDate = null;
+     for (SearchResultEntry entry : entries)
+     {
+       Historical history = Historical.load(entry);
+       if (entrytoRename == null)
+       {
+         entrytoRename = entry;
+         entrytoRenameDate = history.getDNDate();
+       }
+       else if (!history.AddedOrRenamedAfter(entrytoRenameDate))
+       {
+         // this conflict is older than the previous, keep it.
+         entrytoRename = entry;
+         entrytoRenameDate = history.getDNDate();
+       }
+     }
+
+     if (entrytoRename != null)
+     {
+       DN entryDN = entrytoRename.getDN();
+       ModifyDNOperationBasis newOp = renameEntry(
+           entryDN, targetDN.getRDN(), targetDN.getParent(), false);
+
+       ResultCode res = newOp.getResultCode();
+       if (res != ResultCode.SUCCESS)
+       {
+         Message message =
+           ERR_COULD_NOT_SOLVE_CONFLICT.get(entryDN.toString(), res.toString());
+           logError(message);
+       }
+     }
+   }
+
+  /**
+   * Rename an Entry Using a synchronization, non-replicated operation.
+   * This method should be used instead of the InternalConnection methods
+   * when the operation that need to be run must be local only and therefore
+   * not replicated to the RS.
+   *
+   * @param targetDN     The DN of the entry to rename.
+   * @param newRDN       The new RDN to be used.
+   * @param parentDN     The parentDN to be used.
+   * @param markConflict A boolean indicating is this entry should be marked
+   *                     as a conflicting entry. In such case the
+   *                     DS_SYNC_CONFLICT attribute will be added to the entry
+   *                     with the value of its original DN.
+   *                     If false, the DS_SYNC_CONFLICT attribute will be
+   *                     cleared.
+   *
+   * @return The operation that was run to rename the entry.
+   */
+  private ModifyDNOperationBasis renameEntry(
+      DN targetDN, RDN newRDN, DN parentDN, boolean markConflict)
+  {
+    InternalClientConnection conn =
+      InternalClientConnection.getRootConnection();
+
+    ModifyDNOperationBasis newOp =
+       new ModifyDNOperationBasis(
+           conn, InternalClientConnection.nextOperationID(),
+           InternalClientConnection.nextMessageID(), new ArrayList<Control>(0),
+           targetDN, newRDN, false,
+           parentDN);
+     newOp.setInternalOperation(true);
+     newOp.setSynchronizationOperation(true);
+     newOp.setDontSynchronize(true);
+
+     if (markConflict)
+     {
+       AttributeType attrType =
+         DirectoryServer.getAttributeType(DS_SYNC_CONFLICT, true);
+       Attribute attr = Attributes.create(attrType, AttributeValues.create(
+           attrType, targetDN.toString()));
+       Modification mod = new Modification(ModificationType.REPLACE, attr);
+       newOp.addModification(mod);
+     }
+     else
+     {
+       AttributeType attrType =
+         DirectoryServer.getAttributeType(DS_SYNC_CONFLICT, true);
+       Attribute attr = Attributes.empty(attrType);
+       Modification mod = new Modification(ModificationType.DELETE, attr);
+       newOp.addModification(mod);
+     }
+
+     newOp.run();
+    return newOp;
   }
 
   /**
@@ -3188,7 +3330,6 @@
              * and keep the entry as a conflicting entry,
              */
             conflict = true;
-            markConflictEntry(conflictOp, entry.getDN(), entryDN);
             renameConflictEntry(conflictOp, entry.getDN(),
                 Historical.getEntryUuid(entry));
           }
@@ -3233,11 +3374,8 @@
    */
   private void renameConflictEntry(Operation conflictOp, DN dn, String uid)
   {
-    InternalClientConnection conn =
-      InternalClientConnection.getRootConnection();
-
-    ModifyDNOperation newOp = conn.processModifyDN(
-        dn, generateDeleteConflictDn(uid, dn),false, baseDn);
+    ModifyDNOperation newOp =
+      renameEntry(dn, generateDeleteConflictDn(uid, dn), baseDn, true);
 
     if (newOp.getResultCode() != ResultCode.SUCCESS)
     {
@@ -3275,7 +3413,18 @@
     List<Modification> mods = new ArrayList<Modification>();
     Modification mod = new Modification(ModificationType.REPLACE, attr);
     mods.add(mod);
-    ModifyOperation newOp = conn.processModify(currentDN, mods);
+
+    ModifyOperationBasis newOp =
+      new ModifyOperationBasis(
+          conn, InternalClientConnection.nextOperationID(),
+          InternalClientConnection.nextMessageID(), new ArrayList<Control>(0),
+          currentDN, mods);
+    newOp.setInternalOperation(true);
+    newOp.setSynchronizationOperation(true);
+    newOp.setDontSynchronize(true);
+
+    newOp.run();
+
     if (newOp.getResultCode() != ResultCode.SUCCESS)
     {
       // Log information for the repair tool.
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/NamingConflictTest.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/NamingConflictTest.java
index 1977ed7..fde1cfd 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/NamingConflictTest.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/NamingConflictTest.java
@@ -34,6 +34,8 @@
 import org.opends.server.TestCaseUtils;
 import org.opends.server.admin.std.meta.ReplicationDomainCfgDefn.IsolationPolicy;
 import org.opends.server.core.DirectoryServer;
+import org.opends.server.core.ModifyDNOperation;
+import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.replication.ReplicationTestCase;
 import org.opends.server.replication.common.ChangeNumber;
 import org.opends.server.replication.common.ChangeNumberGenerator;
@@ -42,9 +44,12 @@
 import org.opends.server.replication.protocol.DeleteMsg;
 import org.opends.server.types.Attribute;
 import org.opends.server.types.DN;
+import org.opends.server.types.RDN;
 import org.opends.server.types.Entry;
+import org.opends.server.types.ResultCode;
 import org.testng.annotations.Test;
 
+
 import static org.testng.Assert.*;
 
 
@@ -138,7 +143,7 @@
       // and resolve conflict
       domain.replay(queue.take().getUpdateMessage());
 
-      // Expect the conflict resolution 
+      // Expect the conflict resolution
       assertFalse(DirectoryServer.entryExists(entry.getDN()),
       "The modDN conflict was not resolved as expected.");
     }
@@ -149,6 +154,181 @@
   }
 
   /**
+   * Test that when a previous conflict is resolved because
+   * a delete operation has removed one of the conflicting entries
+   * the other conflicting entry is correctly renamed to its
+   * original name.
+   *
+   * @throws Exception if the test fails.
+   */
+  @Test(enabled=true)
+  public void conflictCleaningDelete() throws Exception
+  {
+    TestCaseUtils.initializeTestBackend(true);
+
+    final DN baseDn = DN.decode(TEST_ROOT_DN_STRING);
+
+    TestSynchronousReplayQueue queue = new TestSynchronousReplayQueue();
+    DomainFakeCfg conf = new DomainFakeCfg(baseDn, 1, new TreeSet<String>());
+    conf.setIsolationPolicy(IsolationPolicy.ACCEPT_ALL_UPDATES);
+
+    LDAPReplicationDomain domain =
+      MultimasterReplication.createNewDomain(conf, queue);
+    domain.start();
+
+    try
+    {
+      /*
+       * Create a Change number generator to generate new ChangeNumbers
+       * when we need to send operations messages to the replicationServer.
+       */
+      ChangeNumberGenerator gen = new ChangeNumberGenerator(201, 0);
+
+      String entryldif =
+        "dn: cn=conflictCleaningDelete, "+ TEST_ROOT_DN_STRING + "\n"
+        + "objectClass: top\n" + "objectClass: person\n"
+        + "objectClass: organizationalPerson\n"
+        + "objectClass: inetOrgPerson\n" + "uid: user.1\n"
+        + "description: This is the description for Aaccf Amar.\n" + "st: NC\n"
+        + "postalAddress: Aaccf Amar$17984 Thirteenth Street"
+        + "$Rockford, NC  85762\n" + "mail: user.1@example.com\n"
+        + "cn: Aaccf Amar\n" + "l: Rockford\n"
+        + "street: 17984 Thirteenth Street\n"
+        + "employeeNumber: 1\n"
+        + "sn: Amar\n" + "givenName: Aaccf\n" + "postalCode: 85762\n"
+        + "userPassword: password\n" + "initials: AA\n";
+      Entry entry = TestCaseUtils.entryFromLdifString(entryldif);
+
+      // Add the first entry
+      TestCaseUtils.addEntry(entry);
+      String parentUUID = getEntryUUID(DN.decode(TEST_ROOT_DN_STRING));
+
+      ChangeNumber cn1 = gen.newChangeNumber();
+
+      // Now try to add the same entry with same DN but a different
+      // unique ID though the replication
+      AddMsg  addMsg =
+        new AddMsg(cn1,
+            entry.getDN().toNormalizedString(),
+            "c9cb8c3c-615a-4122-865d-50323aaaed48", parentUUID,
+            entry.getObjectClasses(), entry.getUserAttributes(),
+            null);
+
+      // Put the message in the replay queue
+      domain.processUpdate(addMsg);
+
+      // Make the domain replay the change from the replay queue
+      domain.replay(queue.take().getUpdateMessage());
+
+      // Now delete the first entry that was added at the beginning
+      TestCaseUtils.deleteEntry(entry.getDN());
+
+      // Expect the conflict resolution : the second entry should now
+      // have been renamed with the original DN.
+      Entry resultEntry = DirectoryServer.getEntry(entry.getDN());
+      assertTrue(resultEntry != null, "The conflict was not cleared");
+      assertEquals(getEntryUUID(resultEntry.getDN()),
+          "c9cb8c3c-615a-4122-865d-50323aaaed48",
+          "The wrong entry has been renamed");
+      assertNull(resultEntry.getAttribute(LDAPReplicationDomain.DS_SYNC_CONFLICT));
+    }
+    finally
+    {
+      MultimasterReplication.deleteDomain(baseDn);
+    }
+  }
+
+  /**
+   * Test that when a previous conflict is resolved because
+   * a MODDN operation has removed one of the conflicting entries
+   * the other conflicting entry is correctly renamed to its
+   * original name.
+   *
+   * @throws Exception if the test fails.
+   */
+  @Test(enabled=true)
+  public void conflictCleaningMODDN() throws Exception
+  {
+    TestCaseUtils.initializeTestBackend(true);
+
+    final DN baseDn = DN.decode(TEST_ROOT_DN_STRING);
+
+    TestSynchronousReplayQueue queue = new TestSynchronousReplayQueue();
+    DomainFakeCfg conf = new DomainFakeCfg(baseDn, 1, new TreeSet<String>());
+    conf.setIsolationPolicy(IsolationPolicy.ACCEPT_ALL_UPDATES);
+
+    LDAPReplicationDomain domain =
+      MultimasterReplication.createNewDomain(conf, queue);
+    domain.start();
+
+    try
+    {
+      /*
+       * Create a Change number generator to generate new ChangeNumbers
+       * when we need to send operations messages to the replicationServer.
+       */
+      ChangeNumberGenerator gen = new ChangeNumberGenerator(201, 0);
+
+      String entryldif =
+        "dn: cn=conflictCleaningDelete, "+ TEST_ROOT_DN_STRING + "\n"
+        + "objectClass: top\n" + "objectClass: person\n"
+        + "objectClass: organizationalPerson\n"
+        + "objectClass: inetOrgPerson\n" + "uid: user.1\n"
+        + "description: This is the description for Aaccf Amar.\n" + "st: NC\n"
+        + "postalAddress: Aaccf Amar$17984 Thirteenth Street"
+        + "$Rockford, NC  85762\n" + "mail: user.1@example.com\n"
+        + "cn: Aaccf Amar\n" + "l: Rockford\n"
+        + "street: 17984 Thirteenth Street\n"
+        + "employeeNumber: 1\n"
+        + "sn: Amar\n" + "givenName: Aaccf\n" + "postalCode: 85762\n"
+        + "userPassword: password\n" + "initials: AA\n";
+      Entry entry = TestCaseUtils.entryFromLdifString(entryldif);
+
+      // Add the first entry
+      TestCaseUtils.addEntry(entry);
+      String parentUUID = getEntryUUID(DN.decode(TEST_ROOT_DN_STRING));
+
+      ChangeNumber cn1 = gen.newChangeNumber();
+
+      // Now try to add the same entry with same DN but a different
+      // unique ID though the replication
+      AddMsg  addMsg =
+        new AddMsg(cn1,
+            entry.getDN().toNormalizedString(),
+            "c9cb8c3c-615a-4122-865d-50323aaaed48", parentUUID,
+            entry.getObjectClasses(), entry.getUserAttributes(),
+            null);
+
+      // Put the message in the replay queue
+      domain.processUpdate(addMsg);
+
+      // Make the domain replay the change from the replay queue
+      domain.replay(queue.take().getUpdateMessage());
+
+      // Now delete the first entry that was added at the beginning
+      InternalClientConnection conn =
+        InternalClientConnection.getRootConnection();
+
+      ModifyDNOperation modDNOperation =
+        conn.processModifyDN(entry.getDN(), RDN.decode("cn=foo"), false);
+      assertEquals(modDNOperation.getResultCode(), ResultCode.SUCCESS);
+
+      // Expect the conflict resolution : the second entry should now
+      // have been renamed with the original DN.
+      Entry resultEntry = DirectoryServer.getEntry(entry.getDN());
+      assertTrue(resultEntry != null, "The conflict was not cleared");
+      assertEquals(getEntryUUID(resultEntry.getDN()),
+          "c9cb8c3c-615a-4122-865d-50323aaaed48",
+          "The wrong entry has been renamed");
+      assertNull(resultEntry.getAttribute(LDAPReplicationDomain.DS_SYNC_CONFLICT));
+    }
+    finally
+    {
+      MultimasterReplication.deleteDomain(baseDn);
+    }
+  }
+
+  /**
    * Tests for issue 3891
    *       S1                                       S2
    *       ADD uid=xx,ou=parent,...          [SUBTREE] DEL ou=parent, ...
@@ -161,14 +341,14 @@
    * 2/ removeParentConflict2 (on S1)
    *    - t1(cn1) ADD uid=xx,ou=parent,...
    *             - replay t2(cn2) DEL ou=parent, ....
-   *    => Conflict and no automatic resolution: expect 
+   *    => Conflict and no automatic resolution: expect
    *         - the child entry to be renamed under root entry
    *         - the parent entry to be deleted
    *
    * 3/ removeParentConflict3 (on S2)
    *                         - t2(cn2) DEL or SUBTREE DEL ou=parent, ....
    *                         - t1(cn1) replay ADD uid=xx,ou=parent,...
-   *                        => Conflict and no automatic resolution: expect 
+   *                        => Conflict and no automatic resolution: expect
    *                           - the child entry to be renamed under root entry
    *
    */
@@ -198,11 +378,11 @@
       Entry parentEntry = TestCaseUtils.entryFromLdifString(
           "dn: ou=rpConflict, "+ TEST_ROOT_DN_STRING + "\n"
           + "objectClass: top\n"
-          + "objectClass: organizationalUnit\n");          
+          + "objectClass: organizationalUnit\n");
 
       Entry childEntry = TestCaseUtils.entryFromLdifString(
           "dn: cn=child, ou=rpConflict,"+ TEST_ROOT_DN_STRING + "\n"
-          + "objectClass: top\n" 
+          + "objectClass: top\n"
           + "objectClass: person\n"
           + "objectClass: organizationalPerson\n"
           + "objectClass: inetOrgPerson\n" + "uid: user.1\n"
@@ -219,7 +399,6 @@
       TestCaseUtils.addEntry(childEntry);
 
       String parentUUID = getEntryUUID(parentEntry.getDN());
-      String childUUID = getEntryUUID(childEntry.getDN());
 
       ChangeNumber cn2 = gen.newChangeNumber();
 
@@ -272,11 +451,11 @@
       Entry parentEntry = TestCaseUtils.entryFromLdifString(
           "dn: ou=rpConflict, "+ TEST_ROOT_DN_STRING + "\n"
           + "objectClass: top\n"
-          + "objectClass: organizationalUnit\n");          
+          + "objectClass: organizationalUnit\n");
 
       Entry childEntry = TestCaseUtils.entryFromLdifString(
           "dn: cn=child, ou=rpConflict,"+ TEST_ROOT_DN_STRING + "\n"
-          + "objectClass: top\n" 
+          + "objectClass: top\n"
           + "objectClass: person\n"
           + "objectClass: organizationalPerson\n"
           + "objectClass: inetOrgPerson\n" + "uid: user.1\n"
@@ -357,11 +536,11 @@
       Entry parentEntry = TestCaseUtils.entryFromLdifString(
           "dn: ou=rpConflict, "+ TEST_ROOT_DN_STRING + "\n"
           + "objectClass: top\n"
-          + "objectClass: organizationalUnit\n");          
+          + "objectClass: organizationalUnit\n");
 
       Entry childEntry = TestCaseUtils.entryFromLdifString(
           "dn: cn=child, ou=rpConflict,"+ TEST_ROOT_DN_STRING + "\n"
-          + "objectClass: top\n" 
+          + "objectClass: top\n"
           + "objectClass: person\n"
           + "objectClass: organizationalPerson\n"
           + "objectClass: inetOrgPerson\n" + "uid: user.1\n"
@@ -391,7 +570,7 @@
           childEntry.getObjectClassAttribute(),
           childEntry.getAttributes(),
           new ArrayList<Attribute>());
-      
+
       // Put the message in the replay queue
       domain.processUpdate(addMsg);
       // Make the domain replay the change from the replay queue

--
Gitblit v1.10.0