From 2a6a436cf43f43eeb25210a5c72301a932598d1c Mon Sep 17 00:00:00 2001
From: Jean-Noël Rouvignac <jean-noel.rouvignac@forgerock.com>
Date: Fri, 05 Aug 2016 10:14:28 +0000
Subject: [PATCH] Partial OPENDJ-3106 Migrate Entry

---
 opendj-server-legacy/src/test/java/org/opends/server/types/TestEntry.java                            |   52 ++++
 opendj-server-legacy/src/main/java/org/opends/server/protocols/ldap/SearchResultEntryProtocolOp.java |  108 +++------
 opendj-server-legacy/src/main/java/org/opends/server/backends/RootDSEBackend.java                    |   19 -
 opendj-server-legacy/src/main/java/org/opends/server/backends/SchemaBackend.java                     |   17 
 opendj-server-legacy/src/main/java/org/opends/server/types/Entry.java                                |  115 +++++++++
 opendj-server-legacy/src/main/java/org/opends/server/backends/MonitorBackend.java                    |   23 -
 opendj-server-legacy/src/main/java/org/opends/server/types/SearchFilter.java                         |  163 +++---------
 opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/TestDnKeyFormat.java         |  125 +++------
 opendj-server-legacy/src/main/java/org/opends/server/tools/makeldif/Branch.java                      |   67 ++---
 9 files changed, 330 insertions(+), 359 deletions(-)

diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/MonitorBackend.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/MonitorBackend.java
index 2f65fef..dfd45c0 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/MonitorBackend.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/backends/MonitorBackend.java
@@ -26,7 +26,6 @@
 
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
@@ -133,8 +132,7 @@
     try
     {
       final Entry configEntry = DirectoryServer.getConfigEntry(configEntryDN);
-      addAllNonMonitorConfigAttributes(userAttrs, configEntry.getUserAttributes().values());
-      addAllNonMonitorConfigAttributes(userAttrs, configEntry.getOperationalAttributes().values());
+      addAllNonMonitorConfigAttributes(userAttrs, configEntry.getAllAttributes());
     }
     catch (final Exception e)
     {
@@ -153,16 +151,13 @@
     return ccr;
   }
 
-  private void addAllNonMonitorConfigAttributes(final List<Attribute> userAttrs, Collection<List<Attribute>> attrbutes)
+  private void addAllNonMonitorConfigAttributes(List<Attribute> userAttrs, Iterable<Attribute> attributes)
   {
-    for (final List<Attribute> attrs : attrbutes)
+    for (final Attribute a : attributes)
     {
-      for (final Attribute a : attrs)
+      if (!isMonitorConfigAttribute(a))
       {
-        if (!isMonitorConfigAttribute(a))
-        {
-          userAttrs.add(a);
-        }
+        userAttrs.add(a);
       }
     }
   }
@@ -190,8 +185,7 @@
     // attributes that we don't recognize will be included directly in the base
     // monitor entry.
     userDefinedAttributes = new ArrayList<>();
-    addAll(userDefinedAttributes, configEntry.getUserAttributes().values());
-    addAll(userDefinedAttributes, configEntry.getOperationalAttributes().values());
+    addAllNonMonitorConfigAttributes(userDefinedAttributes, configEntry.getAllAttributes());
 
     // Construct the set of objectclasses to include in the base monitor entry.
     monitorObjectClasses.put(CoreSchema.getTopObjectClass(), OC_TOP);
@@ -217,11 +211,6 @@
     currentConfig = cfg;
   }
 
-  private void addAll(ArrayList<Attribute> attributes, Collection<List<Attribute>> attributesToAdd)
-  {
-    addAllNonMonitorConfigAttributes(attributes, attributesToAdd);
-  }
-
   @Override
   public void createBackup(final BackupConfig backupConfig)
       throws DirectoryException
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/RootDSEBackend.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/RootDSEBackend.java
index a38558a..4439ecb 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/RootDSEBackend.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/backends/RootDSEBackend.java
@@ -238,24 +238,11 @@
    */
   private void addAllUserDefinedAttrs(List<Attribute> userDefinedAttrs, Entry configEntry)
   {
-    for (List<Attribute> attrs : configEntry.getUserAttributes().values())
+    for (Attribute a : configEntry.getAllAttributes())
     {
-      for (Attribute a : attrs)
+      if (!isDSEConfigAttribute(a))
       {
-        if (!isDSEConfigAttribute(a))
-        {
-          userDefinedAttrs.add(a);
-        }
-      }
-    }
-    for (List<Attribute> attrs : configEntry.getOperationalAttributes().values())
-    {
-      for (Attribute a : attrs)
-      {
-        if (!isDSEConfigAttribute(a))
-        {
-          userDefinedAttrs.add(a);
-        }
+        userDefinedAttrs.add(a);
       }
     }
   }
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/backends/SchemaBackend.java b/opendj-server-legacy/src/main/java/org/opends/server/backends/SchemaBackend.java
index 38bb08e..282f166 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/backends/SchemaBackend.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/backends/SchemaBackend.java
@@ -214,8 +214,7 @@
     // attributes that we don't recognize will be included directly in the
     // schema entry.
     userDefinedAttributes = new ArrayList<>();
-    addAllNonSchemaConfigAttributes(userDefinedAttributes, configEntry.getUserAttributes().values());
-    addAllNonSchemaConfigAttributes(userDefinedAttributes, configEntry.getOperationalAttributes().values());
+    addAllNonSchemaConfigAttributes(userDefinedAttributes, configEntry.getAllAttributes());
 
     currentConfig = cfg;
   }
@@ -2802,8 +2801,7 @@
     try
     {
       Entry configEntry = DirectoryServer.getConfigEntry(configEntryDN);
-      addAllNonSchemaConfigAttributes(newUserAttrs, configEntry.getUserAttributes().values());
-      addAllNonSchemaConfigAttributes(newUserAttrs, configEntry.getOperationalAttributes().values());
+      addAllNonSchemaConfigAttributes(newUserAttrs, configEntry.getAllAttributes());
     }
     catch (ConfigException e)
     {
@@ -2870,16 +2868,13 @@
     return ccr;
   }
 
-  private void addAllNonSchemaConfigAttributes(List<Attribute> newUserAttrs, Collection<List<Attribute>> attributes)
+  private void addAllNonSchemaConfigAttributes(List<Attribute> newUserAttrs, Iterable<Attribute> attributes)
   {
-    for (List<Attribute> attrs : attributes)
+    for (Attribute a : attributes)
     {
-      for (Attribute a : attrs)
+      if (!isSchemaConfigAttribute(a))
       {
-        if (!isSchemaConfigAttribute(a))
-        {
-          newUserAttrs.add(a);
-        }
+        newUserAttrs.add(a);
       }
     }
   }
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/protocols/ldap/SearchResultEntryProtocolOp.java b/opendj-server-legacy/src/main/java/org/opends/server/protocols/ldap/SearchResultEntryProtocolOp.java
index db0cd80..35a7b1c 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/protocols/ldap/SearchResultEntryProtocolOp.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/protocols/ldap/SearchResultEntryProtocolOp.java
@@ -34,12 +34,12 @@
 import org.forgerock.opendj.ldap.ByteString;
 import org.forgerock.opendj.ldap.DN;
 import org.forgerock.opendj.ldap.schema.AttributeType;
+import org.forgerock.opendj.ldap.schema.ObjectClass;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.types.Attribute;
 import org.opends.server.types.AttributeBuilder;
 import org.opends.server.types.Entry;
 import org.opends.server.types.LDAPException;
-import org.forgerock.opendj.ldap.schema.ObjectClass;
 import org.opends.server.types.SearchResultEntry;
 import org.opends.server.util.Base64;
 
@@ -163,82 +163,16 @@
       {
         if (ldapVersion == 2)
         {
-          // Merge attributes having the same type into a single
-          // attribute.
-          boolean needsMerge;
-          Map<AttributeType, List<Attribute>> attrs =
-              entry.getUserAttributes();
-          for (Map.Entry<AttributeType, List<Attribute>> attrList : attrs
-              .entrySet())
-          {
-            needsMerge = true;
-
-            if (attrList != null && attrList.getValue().size() == 1)
-            {
-              Attribute a = attrList.getValue().get(0);
-              if (!a.getAttributeDescription().hasOptions())
-              {
-                needsMerge = false;
-                tmp.add(new LDAPAttribute(a));
-              }
-            }
-
-            if (needsMerge)
-            {
-              AttributeBuilder builder =
-                  new AttributeBuilder(attrList.getKey());
-              for (Attribute a : attrList.getValue())
-              {
-                builder.addAll(a);
-              }
-              tmp.add(new LDAPAttribute(builder.toAttribute()));
-            }
-          }
-
-          attrs = entry.getOperationalAttributes();
-          for (Map.Entry<AttributeType, List<Attribute>> attrList : attrs
-              .entrySet())
-          {
-            needsMerge = true;
-
-            if (attrList != null && attrList.getValue().size() == 1)
-            {
-              Attribute a = attrList.getValue().get(0);
-              if (!a.getAttributeDescription().hasOptions())
-              {
-                needsMerge = false;
-                tmp.add(new LDAPAttribute(a));
-              }
-            }
-
-            if (needsMerge)
-            {
-              AttributeBuilder builder = new AttributeBuilder(attrList.getKey());
-              for (Attribute a : attrList.getValue())
-              {
-                builder.addAll(a);
-              }
-              tmp.add(new LDAPAttribute(builder.toAttribute()));
-            }
-          }
+          // Merge attributes having the same type into a single attribute.
+          merge(tmp, entry.getUserAttributes());
+          merge(tmp, entry.getOperationalAttributes());
         }
         else
         {
           // LDAPv3
-          for (List<Attribute> attrList : entry.getUserAttributes().values())
+          for (Attribute a : entry.getAllAttributes())
           {
-            for (Attribute a : attrList)
-            {
-              tmp.add(new LDAPAttribute(a));
-            }
-          }
-
-          for (List<Attribute> attrList : entry.getOperationalAttributes().values())
-          {
-            for (Attribute a : attrList)
-            {
-              tmp.add(new LDAPAttribute(a));
-            }
+            tmp.add(new LDAPAttribute(a));
           }
         }
       }
@@ -251,6 +185,36 @@
     return attributes;
   }
 
+  private void merge(LinkedList<LDAPAttribute> tmp, Map<AttributeType, List<Attribute>> attrs)
+  {
+    boolean needsMerge;
+    for (Map.Entry<AttributeType, List<Attribute>> attrList : attrs.entrySet())
+    {
+      needsMerge = true;
+
+      if (attrList != null && attrList.getValue().size() == 1)
+      {
+        Attribute a = attrList.getValue().get(0);
+        if (!a.getAttributeDescription().hasOptions())
+        {
+          needsMerge = false;
+          tmp.add(new LDAPAttribute(a));
+        }
+      }
+
+      if (needsMerge)
+      {
+        AttributeBuilder builder =
+            new AttributeBuilder(attrList.getKey());
+        for (Attribute a : attrList.getValue())
+        {
+          builder.addAll(a);
+        }
+        tmp.add(new LDAPAttribute(builder.toAttribute()));
+      }
+    }
+  }
+
 
 
   /**
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/tools/makeldif/Branch.java b/opendj-server-legacy/src/main/java/org/opends/server/tools/makeldif/Branch.java
index fdd739d..c2037ec 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/tools/makeldif/Branch.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/tools/makeldif/Branch.java
@@ -121,54 +121,35 @@
       }
     }
 
-    for (List<Attribute> attrList : entry.getUserAttributes().values())
-    {
-      for (Attribute a : attrList)
-      {
-        for (ByteString v : a)
-        {
-          try
-          {
-            String[] valueStrings = new String[] { v.toString() };
-            Tag[] tags = new Tag[] { new StaticTextTag() };
-            tags[0].initializeForBranch(templateFile, this, valueStrings, 0, warnings);
-            lineList.add(new TemplateLine(a.getAttributeDescription().getAttributeType(), 0, tags));
-          }
-          catch (Exception e)
-          {
-            // This should never happen.
-            e.printStackTrace();
-          }
-        }
-      }
-    }
-
-    for (List<Attribute> attrList : entry.getOperationalAttributes().values())
-    {
-      for (Attribute a : attrList)
-      {
-        for (ByteString v : a)
-        {
-          try
-          {
-            String[] valueStrings = new String[] { v.toString() };
-            Tag[] tags = new Tag[] { new StaticTextTag() };
-            tags[0].initializeForBranch(templateFile, this, valueStrings, 0, warnings);
-            lineList.add(new TemplateLine(a.getAttributeDescription().getAttributeType(), 0, tags));
-          }
-          catch (Exception e)
-          {
-            // This should never happen.
-            e.printStackTrace();
-          }
-        }
-      }
-    }
+    addLines(lineList, entry.getAllAttributes(), templateFile, warnings);
 
     rdnLines = new TemplateLine[lineList.size()];
     lineList.toArray(rdnLines);
   }
 
+  private void addLines(List<TemplateLine> lineList, Iterable<Attribute> attrs, TemplateFile templateFile,
+      List<LocalizableMessage> warnings)
+  {
+    for (Attribute a : attrs)
+    {
+      for (ByteString v : a)
+      {
+        try
+        {
+          String[] valueStrings = new String[] { v.toString() };
+          Tag[] tags = new Tag[] { new StaticTextTag() };
+          tags[0].initializeForBranch(templateFile, this, valueStrings, 0, warnings);
+          lineList.add(new TemplateLine(a.getAttributeDescription().getAttributeType(), 0, tags));
+        }
+        catch (Exception e)
+        {
+          // This should never happen.
+          e.printStackTrace();
+        }
+      }
+    }
+  }
+
 
 
   /**
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/types/Entry.java b/opendj-server-legacy/src/main/java/org/opends/server/types/Entry.java
index 43065e1..6869c99 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/types/Entry.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/types/Entry.java
@@ -54,6 +54,7 @@
 import org.forgerock.opendj.ldap.schema.NameForm;
 import org.forgerock.opendj.ldap.schema.ObjectClass;
 import org.forgerock.opendj.ldap.schema.ObjectClassType;
+import org.forgerock.util.Reject;
 import org.forgerock.util.Utils;
 import org.opends.server.api.CompressedSchema;
 import org.opends.server.api.ProtocolElement;
@@ -121,10 +122,7 @@
   /** The DN for this entry. */
   private DN dn;
 
-  /**
-   * A generic attachment that may be used to associate this entry with some
-   * other object.
-   */
+  /** A generic attachment that may be used to associate this entry with some other object. */
   private transient Object attachment;
 
   /**
@@ -326,6 +324,113 @@
     return attributes;
   }
 
+  /** Iterator over a {@code Collection<List<Attribute>>}. */
+  private static final class CollectionListIterator implements Iterator<Attribute>
+  {
+    private final Iterator<List<Attribute>> parentIt;
+    private List<Attribute> subList = Collections.emptyList();
+    private Iterator<Attribute> subIt = subList.iterator();
+
+    private CollectionListIterator(Collection<List<Attribute>> list)
+    {
+      this.parentIt = Reject.checkNotNull(list).iterator();
+      advance();
+    }
+
+    private void advance()
+    {
+      while (!subIt.hasNext())
+      {
+        if (!parentIt.hasNext())
+        {
+          return;
+        }
+        subList = parentIt.next();
+        subIt = subList.iterator();
+      }
+    }
+
+    @Override
+    public boolean hasNext()
+    {
+      return subIt.hasNext();
+    }
+
+    @Override
+    public Attribute next()
+    {
+      final Attribute result = subIt.next();
+      if (!subIt.hasNext())
+      {
+        advance();
+      }
+      return result;
+    }
+
+    @Override
+    public void remove()
+    {
+      throw new UnsupportedOperationException();
+    }
+  }
+
+  /**
+   * Returns an {@code Iterable} containing all of the attributes in this entry,
+   * excluding the objectClass attribute.
+   * <p>
+   * The returned {@code Iterable} may NOT be used to remove attributes.
+   *
+   * @return An {@code Iterable} containing all of the attributes.
+   */
+  public Iterable<Attribute> getAllAttributes()
+  {
+    /** Iterator over all the attributes of this entry. */
+    final class AllAttributesIterator implements Iterator<Attribute>
+    {
+      private boolean iteratesOnOperationalAttributes;
+      private Iterator<Attribute> currentIterator = new CollectionListIterator(getUserAttributes().values());
+
+      @Override
+      public boolean hasNext()
+      {
+        if (currentIterator.hasNext())
+        {
+          return true;
+        }
+        if (iteratesOnOperationalAttributes)
+        {
+          return false;
+        }
+        iteratesOnOperationalAttributes = true;
+        currentIterator = new CollectionListIterator(getOperationalAttributes().values());
+        return currentIterator.hasNext();
+      }
+
+      @Override
+      public Attribute next()
+      {
+        return currentIterator.next();
+      }
+
+      @Override
+      public void remove()
+      {
+        currentIterator.remove();
+      }
+    }
+
+    /** Can return an iterator over all the attributes of this entry. */
+    final class AllAttributesIterable implements Iterable<Attribute>
+    {
+      @Override
+      public Iterator<Attribute> iterator()
+      {
+        return new AllAttributesIterator();
+      }
+    }
+    return new AllAttributesIterable();
+  }
+
   /**
    * Retrieves the entire set of user (i.e., non-operational)
    * attributes for this entry.  The caller should be allowed to
@@ -1567,7 +1672,7 @@
         Collection<NameForm> forms = DirectoryServer.getSchema().getNameForm(structuralClass);
         if (forms != null)
         {
-          List<NameForm> listForms = new ArrayList<NameForm>(forms);
+          List<NameForm> listForms = new ArrayList<>(forms);
           boolean matchFound = false;
           boolean obsolete = true;
           for(int index=0; index <listForms.size(); index++)
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/types/SearchFilter.java b/opendj-server-legacy/src/main/java/org/opends/server/types/SearchFilter.java
index b0870d3..91cf841 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/types/SearchFilter.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/types/SearchFilter.java
@@ -3097,8 +3097,7 @@
                                Entry entry)
           throws DirectoryException
   {
-    // We must have an assertion value for which to make the
-    // determination.
+    // We must have an assertion value for which to make the determination.
     if (assertionValue == null)
     {
       LocalizableMessage message =
@@ -3184,8 +3183,7 @@
     {
       logger.traceException(e);
 
-      // We can't normalize the assertion value, so the result must be
-      // undefined.
+      // We can't normalize the assertion value, so the result must be undefined.
       return ConditionResult.UNDEFINED;
     }
 
@@ -3196,86 +3194,11 @@
     ConditionResult result = ConditionResult.FALSE;
     if (getAttributeType() == null)
     {
-      for (List<Attribute> attrList :
-           entry.getUserAttributes().values())
+      final Iterable<Attribute> attrs = entry.getAllAttributes();
+      result = assertionMatchesAnyAttribute(matchingRule, assertion, attrs, result, entry, completeFilter);
+      if (ConditionResult.TRUE.equals(result))
       {
-        for (Attribute a : attrList)
-        {
-          for (ByteString v : a)
-          {
-            try
-            {
-              ByteString nv = matchingRule.normalizeAttributeValue(v);
-              ConditionResult r = assertion.matches(nv);
-              switch (r)
-              {
-                case TRUE:
-                  return ConditionResult.TRUE;
-                case FALSE:
-                  break;
-                case UNDEFINED:
-                  result = ConditionResult.UNDEFINED;
-                  break;
-                default:
-                  LocalizableMessage message =
-                      ERR_SEARCH_FILTER_INVALID_RESULT_TYPE.
-                        get(entry.getName(), completeFilter, r);
-                  throw new DirectoryException(
-                                 ResultCode.PROTOCOL_ERROR, message);
-              }
-            }
-            catch (Exception e)
-            {
-              logger.traceException(e);
-
-              // We couldn't normalize one of the values.  If we don't
-              // find a definite match, then we should return
-              // undefined.
-              result = ConditionResult.UNDEFINED;
-            }
-          }
-        }
-      }
-
-      for (List<Attribute> attrList :
-           entry.getOperationalAttributes().values())
-      {
-        for (Attribute a : attrList)
-        {
-          for (ByteString v : a)
-          {
-            try
-            {
-              ByteString nv = matchingRule.normalizeAttributeValue(v);
-              ConditionResult r = assertion.matches(nv);
-              switch (r)
-              {
-                case TRUE:
-                  return ConditionResult.TRUE;
-                case FALSE:
-                  break;
-                case UNDEFINED:
-                  result = ConditionResult.UNDEFINED;
-                  break;
-                default:
-                  LocalizableMessage message =
-                      ERR_SEARCH_FILTER_INVALID_RESULT_TYPE.
-                        get(entry.getName(), completeFilter, r);
-                  throw new DirectoryException(
-                                 ResultCode.PROTOCOL_ERROR, message);
-              }
-            }
-            catch (Exception e)
-            {
-              logger.traceException(e);
-
-              // We couldn't normalize one of the values.  If we don't
-              // find a definite match, then we should return
-              // undefined.
-              result = ConditionResult.UNDEFINED;
-            }
-          }
-        }
+        return ConditionResult.TRUE;
       }
 
       Attribute a = entry.getObjectClassAttribute();
@@ -3313,45 +3236,17 @@
     }
     else
     {
-      for (Attribute a : entry.getAttribute(attributeDescription))
+      final Iterable<Attribute> attrs = entry.getAttribute(attributeDescription);
+      result = assertionMatchesAnyAttribute(matchingRule, assertion, attrs, result, entry, completeFilter);
+      if (ConditionResult.TRUE.equals(result))
       {
-        for (ByteString v : a)
-        {
-          try
-          {
-            ByteString nv = matchingRule.normalizeAttributeValue(v);
-            ConditionResult r = assertion.matches(nv);
-            switch (r)
-            {
-            case TRUE:
-              return ConditionResult.TRUE;
-            case FALSE:
-              break;
-            case UNDEFINED:
-              result = ConditionResult.UNDEFINED;
-              break;
-            default:
-              LocalizableMessage message =
-                  ERR_SEARCH_FILTER_INVALID_RESULT_TYPE.get(entry.getName(), completeFilter, r);
-              throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
-            }
-          }
-          catch (Exception e)
-          {
-            logger.traceException(e);
-
-            // We couldn't normalize one of the values.
-            // If we don't find a definite match, then we should return undefined.
-            result = ConditionResult.UNDEFINED;
-          }
-        }
+        return ConditionResult.TRUE;
       }
     }
 
 
     // If we've gotten here, then we know that there is no definite
-    // match in the set of attributes.  If we should check DN
-    // attributes, then do so.
+    // match in the set of attributes. If we should check DN attributes, then do so.
     if (dnAttributes)
     {
       for (RDN rdn : entry.getName())
@@ -3401,6 +3296,42 @@
     return result;
   }
 
+  private ConditionResult assertionMatchesAnyAttribute(MatchingRule matchingRule, Assertion assertion,
+      Iterable<Attribute> attributes, ConditionResult result, Entry entry, SearchFilter filter)
+  {
+    for (Attribute a : attributes)
+    {
+      for (ByteString v : a)
+      {
+        try
+        {
+          ConditionResult r = assertion.matches(matchingRule.normalizeAttributeValue(v));
+          switch (r)
+          {
+          case TRUE:
+            return ConditionResult.TRUE;
+          case FALSE:
+            break;
+          case UNDEFINED:
+            result = ConditionResult.UNDEFINED;
+            break;
+          default:
+            LocalizableMessage message = ERR_SEARCH_FILTER_INVALID_RESULT_TYPE.get(entry.getName(), filter, r);
+            throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
+          }
+        }
+        catch (Exception e)
+        {
+          logger.traceException(e);
+
+          // We couldn't normalize one of the values.
+          // If we don't find a definite match, then we should return undefined.
+          result = ConditionResult.UNDEFINED;
+        }
+      }
+    }
+    return result;
+  }
 
   /**
    * Indicates whether this search filter is equal to the provided
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/TestDnKeyFormat.java b/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/TestDnKeyFormat.java
index d07653f..a6d49b6 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/TestDnKeyFormat.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/TestDnKeyFormat.java
@@ -22,7 +22,6 @@
 
 import java.io.ByteArrayInputStream;
 import java.util.List;
-import java.util.Map;
 
 import org.forgerock.opendj.ldap.ByteString;
 import org.forgerock.opendj.ldap.ByteStringBuilder;
@@ -170,38 +169,16 @@
     buffer.appendBytes(bsb);
 
 
-    // Encode the user attributes in the appropriate manner.
-    encodeV1Attributes(buffer, entry.getUserAttributes());
-
-
-    // The operational attributes will be encoded in the same way as
-    // the user attributes.
-    encodeV1Attributes(buffer, entry.getOperationalAttributes());
+    encodeV1Attributes(buffer, entry.getAllAttributes(), false);
+    encodeV1Attributes(buffer, entry.getAllAttributes(), true);
   }
 
-  private void encodeV1Attributes(ByteStringBuilder buffer,
-                                Map<AttributeType,List<Attribute>> attributes)
+  private void encodeV1Attributes(ByteStringBuilder buffer, Iterable<Attribute> attributes, boolean isOperational)
   {
-    int numAttributes = 0;
-
-    // First count how many attributes are there to encode.
-    for (List<Attribute> attrList : attributes.values())
-    {
-      for (Attribute a : attrList)
-      {
-        if (a.isVirtual() || a.isEmpty())
-        {
-          continue;
-        }
-
-        numAttributes++;
-      }
-    }
-
     // Encoded one-to-five byte number of attributes
-    buffer.appendBERLength(numAttributes);
+    buffer.appendBERLength(countNbAttrsToEncode(attributes, isOperational));
 
-    append(buffer, attributes);
+    append(buffer, attributes, isOperational);
   }
 
     /**
@@ -258,64 +235,53 @@
       buffer.appendBytes(bsb);
     }
 
-
-    // Encode the user attributes in the appropriate manner.
-    encodeV2Attributes(buffer, entry.getUserAttributes(), config);
-
-
-    // The operational attributes will be encoded in the same way as
-    // the user attributes.
-    encodeV2Attributes(buffer, entry.getOperationalAttributes(), config);
+    encodeV2Attributes(buffer, entry.getAllAttributes(), config, false);
+    encodeV2Attributes(buffer, entry.getAllAttributes(), config, true);
   }
 
-  private void encodeV2Attributes(ByteStringBuilder buffer,
-                                Map<AttributeType,List<Attribute>> attributes,
-                                EntryEncodeConfig config)
+  private void encodeV2Attributes(
+      ByteStringBuilder buffer, Iterable<Attribute> attributes, EntryEncodeConfig config, boolean isOperational)
       throws DirectoryException
   {
-    int numAttributes = 0;
+    // Encoded one-to-five byte number of attributes
+    buffer.appendBERLength(countNbAttrsToEncode(attributes, isOperational));
 
-    // First count how many attributes are there to encode.
-    for (List<Attribute> attrList : attributes.values())
+    if (config.compressAttributeDescriptions())
     {
-      for (Attribute a : attrList)
+      for (Attribute a : attributes)
       {
         if (a.isVirtual() || a.isEmpty())
         {
           continue;
         }
 
-        numAttributes++;
-      }
-    }
-
-    // Encoded one-to-five byte number of attributes
-    buffer.appendBERLength(numAttributes);
-
-    if (config.compressAttributeDescriptions())
-    {
-      for (List<Attribute> attrList : attributes.values())
-      {
-        for (Attribute a : attrList)
-        {
-          if (a.isVirtual() || a.isEmpty())
-          {
-            continue;
-          }
-
-          ByteStringBuilder bsb = new ByteStringBuilder();
-          config.getCompressedSchema().encodeAttribute(bsb, a);
-          buffer.appendBERLength(bsb.length());
-          buffer.appendBytes(bsb);
-        }
+        ByteStringBuilder bsb = new ByteStringBuilder();
+        config.getCompressedSchema().encodeAttribute(bsb, a);
+        buffer.appendBERLength(bsb.length());
+        buffer.appendBytes(bsb);
       }
     }
     else
     {
-      append(buffer, attributes);
+      append(buffer, attributes, isOperational);
     }
   }
 
+  private int countNbAttrsToEncode(Iterable<Attribute> attributes, boolean isOperational)
+  {
+    int result = 0;
+    for (Attribute a : attributes)
+    {
+      if (!a.isVirtual()
+          && !a.isEmpty()
+          && a.getAttributeDescription().getAttributeType().isOperational() == isOperational)
+      {
+        result++;
+      }
+    }
+    return result;
+  }
+
   /**
    * The attributes will be encoded as a sequence of:
    * - A UTF-8 byte representation of the attribute name.
@@ -325,22 +291,23 @@
    *   - A one-to-five byte length for the value
    *   - A UTF-8 byte representation for the value
    */
-  private void append(ByteStringBuilder buffer,
-      Map<AttributeType, List<Attribute>> attributes)
+  private void append(ByteStringBuilder buffer, Iterable<Attribute> attributes, boolean isOperational)
   {
-    for (List<Attribute> attrList : attributes.values())
+    for (Attribute a : attributes)
     {
-      for (Attribute a : attrList)
+      if (a.getAttributeDescription().getAttributeType().isOperational() != isOperational)
       {
-        buffer.appendBytes(getBytes(a.getAttributeDescription().toString()));
-        buffer.appendByte(0x00);
+        break;
+      }
 
-        buffer.appendBERLength(a.size());
-        for (ByteString v : a)
-        {
-          buffer.appendBERLength(v.length());
-          buffer.appendBytes(v);
-        }
+      buffer.appendBytes(getBytes(a.getAttributeDescription().toString()));
+      buffer.appendByte(0x00);
+
+      buffer.appendBERLength(a.size());
+      for (ByteString v : a)
+      {
+        buffer.appendBERLength(v.length());
+        buffer.appendBytes(v);
       }
     }
   }
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/types/TestEntry.java b/opendj-server-legacy/src/test/java/org/opends/server/types/TestEntry.java
index 920e457..d057be1 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/types/TestEntry.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/types/TestEntry.java
@@ -21,8 +21,10 @@
 import static org.opends.server.util.CollectionUtils.*;
 import static org.testng.Assert.*;
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Set;
@@ -633,4 +635,54 @@
     assertThat(e.getOperationalAttribute(AttributeDescription.create(uidType, options))).isEmpty();
     assertThat(e.getOperationalAttribute(AttributeDescription.create(mnType, options))).isEmpty();
   }
+
+  @Test
+  public void testGetAllAttributes() throws Exception
+  {
+    Entry e = TestCaseUtils.makeEntry(
+         "dn: cn=Test User,ou=People,dc=example,dc=com",
+         "objectClass: top",
+         "objectClass: person",
+         "objectClass: organizationalPerson",
+         "objectClass: inetOrgPerson",
+         "cn: Test User",
+         "cn;lang-en-US: Test User",
+         "givenName: Test",
+         "givenName;lang-en-US: Test",
+         "sn: User",
+         "sn;lang-en-US: User",
+         "creatorsName: cn=Directory Manager",
+         "createTimestamp: 20070101000000Z",
+         "modifiersName: cn=Directory Manager",
+         "modifyTimestamp: 20070101000001Z");
+
+    List<String> expectedAttrNames = newArrayList(
+        "cn", "cn;lang-en-US", "sn", "sn;lang-en-US", "givenName", "givenName;lang-en-US", "creatorsName",
+        "createTimestamp", "modifyTimestamp", "modifiersName");
+
+    Iterator<Attribute> allAttrsIt = e.getAllAttributes().iterator();
+    Iterator<String> expectedAttrNameIt = expectedAttrNames.iterator();
+    do
+    {
+      assertThat(getNames(e.getAllAttributes())).containsOnly(expectedAttrNames.toArray(new String[0]));
+      assertThat(getName(allAttrsIt.next())).isEqualTo(expectedAttrNameIt.next());
+    }
+    while (allAttrsIt.hasNext());
+    System.out.println();
+  }
+
+  private List<String> getNames(Iterable<Attribute> allAttributes)
+  {
+    List<String> results = new ArrayList<>();
+    for (Attribute attr : allAttributes)
+    {
+      results.add(getName(attr));
+    }
+    return results;
+  }
+
+  private String getName(Attribute attr)
+  {
+    return attr.getAttributeDescription().toString();
+  }
 }

--
Gitblit v1.10.0