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

Jean-Noel Rouvignac
14.25.2014 1f6f4598cae318e881119af7a206c7c5899aff30
OPENDJ-1368 (CR-3177) Remove AttributeValue


Removing calls to Entry.getAttributeValue() and Entry.getAttributeValues() that indirectly calls AttributeValue.getNormalizedValue().
Replaced them with calls to new method Entry.parseAttribute(), added to match the SDK API.

AttributeParser.java: ADDED
Added for Entry to match the SDK API.

AttributeValueDecoder.java: REMOVED
Superseded by Attributeparser.

*Syntax.java:
Removed all subclasses of AttributeValueDecoder.

SubtreeSpecificationSet.java: REMOVED
Now unused.
2 files deleted
1 files added
19 files modified
1674 ■■■■ changed files
opendj3-server-dev/src/server/org/opends/server/admin/AdministrationDataSync.java 46 ●●●● patch | view | raw | blame | history
opendj3-server-dev/src/server/org/opends/server/admin/server/ServerManagementContext.java 37 ●●●●● patch | view | raw | blame | history
opendj3-server-dev/src/server/org/opends/server/api/AttributeValueDecoder.java 58 ●●●●● patch | view | raw | blame | history
opendj3-server-dev/src/server/org/opends/server/crypto/CryptoManagerImpl.java 149 ●●●●● patch | view | raw | blame | history
opendj3-server-dev/src/server/org/opends/server/schema/BinarySyntax.java 25 ●●●●● patch | view | raw | blame | history
opendj3-server-dev/src/server/org/opends/server/schema/BooleanSyntax.java 60 ●●●●● patch | view | raw | blame | history
opendj3-server-dev/src/server/org/opends/server/schema/DirectoryStringSyntax.java 54 ●●●●● patch | view | raw | blame | history
opendj3-server-dev/src/server/org/opends/server/schema/DistinguishedNameSyntax.java 40 ●●●●● patch | view | raw | blame | history
opendj3-server-dev/src/server/org/opends/server/schema/IntegerSyntax.java 40 ●●●● patch | view | raw | blame | history
opendj3-server-dev/src/server/org/opends/server/schema/SubtreeSpecificationSyntax.java 66 ●●●● patch | view | raw | blame | history
opendj3-server-dev/src/server/org/opends/server/types/AttributeParser.java 494 ●●●●● patch | view | raw | blame | history
opendj3-server-dev/src/server/org/opends/server/types/Entry.java 94 ●●●● patch | view | raw | blame | history
opendj3-server-dev/src/server/org/opends/server/types/SubtreeSpecificationSet.java 167 ●●●●● patch | view | raw | blame | history
opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/crypto/GetSymmetricKeyExtendedOperationTestCase.java 14 ●●●● patch | view | raw | blame | history
opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/EntityTagVirtualAttributeProviderTestCase.java 56 ●●●●● patch | view | raw | blame | history
opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyTestCase.java 11 ●●●●● patch | view | raw | blame | history
opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/replication/InitOnLineTest.java 32 ●●●●● patch | view | raw | blame | history
opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/replication/ReplicationTestCase.java 39 ●●●●● patch | view | raw | blame | history
opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/replication/UpdateOperationTest.java 6 ●●●●● patch | view | raw | blame | history
opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/tasks/TasksTestCase.java 29 ●●●●● patch | view | raw | blame | history
opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/types/TestAttributeValue.java 33 ●●●●● patch | view | raw | blame | history
opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/types/TestEntry.java 124 ●●●●● patch | view | raw | blame | history
opendj3-server-dev/src/server/org/opends/server/admin/AdministrationDataSync.java
@@ -26,33 +26,28 @@
 */
package org.opends.server.admin;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
import org.forgerock.opendj.ldap.ModificationType;
import org.forgerock.opendj.ldap.ResultCode;
import org.forgerock.opendj.ldap.SearchScope;
import org.opends.server.core.DirectoryServer;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.protocols.internal.InternalSearchOperation;
import org.opends.server.protocols.ldap.LDAPFilter;
import org.opends.server.schema.DirectoryStringSyntax;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeType;
import org.opends.server.types.Attributes;
import org.forgerock.opendj.ldap.ByteString;
import org.opends.server.types.DN;
import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.Entry;
import org.opends.server.types.LDAPException;
import org.opends.server.types.Modification;
import org.forgerock.opendj.ldap.ModificationType;
import org.forgerock.opendj.ldap.ResultCode;
import org.opends.server.types.SearchResultEntry;
import org.forgerock.opendj.ldap.SearchScope;
/**
 * Check if information found in "cn=admin data" is coherent with
@@ -197,12 +192,6 @@
    }
    // Look for a local server with the Ldap Port.
    String attrName = "hostname";
    AttributeType hostnameType = DirectoryServer.getAttributeType(attrName);
    if (hostnameType == null)
    {
      hostnameType = DirectoryServer.getDefaultAttributeType(attrName);
    }
    try
    {
      InternalSearchOperation op = internalConnection.processSearch(
@@ -213,8 +202,8 @@
        Entry entry = null;
        for (Entry currentEntry : op.getSearchEntries())
        {
          String currentHostname = currentEntry.getAttributeValue(hostnameType,
              DirectoryStringSyntax.DECODER);
          String currentHostname =
              currentEntry.parseAttribute("hostname").asString();
          try
          {
            String currentIPAddress = java.net.InetAddress.getByName(
@@ -222,15 +211,8 @@
            if (currentIPAddress.equals(hostName))
            {
              // Check if one of the port match
              attrName = "ldapport";
              AttributeType portType = DirectoryServer
                  .getAttributeType(attrName);
              if (portType == null)
              {
                portType = DirectoryServer.getDefaultAttributeType(attrName);
              }
              String currentport = currentEntry.getAttributeValue(portType,
                  DirectoryStringSyntax.DECODER);
              String currentport =
                  currentEntry.parseAttribute("ldapport").asString();
              if (currentport.equals(ldapPort))
              {
                entry = currentEntry;
@@ -238,14 +220,8 @@
              }
              if (ldapsPortEnable)
              {
                attrName = "ldapsport";
                portType = DirectoryServer.getAttributeType(attrName);
                if (portType == null)
                {
                  portType = DirectoryServer.getDefaultAttributeType(attrName);
                }
                currentport = currentEntry.getAttributeValue(portType,
                    DirectoryStringSyntax.DECODER);
                currentport =
                    currentEntry.parseAttribute("ldapsport").asString();
                if (currentport.equals(ldapsPort))
                {
                  entry = currentEntry;
opendj3-server-dev/src/server/org/opends/server/admin/server/ServerManagementContext.java
@@ -45,6 +45,8 @@
import java.util.TreeSet;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.opendj.config.server.ConfigException;
import org.opends.server.admin.AbsoluteInheritedDefaultBehaviorProvider;
import org.opends.server.admin.AbstractManagedObjectDefinition;
import org.opends.server.admin.AggregationPropertyDefinition;
@@ -72,17 +74,13 @@
import org.opends.server.admin.DefinitionDecodingException.Reason;
import org.opends.server.admin.std.meta.RootCfgDefn;
import org.opends.server.admin.std.server.RootCfg;
import org.opends.server.api.AttributeValueDecoder;
import org.opends.server.config.ConfigEntry;
import org.forgerock.opendj.config.server.ConfigException;
import org.opends.server.core.DirectoryServer;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeValueIterable;
import org.opends.server.types.AttributeType;
import org.opends.server.types.AttributeValue;
import org.opends.server.types.DN;
import org.opends.server.types.DirectoryException;
/**
 * Server management connection context.
@@ -125,6 +123,7 @@
    /**
     * {@inheritDoc}
     */
    @Override
    public Collection<T> visitAbsoluteInherited(
        AbsoluteInheritedDefaultBehaviorProvider<T> d, Void p) {
      try {
@@ -141,6 +140,7 @@
    /**
     * {@inheritDoc}
     */
    @Override
    public Collection<T> visitAlias(AliasDefaultBehaviorProvider<T> d, Void p) {
      return Collections.emptySet();
    }
@@ -150,6 +150,7 @@
    /**
     * {@inheritDoc}
     */
    @Override
    public Collection<T> visitDefined(DefinedDefaultBehaviorProvider<T> d,
        Void p) {
      Collection<String> stringValues = d.getDefaultValues();
@@ -172,6 +173,7 @@
    /**
     * {@inheritDoc}
     */
    @Override
    public Collection<T> visitRelativeInherited(
        RelativeInheritedDefaultBehaviorProvider<T> d, Void p) {
      try {
@@ -188,6 +190,7 @@
    /**
     * {@inheritDoc}
     */
    @Override
    public Collection<T> visitUndefined(UndefinedDefaultBehaviorProvider<T> d,
        Void p) {
      return Collections.emptySet();
@@ -313,6 +316,7 @@
    /**
     * {@inheritDoc}
     */
    @Override
    public boolean matches(AbstractManagedObjectDefinition<?, ?> d) {
      String oc = LDAPProfile.getInstance().getObjectClass(d);
      return entry.hasObjectClass(oc);
@@ -899,23 +903,14 @@
    // since the attribute should have been defined.
    String attrID = LDAPProfile.getInstance().getAttributeName(d, pd);
    AttributeType type = DirectoryServer.getAttributeType(attrID, true);
    AttributeValueDecoder<AttributeValue> decoder =
      new AttributeValueDecoder<AttributeValue>() {
    List<Attribute> attributes = configEntry.getEntry().getAttribute(type, true);
      public AttributeValue decode(AttributeValue value)
          throws DirectoryException {
        return value;
    List<AttributeValue> results = new LinkedList<AttributeValue>();
    for (AttributeValue v : new AttributeValueIterable(attributes))
    {
      results.add(v);
      }
    };
    List<AttributeValue> values = new LinkedList<AttributeValue>();
    try {
      configEntry.getEntry().getAttributeValues(type, decoder, values);
    } catch (DirectoryException e) {
      // Should not happen.
      throw new RuntimeException(e);
    }
    return values;
    return results;
  }
opendj3-server-dev/src/server/org/opends/server/api/AttributeValueDecoder.java
File was deleted
opendj3-server-dev/src/server/org/opends/server/crypto/CryptoManagerImpl.java
@@ -49,6 +49,7 @@
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.opendj.config.server.ConfigException;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
import org.forgerock.opendj.ldap.ModificationType;
@@ -61,7 +62,6 @@
import org.opends.server.api.Backend;
import org.opends.server.backends.TrustStoreBackend;
import org.opends.server.config.ConfigConstants;
import org.forgerock.opendj.config.server.ConfigException;
import org.opends.server.core.AddOperation;
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.ModifyOperation;
@@ -72,20 +72,24 @@
import org.opends.server.protocols.ldap.ExtendedResponseProtocolOp;
import org.opends.server.protocols.ldap.LDAPMessage;
import org.opends.server.protocols.ldap.LDAPResultCode;
import org.opends.server.schema.BinarySyntax;
import org.opends.server.schema.DirectoryStringSyntax;
import org.opends.server.schema.IntegerSyntax;
import org.opends.server.tools.LDAPConnection;
import org.opends.server.tools.LDAPConnectionOptions;
import org.opends.server.tools.LDAPReader;
import org.opends.server.tools.LDAPWriter;
import org.opends.server.types.*;
import org.opends.server.types.Attribute;
import org.opends.server.types.Attributes;
import org.opends.server.types.DN;
import org.opends.server.types.Entry;
import org.opends.server.types.Modification;
import org.opends.server.types.RDN;
import org.opends.server.util.Base64;
import org.opends.server.util.SelectableCertificateKeyManager;
import org.opends.server.util.ServerConstants;
import org.opends.server.util.StaticUtils;
import static org.opends.messages.CoreMessages.*;
import static org.opends.server.config.ConfigConstants.*;
import static org.opends.server.util.ServerConstants.*;
import static org.opends.server.util.StaticUtils.*;
@@ -534,8 +538,8 @@
          for (Entry e : searchOp.getSearchEntries()) {
            /* attribute ds-cfg-public-key-certificate is a MUST in
               the schema */
            certificate = e.getAttributeValue(
                  attrPublicKeyCertificate, BinarySyntax.DECODER).toByteArray();
            certificate = e.parseAttribute(
                ATTR_CRYPTO_PUBLIC_KEY_CERTIFICATE).asByteString().toByteArray();
          }
          break;
        }
@@ -744,10 +748,9 @@
      for (Entry e : searchOp.getSearchEntries()) {
        /* attribute ds-cfg-key-id is the RDN and attribute
           ds-cfg-public-key-certificate is a MUST in the schema */
        final String keyID = e.getAttributeValue(
                attrKeyID, DirectoryStringSyntax.DECODER);
        final byte[] certificate = e.getAttributeValue(
                attrPublicKeyCertificate, BinarySyntax.DECODER).toByteArray();
        final String keyID = e.parseAttribute(ATTR_CRYPTO_KEY_ID).asString();
        final byte[] certificate = e.parseAttribute(
            ATTR_CRYPTO_PUBLIC_KEY_CERTIFICATE).asByteString().toByteArray();
        certificateMap.put(keyID, certificate);
      }
    }
@@ -1001,7 +1004,7 @@
   * @return The symmetric key value for this server, or null if
   *         none could be obtained.
   */
  private String getSymmetricKey(List<String> symmetricKeys)
  private String getSymmetricKey(Set<String> symmetricKeys)
  {
    InternalClientConnection internalConnection =
         InternalClientConnection.getRootConnection();
@@ -1028,14 +1031,8 @@
             internalSearch.getSearchEntries();
        for (SearchResultEntry resultEntry : resultEntries)
        {
          AttributeType hostnameAttr =
               DirectoryServer.getAttributeType("hostname", true);
          String hostname = resultEntry.getAttributeValue(
               hostnameAttr, DirectoryStringSyntax.DECODER);
          AttributeType ldapPortAttr =
               DirectoryServer.getAttributeType("ldapport", true);
          Integer ldapPort = resultEntry.getAttributeValue(
               ldapPortAttr, IntegerSyntax.DECODER);
          String hostname = resultEntry.parseAttribute("hostname").asString();
          Integer ldapPort = resultEntry.parseAttribute("ldapport").asInteger();
          // Connect to the server.
          AtomicInteger nextMessageID = new AtomicInteger(1);
@@ -1127,28 +1124,20 @@
    try
    {
      String keyID =
           entry.getAttributeValue(attrKeyID,
                                   DirectoryStringSyntax.DECODER);
      int ivLengthBits =
           entry.getAttributeValue(attrInitVectorLength,
                                   IntegerSyntax.DECODER);
      int keyLengthBits =
           entry.getAttributeValue(attrKeyLength,
                                   IntegerSyntax.DECODER);
      String transformation =
           entry.getAttributeValue(attrTransformation,
                                   DirectoryStringSyntax.DECODER);
      String compromisedTime =
           entry.getAttributeValue(attrCompromisedTime,
                                   DirectoryStringSyntax.DECODER);
      String keyID = entry.parseAttribute(ATTR_CRYPTO_KEY_ID).asString();
      int ivLengthBits = entry.parseAttribute(
          ATTR_CRYPTO_INIT_VECTOR_LENGTH_BITS).asInteger();
      int keyLengthBits = entry.parseAttribute(
          ATTR_CRYPTO_KEY_LENGTH_BITS).asInteger();
      String transformation = entry.parseAttribute(
          ATTR_CRYPTO_CIPHER_TRANSFORMATION_NAME).asString();
      String compromisedTime = entry.parseAttribute(
          ATTR_CRYPTO_KEY_COMPROMISED_TIME).asString();
      boolean isCompromised = compromisedTime != null;
      ArrayList<String> symmetricKeys = new ArrayList<String>();
      entry.getAttributeValues(attrSymmetricKey,
                             DirectoryStringSyntax.DECODER,
                             symmetricKeys);
      Set<String> symmetricKeys =
          entry.parseAttribute(ATTR_CRYPTO_SYMMETRIC_KEY).asSetOfString();
      // Find the symmetric key value that was wrapped using
      // our instance key.
@@ -1194,7 +1183,11 @@
                ERR_CRYPTOMGR_IMPORT_KEY_ENTRY_FAILED_TO_ADD_KEY.get(entry.getName()));
      }
    }
    catch (DirectoryException ex)
    catch (CryptoManagerException e)
    {
      throw e;
    }
    catch (Exception ex)
    {
      logger.traceException(ex);
      throw new CryptoManagerException(
@@ -1226,25 +1219,18 @@
    try
    {
      String keyID =
           entry.getAttributeValue(attrKeyID,
                                   DirectoryStringSyntax.DECODER);
      int keyLengthBits =
           entry.getAttributeValue(attrKeyLength,
                                   IntegerSyntax.DECODER);
      String algorithm =
           entry.getAttributeValue(attrMacAlgorithm,
                                   DirectoryStringSyntax.DECODER);
      String compromisedTime =
           entry.getAttributeValue(attrCompromisedTime,
                                   DirectoryStringSyntax.DECODER);
      String keyID = entry.parseAttribute(ATTR_CRYPTO_KEY_ID).asString();
      int keyLengthBits = entry.parseAttribute(
          ATTR_CRYPTO_KEY_LENGTH_BITS).asInteger();
      String algorithm = entry.parseAttribute(
          ATTR_CRYPTO_MAC_ALGORITHM_NAME).asString();
      String compromisedTime = entry.parseAttribute(
          ATTR_CRYPTO_KEY_COMPROMISED_TIME).asString();
      boolean isCompromised = compromisedTime != null;
      ArrayList<String> symmetricKeys = new ArrayList<String>();
      entry.getAttributeValues(attrSymmetricKey,
                             DirectoryStringSyntax.DECODER,
                             symmetricKeys);
      Set<String> symmetricKeys =
          entry.parseAttribute(ATTR_CRYPTO_SYMMETRIC_KEY).asSetOfString();
      // Find the symmetric key value that was wrapped using our
      // instance key.
@@ -1294,9 +1280,12 @@
                                      secretKey, keyLengthBits,
                                      isCompromised);
      }
    }
    catch (DirectoryException ex)
    catch (CryptoManagerException e)
    {
      throw e;
    }
    catch (Exception ex)
    {
      logger.traceException(ex);
      throw new CryptoManagerException(
@@ -1602,6 +1591,15 @@
    private boolean fIsCompromised = false;
  }
  private static void putSingleValueAttribute(
      Map<AttributeType, List<Attribute>> attrs, AttributeType type,
      String value)
  {
    ArrayList<Attribute> attrList = new ArrayList<Attribute>(1);
    attrList.add(Attributes.create(type, AttributeValues.create(type, value)));
    attrs.put(type, attrList);
  }
  /**
   * This class corresponds to the cipher key entry in ADS. It is
   * used in the local cache of key entries that have been requested
@@ -1704,27 +1702,15 @@
      userAttrs.put(attrKeyID, attrList);
      // Add the transformation name attribute.
      attrList = new ArrayList<Attribute>(1);
      attrList.add(Attributes.create(attrTransformation,
          AttributeValues.create(attrTransformation,
              keyEntry.getType())));
      userAttrs.put(attrTransformation, attrList);
      putSingleValueAttribute(userAttrs, attrTransformation, keyEntry.getType());
      // Add the init vector length attribute.
      attrList = new ArrayList<Attribute>(1);
      attrList.add(Attributes.create(attrInitVectorLength,
          AttributeValues.create(attrInitVectorLength,
              String.valueOf(keyEntry
              .getIVLengthBits()))));
      userAttrs.put(attrInitVectorLength, attrList);
      putSingleValueAttribute(userAttrs, attrInitVectorLength,
          String.valueOf(keyEntry.getIVLengthBits()));
      // Add the key length attribute.
      attrList = new ArrayList<Attribute>(1);
      attrList.add(Attributes.create(attrKeyLength,
          AttributeValues.create(attrKeyLength,
              String.valueOf(keyEntry.getKeyLengthBits()))));
      userAttrs.put(attrKeyLength, attrList);
      putSingleValueAttribute(userAttrs, attrKeyLength,
          String.valueOf(keyEntry.getKeyLengthBits()));
      // Get the trusted certificates.
@@ -2243,23 +2229,14 @@
      // Add the key ID attribute.
      ArrayList<Attribute> attrList = new ArrayList<Attribute>(1);
      attrList.add(Attributes.create(attrKeyID,
                                 distinguishedValue));
      attrList.add(Attributes.create(attrKeyID, distinguishedValue));
      userAttrs.put(attrKeyID, attrList);
      // Add the mac algorithm name attribute.
      attrList = new ArrayList<Attribute>(1);
      attrList.add(Attributes.create(attrMacAlgorithm,
          AttributeValues.create(attrMacAlgorithm, keyEntry.getType())));
      userAttrs.put(attrMacAlgorithm, attrList);
      putSingleValueAttribute(userAttrs, attrMacAlgorithm, keyEntry.getType());
      // Add the key length attribute.
      attrList = new ArrayList<Attribute>(1);
      attrList.add(Attributes.create(attrKeyLength, AttributeValues.create(
          attrKeyLength, String.valueOf(keyEntry.getKeyLengthBits()))));
      userAttrs.put(attrKeyLength, attrList);
      putSingleValueAttribute(userAttrs, attrKeyLength, String.valueOf(keyEntry.getKeyLengthBits()));
      // Get the trusted certificates.
      Map<String, byte[]> trustedCerts =
opendj3-server-dev/src/server/org/opends/server/schema/BinarySyntax.java
@@ -28,14 +28,11 @@
import org.forgerock.i18n.LocalizableMessageBuilder;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.opendj.config.server.ConfigException;
import org.forgerock.opendj.ldap.ByteSequence;
import org.forgerock.opendj.ldap.ByteString;
import org.opends.server.admin.std.server.AttributeSyntaxCfg;
import org.opends.server.api.*;
import org.forgerock.opendj.config.server.ConfigException;
import org.opends.server.core.DirectoryServer;
import org.opends.server.types.AttributeValue;
import org.opends.server.types.DirectoryException;
import static org.opends.messages.SchemaMessages.*;
import static org.opends.server.schema.SchemaConstants.*;
@@ -61,26 +58,6 @@
  private SubstringMatchingRule defaultSubstringMatchingRule;
  /**
   * A {@code byte[]} attribute value decoder for this syntax.
   */
  public static final AttributeValueDecoder<ByteString> DECODER =
    new AttributeValueDecoder<ByteString>()
  {
    /**
     * {@inheritDoc}
     */
    @Override
    public ByteString decode(AttributeValue value) throws DirectoryException {
      // Make sure that the value is valid.
      value.getNormalizedValue();
      return value.getValue();
    }
  };
  /**
   * Creates a new instance of this syntax.  Note that the only thing that
   * should be done here is to invoke the default constructor for the
opendj3-server-dev/src/server/org/opends/server/schema/BooleanSyntax.java
@@ -26,27 +26,24 @@
 */
package org.opends.server.schema;
import org.forgerock.i18n.LocalizableMessageBuilder;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.opendj.config.server.ConfigException;
import org.forgerock.opendj.ldap.ByteSequence;
import org.forgerock.opendj.ldap.ByteString;
import org.opends.server.admin.std.server.AttributeSyntaxCfg;
import org.opends.server.api.ApproximateMatchingRule;
import org.opends.server.api.AttributeSyntax;
import org.opends.server.api.AttributeValueDecoder;
import org.opends.server.api.EqualityMatchingRule;
import org.opends.server.api.OrderingMatchingRule;
import org.opends.server.api.SubstringMatchingRule;
import org.forgerock.opendj.config.server.ConfigException;
import org.opends.server.core.DirectoryServer;
import org.opends.server.types.*;
import org.forgerock.opendj.ldap.ResultCode;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.ByteSequence;
import static org.opends.messages.SchemaMessages.*;
import org.forgerock.i18n.LocalizableMessageBuilder;
import static org.opends.server.schema.SchemaConstants.*;
import org.opends.server.types.AttributeValue;
import org.opends.server.types.AttributeValues;
import org.opends.server.util.ServerConstants;
import static org.opends.messages.SchemaMessages.*;
import static org.opends.server.schema.SchemaConstants.*;
/**
 * This class defines the Boolean attribute syntax, which only allows values of
@@ -67,36 +64,6 @@
  /**
   * A {@link Boolean} attribute value decoder for this syntax.
   */
  public static final AttributeValueDecoder<Boolean> DECODER =
    new AttributeValueDecoder<Boolean>()
  {
    /**
     * {@inheritDoc}
     */
    public Boolean decode(AttributeValue value) throws DirectoryException
    {
      ByteString normalizedValue = value.getNormalizedValue();
      if (normalizedValue.equals(ServerConstants.TRUE_VALUE))
      {
        return true;
      }
      else if (normalizedValue.equals(ServerConstants.FALSE_VALUE))
      {
        return false;
      }
      else
      {
        throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
            WARN_ATTR_SYNTAX_ILLEGAL_BOOLEAN.get(normalizedValue));
      }
    }
  };
  /**
   * Creates a new instance of this syntax.  Note that the only thing that
   * should be done here is to invoke the default constructor for the
   * superclass.  All initialization should be performed in the
@@ -112,6 +79,7 @@
  /**
   * {@inheritDoc}
   */
  @Override
  public void initializeSyntax(AttributeSyntaxCfg configuration)
         throws ConfigException
  {
@@ -130,6 +98,7 @@
   *
   * @return  The common name for this attribute syntax.
   */
  @Override
  public String getName()
  {
    return SYNTAX_BOOLEAN_NAME;
@@ -142,6 +111,7 @@
   *
   * @return  The OID for this attribute syntax.
   */
  @Override
  public String getOID()
  {
    return SYNTAX_BOOLEAN_OID;
@@ -154,6 +124,7 @@
   *
   * @return  A description for this attribute syntax.
   */
  @Override
  public String getDescription()
  {
    return SYNTAX_BOOLEAN_DESCRIPTION;
@@ -169,6 +140,7 @@
   *          attributes with this syntax, or <CODE>null</CODE> if equality
   *          matches will not be allowed for this type by default.
   */
  @Override
  public EqualityMatchingRule getEqualityMatchingRule()
  {
    return defaultEqualityMatchingRule;
@@ -184,6 +156,7 @@
   *          attributes with this syntax, or <CODE>null</CODE> if ordering
   *          matches will not be allowed for this type by default.
   */
  @Override
  public OrderingMatchingRule getOrderingMatchingRule()
  {
    // Ordering matches are not allowed by default.
@@ -200,6 +173,7 @@
   *          attributes with this syntax, or <CODE>null</CODE> if substring
   *          matches will not be allowed for this type by default.
   */
  @Override
  public SubstringMatchingRule getSubstringMatchingRule()
  {
    // Substring matches are not allowed by default.
@@ -216,6 +190,7 @@
   *          attributes with this syntax, or <CODE>null</CODE> if approximate
   *          matches will not be allowed for this type by default.
   */
  @Override
  public ApproximateMatchingRule getApproximateMatchingRule()
  {
    // Approximate matches are not allowed by default.
@@ -236,6 +211,7 @@
   * @return  <CODE>true</CODE> if the provided value is acceptable for use with
   *          this syntax, or <CODE>false</CODE> if not.
   */
  @Override
  public boolean valueIsAcceptable(ByteSequence value,
                                   LocalizableMessageBuilder invalidReason)
  {
@@ -281,6 +257,7 @@
  /**
   * {@inheritDoc}
   */
  @Override
  public boolean isBEREncodingRequired()
  {
    return false;
@@ -291,6 +268,7 @@
  /**
   * {@inheritDoc}
   */
  @Override
  public boolean isHumanReadable()
  {
    return true;
opendj3-server-dev/src/server/org/opends/server/schema/DirectoryStringSyntax.java
@@ -25,31 +25,25 @@
 *      Portions Copyright 2012-2014 ForgeRock AS
 */
package org.opends.server.schema;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import java.util.List;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.LocalizableMessageBuilder;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.opendj.config.server.ConfigException;
import org.forgerock.opendj.ldap.ByteSequence;
import org.forgerock.opendj.ldap.ResultCode;
import org.opends.server.admin.server.ConfigurationChangeListener;
import org.opends.server.admin.std.server.DirectoryStringAttributeSyntaxCfg;
import org.opends.server.api.ApproximateMatchingRule;
import org.opends.server.api.AttributeSyntax;
import org.opends.server.api.AttributeValueDecoder;
import org.opends.server.api.EqualityMatchingRule;
import org.opends.server.api.OrderingMatchingRule;
import org.opends.server.api.SubstringMatchingRule;
import org.forgerock.opendj.config.server.ConfigException;
import org.opends.server.core.DirectoryServer;
import org.opends.server.types.ConfigChangeResult;
import org.opends.server.types.*;
import org.forgerock.opendj.ldap.ResultCode;
import org.forgerock.opendj.ldap.ByteSequence;
import static org.opends.messages.SchemaMessages.*;
import org.forgerock.i18n.LocalizableMessageBuilder;
import static org.opends.server.schema.SchemaConstants.*;
@@ -85,26 +79,6 @@
  private SubstringMatchingRule defaultSubstringMatchingRule;
  /**
   * A {@link String} attribute value decoder for this syntax.
   */
  public static final AttributeValueDecoder<String> DECODER =
    new AttributeValueDecoder<String>()
  {
    /**
     * {@inheritDoc}
     */
    public String decode(AttributeValue value) throws DirectoryException
    {
      // Make sure that the value is valid.
      value.getNormalizedValue();
      return value.getValue().toString();
    }
  };
  /**
   * Creates a new instance of this syntax.  Note that the only thing that
   * should be done here is to invoke the default constructor for the
@@ -121,6 +95,7 @@
  /**
   * {@inheritDoc}
   */
  @Override
  public void initializeSyntax(DirectoryStringAttributeSyntaxCfg configuration)
         throws ConfigException
  {
@@ -176,6 +151,7 @@
  /**
   * Performs any finalization that may be necessary for this attribute syntax.
   */
  @Override
  public void finalizeSyntax()
  {
    currentConfig.removeDirectoryStringChangeListener(this);
@@ -188,6 +164,7 @@
   *
   * @return  The common name for this attribute syntax.
   */
  @Override
  public String getName()
  {
    return SYNTAX_DIRECTORY_STRING_NAME;
@@ -200,6 +177,7 @@
   *
   * @return  The OID for this attribute syntax.
   */
  @Override
  public String getOID()
  {
    return SYNTAX_DIRECTORY_STRING_OID;
@@ -212,6 +190,7 @@
   *
   * @return  A description for this attribute syntax.
   */
  @Override
  public String getDescription()
  {
    return SYNTAX_DIRECTORY_STRING_DESCRIPTION;
@@ -227,6 +206,7 @@
   *          attributes with this syntax, or <CODE>null</CODE> if equality
   *          matches will not be allowed for this type by default.
   */
  @Override
  public EqualityMatchingRule getEqualityMatchingRule()
  {
    return defaultEqualityMatchingRule;
@@ -242,6 +222,7 @@
   *          attributes with this syntax, or <CODE>null</CODE> if ordering
   *          matches will not be allowed for this type by default.
   */
  @Override
  public OrderingMatchingRule getOrderingMatchingRule()
  {
    return defaultOrderingMatchingRule;
@@ -257,6 +238,7 @@
   *          attributes with this syntax, or <CODE>null</CODE> if substring
   *          matches will not be allowed for this type by default.
   */
  @Override
  public SubstringMatchingRule getSubstringMatchingRule()
  {
    return defaultSubstringMatchingRule;
@@ -272,6 +254,7 @@
   *          attributes with this syntax, or <CODE>null</CODE> if approximate
   *          matches will not be allowed for this type by default.
   */
  @Override
  public ApproximateMatchingRule getApproximateMatchingRule()
  {
    return defaultApproximateMatchingRule;
@@ -291,6 +274,7 @@
   * @return  <CODE>true</CODE> if the provided value is acceptable for use with
   *          this syntax, or <CODE>false</CODE> if not.
   */
  @Override
  public boolean valueIsAcceptable(ByteSequence value,
                                   LocalizableMessageBuilder invalidReason)
  {
@@ -328,6 +312,7 @@
  /**
   * {@inheritDoc}
   */
  @Override
  public boolean isConfigurationChangeAcceptable(
                      DirectoryStringAttributeSyntaxCfg configuration,
                      List<LocalizableMessage> unacceptableReasons)
@@ -341,6 +326,7 @@
  /**
   * {@inheritDoc}
   */
  @Override
  public ConfigChangeResult applyConfigurationChange(
              DirectoryStringAttributeSyntaxCfg configuration)
  {
@@ -355,6 +341,7 @@
  /**
   * {@inheritDoc}
   */
  @Override
  public boolean isBEREncodingRequired()
  {
    return false;
@@ -365,6 +352,7 @@
  /**
   * {@inheritDoc}
   */
  @Override
  public boolean isHumanReadable()
  {
    return true;
opendj3-server-dev/src/server/org/opends/server/schema/DistinguishedNameSyntax.java
@@ -28,21 +28,21 @@
import org.forgerock.i18n.LocalizableMessageBuilder;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.opendj.config.server.ConfigException;
import org.forgerock.opendj.ldap.ByteSequence;
import org.opends.server.admin.std.server.AttributeSyntaxCfg;
import org.opends.server.api.ApproximateMatchingRule;
import org.opends.server.api.AttributeSyntax;
import org.opends.server.api.AttributeValueDecoder;
import org.opends.server.api.EqualityMatchingRule;
import org.opends.server.api.OrderingMatchingRule;
import org.opends.server.api.SubstringMatchingRule;
import org.forgerock.opendj.config.server.ConfigException;
import org.opends.server.core.DirectoryServer;
import org.opends.server.types.DN;
import org.opends.server.types.DirectoryException;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.opends.server.types.*;
import org.forgerock.opendj.ldap.ByteSequence;
import static org.opends.messages.SchemaMessages.*;
import org.forgerock.i18n.LocalizableMessageBuilder;
import static org.opends.server.schema.SchemaConstants.*;
@@ -67,23 +67,6 @@
  /**
   * A {@link DN} attribute value decoder for this syntax.
   */
  public static final AttributeValueDecoder<DN> DECODER =
    new AttributeValueDecoder<DN>()
  {
    /**
     * {@inheritDoc}
     */
    public DN decode(AttributeValue value) throws DirectoryException
    {
      return DN.valueOf(value.getValue().toString());
    }
  };
  /**
   * Creates a new instance of this syntax.  Note that the only thing that
   * should be done here is to invoke the default constructor for the
   * superclass.  All initialization should be performed in the
@@ -99,6 +82,7 @@
  /**
   * {@inheritDoc}
   */
  @Override
  public void initializeSyntax(AttributeSyntaxCfg configuration)
         throws ConfigException
  {
@@ -124,6 +108,7 @@
   *
   * @return  The common name for this attribute syntax.
   */
  @Override
  public String getName()
  {
    return SYNTAX_DN_NAME;
@@ -136,6 +121,7 @@
   *
   * @return  The OID for this attribute syntax.
   */
  @Override
  public String getOID()
  {
    return SYNTAX_DN_OID;
@@ -148,6 +134,7 @@
   *
   * @return  A description for this attribute syntax.
   */
  @Override
  public String getDescription()
  {
    return SYNTAX_DN_DESCRIPTION;
@@ -163,6 +150,7 @@
   *          attributes with this syntax, or <CODE>null</CODE> if equality
   *          matches will not be allowed for this type by default.
   */
  @Override
  public EqualityMatchingRule getEqualityMatchingRule()
  {
    return defaultEqualityMatchingRule;
@@ -178,6 +166,7 @@
   *          attributes with this syntax, or <CODE>null</CODE> if ordering
   *          matches will not be allowed for this type by default.
   */
  @Override
  public OrderingMatchingRule getOrderingMatchingRule()
  {
    // There is no ordering matching rule by default.
@@ -194,6 +183,7 @@
   *          attributes with this syntax, or <CODE>null</CODE> if substring
   *          matches will not be allowed for this type by default.
   */
  @Override
  public SubstringMatchingRule getSubstringMatchingRule()
  {
    return defaultSubstringMatchingRule;
@@ -209,6 +199,7 @@
   *          attributes with this syntax, or <CODE>null</CODE> if approximate
   *          matches will not be allowed for this type by default.
   */
  @Override
  public ApproximateMatchingRule getApproximateMatchingRule()
  {
    // There is no approximate matching rule by default.
@@ -229,6 +220,7 @@
   * @return  <CODE>true</CODE> if the provided value is acceptable for use with
   *          this syntax, or <CODE>false</CODE> if not.
   */
  @Override
  public boolean valueIsAcceptable(ByteSequence value,
                                   LocalizableMessageBuilder invalidReason)
  {
@@ -259,6 +251,7 @@
  /**
   * {@inheritDoc}
   */
  @Override
  public boolean isBEREncodingRequired()
  {
    return false;
@@ -269,6 +262,7 @@
  /**
   * {@inheritDoc}
   */
  @Override
  public boolean isHumanReadable()
  {
    return true;
opendj3-server-dev/src/server/org/opends/server/schema/IntegerSyntax.java
@@ -26,24 +26,19 @@
 */
package org.opends.server.schema;
import org.forgerock.i18n.LocalizableMessageBuilder;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.opendj.config.server.ConfigException;
import org.forgerock.opendj.ldap.ByteSequence;
import org.opends.server.admin.std.server.AttributeSyntaxCfg;
import org.opends.server.api.ApproximateMatchingRule;
import org.opends.server.api.AttributeSyntax;
import org.opends.server.api.AttributeValueDecoder;
import org.opends.server.api.EqualityMatchingRule;
import org.opends.server.api.OrderingMatchingRule;
import org.opends.server.api.SubstringMatchingRule;
import org.forgerock.opendj.config.server.ConfigException;
import org.opends.server.core.DirectoryServer;
import org.opends.server.types.*;
import org.forgerock.opendj.ldap.ResultCode;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.ByteSequence;
import static org.opends.messages.SchemaMessages.*;
import org.forgerock.i18n.LocalizableMessageBuilder;
import static org.opends.server.schema.SchemaConstants.*;
@@ -68,34 +63,6 @@
  private SubstringMatchingRule defaultSubstringMatchingRule;
  /**
   * An {@link Integer} attribute value decoder for this syntax.
   */
  public static final AttributeValueDecoder<Integer> DECODER =
    new AttributeValueDecoder<Integer>()
  {
    /**
     * {@inheritDoc}
     */
    @Override
    public Integer decode(AttributeValue value) throws DirectoryException
    {
      ByteString nvalue = value.getNormalizedValue();
      try
      {
        return Integer.valueOf(nvalue.toString());
      }
      catch (NumberFormatException e)
      {
        throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX,
            WARN_ATTR_SYNTAX_ILLEGAL_INTEGER.get(nvalue));
      }
    }
  };
  /**
   * Creates a new instance of this syntax. Note that the only thing
   * that should be done here is to invoke the default constructor for
@@ -396,6 +363,7 @@
  /**
   * {@inheritDoc}
   */
  @Override
  public boolean isHumanReadable()
  {
    return true;
opendj3-server-dev/src/server/org/opends/server/schema/SubtreeSpecificationSyntax.java
@@ -26,22 +26,23 @@
 */
package org.opends.server.schema;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import static org.opends.messages.SchemaMessages.*;
import org.forgerock.i18n.LocalizableMessageBuilder;
import static org.opends.server.schema.SchemaConstants.*;
import org.forgerock.i18n.LocalizableMessageBuilder;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.opendj.config.server.ConfigException;
import org.forgerock.opendj.ldap.ByteSequence;
import org.opends.server.admin.std.server.AttributeSyntaxCfg;
import org.opends.server.api.ApproximateMatchingRule;
import org.opends.server.api.AttributeSyntax;
import org.opends.server.api.AttributeValueDecoder;
import org.opends.server.api.EqualityMatchingRule;
import org.opends.server.api.OrderingMatchingRule;
import org.opends.server.api.SubstringMatchingRule;
import org.forgerock.opendj.config.server.ConfigException;
import org.opends.server.core.DirectoryServer;
import org.opends.server.types.*;
import org.forgerock.opendj.ldap.ByteSequence;
import org.opends.server.types.DN;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.SubtreeSpecification;
/**
@@ -63,48 +64,6 @@
  private SubstringMatchingRule defaultSubstringMatchingRule;
  /**
   * Create a new attribute value decoder with the specified root DN.
   *
   * @param rootDN
   *          The root DN for all decoded subtree specifications.
   * @return The attribute value decoder.
   */
  public static AttributeValueDecoder<SubtreeSpecification>
      createAttributeValueDecoder(DN rootDN) {
    return new Decoder(rootDN);
  }
  /**
   * Internal class implementing an attribute value decoder.
   */
  private static class Decoder implements
      AttributeValueDecoder<SubtreeSpecification> {
    // The root DN for all decoded relative subtree specifications.
    private DN rootDN;
    /**
     * Create a new decoder with the specified root DN.
     *
     * @param rootDN
     *          The root DN for all decoded relative subtree
     *          specifications.
     */
    public Decoder(DN rootDN) {
      this.rootDN = rootDN;
    }
    /**
     * {@inheritDoc}
     */
    public SubtreeSpecification decode(AttributeValue value)
        throws DirectoryException {
      return SubtreeSpecification.valueOf(rootDN, value
          .getValue().toString());
    }
  }
  /**
   * Creates a new instance of this syntax. Note that the only thing
   * that should be done here is to invoke the default constructor for
   * the superclass. All initialization should be performed in the
@@ -117,6 +76,7 @@
  /**
   * {@inheritDoc}
   */
  @Override
  public void initializeSyntax(AttributeSyntaxCfg configuration)
      throws ConfigException {
@@ -147,6 +107,7 @@
   *
   * @return The common name for this attribute syntax.
   */
  @Override
  public String getName() {
    return SYNTAX_SUBTREE_SPECIFICATION_NAME;
@@ -157,6 +118,7 @@
   *
   * @return The OID for this attribute syntax.
   */
  @Override
  public String getOID() {
    return SYNTAX_SUBTREE_SPECIFICATION_OID;
@@ -167,6 +129,7 @@
   *
   * @return A description for this attribute syntax.
   */
  @Override
  public String getDescription() {
    return SYNTAX_SUBTREE_SPECIFICATION_DESCRIPTION;
@@ -181,6 +144,7 @@
   *         equality matches will not be allowed for this type by
   *         default.
   */
  @Override
  public EqualityMatchingRule getEqualityMatchingRule() {
    return defaultEqualityMatchingRule;
@@ -195,6 +159,7 @@
   *         ordering matches will not be allowed for this type by
   *         default.
   */
  @Override
  public OrderingMatchingRule getOrderingMatchingRule() {
    return defaultOrderingMatchingRule;
@@ -209,6 +174,7 @@
   *         substring matches will not be allowed for this type by
   *         default.
   */
  @Override
  public SubstringMatchingRule getSubstringMatchingRule() {
    return defaultSubstringMatchingRule;
@@ -223,6 +189,7 @@
   *         approximate matches will not be allowed for this type by
   *         default.
   */
  @Override
  public ApproximateMatchingRule getApproximateMatchingRule() {
    // There is no approximate matching rule by default.
@@ -241,6 +208,7 @@
   * @return <CODE>true</CODE> if the provided value is acceptable for
   *         use with this syntax, or <CODE>false</CODE> if not.
   */
  @Override
  public boolean valueIsAcceptable(ByteSequence value,
                                   LocalizableMessageBuilder invalidReason) {
@@ -260,6 +228,7 @@
 /**
   * {@inheritDoc}
   */
  @Override
  public boolean isBEREncodingRequired()
  {
    return false;
@@ -270,6 +239,7 @@
  /**
   * {@inheritDoc}
   */
  @Override
  public boolean isHumanReadable()
  {
    return true;
opendj3-server-dev/src/server/org/opends/server/types/AttributeParser.java
New file
@@ -0,0 +1,494 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
 * or http://forgerock.org/license/CDDLv1.0.html.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at legal-notices/CDDLv1_0.txt.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2012-2014 ForgeRock AS.
 */
package org.opends.server.types;
import java.util.*;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.Function;
import org.forgerock.opendj.ldap.Functions;
import org.forgerock.opendj.ldap.GeneralizedTime;
import org.forgerock.opendj.ldap.schema.Schema;
/**
 * A fluent API for parsing attributes as different types of object. An
 * attribute parser is obtained from an entry using the method
 * {@link Entry#parseAttribute} or from an attribute using
 * {@link Attribute#parse}.
 * <p>
 * Methods throw an {@code IllegalArgumentException} when a value cannot be
 * parsed (e.g. because its syntax is invalid). Methods which return a
 * {@code Set} always return a modifiable non-{@code null} result, even if the
 * attribute is {@code null} or empty.
 * <p>
 * Examples:
 *
 * <pre>
 * Entry entry = ...;
 *
 * Calendar timestamp = entry.parseAttribute("createTimestamp").asCalendar();
 * boolean isEnabled = entry.parseAttribute("enabled").asBoolean(false);
 *
 * Entry group = ...;
 * Schema schema = ...;
 *
 * Set&lt;DN&gt; members = group.parseAttribute("member").usingSchema(schema).asSetOfDN();
 * </pre>
 *
 * @see Entry#parseAttribute
 * @see Attribute#parse
 */
public final class AttributeParser {
    // TODO: enums, filters, rdns?
    private static final AttributeParser NULL_INSTANCE = new AttributeParser(null);
    /**
     * Returns an attribute parser for the provided attribute. {@code null}
     * attributes are permitted and will be treated as if an empty attribute was
     * provided.
     *
     * @param attribute
     *            The attribute to be parsed, which may be {@code null}.
     * @return The attribute parser.
     */
    public static AttributeParser parseAttribute(final Attribute attribute) {
        return isEmpty(attribute) ? NULL_INSTANCE : new AttributeParser(attribute);
    }
    private static boolean isEmpty(final Attribute attribute) {
        return (attribute == null) || attribute.isEmpty();
    }
    private final Attribute attribute;
    private Schema schema;
    private AttributeParser(final Attribute attribute) {
        this.attribute = attribute;
    }
    /**
     * Returns the first value decoded as a {@code T} using the provided
     * {@link Function}, or {@code null} if the attribute does not contain any
     * values.
     *
     * @param <T>
     *            The type of the value to be decoded.
     * @param f
     *            The function which should be used to decode the value.
     * @return The first value decoded as a {@code T}.
     */
    public <T> T as(final Function<ByteString, ? extends T, Void> f) {
        return as(f, null);
    }
    /**
     * Returns the first value decoded as a {@code T} using the provided
     * {@link Function}, or {@code defaultValue} if the attribute does not
     * contain any values.
     *
     * @param <T>
     *            The type of the value to be decoded.
     * @param f
     *            The function which should be used to decode the value.
     * @param defaultValue
     *            The default value to return if the attribute is empty.
     * @return The first value decoded as a {@code T}.
     */
    public <T> T as(final Function<ByteString, ? extends T, Void> f, final T defaultValue) {
        if (!isEmpty(attribute)) {
            return f.apply(attribute.iterator().next().getValue(), null);
        } else {
            return defaultValue;
        }
    }
    /**
     * Returns the first value decoded as a boolean, or {@code null} if the
     * attribute does not contain any values.
     *
     * @return The first value decoded as a boolean.
     */
    public Boolean asBoolean() {
        return isEmpty(attribute) ? null : asBoolean(false /* ignored */);
    }
    /**
     * Returns the first value decoded as an {@code Boolean}, or
     * {@code defaultValue} if the attribute does not contain any values.
     *
     * @param defaultValue
     *            The default value to return if the attribute is empty.
     * @return The first value decoded as an {@code Boolean}.
     */
    public boolean asBoolean(final boolean defaultValue) {
        return as(Functions.byteStringToBoolean(), defaultValue);
    }
    /**
     * Returns the first value, or {@code null} if the attribute does not
     * contain any values.
     *
     * @return The first value.
     */
    public ByteString asByteString() {
        return asByteString(null);
    }
    /**
     * Returns the first value, or {@code defaultValue} if the attribute does
     * not contain any values.
     *
     * @param defaultValue
     *            The default value to return if the attribute is empty.
     * @return The first value.
     */
    public ByteString asByteString(final ByteString defaultValue) {
        return as(Functions.<ByteString> identityFunction(), defaultValue);
    }
    /**
     * Returns the first value decoded as a {@code GeneralizedTime} using the
     * generalized time syntax, or {@code null} if the attribute does not
     * contain any values.
     *
     * @return The first value decoded as a {@code GeneralizedTime}.
     */
    public GeneralizedTime asGeneralizedTime() {
        return asGeneralizedTime(null);
    }
    /**
     * Returns the first value decoded as an {@code GeneralizedTime} using the
     * generalized time syntax, or {@code defaultValue} if the attribute does
     * not contain any values.
     *
     * @param defaultValue
     *            The default value to return if the attribute is empty.
     * @return The first value decoded as an {@code GeneralizedTime}.
     */
    public GeneralizedTime asGeneralizedTime(final GeneralizedTime defaultValue) {
        return as(Functions.byteStringToGeneralizedTime(), defaultValue);
    }
    /**
     * Returns the first value decoded as an {@code Integer}, or {@code null} if
     * the attribute does not contain any values.
     *
     * @return The first value decoded as an {@code Integer}.
     */
    public Integer asInteger() {
        return isEmpty(attribute) ? null : asInteger(0 /* ignored */);
    }
    /**
     * Returns the first value decoded as an {@code Integer}, or
     * {@code defaultValue} if the attribute does not contain any values.
     *
     * @param defaultValue
     *            The default value to return if the attribute is empty.
     * @return The first value decoded as an {@code Integer}.
     */
    public int asInteger(final int defaultValue) {
        return as(Functions.byteStringToInteger(), defaultValue);
    }
    /**
     * Returns the first value decoded as a {@code Long}, or {@code null} if the
     * attribute does not contain any values.
     *
     * @return The first value decoded as a {@code Long}.
     */
    public Long asLong() {
        return isEmpty(attribute) ? null : asLong(0L /* ignored */);
    }
    /**
     * Returns the first value decoded as a {@code Long}, or
     * {@code defaultValue} if the attribute does not contain any values.
     *
     * @param defaultValue
     *            The default value to return if the attribute is empty.
     * @return The first value decoded as a {@code Long}.
     */
    public long asLong(final long defaultValue) {
        return as(Functions.byteStringToLong(), defaultValue);
    }
    /**
     * Returns the values decoded as a set of {@code T}s using the provided
     * {@link Function}, or {@code defaultValues} if the attribute does not
     * contain any values.
     *
     * @param <T>
     *            The type of the values to be decoded.
     * @param f
     *            The function which should be used to decode values.
     * @param defaultValues
     *            The default values to return if the attribute is empty.
     * @return The values decoded as a set of {@code T}s.
     */
    public <T> Set<T> asSetOf(final Function<ByteString, ? extends T, Void> f,
            final Collection<? extends T> defaultValues) {
        if (!isEmpty(attribute)) {
            final LinkedHashSet<T> result = new LinkedHashSet<T>(attribute.size());
            for (final AttributeValue v : attribute) {
                result.add(f.apply(v.getValue(), null));
            }
            return result;
        } else if (defaultValues != null) {
            return new LinkedHashSet<T>(defaultValues);
        } else {
            return new LinkedHashSet<T>(0);
        }
    }
    /**
     * Returns the values decoded as a set of {@code T}s using the provided
     * {@link Function}, or {@code defaultValues} if the attribute does not
     * contain any values.
     *
     * @param <T>
     *            The type of the values to be decoded.
     * @param f
     *            The function which should be used to decode values.
     * @param defaultValues
     *            The default values to return if the attribute is empty.
     * @return The values decoded as a set of {@code T}s.
     */
    public <T> Set<T> asSetOf(final Function<ByteString, ? extends T, Void> f,
            final T... defaultValues) {
        return asSetOf(f, Arrays.asList(defaultValues));
    }
    /**
     * Returns the values decoded as a set of {@code Boolean}s, or
     * {@code defaultValues} if the attribute does not contain any values.
     *
     * @param defaultValues
     *            The default values to return if the attribute is empty.
     * @return The values decoded as a set of {@code Boolean}s.
     */
    public Set<Boolean> asSetOfBoolean(final Boolean... defaultValues) {
        return asSetOfBoolean(Arrays.asList(defaultValues));
    }
    /**
     * Returns the values decoded as a set of {@code Boolean}s, or
     * {@code defaultValues} if the attribute does not contain any values.
     *
     * @param defaultValues
     *            The default values to return if the attribute is empty.
     * @return The values decoded as a set of {@code Boolean}s.
     */
    public Set<Boolean> asSetOfBoolean(final Collection<Boolean> defaultValues) {
        return asSetOf(Functions.byteStringToBoolean(), defaultValues);
    }
    /**
     * Returns the values contained in the attribute, or {@code defaultValues}
     * if the attribute does not contain any values.
     *
     * @param defaultValues
     *            The default values to return if the attribute is empty.
     * @return The values contained in the attribute.
     */
    public Set<ByteString> asSetOfByteString(final ByteString... defaultValues) {
        return asSetOfByteString(Arrays.asList(defaultValues));
    }
    /**
     * Returns the values contained in the attribute, or {@code defaultValues}
     * if the attribute does not contain any values.
     *
     * @param defaultValues
     *            The default values to return if the attribute is empty.
     * @return The values contained in the attribute.
     */
    public Set<ByteString> asSetOfByteString(final Collection<ByteString> defaultValues) {
        return asSetOf(Functions.<ByteString> identityFunction(), defaultValues);
    }
    /**
     * Returns the values decoded as a set of {@code GeneralizedTime}s using the
     * generalized time syntax, or {@code defaultValues} if the attribute does
     * not contain any values.
     *
     * @param defaultValues
     *            The default values to return if the attribute is empty.
     * @return The values decoded as a set of {@code GeneralizedTime}s.
     */
    public Set<GeneralizedTime> asSetOfGeneralizedTime(
            final Collection<GeneralizedTime> defaultValues) {
        return asSetOf(Functions.byteStringToGeneralizedTime(), defaultValues);
    }
    /**
     * Returns the values decoded as a set of {@code GeneralizedTime}s using the
     * generalized time syntax, or {@code defaultValues} if the attribute does
     * not contain any values.
     *
     * @param defaultValues
     *            The default values to return if the attribute is empty.
     * @return The values decoded as a set of {@code GeneralizedTime}s.
     */
    public Set<GeneralizedTime> asSetOfGeneralizedTime(final GeneralizedTime... defaultValues) {
        return asSetOfGeneralizedTime(Arrays.asList(defaultValues));
    }
    /**
     * Returns the values decoded as a set of {@code Integer}s, or
     * {@code defaultValues} if the attribute does not contain any values.
     *
     * @param defaultValues
     *            The default values to return if the attribute is empty.
     * @return The values decoded as a set of {@code Integer}s.
     */
    public Set<Integer> asSetOfInteger(final Collection<Integer> defaultValues) {
        return asSetOf(Functions.byteStringToInteger(), defaultValues);
    }
    /**
     * Returns the values decoded as a set of {@code Integer}s, or
     * {@code defaultValues} if the attribute does not contain any values.
     *
     * @param defaultValues
     *            The default values to return if the attribute is empty.
     * @return The values decoded as a set of {@code Integer}s.
     */
    public Set<Integer> asSetOfInteger(final Integer... defaultValues) {
        return asSetOfInteger(Arrays.asList(defaultValues));
    }
    /**
     * Returns the values decoded as a set of {@code Long}s, or
     * {@code defaultValues} if the attribute does not contain any values.
     *
     * @param defaultValues
     *            The default values to return if the attribute is empty.
     * @return The values decoded as a set of {@code Long}s.
     */
    public Set<Long> asSetOfLong(final Collection<Long> defaultValues) {
        return asSetOf(Functions.byteStringToLong(), defaultValues);
    }
    /**
     * Returns the values decoded as a set of {@code Long}s, or
     * {@code defaultValues} if the attribute does not contain any values.
     *
     * @param defaultValues
     *            The default values to return if the attribute is empty.
     * @return The values decoded as a set of {@code Long}s.
     */
    public Set<Long> asSetOfLong(final Long... defaultValues) {
        return asSetOfLong(Arrays.asList(defaultValues));
    }
    /**
     * Returns the values decoded as a set of {@code String}s, or
     * {@code defaultValues} if the attribute does not contain any values.
     *
     * @param defaultValues
     *            The default values to return if the attribute is empty.
     * @return The values decoded as a set of {@code String}s.
     */
    public Set<String> asSetOfString(final Collection<String> defaultValues) {
        return asSetOf(Functions.byteStringToString(), defaultValues);
    }
    /**
     * Returns the values decoded as a set of {@code String}s, or
     * {@code defaultValues} if the attribute does not contain any values.
     *
     * @param defaultValues
     *            The default values to return if the attribute is empty.
     * @return The values decoded as a set of {@code String}s.
     */
    public Set<String> asSetOfString(final String... defaultValues) {
        return asSetOfString(Arrays.asList(defaultValues));
    }
    /**
     * Returns the first value decoded as a {@code String}, or {@code null} if
     * the attribute does not contain any values.
     *
     * @return The first value decoded as a {@code String}.
     */
    public String asString() {
        return asString(null);
    }
    /**
     * Returns the first value decoded as a {@code String}, or
     * {@code defaultValue} if the attribute does not contain any values.
     *
     * @param defaultValue
     *            The default value to return if the attribute is empty.
     * @return The first value decoded as a {@code String}.
     */
    public String asString(final String defaultValue) {
        return as(Functions.byteStringToString(), defaultValue);
    }
    /**
     * Throws a {@code NoSuchElementException} if the attribute referenced by
     * this parser is {@code null} or empty.
     *
     * @return A reference to this attribute parser.
     * @throws NoSuchElementException
     *             If the attribute referenced by this parser is {@code null} or
     *             empty.
     */
    public AttributeParser requireValue() throws NoSuchElementException {
        if (isEmpty(attribute)) {
            throw new NoSuchElementException();
        } else {
            return this;
        }
    }
    /**
     * Sets the {@code Schema} which will be used when parsing schema sensitive
     * values such as DNs and attribute descriptions.
     *
     * @param schema
     *            The {@code Schema} which will be used when parsing schema
     *            sensitive values.
     * @return This attribute parser.
     */
    public AttributeParser usingSchema(final Schema schema) {
        // Avoid modifying the null instance: a schema will not be needed
        // anyway.
        if (this != NULL_INSTANCE) {
            this.schema = schema;
        }
        return this;
    }
    private Schema getSchema() {
        return schema == null ? Schema.getDefaultSchema() : schema;
    }
}
opendj3-server-dev/src/server/org/opends/server/types/Entry.java
@@ -33,6 +33,7 @@
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.LocalizableMessageBuilder;
import org.forgerock.i18n.LocalizedIllegalArgumentException;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.opendj.ldap.ByteSequence;
import org.forgerock.opendj.ldap.ByteSequenceReader;
@@ -42,7 +43,6 @@
import org.forgerock.opendj.ldap.ResultCode;
import org.forgerock.opendj.ldap.SearchScope;
import org.forgerock.opendj.ldap.schema.ObjectClassType;
import org.opends.server.api.AttributeValueDecoder;
import org.opends.server.api.CompressedSchema;
import org.opends.server.api.MatchingRule;
import org.opends.server.api.ProtocolElement;
@@ -861,87 +861,27 @@
  }
  /**
   * Retrieves the requested attribute type from the entry and decodes
   * a single value as an object of type T.
   * Returns a parser for the named attribute contained in this entry.
   * <p>
   * If the requested attribute type is not present then
   * <code>null</code> is returned. If more than one attribute value
   * is present, then the first value found will be decoded and
   * returned.
   * <p>
   * The attribute value is decoded using the specified
   * {@link org.opends.server.api.AttributeValueDecoder}.
   * The attribute description will be decoded using the schema associated
   * with this entry (usually the default schema).
   *
   * @param <T>
   *          Decode the attribute value to an object of this type.
   * @param attributeType
   *          The attribute type to retrieve.
   * @param decoder
   *          The attribute value decoder.
   * @return The decoded attribute value or <code>null</code> if no
   *         attribute value having the specified attribute type was
   *         found.
   * @throws DirectoryException
   *           If the requested attribute value could not be decoded
   *           successfully.
   * @param attributeDescription
   *            The name of the attribute to be parsed.
   * @return A parser for the named attribute.
   * @throws LocalizedIllegalArgumentException
   *             If {@code attributeDescription} could not be decoded using
   *             the schema associated with this entry.
   * @throws NullPointerException
   *             If {@code attributeDescription} was {@code null}.
   */
  public final <T> T getAttributeValue(AttributeType attributeType,
      AttributeValueDecoder<T> decoder) throws DirectoryException
  public AttributeParser parseAttribute(String attributeDescription)
      throws LocalizedIllegalArgumentException, NullPointerException
  {
    List<Attribute> attributes = getAttribute(attributeType, true);
    AttributeValueIterable values = new AttributeValueIterable(attributes);
    Iterator<AttributeValue> iterator = values.iterator();
    if (iterator.hasNext())
    {
      return decoder.decode(iterator.next());
    }
    return null;
  }
  /**
   * Retrieves the requested attribute type from the entry and decodes
   * any values as objects of type T and then places them in the
   * specified collection.
   * <p>
   * If the requested attribute type is not present then no decoded
   * values will be added to the container.
   * <p>
   * The attribute value is decoded using the specified
   * {@link org.opends.server.api.AttributeValueDecoder}.
   *
   * @param <T>
   *          Decode the attribute values to objects of this type.
   * @param attributeType
   *          The attribute type to retrieve.
   * @param decoder
   *          The attribute value decoder.
   * @param collection
   *          The collection to which decoded values should be added.
   * @return The collection containing the decoded attribute value.
   * @throws DirectoryException
   *           If one or more of the requested attribute values could
   *           not be decoded successfully.
   */
  public final <T> Collection<T> getAttributeValues(
      AttributeType attributeType,
      AttributeValueDecoder<? extends T> decoder,
      Collection<T> collection)
      throws DirectoryException
  {
    List<Attribute> attributes = getAttribute(attributeType, true);
    AttributeValueIterable values =
         new AttributeValueIterable(attributes);
    for (AttributeValue value : values)
    {
      collection.add(decoder.decode(value));
    }
    return collection;
    final List<Attribute> attribute = getAttribute(attributeDescription);
    boolean notEmpty = attribute != null && !attribute.isEmpty();
    return AttributeParser.parseAttribute(notEmpty ? attribute.get(0) : null);
  }
opendj3-server-dev/src/server/org/opends/server/types/SubtreeSpecificationSet.java
File was deleted
opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/crypto/GetSymmetricKeyExtendedOperationTestCase.java
@@ -30,6 +30,7 @@
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
import org.forgerock.opendj.ldap.ResultCode;
import org.forgerock.opendj.ldap.SearchScope;
import org.opends.admin.ads.ADSContext;
import org.opends.server.TestCaseUtils;
@@ -38,13 +39,14 @@
import org.opends.server.core.ExtendedOperation;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.protocols.internal.InternalSearchOperation;
import org.opends.server.schema.DirectoryStringSyntax;
import org.opends.server.types.*;
import org.forgerock.opendj.ldap.ResultCode;
import org.opends.server.types.DN;
import org.opends.server.types.Entry;
import org.opends.server.types.SearchFilter;
import org.opends.server.util.ServerConstants;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import static org.opends.server.config.ConfigConstants.*;
import static org.testng.Assert.*;
/**
@@ -124,11 +126,9 @@
    final InternalClientConnection internalConnection =
         InternalClientConnection.getRootConnection();
    final String instanceKeyID = cm.getInstanceKeyID();
    final AttributeType attrSymmetricKey = DirectoryServer.getAttributeType(
         ConfigConstants.ATTR_CRYPTO_SYMMETRIC_KEY);
    for (Entry e : searchOp.getSearchEntries()) {
      final String symmetricKeyAttributeValue
              = e.getAttributeValue(attrSymmetricKey, DirectoryStringSyntax.DECODER);
      final String symmetricKeyAttributeValue =
          e.parseAttribute(ATTR_CRYPTO_SYMMETRIC_KEY).asString();
      final ByteString requestValue =
           GetSymmetricKeyExtendedOperation.encodeRequestValue(
                symmetricKeyAttributeValue, instanceKeyID);
opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/EntityTagVirtualAttributeProviderTestCase.java
@@ -37,6 +37,10 @@
import org.forgerock.i18n.LocalizableMessageBuilder;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.ConditionResult;
import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
import org.forgerock.opendj.ldap.ModificationType;
import org.forgerock.opendj.ldap.ResultCode;
import org.forgerock.opendj.ldap.SearchScope;
import org.opends.server.TestCaseUtils;
import org.opends.server.admin.server.ConfigurationChangeListener;
import org.opends.server.admin.std.meta.EntityTagVirtualAttributeCfgDefn.ChecksumAlgorithm;
@@ -58,21 +62,16 @@
import org.opends.server.protocols.internal.InternalSearchOperation;
import org.opends.server.protocols.ldap.LDAPFilter;
import org.opends.server.protocols.ldap.LDAPModification;
import org.opends.server.schema.DirectoryStringSyntax;
import org.opends.server.types.AttributeType;
import org.opends.server.types.AttributeValue;
import org.opends.server.types.AttributeValues;
import org.opends.server.types.Control;
import org.opends.server.types.DN;
import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.Entry;
import org.forgerock.opendj.ldap.ModificationType;
import org.opends.server.types.RawAttribute;
import org.opends.server.types.RawModification;
import org.forgerock.opendj.ldap.ResultCode;
import org.opends.server.types.SearchFilter;
import org.forgerock.opendj.ldap.SearchScope;
import org.opends.server.types.VirtualAttributeRule;
import org.opends.server.util.StaticUtils;
import org.testng.annotations.BeforeClass;
@@ -623,8 +622,6 @@
  public void testOptimisticConcurrency() throws Exception
  {
    // Use an internal connection.
    AttributeType etagType = DirectoryServer.getAttributeType(ETAG);
    AttributeType descrType = DirectoryServer.getAttributeType(DESCRIPTION);
    String userDN = "uid=test.user,ou=People,o=test";
    InternalClientConnection conn = InternalClientConnection
        .getRootConnection();
@@ -653,8 +650,7 @@
    // Read the user entry and get the etag.
    Entry e1 = readEntry(conn, userDN);
    String etag1 = e1
        .getAttributeValue(etagType, DirectoryStringSyntax.DECODER);
    String etag1 = e1.parseAttribute(ETAG).asString();
    assertNotNull(etag1);
    // Apply a change using the assertion control for optimistic concurrency.
@@ -672,13 +668,11 @@
    // the etag has changed.
    Entry e2 = readEntry(conn, userDN);
    String etag2 = e2
        .getAttributeValue(etagType, DirectoryStringSyntax.DECODER);
    String etag2 = e2.parseAttribute(ETAG).asString();
    assertNotNull(etag2);
    assertFalse(etag1.equals(etag2));
    String description2 = e2.getAttributeValue(descrType,
        DirectoryStringSyntax.DECODER);
    String description2 = e2.parseAttribute(DESCRIPTION).asString();
    assertNotNull(description2);
    assertEquals(description2, "first modify");
@@ -693,13 +687,11 @@
    // changed.
    Entry e3 = readEntry(conn, userDN);
    String etag3 = e3
        .getAttributeValue(etagType, DirectoryStringSyntax.DECODER);
    String etag3 = e3.parseAttribute(ETAG).asString();
    assertNotNull(etag3);
    assertEquals(etag2, etag3);
    String description3 = e3.getAttributeValue(descrType,
        DirectoryStringSyntax.DECODER);
    String description3 = e3.parseAttribute(DESCRIPTION).asString();
    assertNotNull(description3);
    assertEquals(description3, description2);
  }
@@ -716,8 +708,6 @@
  @Test
  public void testPreReadControl() throws Exception
  {
    AttributeType etagType = DirectoryServer.getAttributeType(ETAG);
    AttributeType descrType = DirectoryServer.getAttributeType(DESCRIPTION);
    String userDN = "uid=test.user,ou=People,o=test";
    // Use an internal connection.
@@ -749,8 +739,7 @@
    // Read the user entry and get the etag.
    Entry e1 = readEntry(conn, userDN);
    String etag1 = e1
        .getAttributeValue(etagType, DirectoryStringSyntax.DECODER);
    String etag1 = e1.parseAttribute(ETAG).asString();
    assertNotNull(etag1);
    // Apply a change using the pre and post read controls.
@@ -767,13 +756,11 @@
    // the etag has changed.
    Entry e2 = readEntry(conn, userDN);
    String etag2 = e2
        .getAttributeValue(etagType, DirectoryStringSyntax.DECODER);
    String etag2 = e2.parseAttribute(ETAG).asString();
    assertNotNull(etag2);
    assertFalse(etag1.equals(etag2));
    String description2 = e2.getAttributeValue(descrType,
        DirectoryStringSyntax.DECODER);
    String description2 = e2.parseAttribute(DESCRIPTION).asString();
    assertNotNull(description2);
    assertEquals(description2, "modified value");
@@ -788,8 +775,8 @@
      }
    }
    assertNotNull(preReadControl);
    String etagPreRead = preReadControl.getSearchEntry().getAttributeValue(
        etagType, DirectoryStringSyntax.DECODER);
    String etagPreRead =
        preReadControl.getSearchEntry().parseAttribute(ETAG).asString();
    assertEquals(etagPreRead, etag1);
  }
@@ -805,8 +792,6 @@
  @Test
  public void testPostReadControl() throws Exception
  {
    AttributeType etagType = DirectoryServer.getAttributeType(ETAG);
    AttributeType descrType = DirectoryServer.getAttributeType(DESCRIPTION);
    String userDN = "uid=test.user,ou=People,o=test";
    // Use an internal connection.
@@ -838,8 +823,7 @@
    // Read the user entry and get the etag.
    Entry e1 = readEntry(conn, userDN);
    String etag1 = e1
        .getAttributeValue(etagType, DirectoryStringSyntax.DECODER);
    String etag1 = e1.parseAttribute(ETAG).asString();
    assertNotNull(etag1);
    // Apply a change using the pre and post read controls.
@@ -856,13 +840,11 @@
    // the etag has changed.
    Entry e2 = readEntry(conn, userDN);
    String etag2 = e2
        .getAttributeValue(etagType, DirectoryStringSyntax.DECODER);
    String etag2 = e2.parseAttribute(ETAG).asString();
    assertNotNull(etag2);
    assertFalse(etag1.equals(etag2));
    String description2 = e2.getAttributeValue(descrType,
        DirectoryStringSyntax.DECODER);
    String description2 = e2.parseAttribute(DESCRIPTION).asString();
    assertNotNull(description2);
    assertEquals(description2, "modified value");
@@ -877,8 +859,8 @@
      }
    }
    assertNotNull(postReadControl);
    String etagPostRead = postReadControl.getSearchEntry().getAttributeValue(
        etagType, DirectoryStringSyntax.DECODER);
    String etagPostRead =
        postReadControl.getSearchEntry().parseAttribute(ETAG).asString();
    assertEquals(etagPostRead, etag2);
  }
opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/LDAPPassThroughAuthenticationPolicyTestCase.java
@@ -4334,13 +4334,10 @@
    Entry updatedTestUser = DirectoryServer.getEntry(DN
        .valueOf("cn=test user,o=test"));
    String newCachedPassword = updatedTestUser.getAttributeValue(
        DirectoryServer.getAttributeType("ds-pta-cached-password"),
        DirectoryStringSyntax.DECODER);
    String newCachedPasswordTime = updatedTestUser.getAttributeValue(
        DirectoryServer.getAttributeType("ds-pta-cached-password-time"),
        DirectoryStringSyntax.DECODER);
    String newCachedPassword =
        updatedTestUser.parseAttribute("ds-pta-cached-password").asString();
    String newCachedPasswordTime =
        updatedTestUser.parseAttribute("ds-pta-cached-password-time").asString();
    if (expectCacheInfo)
    {
opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/replication/InitOnLineTest.java
@@ -31,11 +31,11 @@
import org.assertj.core.api.Assertions;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.opendj.ldap.ResultCode;
import org.forgerock.opendj.ldap.SearchScope;
import org.opends.server.TestCaseUtils;
import org.opends.server.backends.task.TaskState;
import org.opends.server.core.AddOperation;
import org.opends.server.core.DirectoryServer;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.protocols.internal.InternalSearchOperation;
import org.opends.server.replication.common.ServerStatus;
@@ -45,9 +45,10 @@
import org.opends.server.replication.server.ReplicationServer;
import org.opends.server.replication.server.ReplicationServerDomain;
import org.opends.server.replication.service.ReplicationBroker;
import org.opends.server.schema.DirectoryStringSyntax;
import org.opends.server.types.*;
import org.forgerock.opendj.ldap.ResultCode;
import org.opends.server.types.DN;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.Entry;
import org.opends.server.types.SearchFilter;
import org.opends.server.util.Base64;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
@@ -230,22 +231,15 @@
      Entry resultEntry = getCompletionTime(taskEntry);
      // Check that the task state is as expected.
      AttributeType taskStateType =
          DirectoryServer.getAttributeType(ATTR_TASK_STATE.toLowerCase());
      String stateString =
          resultEntry.getAttributeValue(taskStateType,
              DirectoryStringSyntax.DECODER);
          resultEntry.parseAttribute(ATTR_TASK_STATE.toLowerCase()).asString();
      TaskState taskState = TaskState.fromString(stateString);
      assertEquals(taskState, expectedState,
          "The task completed in an unexpected state");
      // Check that the task contains some log messages.
      AttributeType logMessagesType = DirectoryServer.getAttributeType(
          ATTR_TASK_LOG_MESSAGES.toLowerCase());
      List<String> logMessages = new ArrayList<String>();
      resultEntry.getAttributeValues(logMessagesType,
          DirectoryStringSyntax.DECODER,
          logMessages);
      Set<String> logMessages = resultEntry.parseAttribute(
          ATTR_TASK_LOG_MESSAGES.toLowerCase()).asSetOfString();
      if (taskState != TaskState.COMPLETED_SUCCESSFULLY &&
          logMessages.isEmpty())
      {
@@ -268,8 +262,6 @@
    // Wait until the task completes.
    int timeout = 2000;
    AttributeType completionTimeType = DirectoryServer.getAttributeType(
        ATTR_TASK_COMPLETION_TIME.toLowerCase());
    SearchFilter filter =
        SearchFilter.createFilterFromString("(objectclass=*)");
@@ -280,9 +272,8 @@
          taskEntry.getName(), SearchScope.BASE_OBJECT, filter);
      Entry resultEntry = searchOperation.getSearchEntries().getFirst();
      String completionTime = resultEntry.getAttributeValue(
          completionTimeType, DirectoryStringSyntax.DECODER);
      String completionTime = resultEntry.parseAttribute(
          ATTR_TASK_COMPLETION_TIME.toLowerCase()).asString();
      if (completionTime != null)
      {
        return resultEntry;
@@ -300,8 +291,7 @@
  private void assertAttributeValue(Entry resultEntry, String lowerAttrName,
      long expected, String message) throws DirectoryException
  {
    AttributeType type = DirectoryServer.getAttributeType(lowerAttrName, true);
    String value = resultEntry.getAttributeValue(type, DirectoryStringSyntax.DECODER);
    String value = resultEntry.parseAttribute(lowerAttrName).asString();
    assertEquals(Long.decode(value).longValue(), expected, message);
  }
opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/replication/ReplicationTestCase.java
@@ -32,13 +32,14 @@
import org.assertj.core.api.Assertions;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.opendj.config.server.ConfigException;
import org.forgerock.opendj.ldap.ModificationType;
import org.forgerock.opendj.ldap.ResultCode;
import org.forgerock.opendj.ldap.SearchScope;
import org.opends.server.DirectoryServerTestCase;
import org.opends.server.TestCaseUtils;
import org.opends.server.admin.std.server.ReplicationDomainCfg;
import org.opends.server.backends.task.TaskState;
import org.forgerock.opendj.config.server.ConfigException;
import org.opends.server.core.AddOperation;
import org.opends.server.core.DeleteOperation;
import org.opends.server.core.DirectoryServer;
@@ -52,18 +53,15 @@
import org.opends.server.replication.server.ReplicationServer;
import org.opends.server.replication.server.changelog.je.JEChangelogDB;
import org.opends.server.replication.service.ReplicationBroker;
import org.opends.server.schema.IntegerSyntax;
import org.opends.server.types.*;
import org.forgerock.opendj.ldap.ResultCode;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import static org.forgerock.opendj.ldap.ResultCode.*;
import static org.forgerock.opendj.ldap.SearchScope.*;
import static org.opends.server.TestCaseUtils.*;
import static org.opends.server.config.ConfigConstants.*;
import static org.opends.server.schema.DirectoryStringSyntax.*;
import static org.forgerock.opendj.ldap.ResultCode.*;
import static org.testng.Assert.*;
/**
@@ -499,8 +497,7 @@
    assertFalse(op.getSearchEntries().isEmpty(), "Could not read monitoring information");
    SearchResultEntry entry = op.getSearchEntries().getFirst();
    AttributeType attrType = DirectoryServer.getDefaultAttributeType(attr);
    return entry.getAttributeValue(attrType, IntegerSyntax.DECODER).longValue();
    return entry.parseAttribute(attr).asLong();
  }
  /**
@@ -632,8 +629,6 @@
                 "Add of the task definition was not successful");
    // Wait until the task completes.
    AttributeType completionTimeType = DirectoryServer.getAttributeType(
         ATTR_TASK_COMPLETION_TIME.toLowerCase());
    SearchFilter filter = SearchFilter.createFilterFromString("(objectclass=*)");
    Entry resultEntry = null;
    String completionTime = null;
@@ -649,7 +644,8 @@
        continue;
      }
      resultEntry = searchOperation.getSearchEntries().get(0);
      completionTime = resultEntry.getAttributeValue(completionTimeType, DECODER);
      completionTime = resultEntry.parseAttribute(
          ATTR_TASK_COMPLETION_TIME.toLowerCase()).asString();
      if (completionTime == null)
      {
        if (System.currentTimeMillis() - startMillisecs > 1000*30)
@@ -663,9 +659,8 @@
    assertNotNull(completionTime, "The task has not completed after 30 seconds.");
    // Check that the task state is as expected.
    AttributeType taskStateType =
         DirectoryServer.getAttributeType(ATTR_TASK_STATE.toLowerCase());
    String stateString = resultEntry.getAttributeValue(taskStateType, DECODER);
    String stateString = resultEntry.parseAttribute(
        ATTR_TASK_STATE.toLowerCase()).asString();
    TaskState taskState = TaskState.fromString(stateString);
    assertEquals(taskState, TaskState.COMPLETED_SUCCESSFULLY,
                 "The task completed in an unexpected state");
@@ -744,9 +739,8 @@
      resultEntry = searchOperation.getSearchEntries().getFirst();
      // Check that the task state is as expected.
      AttributeType taskStateType =
          DirectoryServer.getAttributeType(ATTR_TASK_STATE.toLowerCase());
      String stateString = resultEntry.getAttributeValue(taskStateType, DECODER);
      String stateString = resultEntry.parseAttribute(
          ATTR_TASK_STATE.toLowerCase()).asString();
      taskState = TaskState.fromString(stateString);
      Thread.sleep(100);
@@ -757,10 +751,8 @@
        && (System.currentTimeMillis() - startTime < maxWaitTimeInMillis));
    // Check that the task contains some log messages.
    AttributeType logMessagesType =
        DirectoryServer.getAttributeType(ATTR_TASK_LOG_MESSAGES.toLowerCase());
    List<String> logMessages = new ArrayList<String>();
    resultEntry.getAttributeValues(logMessagesType, DECODER, logMessages);
    Set<String> logMessages = resultEntry.parseAttribute(
        ATTR_TASK_LOG_MESSAGES.toLowerCase()).asSetOfString();
    if (taskState != TaskState.COMPLETED_SUCCESSFULLY
        && taskState != TaskState.RUNNING)
@@ -768,13 +760,14 @@
      assertFalse(logMessages.isEmpty(),
          "No log messages were written to the task entry on a failed task");
    }
    if (logMessages.size() != 0)
    if (!logMessages.isEmpty())
    {
      logger.trace(logMessages.get(0));
      String firstLogMsg = logMessages.iterator().next();
      logger.trace(firstLogMsg);
      if (expectedMessage != null)
      {
        logger.trace(expectedMessage);
        assertTrue(logMessages.get(0).indexOf(expectedMessage.toString()) > 0);
        assertTrue(firstLogMsg.indexOf(expectedMessage.toString()) > 0);
      }
    }
opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/replication/UpdateOperationTest.java
@@ -35,6 +35,7 @@
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.opendj.ldap.ModificationType;
import org.forgerock.opendj.ldap.ResultCode;
import org.opends.server.TestCaseUtils;
import org.opends.server.core.AddOperation;
import org.opends.server.core.DeleteOperation;
@@ -47,9 +48,7 @@
import org.opends.server.replication.plugin.LDAPReplicationDomain;
import org.opends.server.replication.protocol.*;
import org.opends.server.replication.service.ReplicationBroker;
import org.opends.server.schema.DirectoryStringSyntax;
import org.opends.server.types.*;
import org.forgerock.opendj.ldap.ResultCode;
import org.opends.server.util.TimeThread;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
@@ -1315,8 +1314,7 @@
      // Get the UUID of the test entry.
      Entry resultEntry = getEntry(tmp.getName(), 1, true);
      AttributeType uuidType = DirectoryServer.getAttributeType("entryuuid");
      String uuid = resultEntry.getAttributeValue(uuidType, DirectoryStringSyntax.DECODER);
      String uuid = resultEntry.parseAttribute("entryuuid").asString();
      // Register a short circuit that will fake a no-such-object result code
      // on a delete.  This will cause a replication replay loop.
opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/tasks/TasksTestCase.java
@@ -26,8 +26,9 @@
 */
package org.opends.server.tasks;
import java.util.ArrayList;
import java.util.Set;
import org.forgerock.opendj.ldap.ResultCode;
import org.forgerock.opendj.ldap.SearchScope;
import org.opends.server.DirectoryServerTestCase;
import org.opends.server.backends.task.Task;
@@ -37,9 +38,9 @@
import org.opends.server.core.DirectoryServer;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.protocols.internal.InternalSearchOperation;
import org.opends.server.schema.DirectoryStringSyntax;
import org.opends.server.types.*;
import org.forgerock.opendj.ldap.ResultCode;
import org.opends.server.types.DN;
import org.opends.server.types.Entry;
import org.opends.server.types.SearchFilter;
import org.testng.annotations.Test;
import static org.opends.server.config.ConfigConstants.*;
@@ -88,8 +89,6 @@
                 "Add of the task definition was not successful");
    // Wait until the task completes.
    AttributeType completionTimeType = DirectoryServer.getAttributeType(
         ATTR_TASK_COMPLETION_TIME.toLowerCase());
    SearchFilter filter =
         SearchFilter.createFilterFromString("(objectclass=*)");
    Entry resultEntry = null;
@@ -110,9 +109,8 @@
//        fail("Task entry was not returned from the search.");
        continue;
      }
      completionTime =
           resultEntry.getAttributeValue(completionTimeType,
                                         DirectoryStringSyntax.DECODER);
      completionTime = resultEntry.parseAttribute(
          ATTR_TASK_COMPLETION_TIME.toLowerCase()).asString();
      if (completionTime == null)
      {
@@ -130,22 +128,15 @@
    }
    // Check that the task state is as expected.
    AttributeType taskStateType =
         DirectoryServer.getAttributeType(ATTR_TASK_STATE.toLowerCase());
    String stateString =
         resultEntry.getAttributeValue(taskStateType,
                                       DirectoryStringSyntax.DECODER);
        resultEntry.parseAttribute(ATTR_TASK_STATE.toLowerCase()).asString();
    TaskState taskState = TaskState.fromString(stateString);
    assertEquals(taskState, expectedState,
                 "The task completed in an unexpected state");
    // Check that the task contains some log messages.
    AttributeType logMessagesType = DirectoryServer.getAttributeType(
         ATTR_TASK_LOG_MESSAGES.toLowerCase());
    ArrayList<String> logMessages = new ArrayList<String>();
    resultEntry.getAttributeValues(logMessagesType,
                                   DirectoryStringSyntax.DECODER,
                                   logMessages);
    Set<String> logMessages = resultEntry.parseAttribute(
        ATTR_TASK_LOG_MESSAGES.toLowerCase()).asSetOfString();
    if (taskState != TaskState.COMPLETED_SUCCESSFULLY &&
        logMessages.size() == 0)
    {
opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/types/TestAttributeValue.java
@@ -26,11 +26,10 @@
 */
package org.opends.server.types;
import org.forgerock.opendj.ldap.ByteString;
import org.opends.server.core.DirectoryServer;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import org.testng.Assert;
import org.opends.server.core.DirectoryServer;
/**
 * Test case for AttributeValues
@@ -81,32 +80,4 @@
    Assert.assertEquals(h1 == h2, result);
  }
  /**
   * Check that the {@link AttributeValue#getNormalizedValue()} method
   * works as expected.
   *
   * @param value1
   *          The first test value.
   * @param value2
   *          The second test value.
   * @param result
   *          The expected result.
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test(dataProvider = "generateHashCodeTestData")
  public void testGetNormalizedValue(String value1, String value2,
      boolean result) throws Exception {
    AttributeType type = DirectoryServer.getDefaultAttributeType("test");
    AttributeValue av1 = AttributeValues.create(type, value1);
    AttributeValue av2 = AttributeValues.create(type, value2);
    ByteString r1 = av1.getNormalizedValue();
    ByteString r2 = av2.getNormalizedValue();
    Assert.assertEquals(r1.equals(r2), result);
  }
}
opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/types/TestEntry.java
@@ -26,27 +26,29 @@
 */
package org.opends.server.types;
import org.forgerock.opendj.ldap.ByteString;
import static org.testng.Assert.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.opends.server.TestCaseUtils;
import org.assertj.core.api.Assertions;
import org.forgerock.i18n.LocalizableMessageBuilder;
import org.forgerock.i18n.LocalizedIllegalArgumentException;
import org.forgerock.opendj.ldap.ByteString;
import org.opends.server.TestCaseUtils;
import org.opends.server.core.DirectoryServer;
import org.opends.server.schema.*;
import org.testng.annotations.Test;
import org.opends.server.schema.AttributeTypeSyntax;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import static org.testng.Assert.*;
/**
 * This class defines a set of tests for the {@link Entry} class.
 * <p>
 * At the moment this test suite only tests the getAttributeValue and
 * getAttributeValues methods.
 * At the moment this test suite only tests the parseAttribute method.
 */
public final class TestEntry extends TypesTestCase {
@@ -60,9 +62,7 @@
   * @return The test entry.
   */
  private Entry createTestEntry(AttributeType type, String value) {
    String[] values = new String[1];
    values[0] = value;
    String[] values = new String[] { value };
    return createTestEntry(type, values);
  }
@@ -131,88 +131,68 @@
  }
  /**
   * Test the
   * {@link Entry#getAttributeValue(AttributeType, AttributeValueDecoder)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   * Test the {@link Entry#parseAttribute(String)} method.
   */
  @Test
  public void testGetAttributeValueNotFound() throws Exception {
  public void testParseAttributeNotFound() throws Exception {
    AttributeType type1 = DirectoryServer.getAttributeType("description");
    AttributeType type2 = DirectoryServer.getAttributeType("inheritable");
    Entry entry = createTestEntry(type1, "hello world");
    assertEquals(null, entry
        .getAttributeValue(type2, BooleanSyntax.DECODER));
    assertEquals(null, entry.parseAttribute(type2.getNameOrOID()).asString());
  }
  /**
   * Test the
   * {@link Entry#getAttributeValue(AttributeType, AttributeValueDecoder)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   * Test the {@link Entry#parseAttribute(String)} method.
   */
  @Test
  public void testGetAttributeValueBooleanTrue() throws Exception {
  public void testParseAttributeBooleanTrue() throws Exception {
    AttributeType type = DirectoryServer.getAttributeType("inheritable");
    Entry entry = createTestEntry(type, "true");
    assertEquals(Boolean.TRUE, entry.getAttributeValue(type,
        BooleanSyntax.DECODER));
    assertEquals(entry.parseAttribute(type.getNameOrOID()).asBoolean(),
        Boolean.TRUE);
  }
  /**
   * Test the
   * {@link Entry#getAttributeValue(AttributeType, AttributeValueDecoder)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   * Test the {@link Entry#parseAttribute(String)} method.
   */
  @Test
  public void testGetAttributeValueBooleanFalse() throws Exception {
  public void testParseAttributeBooleanFalse() throws Exception
  {
    AttributeType type = DirectoryServer.getAttributeType("inheritable");
    Entry entry = createTestEntry(type, "false");
    assertEquals(Boolean.FALSE, entry.getAttributeValue(type,
        BooleanSyntax.DECODER));
    assertEquals(entry.parseAttribute(type.getNameOrOID()).asBoolean(),
        Boolean.FALSE);
  }
  /**
   * Test the
   * {@link Entry#getAttributeValue(AttributeType, AttributeValueDecoder)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   * Test the {@link Entry#parseAttribute(String)} method.
   */
  @Test(expectedExceptions = DirectoryException.class)
  public void testGetAttributeValueBooleanBad() throws Exception {
  @Test(expectedExceptions = LocalizedIllegalArgumentException.class)
  public void testParseAttributeBooleanBad() throws Exception
  {
    AttributeType type = DirectoryServer.getAttributeType("inheritable");
    Entry entry = createTestEntry(type, "bad-value");
    entry.getAttributeValue(type, BooleanSyntax.DECODER);
    entry.parseAttribute(type.getNameOrOID()).asBoolean();
    throw new RuntimeException(
         "An illegal boolean value did not throw an exception");
  }
  /**
   * Test the
   * {@link Entry#getAttributeValue(AttributeType, AttributeValueDecoder)}
   * method.
   * Test the {@link Entry#parseAttribute(String)} method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test
  public void testGetAttributeValuesInteger() throws Exception {
  public void testParseAttributesInteger() throws Exception
  {
    AttributeType type = DirectoryServer
        .getAttributeType("supportedldapversion");
    String[] values = new String[] { "-4", "-2", "0", "1", "3" };
@@ -223,43 +203,33 @@
    }
    Entry entry = createTestEntry(type, values);
    HashSet<Integer> result = new HashSet<Integer>();
    entry.getAttributeValues(type, IntegerSyntax.DECODER, result);
    assertEquals(expected, result);
    Set<Integer> result =
        entry.parseAttribute("supportedldapversion").asSetOfInteger();
    Assertions.assertThat(result).isEqualTo(expected);
  }
  /**
   * Test the
   * {@link Entry#getAttributeValue(AttributeType, AttributeValueDecoder)}
   * method.
   * Test the {@link Entry#parseAttribute(String)} method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   */
  @Test(expectedExceptions = DirectoryException.class)
  public void testGetAttributeValueIntegerBad() throws Exception {
  @Test(expectedExceptions = LocalizedIllegalArgumentException.class)
  public void testParseAttributeIntegerBad() throws Exception
  {
    AttributeType type = DirectoryServer
        .getAttributeType("supportedldapversion");
    String[] values = new String[] { "-4", "-2", "xxx", "1", "3" };
    HashSet<Integer> result = new HashSet<Integer>();
    Entry entry = createTestEntry(type, values);
    entry.getAttributeValues(type, IntegerSyntax.DECODER, result);
    throw new RuntimeException(
         "An illegal integer value did not throw an exception");
    entry.parseAttribute("supportedldapversion").asSetOfInteger();
  }
  /**
   * Test the
   * {@link Entry#getAttributeValue(AttributeType, AttributeValueDecoder)}
   * method.
   *
   * @throws Exception
   *           If the test failed unexpectedly.
   * Test the {@link Entry#parseAttribute(String)} method.
   */
  @Test
  public void testGetAttributeValuesSubtreeSpecification()
  public void testParseAttributesSubtreeSpecification()
      throws Exception {
    // Define a dummy attribute type, in case there is not one already
    // in the core schema.
@@ -279,15 +249,19 @@
    // Relative to the root DN.
    DN rootDN = DN.rootDN();
    SubtreeSpecificationSet expected = new SubtreeSpecificationSet();
    Set<SubtreeSpecification> expected = new HashSet<SubtreeSpecification>();
    for (String value : values) {
      expected.add(SubtreeSpecification.valueOf(rootDN, value));
    }
    Entry entry = createTestEntry(type, values);
    SubtreeSpecificationSet result = new SubtreeSpecificationSet();
    entry.getAttributeValues(type, SubtreeSpecificationSyntax
        .createAttributeValueDecoder(rootDN), result);
    Set<SubtreeSpecification> result = new HashSet<SubtreeSpecification>();
    List<Attribute> attributes = entry.getAttribute(type, true);
    for (AttributeValue value : new AttributeValueIterable(attributes))
    {
      String v = value.getValue().toString();
      result.add(SubtreeSpecification.valueOf(rootDN, v));
    }
    assertEquals(expected, result);
  }