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

Jean-Noël Rouvignac
05.10.2016 2a6a436cf43f43eeb25210a5c72301a932598d1c
Partial OPENDJ-3106 Migrate Entry

Entry.java:
Add getAllAttributes() (like SDK's method) + make use of it in client code
9 files modified
627 ■■■■ changed files
opendj-server-legacy/src/main/java/org/opends/server/backends/MonitorBackend.java 19 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/backends/RootDSEBackend.java 15 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/backends/SchemaBackend.java 13 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/protocols/ldap/SearchResultEntryProtocolOp.java 88 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/tools/makeldif/Branch.java 67 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/types/Entry.java 115 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/types/SearchFilter.java 159 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/backends/pluggable/TestDnKeyFormat.java 99 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/types/TestEntry.java 52 ●●●●● patch | view | raw | blame | history
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,11 +151,9 @@
    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 : attrs)
    for (final Attribute a : attributes)
      {
        if (!isMonitorConfigAttribute(a))
        {
@@ -165,7 +161,6 @@
        }
      }
    }
  }
  @Override
  public void configureBackend(final MonitorBackendCfg config, ServerContext serverContext)
@@ -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
opendj-server-legacy/src/main/java/org/opends/server/backends/RootDSEBackend.java
@@ -238,9 +238,7 @@
   */
  private void addAllUserDefinedAttrs(List<Attribute> userDefinedAttrs, Entry configEntry)
  {
    for (List<Attribute> attrs : configEntry.getUserAttributes().values())
    {
      for (Attribute a : attrs)
    for (Attribute a : configEntry.getAllAttributes())
      {
        if (!isDSEConfigAttribute(a))
        {
@@ -248,17 +246,6 @@
        }
      }
    }
    for (List<Attribute> attrs : configEntry.getOperationalAttributes().values())
    {
      for (Attribute a : attrs)
      {
        if (!isDSEConfigAttribute(a))
        {
          userDefinedAttrs.add(a);
        }
      }
    }
  }
  @Override
  public void closeBackend()
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,11 +2868,9 @@
    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 : attrs)
    for (Attribute a : attributes)
      {
        if (!isSchemaConfigAttribute(a))
        {
@@ -2882,7 +2878,6 @@
        }
      }
    }
  }
  /**
   * Indicates whether to treat common schema attributes like user attributes
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,13 +163,32 @@
      {
        if (ldapVersion == 2)
        {
          // Merge attributes having the same type into a single
          // attribute.
          // Merge attributes having the same type into a single attribute.
          merge(tmp, entry.getUserAttributes());
          merge(tmp, entry.getOperationalAttributes());
        }
        else
        {
          // LDAPv3
          for (Attribute a : entry.getAllAttributes())
          {
            tmp.add(new LDAPAttribute(a));
          }
        }
      }
      attributes = tmp;
      // Since the attributes are mutable, null out the entry for consistency.
      entry = null;
    }
    return attributes;
  }
  private void merge(LinkedList<LDAPAttribute> tmp, Map<AttributeType, List<Attribute>> attrs)
  {
          boolean needsMerge;
          Map<AttributeType, List<Attribute>> attrs =
              entry.getUserAttributes();
          for (Map.Entry<AttributeType, List<Attribute>> attrList : attrs
              .entrySet())
    for (Map.Entry<AttributeType, List<Attribute>> attrList : attrs.entrySet())
          {
            needsMerge = true;
@@ -194,61 +213,6 @@
              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()));
            }
          }
        }
        else
        {
          // LDAPv3
          for (List<Attribute> attrList : entry.getUserAttributes().values())
          {
            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));
            }
          }
        }
      }
      attributes = tmp;
      // Since the attributes are mutable, null out the entry for consistency.
      entry = null;
    }
    return attributes;
  }
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();
        }
      }
    }
  }
  /**
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++)
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;
            }
          }
        }
      }
      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;
          }
        }
      }
    }
    // 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
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,45 +235,20 @@
      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;
    // 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));
    if (config.compressAttributeDescriptions())
    {
      for (List<Attribute> attrList : attributes.values())
      {
        for (Attribute a : attrList)
      for (Attribute a : attributes)
        {
          if (a.isVirtual() || a.isEmpty())
          {
@@ -309,13 +261,27 @@
          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,13 +291,15 @@
   *   - 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)
      {
        break;
      }
        buffer.appendBytes(getBytes(a.getAttributeDescription().toString()));
        buffer.appendByte(0x00);
@@ -343,7 +311,6 @@
        }
      }
    }
  }
  /**
   * Test entry.
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();
  }
}