From 77cc4232cd6246202e3d31ac3b35dd8f872b0e93 Mon Sep 17 00:00:00 2001
From: matthew_swift <matthew_swift@localhost>
Date: Wed, 16 Sep 2009 16:57:01 +0000
Subject: [PATCH] Fix issue 4194: Modifying objectclasses makes them disappear.

---
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/ModifyOperationTestCase.java |   20 +++++++---
 opendj-sdk/opends/src/server/org/opends/server/types/Entry.java                                          |    3 -
 opendj-sdk/opends/src/server/org/opends/server/core/SearchOperationBasis.java                            |   54 ++++++++++++++-------------
 3 files changed, 43 insertions(+), 34 deletions(-)

diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/SearchOperationBasis.java b/opendj-sdk/opends/src/server/org/opends/server/core/SearchOperationBasis.java
index e85f50e..13c5257 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/SearchOperationBasis.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/SearchOperationBasis.java
@@ -32,8 +32,8 @@
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.LinkedHashSet;
-import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.atomic.AtomicBoolean;
 import org.opends.server.api.ClientConnection;
 import org.opends.server.api.plugin.PluginResult;
@@ -694,6 +694,8 @@
 
     // Make a copy of the entry and pare it down to only include the set
     // of requested attributes.
+
+    // NOTE: that this copy will include the objectClass attribute.
     Entry entryToReturn =
         entry.filterEntry(getAttributes(), typesOnly,
             isVirtualAttributesOnly(), isRealAttributesOnly());
@@ -705,6 +707,9 @@
     if ((matchedValuesControl != null) && (! typesOnly))
     {
       // First, look at the set of objectclasses.
+
+      // NOTE: the objectClass attribute is also present and must be
+      // dealt with later.
       AttributeType attrType = DirectoryServer.getObjectClassAttributeType();
       Iterator<String> ocIterator =
            entryToReturn.getObjectClasses().values().iterator();
@@ -720,15 +725,16 @@
       }
 
 
-      // Build a list of all filtered attributes. These will be
-      // replaced in the entry after processing.
-      List<Attribute> modifiedAttributes = new LinkedList<Attribute>();
-
-
-      // Next, the set of user attributes.
-      for (AttributeType t : entryToReturn.getUserAttributes().keySet())
+      // Next, the set of user attributes (incl. objectClass attribute).
+      for (Map.Entry<AttributeType, List<Attribute>> e : entryToReturn
+          .getUserAttributes().entrySet())
       {
-        for (Attribute a : entryToReturn.getUserAttribute(t))
+        AttributeType t = e.getKey();
+        List<Attribute> oldAttributes = e.getValue();
+        List<Attribute> newAttributes =
+            new ArrayList<Attribute>(oldAttributes.size());
+
+        for (Attribute a : oldAttributes)
         {
           // Assume that the attribute will be either empty or contain
           // very few values.
@@ -740,19 +746,26 @@
               builder.add(v);
             }
           }
-          modifiedAttributes.add(builder.toAttribute());
+          newAttributes.add(builder.toAttribute());
         }
+        e.setValue(newAttributes);
       }
 
 
       // Then the set of operational attributes.
-      for (AttributeType t : entryToReturn.getOperationalAttributes().keySet())
+      for (Map.Entry<AttributeType, List<Attribute>> e : entryToReturn
+          .getOperationalAttributes().entrySet())
       {
-        for (Attribute a : entryToReturn.getUserAttribute(t))
+        AttributeType t = e.getKey();
+        List<Attribute> oldAttributes = e.getValue();
+        List<Attribute> newAttributes =
+            new ArrayList<Attribute>(oldAttributes.size());
+
+        for (Attribute a : oldAttributes)
         {
           // Assume that the attribute will be either empty or contain
           // very few values.
-          AttributeBuilder builder = new AttributeBuilder(a);
+          AttributeBuilder builder = new AttributeBuilder(a, true);
           for (AttributeValue v : a)
           {
             if (matchedValuesControl.valueMatches(t, v))
@@ -760,20 +773,9 @@
               builder.add(v);
             }
           }
-          modifiedAttributes.add(builder.toAttribute());
+          newAttributes.add(builder.toAttribute());
         }
-      }
-
-
-      // Replace any modified attributes.
-      for (Attribute a : modifiedAttributes)
-      {
-        entryToReturn.replaceAttribute(a);
-        if (a.isEmpty())
-        {
-          // Add a place holder.
-          entryToReturn.addAttribute(a, null);
-        }
+        e.setValue(newAttributes);
       }
     }
 
diff --git a/opendj-sdk/opends/src/server/org/opends/server/types/Entry.java b/opendj-sdk/opends/src/server/org/opends/server/types/Entry.java
index 3829f3a..2942527 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/types/Entry.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/types/Entry.java
@@ -4827,8 +4827,7 @@
         }
       }
 
-      // Fall through - search results have an object attribute
-      // as well.
+      return;
     }
 
     List<Attribute> attributes;
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/ModifyOperationTestCase.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/ModifyOperationTestCase.java
index ae7100a..01fcd5e 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/ModifyOperationTestCase.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/ModifyOperationTestCase.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 package org.opends.server.core;
 
@@ -44,8 +44,6 @@
 import org.opends.server.plugins.DisconnectClientPlugin;
 import org.opends.server.plugins.ShortCircuitPlugin;
 import org.opends.server.plugins.UpdatePreOpPlugin;
-import org.opends.server.protocols.asn1.ASN1Reader;
-import org.opends.server.protocols.asn1.ASN1Writer;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.protocols.internal.InternalSearchOperation;
 import org.opends.server.protocols.ldap.BindRequestProtocolOp;
@@ -3403,9 +3401,19 @@
     assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS);
     retrieveSuccessfulOperationElements(modifyOperation);
 
-    Entry e = DirectoryServer.getEntry(DN.decode("uid=test.user," + baseDN));
-    assertTrue(e.hasObjectClass(
-         DirectoryServer.getObjectClass("extensibleobject", true)));
+    Entry e =
+        DirectoryServer.getEntry(DN.decode("uid=test.user," + baseDN));
+    assertTrue(e.hasObjectClass(DirectoryServer.getObjectClass(
+        "extensibleobject", true)));
+    assertTrue(e.hasObjectClass(DirectoryServer.getObjectClass(
+        "inetOrgPerson", true)));
+    assertTrue(e.hasObjectClass(DirectoryServer.getObjectClass(
+        "organizationalPerson", true)));
+    assertTrue(e.hasObjectClass(DirectoryServer.getObjectClass(
+        "person", true)));
+    assertTrue(e.hasObjectClass(DirectoryServer.getObjectClass("top",
+        true)));
+    assertEquals(e.getUserAttributes().size(), 8, "Incorrect number of user attributes");
   }
 
 

--
Gitblit v1.10.0