From 785bdb7fee8930a9d57679c5712f5e8456128a37 Mon Sep 17 00:00:00 2001
From: Jean-Noël Rouvignac <jean-noel.rouvignac@forgerock.com>
Date: Mon, 07 Mar 2016 15:08:55 +0000
Subject: [PATCH] OPENDJ-1342 Migrate AVA, RDN, and DN classes: Removed DN and RDN server classes

---
 /dev/null                                                               |  842 ----------------------------------------------------
 opendj-server-legacy/src/test/java/org/opends/server/types/TestDN.java  |   35 -
 opendj-server-legacy/src/test/java/org/opends/server/types/TestRDN.java |   51 --
 3 files changed, 11 insertions(+), 917 deletions(-)

diff --git a/opendj-server-legacy/src/main/java/org/opends/server/types/DN.java b/opendj-server-legacy/src/main/java/org/opends/server/types/DN.java
deleted file mode 100644
index 9654771..0000000
--- a/opendj-server-legacy/src/main/java/org/opends/server/types/DN.java
+++ /dev/null
@@ -1,2561 +0,0 @@
-/*
- * The contents of this file are subject to the terms of the Common Development and
- * Distribution License (the License). You may not use this file except in compliance with the
- * License.
- *
- * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
- * specific language governing permission and limitations under the License.
- *
- * When distributing Covered Software, include this CDDL Header Notice in each file and include
- * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
- * Header, with the fields enclosed by brackets [] replaced by your own identifying
- * information: "Portions Copyright [year] [name of copyright owner]".
- *
- * Copyright 2006-2009 Sun Microsystems, Inc.
- * Portions Copyright 2012-2016 ForgeRock AS.
- */
-package org.opends.server.types;
-
-import static org.forgerock.util.Reject.*;
-import static org.opends.messages.SchemaMessages.*;
-import static org.opends.server.config.ConfigConstants.*;
-import static org.opends.server.core.DirectoryServer.*;
-import static org.opends.server.util.StaticUtils.*;
-
-import java.io.Serializable;
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.UUID;
-
-import org.forgerock.i18n.LocalizableMessage;
-import org.forgerock.i18n.slf4j.LocalizedLogger;
-import org.forgerock.opendj.ldap.ByteSequence;
-import org.forgerock.opendj.ldap.ByteSequenceReader;
-import org.forgerock.opendj.ldap.ByteString;
-import org.forgerock.opendj.ldap.ByteStringBuilder;
-import org.forgerock.opendj.ldap.ResultCode;
-import org.forgerock.opendj.ldap.SearchScope;
-import org.forgerock.opendj.ldap.schema.AttributeType;
-import org.forgerock.util.Reject;
-import org.opends.server.core.DirectoryServer;
-
-/**
- * This class defines a data structure for storing and interacting
- * with the distinguished names associated with entries in the
- * Directory Server.
- */
-@org.opends.server.types.PublicAPI(
-     stability=org.opends.server.types.StabilityLevel.UNCOMMITTED,
-     mayInstantiate=true,
-     mayExtend=false,
-     mayInvoke=true)
-public final class DN implements Comparable<DN>, Iterable<RDN>, Serializable
-{
-  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
-  /** A singleton instance of the root/null DN (a DN with no components). */
-  private static final DN ROOT_DN = new DN();
-
-  /** RDN separator for normalized byte string of a DN. */
-  public static final byte NORMALIZED_RDN_SEPARATOR = 0x00;
-
-  /** AVA separator for normalized byte string of a DN. */
-  public static final byte NORMALIZED_AVA_SEPARATOR = 0x01;
-
-  /** Escape byte for normalized byte string of a DN. */
-  public static final byte NORMALIZED_ESC_BYTE = 0x02;
-
-  /**
-   * The serial version identifier required to satisfy the compiler
-   * because this class implements the
-   * <CODE>java.io.Serializable</CODE> interface.  This value was
-   * generated using the <CODE>serialver</CODE> command-line utility
-   * included with the Java SDK.
-   */
-  private static final long serialVersionUID = 1184263456768819888L;
-
-  /** The number of RDN components that comprise this DN. */
-  private final int numComponents;
-
-  /**
-   * The set of RDN components that comprise this DN, arranged with the suffix
-   * as the last element.
-   */
-  private final RDN[] rdnComponents;
-
-  /** The string representation of this DN. */
-  private String dnString;
-
-  /**
-   * The normalized byte string representation of this DN, which is not
-   * a valid DN and is not reversible to a valid DN.
-   */
-  private ByteString normalizedDN;
-
-  /**
-   * Creates a new DN with no RDN components (i.e., a null DN or root
-   * DSE).
-   */
-  public DN()
-  {
-    this(new RDN[0]);
-  }
-
-  /**
-   * Creates a new DN with the provided set of RDNs, arranged with the
-   * suffix as the last element.
-   *
-   * @param  rdnComponents  The set of RDN components that make up
-   *                        this DN.
-   */
-  public DN(RDN[] rdnComponents)
-  {
-    if (rdnComponents == null)
-    {
-      this.rdnComponents = new RDN[0];
-    }
-    else
-    {
-      this.rdnComponents = rdnComponents;
-    }
-
-    numComponents = this.rdnComponents.length;
-    dnString      = null;
-    normalizedDN  = null;
-  }
-
-
-
-  /**
-   * Creates a new DN with the provided set of RDNs, arranged with the
-   * suffix as the last element.
-   *
-   * @param  rdnComponents  The set of RDN components that make up
-   *                        this DN.
-   */
-  public DN(List<RDN> rdnComponents)
-  {
-    if (rdnComponents == null || rdnComponents.isEmpty())
-    {
-      this.rdnComponents = new RDN[0];
-    }
-    else
-    {
-      this.rdnComponents = new RDN[rdnComponents.size()];
-      rdnComponents.toArray(this.rdnComponents);
-    }
-
-    numComponents = this.rdnComponents.length;
-    dnString      = null;
-    normalizedDN  = null;
-  }
-
-
-
-  /**
-   * Creates a new DN with the given RDN below the specified parent.
-   *
-   * @param  rdn       The RDN to use for the new DN.  It must not be
-   *                   {@code null}.
-   * @param  parentDN  The DN of the entry below which the new DN
-   *                   should exist. It must not be {@code null}.
-   */
-  public DN(RDN rdn, DN parentDN)
-  {
-    ifNull(rdn, parentDN);
-    if (parentDN.isRootDN())
-    {
-      rdnComponents = new RDN[] { rdn };
-    }
-    else
-    {
-      rdnComponents = new RDN[parentDN.numComponents + 1];
-      rdnComponents[0] = rdn;
-      System.arraycopy(parentDN.rdnComponents, 0, rdnComponents, 1,
-                       parentDN.numComponents);
-    }
-
-    numComponents = this.rdnComponents.length;
-    dnString      = null;
-    normalizedDN  = null;
-  }
-
-
-
-  /**
-   * Retrieves a singleton instance of the null DN.
-   *
-   * @return  A singleton instance of the null DN.
-   */
-  public static DN rootDN()
-  {
-    return ROOT_DN;
-  }
-
-
-
-  /**
-   * Indicates whether this represents a null DN.  This could target
-   * the root DSE for the Directory Server, or the authorization DN
-   * for an anonymous or unauthenticated client.
-   *
-   * @return  <CODE>true</CODE> if this does represent a null DN, or
-   *          <CODE>false</CODE> if it does not.
-   */
-  public boolean isRootDN()
-  {
-    return numComponents == 0;
-  }
-
-
-
-  /**
-   * Retrieves the number of RDN components for this DN.
-   *
-   * @return  The number of RDN components for this DN.
-   */
-  public int size()
-  {
-    return numComponents;
-  }
-
-
-
-  /**
-   * Retrieves the outermost RDN component for this DN (i.e., the one
-   * that is furthest from the suffix).
-   *
-   * @return  The outermost RDN component for this DN, or
-   *          <CODE>null</CODE> if there are no RDN components in the
-   *          DN.
-   */
-  public RDN rdn()
-  {
-    if (numComponents == 0)
-    {
-      return null;
-    }
-    else
-    {
-      return rdnComponents[0];
-    }
-  }
-
-  /**
-   * Returns a copy of this DN whose parent DN, {@code fromDN}, has been renamed
-   * to the new parent DN, {@code toDN}. If this DN is not subordinate or equal
-   * to {@code fromDN} then this DN is returned (i.e. the DN is not renamed).
-   *
-   * @param fromDN
-   *          The old parent DN.
-   * @param toDN
-   *          The new parent DN.
-   * @return The renamed DN, or this DN if no renaming was performed.
-   */
-  public DN rename(final DN fromDN, final DN toDN)
-  {
-    Reject.ifNull(fromDN, toDN);
-
-    if (!isSubordinateOrEqualTo(fromDN))
-    {
-      return this;
-    }
-    else if (equals(fromDN))
-    {
-      return toDN;
-    }
-    else
-    {
-      final int sizeOfRdns = size() - fromDN.size();
-      RDN[] childRdns = new RDN[sizeOfRdns];
-      System.arraycopy(rdnComponents, 0, childRdns, 0, sizeOfRdns);
-      return toDN.concat(childRdns);
-    }
-  }
-
-
-
-  /**
-   * Retrieves the RDN component at the specified position in the set
-   * of components for this DN.
-   *
-   * @param  pos  The position of the RDN component to retrieve.
-   *
-   * @return  The RDN component at the specified position in the set
-   *          of components for this DN.
-   */
-  public RDN rdn(int pos)
-  {
-    return rdnComponents[pos];
-  }
-
-
-
-  /**
-   * Retrieves the DN of the entry that is the immediate parent for
-   * this entry.  Note that this method does not take the server's
-   * naming context configuration into account when making the
-   * determination.
-   *
-   * @return  The DN of the entry that is the immediate parent for
-   *          this entry, or <CODE>null</CODE> if the entry with this
-   *          DN does not have a parent.
-   */
-  public DN parent()
-  {
-    if (numComponents <= 1)
-    {
-      return null;
-    }
-
-    RDN[] parentComponents = new RDN[numComponents-1];
-    System.arraycopy(rdnComponents, 1, parentComponents, 0,
-                     numComponents-1);
-    return new DN(parentComponents);
-  }
-
-
-
-  /**
-   * Creates a new DN that is a child of this DN, using the specified
-   * RDN.
-   *
-   * @param  rdn  The RDN for the child of this DN.
-   *
-   * @return  A new DN that is a child of this DN, using the specified
-   *          RDN.
-   */
-  public DN child(RDN rdn)
-  {
-    RDN[] newComponents = new RDN[rdnComponents.length+1];
-    newComponents[0] = rdn;
-    System.arraycopy(rdnComponents, 0, newComponents, 1,
-                     rdnComponents.length);
-
-    return new DN(newComponents);
-  }
-
-
-
-  /**
-   * Creates a new DN that is a descendant of this DN, using the
-   * specified RDN components.
-   *
-   * @param  rdnComponents  The RDN components for the descendant of
-   *                        this DN.
-   *
-   * @return  A new DN that is a descendant of this DN, using the
-   *          specified RDN components.
-   */
-  private DN concat(RDN[] rdnComponents)
-  {
-    RDN[] newComponents =
-         new RDN[rdnComponents.length+this.rdnComponents.length];
-    System.arraycopy(rdnComponents, 0, newComponents, 0,
-                     rdnComponents.length);
-    System.arraycopy(this.rdnComponents, 0, newComponents,
-                     rdnComponents.length, this.rdnComponents.length);
-
-    return new DN(newComponents);
-  }
-
-
-
-  /**
-   * Creates a new DN that is a descendant of this DN, using the
-   * specified DN as a relative base DN.  That is, the resulting DN
-   * will first have the components of the provided DN followed by the
-   * components of this DN.
-   *
-   * @param  relativeBaseDN  The relative base DN to concatenate onto
-   *                         this DN.
-   *
-   * @return  A new DN that is a descendant of this DN, using the
-   *          specified DN as a relative base DN.
-   */
-  public DN child(DN relativeBaseDN)
-  {
-    RDN[] newComponents =
-               new RDN[rdnComponents.length+
-                       relativeBaseDN.rdnComponents.length];
-
-    System.arraycopy(relativeBaseDN.rdnComponents, 0, newComponents,
-                     0, relativeBaseDN.rdnComponents.length);
-    System.arraycopy(rdnComponents, 0, newComponents,
-                     relativeBaseDN.rdnComponents.length,
-                     rdnComponents.length);
-
-    return new DN(newComponents);
-  }
-
-
-
-  /**
-   * Indicates whether this DN is a descendant of the provided DN
-   * (i.e., that the RDN components of the provided DN are the
-   * same as the last RDN components for this DN).  Note that if
-   * this DN equals the provided DN it is still considered to be
-   * a descendant of the provided DN by this method as both then
-   * reside within the same subtree.
-   *
-   * @param  dn  The DN for which to make the determination.
-   *
-   * @return  <CODE>true</CODE> if this DN is a descendant of the
-   *          provided DN, or <CODE>false</CODE> if not.
-   */
-  public boolean isSubordinateOrEqualTo(DN dn)
-  {
-    int offset = numComponents - dn.numComponents;
-    if (offset < 0)
-    {
-      return false;
-    }
-
-    for (int i=0; i < dn.numComponents; i++)
-    {
-      if (! rdnComponents[i+offset].equals(dn.rdnComponents[i]))
-      {
-        return false;
-      }
-    }
-
-    return true;
-  }
-
-
-
-  /**
-   * Indicates whether this DN is an ancestor of the provided DN
-   * (i.e., that the RDN components of this DN are the same as the
-   * last RDN components for the provided DN).
-   *
-   * @param  dn  The DN for which to make the determination.
-   *
-   * @return  <CODE>true</CODE> if this DN is an ancestor of the
-   *          provided DN, or <CODE>false</CODE> if not.
-   */
-  public boolean isSuperiorOrEqualTo(DN dn)
-  {
-    int offset = dn.numComponents - numComponents;
-    if (offset < 0)
-    {
-      return false;
-    }
-
-    for (int i=0; i < numComponents; i++)
-    {
-      if (! rdnComponents[i].equals(dn.rdnComponents[i+offset]))
-      {
-        return false;
-      }
-    }
-
-    return true;
-  }
-
-
-
-  /**
-   * Indicates whether this entry falls within the range of the
-   * provided search base DN and scope.
-   *
-   * @param  baseDN  The base DN for which to make the determination.
-   * @param  scope   The search scope for which to make the
-   *                 determination.
-   *
-   * @return  <CODE>true</CODE> if this entry is within the given
-   *          base and scope, or <CODE>false</CODE> if it is not.
-   */
-  public boolean isInScopeOf(DN baseDN, SearchScope scope)
-  {
-    switch (scope.asEnum())
-    {
-      case BASE_OBJECT:
-        // The base DN must equal this DN.
-        return equals(baseDN);
-
-      case SINGLE_LEVEL:
-        // The parent DN must equal the base DN.
-        return baseDN.equals(parent());
-
-      case WHOLE_SUBTREE:
-        // This DN must be a descendant of the provided base DN.
-      return isSubordinateOrEqualTo(baseDN);
-
-      case SUBORDINATES:
-        // This DN must be a descendant of the provided base DN, but
-        // not equal to it.
-      return !equals(baseDN) && isSubordinateOrEqualTo(baseDN);
-
-      default:
-        // This is a scope that we don't recognize.
-        return false;
-    }
-  }
-
-  /**
-   * Decodes the provided ASN.1 octet string as a DN.
-   *
-   * @param  dnString  The ASN.1 octet string to decode as a DN.
-   *
-   * @return  The decoded DN.
-   *
-   * @throws  DirectoryException  If a problem occurs while trying to
-   *                              decode the provided ASN.1 octet
-   *                              string as a DN.
-   */
-  public static DN valueOf(ByteSequence dnString)
-         throws DirectoryException
-  {
-    // A null or empty DN is acceptable.
-    if (dnString == null)
-    {
-      return rootDN();
-    }
-
-    int    length  = dnString.length();
-    if (length == 0)
-    {
-      return rootDN();
-    }
-
-
-    // See if we are dealing with any non-ASCII characters, or any
-    // escaped characters.  If so, then the easiest and safest
-    // approach is to convert the DN to a string and decode it that
-    // way.
-    byte b;
-    for (int i = 0; i < length; i++)
-    {
-      b = dnString.byteAt(i);
-      if ((b & 0x7F) != b || b == '\\')
-      {
-        return valueOf(dnString.toString());
-      }
-    }
-
-
-    // Iterate through the DN string.  The first thing to do is to get
-    // rid of any leading spaces.
-    ByteSequenceReader dnReader = dnString.asReader();
-    b = ' ';
-    while (dnReader.remaining() > 0 && (b = dnReader.readByte()) == ' ')
-    {}
-
-    if(b == ' ')
-    {
-      // This means that the DN was completely comprised of spaces
-      // and therefore should be considered the same as a null or
-      // empty DN.
-      return rootDN();
-    }
-
-    dnReader.skip(-1);
-    // We know that it's not an empty DN, so we can do the real
-    // processing.  Create a loop and iterate through all the RDN
-    // components.
-    boolean allowExceptions =
-         DirectoryServer.allowAttributeNameExceptions();
-    LinkedList<RDN> rdnComponents = new LinkedList<>();
-    while (true)
-    {
-      ByteString attributeName =
-          parseAttributeName(dnReader, allowExceptions);
-
-
-      // Make sure that we're not at the end of the DN string because
-      // that would be invalid.
-      if (dnReader.remaining() <= 0)
-      {
-        throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-            ERR_ATTR_SYNTAX_DN_END_WITH_ATTR_NAME.get(dnString, attributeName));
-      }
-
-
-      // Skip over any spaces between the attribute name and its value.
-      b = ' ';
-      while (dnReader.remaining() > 0 && (b = dnReader.readByte()) == ' ')
-      {}
-
-
-      if(b == ' ')
-      {
-        // This means that we hit the end of the value before
-        // finding a '='.  This is illegal because there is no
-        // attribute-value separator.
-        throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-            ERR_ATTR_SYNTAX_DN_END_WITH_ATTR_NAME.get(dnString, attributeName));
-      }
-
-      // The next character must be an equal sign.  If it is not,
-      // then that's an error.
-      if (b != '=')
-      {
-        throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-            ERR_ATTR_SYNTAX_DN_NO_EQUAL.get(dnString, attributeName, (char) b));
-      }
-
-
-      // Skip over any spaces after the equal sign.
-      b = ' ';
-      while (dnReader.remaining() > 0 && (b = dnReader.readByte()) == ' ')
-      {}
-
-
-      // If we are at the end of the DN string, then that must mean
-      // that the attribute value was empty.  This will probably never
-      // happen in a real-world environment, but technically isn't
-      // illegal.  If it does happen, then go ahead and create the RDN
-      // component and return the DN.
-      if (b == ' ')
-      {
-        rdnComponents.add(newRDN(attributeName, ByteString.empty()));
-        return new DN(rdnComponents);
-      }
-
-      dnReader.skip(-1);
-
-      // Parse the value for this RDN component.
-      ByteString parsedValue = parseAttributeValue(dnReader);
-
-
-      // Create the new RDN with the provided information.
-      RDN rdn = newRDN(attributeName, parsedValue);
-
-      // Skip over any spaces that might be after the attribute value.
-      b = ' ';
-      while (dnReader.remaining() > 0 && (b = dnReader.readByte()) == ' ')
-      {}
-
-
-      // Most likely, we will be at either the end of the RDN
-      // component or the end of the DN.  If so, then handle that
-      // appropriately.
-      if (b == ' ')
-      {
-        // We're at the end of the DN string and should have a valid
-        // DN so return it.
-        rdnComponents.add(rdn);
-        return new DN(rdnComponents);
-      }
-      else if (b == ',' || b == ';')
-      {
-        // We're at the end of the RDN component, so add it to the
-        // list, skip over the comma/semicolon, and start on the next
-        // component.
-        rdnComponents.add(rdn);
-        continue;
-      }
-      else if (b != '+')
-      {
-        // This should not happen.  At any rate, it's an illegal
-        // character, so throw an exception.
-        throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-            ERR_ATTR_SYNTAX_DN_INVALID_CHAR.get(
-                dnReader, (char) b, dnReader.position()-1));
-      }
-
-
-      // If we have gotten here, then this must be a multi-valued RDN.
-      // In that case, parse the remaining attribute/value pairs and
-      // add them to the RDN that we've already created.
-      while (true)
-      {
-        // Skip over the plus sign and any spaces that may follow it
-        // before the next attribute name.
-        b = ' ';
-        while (dnReader.remaining() > 0 &&
-            (b = dnReader.readByte()) == ' ')
-        {}
-
-        dnReader.skip(-1);
-        // Parse the attribute name from the DN string.
-        attributeName = parseAttributeName(dnReader, allowExceptions);
-
-
-        // Make sure that we're not at the end of the DN string
-        // because that would be invalid.
-        if (b == ' ')
-        {
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-              ERR_ATTR_SYNTAX_DN_END_WITH_ATTR_NAME.get(dnString, attributeName));
-        }
-
-
-        // Skip over any spaces between the attribute name and its value.
-        b = ' ';
-        while (dnReader.remaining() > 0 &&
-            (b = dnReader.readByte()) == ' ')
-        {}
-
-        if(b == ' ')
-        {
-          // This means that we hit the end of the value before
-          // finding a '='.  This is illegal because there is no
-          // attribute-value separator.
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-              ERR_ATTR_SYNTAX_DN_END_WITH_ATTR_NAME.get(dnString, attributeName));
-        }
-
-
-        // The next character must be an equal sign.  If it is not,
-        // then that's an error.
-        if (b != '=')
-        {
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-              ERR_ATTR_SYNTAX_DN_NO_EQUAL.get(dnString, attributeName, (char) b));
-        }
-
-
-        // Skip over any spaces after the equal sign.
-        b = ' ';
-        while (dnReader.remaining() > 0 &&
-            (b = dnReader.readByte()) == ' ')
-        {}
-
-
-        // If we are at the end of the DN string, then that must mean
-        // that the attribute value was empty.  This will probably
-        // never happen in a real-world environment, but technically
-        // isn't illegal.  If it does happen, then go ahead and create
-        // the RDN component and return the DN.
-        if (b == ' ')
-        {
-          addValue(attributeName, rdn, ByteString.empty());
-          rdnComponents.add(rdn);
-          return new DN(rdnComponents);
-        }
-
-        dnReader.skip(-1);
-
-        // Parse the value for this RDN component.
-        parsedValue = parseAttributeValue(dnReader);
-        addValue(attributeName, rdn, parsedValue);
-
-        // Skip over any spaces that might be after the attribute value.
-        // Skip over any spaces that might be after the attribute value.
-        b = ' ';
-        while (dnReader.remaining() > 0 &&
-            (b = dnReader.readByte()) == ' ')
-        {}
-
-
-        // Most likely, we will be at either the end of the RDN
-        // component or the end of the DN.  If so, then handle that
-        // appropriately.
-        if (b == ' ')
-        {
-          // We're at the end of the DN string and should have a valid
-          // DN so return it.
-          rdnComponents.add(rdn);
-          return new DN(rdnComponents);
-        }
-        else if (b == ',' || b == ';')
-        {
-          // We're at the end of the RDN component, so add it to the
-          // list, skip over the comma/semicolon, and start on the
-          // next component.
-          rdnComponents.add(rdn);
-          break;
-        }
-        else if (b != '+')
-        {
-          // This should not happen.  At any rate, it's an illegal
-          // character, so throw an exception.
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-              ERR_ATTR_SYNTAX_DN_INVALID_CHAR.get(
-                  dnString, (char) b, dnReader.position()-1));
-        }
-      }
-    }
-  }
-
-  private static RDN newRDN(ByteString attrName, ByteString value)
-  {
-    String name = attrName.toString();
-    AttributeType attrType = getAttributeType(name);
-    return new RDN(attrType, name, value);
-  }
-
-  private static void addValue(ByteString attributeName, RDN rdn, ByteString empty)
-  {
-    String name = attributeName.toString();
-    AttributeType attrType = getAttributeType(name);
-    rdn.addValue(attrType, name, empty);
-  }
-
-  /**
-   * Decodes the provided string as a DN.
-   *
-   * @param  dnString  The string to decode as a DN.
-   *
-   * @return  The decoded DN.
-   *
-   * @throws  DirectoryException  If a problem occurs while trying to
-   *                              decode the provided string as a DN.
-   */
-  public static DN valueOf(String dnString)
-         throws DirectoryException
-  {
-    // A null or empty DN is acceptable.
-    if (dnString == null)
-    {
-      return rootDN();
-    }
-
-    int length = dnString.length();
-    if (length == 0)
-    {
-      return rootDN();
-    }
-
-
-    // Iterate through the DN string.  The first thing to do is to get
-    // rid of any leading spaces.
-    int pos = 0;
-    char c = dnString.charAt(pos);
-    while (c == ' ')
-    {
-      pos++;
-      if (pos == length)
-      {
-        // This means that the DN was completely comprised of spaces
-        // and therefore should be considered the same as a null or
-        // empty DN.
-        return rootDN();
-      }
-      else
-      {
-        c = dnString.charAt(pos);
-      }
-    }
-
-
-    // We know that it's not an empty DN, so we can do the real
-    // processing.  Create a loop and iterate through all the RDN
-    // components.
-    boolean allowExceptions =
-         DirectoryServer.allowAttributeNameExceptions();
-    LinkedList<RDN> rdnComponents = new LinkedList<>();
-    while (true)
-    {
-      StringBuilder attributeName = new StringBuilder();
-      pos = parseAttributeName(dnString, pos, attributeName,
-                               allowExceptions);
-
-
-      // Make sure that we're not at the end of the DN string because
-      // that would be invalid.
-      if (pos >= length)
-      {
-        throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-            ERR_ATTR_SYNTAX_DN_END_WITH_ATTR_NAME.get(dnString, attributeName));
-      }
-
-
-      // Skip over any spaces between the attribute name and its value.
-      c = dnString.charAt(pos);
-      while (c == ' ')
-      {
-        pos++;
-        if (pos >= length)
-        {
-          // This means that we hit the end of the value before
-          // finding a '='.  This is illegal because there is no
-          // attribute-value separator.
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-              ERR_ATTR_SYNTAX_DN_END_WITH_ATTR_NAME.get(dnString, attributeName));
-        }
-        c = dnString.charAt(pos);
-      }
-
-
-      // The next character must be an equal sign.  If it is not, then
-      // that's an error.
-      if (c == '=')
-      {
-        pos++;
-      }
-      else
-      {
-        throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-            ERR_ATTR_SYNTAX_DN_NO_EQUAL.get(dnString, attributeName, c));
-      }
-
-
-      // Skip over any spaces after the equal sign.
-      while (pos < length && ((c = dnString.charAt(pos)) == ' '))
-      {
-        pos++;
-      }
-
-
-      // If we are at the end of the DN string, then that must mean
-      // that the attribute value was empty.  This will probably never
-      // happen in a real-world environment, but technically isn't
-      // illegal.  If it does happen, then go ahead and create the
-      // RDN component and return the DN.
-      if (pos >= length)
-      {
-        rdnComponents.add(newRDN(attributeName, ByteString.empty()));
-        return new DN(rdnComponents);
-      }
-
-
-      // Parse the value for this RDN component.
-      ByteStringBuilder parsedValue = new ByteStringBuilder(0);
-      pos = parseAttributeValue(dnString, pos, parsedValue);
-
-
-      // Create the new RDN with the provided information.
-      RDN rdn = newRDN(attributeName, parsedValue.toByteString());
-
-
-      // Skip over any spaces that might be after the attribute value.
-      while (pos < length && ((c = dnString.charAt(pos)) == ' '))
-      {
-        pos++;
-      }
-
-
-      // Most likely, we will be at either the end of the RDN
-      // component or the end of the DN.  If so, then handle that
-      // appropriately.
-      if (pos >= length)
-      {
-        // We're at the end of the DN string and should have a valid
-        // DN so return it.
-        rdnComponents.add(rdn);
-        return new DN(rdnComponents);
-      }
-      else if (c == ',' || c == ';')
-      {
-        // We're at the end of the RDN component, so add it to the
-        // list, skip over the comma/semicolon, and start on the next
-        // component.
-        rdnComponents.add(rdn);
-        pos++;
-        continue;
-      }
-      else if (c != '+')
-      {
-        // This should not happen.  At any rate, it's an illegal
-        // character, so throw an exception.
-        LocalizableMessage message =
-            ERR_ATTR_SYNTAX_DN_INVALID_CHAR.get(dnString, c, pos);
-        throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                     message);
-      }
-
-
-      // If we have gotten here, then this must be a multi-valued RDN.
-      // In that case, parse the remaining attribute/value pairs and
-      // add them to the RDN that we've already created.
-      while (true)
-      {
-        // Skip over the plus sign and any spaces that may follow it
-        // before the next attribute name.
-        pos++;
-        while (pos < length && dnString.charAt(pos) == ' ')
-        {
-          pos++;
-        }
-
-
-        // Parse the attribute name from the DN string.
-        attributeName = new StringBuilder();
-        pos = parseAttributeName(dnString, pos, attributeName,
-                                 allowExceptions);
-
-
-        // Make sure that we're not at the end of the DN string
-        // because that would be invalid.
-        if (pos >= length)
-        {
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-              ERR_ATTR_SYNTAX_DN_END_WITH_ATTR_NAME.get(dnString, attributeName));
-        }
-
-
-        // Skip over any spaces between the attribute name and its value.
-        c = dnString.charAt(pos);
-        while (c == ' ')
-        {
-          pos++;
-          if (pos >= length)
-          {
-            // This means that we hit the end of the value before
-            // finding a '='.  This is illegal because there is no
-            // attribute-value separator.
-            throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                ERR_ATTR_SYNTAX_DN_END_WITH_ATTR_NAME.get(dnString, attributeName));
-          }
-          c = dnString.charAt(pos);
-        }
-
-
-        // The next character must be an equal sign.  If it is not,
-        // then that's an error.
-        if (c == '=')
-        {
-          pos++;
-        }
-        else
-        {
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-              ERR_ATTR_SYNTAX_DN_NO_EQUAL.get(dnString, attributeName, c));
-        }
-
-
-        // Skip over any spaces after the equal sign.
-        while (pos < length && ((c = dnString.charAt(pos)) == ' '))
-        {
-          pos++;
-        }
-
-
-        // If we are at the end of the DN string, then that must mean
-        // that the attribute value was empty.  This will probably
-        // never happen in a real-world environment, but technically
-        // isn't illegal.  If it does happen, then go ahead and create
-        // the RDN component and return the DN.
-        if (pos >= length)
-        {
-          addValue(attributeName, rdn, ByteString.empty());
-          rdnComponents.add(rdn);
-          return new DN(rdnComponents);
-        }
-
-
-        // Parse the value for this RDN component.
-        parsedValue.clear();
-        pos = parseAttributeValue(dnString, pos, parsedValue);
-        addValue(attributeName, rdn, parsedValue.toByteString());
-
-
-        // Skip over any spaces that might be after the attribute value.
-        while (pos < length && ((c = dnString.charAt(pos)) == ' '))
-        {
-          pos++;
-        }
-
-
-        // Most likely, we will be at either the end of the RDN
-        // component or the end of the DN.  If so, then handle that
-        // appropriately.
-        if (pos >= length)
-        {
-          // We're at the end of the DN string and should have a valid
-          // DN so return it.
-          rdnComponents.add(rdn);
-          return new DN(rdnComponents);
-        }
-        else if (c == ',' || c == ';')
-        {
-          // We're at the end of the RDN component, so add it to the
-          // list, skip over the comma/semicolon, and start on the
-          // next component.
-          rdnComponents.add(rdn);
-          pos++;
-          break;
-        }
-        else if (c != '+')
-        {
-          // This should not happen.  At any rate, it's an illegal
-          // character, so throw an exception.
-          LocalizableMessage message =
-              ERR_ATTR_SYNTAX_DN_INVALID_CHAR.get(dnString, c, pos);
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                       message);
-        }
-      }
-    }
-  }
-
-  private static RDN newRDN(StringBuilder attributeName, ByteString value)
-  {
-    String name = attributeName.toString();
-    AttributeType attrType = getAttributeType(name);
-    return new RDN(attrType, name, value);
-  }
-
-  private static void addValue(StringBuilder attributeName, RDN rdn, ByteString empty)
-  {
-    String name = attributeName.toString();
-    AttributeType attrType = getAttributeType(name);
-    rdn.addValue(attrType, name, empty);
-  }
-
-  /**
-   * Parses an attribute name from the provided DN string starting at
-   * the specified location.
-   *
-   * @param  dnBytes          The byte array containing the DN to
-   *                          parse.
-   * @param  allowExceptions  Indicates whether to allow certain
-   *                          exceptions to the strict requirements
-   *                          for attribute names.
-   *
-   * @return  The parsed attribute name.
-   *
-   * @throws  DirectoryException  If it was not possible to parse a
-   *                              valid attribute name from the
-   *                              provided DN string.
-   */
-  static ByteString parseAttributeName(ByteSequenceReader dnBytes,
-                                boolean allowExceptions)
-          throws DirectoryException
-  {
-    // Skip over any leading spaces.
-    while(dnBytes.remaining() > 0 && dnBytes.readByte() == ' ')
-    {}
-
-    if(dnBytes.remaining() <= 0)
-    {
-      // This means that the remainder of the DN was completely
-      // comprised of spaces.  If we have gotten here, then we
-      // know that there is at least one RDN component, and
-      // therefore the last non-space character of the DN must
-      // have been a comma. This is not acceptable.
-      throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-          ERR_ATTR_SYNTAX_DN_END_WITH_COMMA.get(dnBytes));
-    }
-
-    dnBytes.skip(-1);
-    int nameStartPos = dnBytes.position();
-    ByteString nameBytes = null;
-
-    // Next, we should find the attribute name for this RDN component.
-    // It may either be a name (with only letters, digits, and dashes
-    // and starting with a letter) or an OID (with only digits and
-    // periods, optionally prefixed with "oid."), and there is also a
-    // special case in which we will allow underscores.  Because of
-    // the complexity involved, read the entire name first with
-    // minimal validation and then do more thorough validation later.
-    boolean       checkForOID   = false;
-    boolean       endOfName     = false;
-    while (dnBytes.remaining() > 0)
-    {
-      // To make the switch more efficient, we'll include all ASCII
-      // characters in the range of allowed values and then reject the
-      // ones that aren't allowed.
-      byte b = dnBytes.readByte();
-      switch (b)
-      {
-        case ' ':
-          // This should denote the end of the attribute name.
-          endOfName = true;
-          break;
-
-
-        case '!':
-        case '"':
-        case '#':
-        case '$':
-        case '%':
-        case '&':
-        case '\'':
-        case '(':
-        case ')':
-        case '*':
-        case '+':
-        case ',':
-          // None of these are allowed in an attribute name or any
-          // character immediately following it.
-        throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX, invalidChar(dnBytes, b));
-
-
-        case '-':
-          // This will be allowed as long as it isn't the first
-          // character in the attribute name.
-          if (dnBytes.position() == nameStartPos + 1)
-          {
-            throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_INITIAL_DASH.get(dnBytes));
-          }
-          break;
-
-
-        case '.':
-          // The period could be allowed if the attribute name is
-          // actually expressed as an OID.  We'll accept it for now,
-          // but make sure to check it later.
-          checkForOID = true;
-          break;
-
-
-        case '/':
-          // This is not allowed in an attribute name or any character
-          // immediately following it.
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX, invalidChar(dnBytes, b));
-
-
-        case '0':
-        case '1':
-        case '2':
-        case '3':
-        case '4':
-        case '5':
-        case '6':
-        case '7':
-        case '8':
-        case '9':
-          // Digits are always allowed if they are not the first
-          // character.  However, they may be allowed if they are the
-          // first character if the valid is an OID or if the
-          // attribute name exceptions option is enabled.  Therefore,
-          // we'll accept it now and check it later.
-          break;
-
-
-        case ':':
-        case ';': // NOTE:  attribute options are not allowed in a DN.
-        case '<':
-          // None of these are allowed in an attribute name or any
-          // character immediately following it.
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX, invalidChar(dnBytes, b));
-
-
-        case '=':
-          // This should denote the end of the attribute name.
-          endOfName = true;
-          break;
-
-
-        case '>':
-        case '?':
-        case '@':
-          // None of these are allowed in an attribute name or any
-          // character immediately following it.
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX, invalidChar(dnBytes, b));
-
-
-        case 'A':
-        case 'B':
-        case 'C':
-        case 'D':
-        case 'E':
-        case 'F':
-        case 'G':
-        case 'H':
-        case 'I':
-        case 'J':
-        case 'K':
-        case 'L':
-        case 'M':
-        case 'N':
-        case 'O':
-        case 'P':
-        case 'Q':
-        case 'R':
-        case 'S':
-        case 'T':
-        case 'U':
-        case 'V':
-        case 'W':
-        case 'X':
-        case 'Y':
-        case 'Z':
-          // These will always be allowed.
-          break;
-
-
-        case '[':
-        case '\\':
-        case ']':
-        case '^':
-          // None of these are allowed in an attribute name or any
-          // character immediately following it.
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX, invalidChar(dnBytes, b));
-
-
-        case '_':
-          // This will never be allowed as the first character.  It
-          // may be allowed for subsequent characters if the attribute
-          // name exceptions option is enabled.
-          if (dnBytes.position() == nameStartPos + 1)
-          {
-            throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_INITIAL_UNDERSCORE.get(
-                    dnBytes, ATTR_ALLOW_ATTRIBUTE_NAME_EXCEPTIONS));
-          }
-          else if (!allowExceptions)
-          {
-            throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_UNDERSCORE_CHAR.get(
-                    dnBytes, ATTR_ALLOW_ATTRIBUTE_NAME_EXCEPTIONS));
-          }
-          break;
-
-
-        case '`':
-          // This is not allowed in an attribute name or any character
-          // immediately following it.
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX, invalidChar(dnBytes, b));
-
-
-        case 'a':
-        case 'b':
-        case 'c':
-        case 'd':
-        case 'e':
-        case 'f':
-        case 'g':
-        case 'h':
-        case 'i':
-        case 'j':
-        case 'k':
-        case 'l':
-        case 'm':
-        case 'n':
-        case 'o':
-        case 'p':
-        case 'q':
-        case 'r':
-        case 's':
-        case 't':
-        case 'u':
-        case 'v':
-        case 'w':
-        case 'x':
-        case 'y':
-        case 'z':
-          // These will always be allowed.
-          break;
-
-
-        default:
-          // This is not allowed in an attribute name or any character
-          // immediately following it.
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX, invalidChar(dnBytes, b));
-      }
-
-
-      if (endOfName)
-      {
-        int nameEndPos = dnBytes.position() - 1;
-        dnBytes.position(nameStartPos);
-        nameBytes = dnBytes.readByteString(nameEndPos - nameStartPos);
-        break;
-      }
-    }
-
-
-    // We should now have the full attribute name.  However, we may
-    // still need to perform some validation, particularly if the name
-    // contains a period or starts with a digit.  It must also have at
-    // least one character.
-    if (nameBytes == null || nameBytes.length() == 0)
-    {
-      LocalizableMessage message = ERR_ATTR_SYNTAX_DN_ATTR_NO_NAME.get(dnBytes);
-      throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX, message);
-    }
-    else if (checkForOID)
-    {
-      boolean validOID = true;
-
-      int namePos = 0;
-      int nameLength = nameBytes.length();
-      byte ch0 = nameBytes.byteAt(0);
-      if (ch0 == 'o' || ch0 == 'O')
-      {
-        if (nameLength <= 4)
-        {
-          validOID = false;
-        }
-        else
-        {
-          byte ch1 = nameBytes.byteAt(1);
-          byte ch2 = nameBytes.byteAt(2);
-          if ((ch1 == 'i' || ch1 == 'I')
-              && (ch2 == 'd' || ch2 == 'D')
-              && nameBytes.byteAt(3) == '.')
-          {
-            nameBytes = nameBytes.subSequence(4, nameBytes.length());
-            nameLength -= 4;
-          }
-          else
-          {
-            validOID = false;
-          }
-        }
-      }
-
-      while (validOID && namePos < nameLength)
-      {
-        byte ch = nameBytes.byteAt(namePos++);
-        if (isDigit((char)ch))
-        {
-          while (validOID && namePos < nameLength &&
-                 isDigit((char)nameBytes.byteAt(namePos)))
-          {
-            namePos++;
-          }
-
-          if (namePos < nameLength && nameBytes.byteAt(namePos) != '.')
-          {
-            validOID = false;
-          }
-        }
-        else if (ch == '.')
-        {
-          if (namePos == 1 || nameBytes.byteAt(namePos-2) == '.')
-          {
-            validOID = false;
-          }
-        }
-        else
-        {
-          validOID = false;
-        }
-      }
-
-
-      if (validOID && nameBytes.byteAt(nameLength-1) == '.')
-      {
-        validOID = false;
-      }
-
-
-      if (!validOID)
-      {
-        throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-            ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_PERIOD.get(dnBytes, nameBytes));
-      }
-    }
-    else if (isDigit((char)nameBytes.byteAt(0)) && !allowExceptions)
-    {
-      LocalizableMessage message = ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_INITIAL_DIGIT.
-          get(dnBytes, (char)nameBytes.byteAt(0),
-              ATTR_ALLOW_ATTRIBUTE_NAME_EXCEPTIONS);
-      throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX, message);
-    }
-
-    return nameBytes;
-  }
-
-  private static LocalizableMessage invalidChar(ByteSequenceReader dnBytes, byte b)
-  {
-    return ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_CHAR.get(
-        dnBytes, (char) b, dnBytes.position()-1);
-  }
-
-
-  /**
-   * Parses an attribute name from the provided DN string starting at
-   * the specified location.
-   *
-   * @param  dnString         The DN string to be parsed.
-   * @param  pos              The position at which to start parsing
-   *                          the attribute name.
-   * @param  attributeName    The buffer to which to append the parsed
-   *                          attribute name.
-   * @param  allowExceptions  Indicates whether to allow certain
-   *                          exceptions to the strict requirements
-   *                          for attribute names.
-   *
-   * @return  The position of the first character that is not part of
-   *          the attribute name.
-   *
-   * @throws  DirectoryException  If it was not possible to parse a
-   *                              valid attribute name from the
-   *                              provided DN string.
-   */
-  static int parseAttributeName(String dnString, int pos,
-                                StringBuilder attributeName,
-                                boolean allowExceptions)
-          throws DirectoryException
-  {
-    int length = dnString.length();
-
-
-    // Skip over any leading spaces.
-    if (pos < length)
-    {
-      while (dnString.charAt(pos) == ' ')
-      {
-        pos++;
-        if (pos == length)
-        {
-          // This means that the remainder of the DN was completely
-          // comprised of spaces.  If we have gotten here, then we
-          // know that there is at least one RDN component, and
-          // therefore the last non-space character of the DN must
-          // have been a comma. This is not acceptable.
-          LocalizableMessage message =
-              ERR_ATTR_SYNTAX_DN_END_WITH_COMMA.get(dnString);
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                       message);
-        }
-      }
-    }
-
-    // Next, we should find the attribute name for this RDN component.
-    // It may either be a name (with only letters, digits, and dashes
-    // and starting with a letter) or an OID (with only digits and
-    // periods, optionally prefixed with "oid."), and there is also a
-    // special case in which we will allow underscores.  Because of
-    // the complexity involved, read the entire name first with
-    // minimal validation and then do more thorough validation later.
-    boolean       checkForOID   = false;
-    boolean       endOfName     = false;
-    while (pos < length)
-    {
-      // To make the switch more efficient, we'll include all ASCII
-      // characters in the range of allowed values and then reject the
-      // ones that aren't allowed.
-      char c = dnString.charAt(pos);
-      switch (c)
-      {
-        case ' ':
-          // This should denote the end of the attribute name.
-          endOfName = true;
-          break;
-
-
-        case '!':
-        case '"':
-        case '#':
-        case '$':
-        case '%':
-        case '&':
-        case '\'':
-        case '(':
-        case ')':
-        case '*':
-        case '+':
-        case ',':
-          // None of these are allowed in an attribute name or any
-          // character immediately following it.
-          LocalizableMessage message = ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_CHAR.get(
-              dnString, c, pos);
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                       message);
-
-
-        case '-':
-          // This will be allowed as long as it isn't the first
-          // character in the attribute name.
-          if (attributeName.length() > 0)
-          {
-            attributeName.append(c);
-          }
-          else
-          {
-            message = ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_INITIAL_DASH.
-                  get(dnString);
-            throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                         message);
-          }
-          break;
-
-
-        case '.':
-          // The period could be allowed if the attribute name is
-          // actually expressed as an OID.  We'll accept it for now,
-          // but make sure to check it later.
-          attributeName.append(c);
-          checkForOID = true;
-          break;
-
-
-        case '/':
-          // This is not allowed in an attribute name or any character
-          // immediately following it.
-          message = ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_CHAR.get(
-              dnString, c, pos);
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                       message);
-
-
-        case '0':
-        case '1':
-        case '2':
-        case '3':
-        case '4':
-        case '5':
-        case '6':
-        case '7':
-        case '8':
-        case '9':
-          // Digits are always allowed if they are not the first
-          // character. However, they may be allowed if they are the
-          // first character if the valid is an OID or if the
-          // attribute name exceptions option is enabled.  Therefore,
-          // we'll accept it now and check it later.
-          attributeName.append(c);
-          break;
-
-
-        case ':':
-        case ';': // NOTE:  attribute options are not allowed in a DN.
-        case '<':
-          // None of these are allowed in an attribute name or any
-          // character immediately following it.
-          message = ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_CHAR.get(
-              dnString, c, pos);
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                       message);
-
-
-        case '=':
-          // This should denote the end of the attribute name.
-          endOfName = true;
-          break;
-
-
-        case '>':
-        case '?':
-        case '@':
-          // None of these are allowed in an attribute name or any
-          // character immediately following it.
-          message = ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_CHAR.get(
-              dnString, c, pos);
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                       message);
-
-
-        case 'A':
-        case 'B':
-        case 'C':
-        case 'D':
-        case 'E':
-        case 'F':
-        case 'G':
-        case 'H':
-        case 'I':
-        case 'J':
-        case 'K':
-        case 'L':
-        case 'M':
-        case 'N':
-        case 'O':
-        case 'P':
-        case 'Q':
-        case 'R':
-        case 'S':
-        case 'T':
-        case 'U':
-        case 'V':
-        case 'W':
-        case 'X':
-        case 'Y':
-        case 'Z':
-          // These will always be allowed.
-          attributeName.append(c);
-          break;
-
-
-        case '[':
-        case '\\':
-        case ']':
-        case '^':
-          // None of these are allowed in an attribute name or any
-          // character immediately following it.
-          message = ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_CHAR.get(
-              dnString, c, pos);
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                       message);
-
-
-        case '_':
-          // This will never be allowed as the first character.  It
-          // may be allowed for subsequent characters if the attribute
-          // name exceptions option is enabled.
-          if (attributeName.length() == 0)
-          {
-            message =
-                   ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_INITIAL_UNDERSCORE.
-                  get(dnString, ATTR_ALLOW_ATTRIBUTE_NAME_EXCEPTIONS);
-            throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                         message);
-          }
-          else if (allowExceptions)
-          {
-            attributeName.append(c);
-          }
-          else
-          {
-            message = ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_UNDERSCORE_CHAR.
-                  get(dnString, ATTR_ALLOW_ATTRIBUTE_NAME_EXCEPTIONS);
-            throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                         message);
-          }
-          break;
-
-
-        case '`':
-          // This is not allowed in an attribute name or any character
-          // immediately following it.
-          message = ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_CHAR.get(
-              dnString, c, pos);
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                       message);
-
-
-        case 'a':
-        case 'b':
-        case 'c':
-        case 'd':
-        case 'e':
-        case 'f':
-        case 'g':
-        case 'h':
-        case 'i':
-        case 'j':
-        case 'k':
-        case 'l':
-        case 'm':
-        case 'n':
-        case 'o':
-        case 'p':
-        case 'q':
-        case 'r':
-        case 's':
-        case 't':
-        case 'u':
-        case 'v':
-        case 'w':
-        case 'x':
-        case 'y':
-        case 'z':
-          // These will always be allowed.
-          attributeName.append(c);
-          break;
-
-
-        default:
-          // This is not allowed in an attribute name or any character
-          // immediately following it.
-          message = ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_CHAR.get(
-              dnString, c, pos);
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                       message);
-      }
-
-
-      if (endOfName)
-      {
-        break;
-      }
-
-      pos++;
-    }
-
-
-    // We should now have the full attribute name.  However, we may
-    // still need to perform some validation, particularly if the
-    // name contains a period or starts with a digit.  It must also
-    // have at least one character.
-    if (attributeName.length() == 0)
-    {
-      LocalizableMessage message = ERR_ATTR_SYNTAX_DN_ATTR_NO_NAME.get(dnString);
-      throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                   message);
-    }
-    else if (checkForOID)
-    {
-      boolean validOID = true;
-
-      int namePos = 0;
-      int nameLength = attributeName.length();
-      char ch0 = attributeName.charAt(0);
-      if (ch0 == 'o' || ch0 == 'O')
-      {
-        if (nameLength <= 4)
-        {
-          validOID = false;
-        }
-        else
-        {
-          char ch1 = attributeName.charAt(1);
-          char ch2 = attributeName.charAt(2);
-          if ((ch1 == 'i' || ch1 == 'I')
-              && (ch2 == 'd' || ch2 == 'D')
-              && attributeName.charAt(3) == '.')
-          {
-            attributeName.delete(0, 4);
-            nameLength -= 4;
-          }
-          else
-          {
-            validOID = false;
-          }
-        }
-      }
-
-      while (validOID && namePos < nameLength)
-      {
-        char ch = attributeName.charAt(namePos++);
-        if (isDigit(ch))
-        {
-          while (validOID && namePos < nameLength &&
-                 isDigit(attributeName.charAt(namePos)))
-          {
-            namePos++;
-          }
-
-          if (namePos < nameLength && attributeName.charAt(namePos) != '.')
-          {
-            validOID = false;
-          }
-        }
-        else if (ch == '.')
-        {
-          if (namePos == 1 || attributeName.charAt(namePos-2) == '.')
-          {
-            validOID = false;
-          }
-        }
-        else
-        {
-          validOID = false;
-        }
-      }
-
-
-      if (validOID && attributeName.charAt(nameLength-1) == '.')
-      {
-        validOID = false;
-      }
-
-      if (! validOID)
-      {
-        throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-            ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_PERIOD.get(dnString, attributeName));
-      }
-    }
-    else if (isDigit(attributeName.charAt(0)) && !allowExceptions)
-    {
-      LocalizableMessage message = ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_INITIAL_DIGIT.
-          get(dnString, attributeName.charAt(0),
-              ATTR_ALLOW_ATTRIBUTE_NAME_EXCEPTIONS);
-      throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX, message);
-    }
-
-    return pos;
-  }
-
-
-
-  /**
-   * Parses the attribute value from the provided DN string starting
-   * at the specified location.  When the value has been parsed, it
-   * will be assigned to the provided ASN.1 octet string.
-   *
-   * @param  dnBytes         The byte array containing the DN to be
-   *                         parsed.
-   *
-   * @return  The parsed attribute value.
-   *
-   * @throws  DirectoryException  If it was not possible to parse a
-   *                              valid attribute value from the
-   *                              provided DN string.
-   */
-  static ByteString parseAttributeValue(ByteSequenceReader dnBytes)
-          throws DirectoryException
-  {
-    // All leading spaces have already been stripped so we can start
-    // reading the value.  However, it may be empty so check for that.
-    if (dnBytes.remaining() <= 0)
-    {
-      return ByteString.empty();
-    }
-
-
-    // Look at the first character.  If it is an octothorpe (#), then
-    // that means that the value should be a hex string.
-    byte b = dnBytes.readByte();
-    if (b == '#')
-    {
-      // The first two characters must be hex characters.
-      StringBuilder hexString = new StringBuilder();
-      if (dnBytes.remaining() < 2)
-      {
-        throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-            ERR_ATTR_SYNTAX_DN_HEX_VALUE_TOO_SHORT.get(dnBytes));
-      }
-
-      for (int i=0; i < 2; i++)
-      {
-        b = dnBytes.readByte();
-        if (isHexDigit(b))
-        {
-          hexString.append((char) b);
-        }
-        else
-        {
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-              ERR_ATTR_SYNTAX_DN_INVALID_HEX_DIGIT.get(dnBytes, (char) b));
-        }
-      }
-
-
-      // The rest of the value must be a multiple of two hex
-      // characters.  The end of the value may be designated by the
-      // end of the DN, a comma or semicolon, a plus sign, or a space.
-      while (dnBytes.remaining() > 0)
-      {
-        b = dnBytes.readByte();
-        if (isHexDigit(b))
-        {
-          hexString.append((char) b);
-
-          if (dnBytes.remaining() > 0)
-          {
-            b = dnBytes.readByte();
-            if (isHexDigit(b))
-            {
-              hexString.append((char) b);
-            }
-            else
-            {
-              throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                  ERR_ATTR_SYNTAX_DN_INVALID_HEX_DIGIT.get(dnBytes, (char) b));
-            }
-          }
-          else
-          {
-            throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                ERR_ATTR_SYNTAX_DN_HEX_VALUE_TOO_SHORT.get(dnBytes));
-          }
-        }
-        else if (b == ' ' || b == ',' || b == ';' || b == '+')
-        {
-          // This denotes the end of the value.
-          dnBytes.skip(-1);
-          break;
-        }
-        else
-        {
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-              ERR_ATTR_SYNTAX_DN_INVALID_HEX_DIGIT.get(dnBytes, (char) b));
-        }
-      }
-
-
-      // At this point, we should have a valid hex string.  Convert it
-      // to a byte array and set that as the value of the provided
-      // octet string.
-      try
-      {
-        return ByteString.wrap(hexStringToByteArray(hexString.toString()));
-      }
-      catch (Exception e)
-      {
-        logger.traceException(e);
-
-        throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-            ERR_ATTR_SYNTAX_DN_ATTR_VALUE_DECODE_FAILURE.get(dnBytes, e));
-      }
-    }
-
-
-    // If the first character is a quotation mark, then the value
-    // should continue until the corresponding closing quotation mark.
-    else if (b == '"')
-    {
-      int valueStartPos = dnBytes.position();
-
-      // Keep reading until we find a closing quotation mark.
-      while (true)
-      {
-        if (dnBytes.remaining() <= 0)
-        {
-          // We hit the end of the DN before the closing quote.
-          // That's an error.
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-              ERR_ATTR_SYNTAX_DN_UNMATCHED_QUOTE.get(dnBytes));
-        }
-
-        if (dnBytes.readByte() == '"')
-        {
-          // This is the end of the value.
-          break;
-        }
-      }
-
-      int valueEndPos = dnBytes.position();
-      dnBytes.position(valueStartPos);
-      ByteString bs = dnBytes.readByteString(valueEndPos - valueStartPos - 1);
-      dnBytes.skip(1);
-      return bs;
-    }
-
-    else if(b == '+' || b == ',')
-    {
-      //We don't allow an empty attribute value. So do not allow the
-      // first character to be a '+' or ',' since it is not escaped
-      // by the user.
-      throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-          ERR_ATTR_SYNTAX_DN_INVALID_REQUIRES_ESCAPE_CHAR.get(dnBytes, dnBytes.position()));
-    }
-
-    // Otherwise, use general parsing to find the end of the value.
-    else
-    {
-      // Keep reading until we find a comma/semicolon, a plus sign, or
-      // the end of the DN.
-      int valueEndPos = dnBytes.position();
-      int valueStartPos = valueEndPos - 1;
-      while (true)
-      {
-        if (dnBytes.remaining() <= 0)
-        {
-          // This is the end of the DN and therefore the end of the value.
-          break;
-        }
-
-        b = dnBytes.readByte();
-        if (b == ',' || b == ';' || b == '+')
-        {
-          dnBytes.skip(-1);
-          break;
-        }
-
-        if(b != ' ')
-        {
-          valueEndPos = dnBytes.position();
-        }
-      }
-
-
-      // Convert the byte buffer to an array.
-      dnBytes.position(valueStartPos);
-      return dnBytes.readByteString(valueEndPos - valueStartPos);
-    }
-  }
-
-
-
-  /**
-   * Parses the attribute value from the provided DN string starting
-   * at the specified location.  When the value has been parsed, it
-   * will be assigned to the provided ASN.1 octet string.
-   *
-   * @param  dnString        The DN string to be parsed.
-   * @param  pos             The position of the first character in
-   *                         the attribute value to parse.
-   * @param  attributeValue  The ASN.1 octet string whose value should
-   *                         be set to the parsed attribute value when
-   *                         this method completes successfully.
-   *
-   * @return  The position of the first character that is not part of
-   *          the attribute value.
-   *
-   * @throws  DirectoryException  If it was not possible to parse a
-   *                              valid attribute value from the
-   *                              provided DN string.
-   */
-  static int parseAttributeValue(String dnString, int pos,
-                                 ByteStringBuilder attributeValue)
-          throws DirectoryException
-  {
-    // All leading spaces have already been stripped so we can start
-    // reading the value.  However, it may be empty so check for that.
-    int length = dnString.length();
-    if (pos >= length)
-    {
-      attributeValue.appendUtf8("");
-      return pos;
-    }
-
-
-    // Look at the first character.  If it is an octothorpe (#), then
-    // that means that the value should be a hex string.
-    char c = dnString.charAt(pos++);
-    if (c == '#')
-    {
-      // The first two characters must be hex characters.
-      StringBuilder hexString = new StringBuilder();
-      if (pos+2 > length)
-      {
-        LocalizableMessage message =
-            ERR_ATTR_SYNTAX_DN_HEX_VALUE_TOO_SHORT.get(dnString);
-        throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                     message);
-      }
-
-      for (int i=0; i < 2; i++)
-      {
-        c = dnString.charAt(pos++);
-        if (isHexDigit(c))
-        {
-          hexString.append(c);
-        }
-        else
-        {
-          LocalizableMessage message =
-              ERR_ATTR_SYNTAX_DN_INVALID_HEX_DIGIT.get(dnString, c);
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                       message);
-        }
-      }
-
-
-      // The rest of the value must be a multiple of two hex
-      // characters.  The end of the value may be designated by the
-      // end of the DN, a comma or semicolon, or a space.
-      while (pos < length)
-      {
-        c = dnString.charAt(pos++);
-        if (isHexDigit(c))
-        {
-          hexString.append(c);
-
-          if (pos < length)
-          {
-            c = dnString.charAt(pos++);
-            if (isHexDigit(c))
-            {
-              hexString.append(c);
-            }
-            else
-            {
-              LocalizableMessage message = ERR_ATTR_SYNTAX_DN_INVALID_HEX_DIGIT.
-                  get(dnString, c);
-              throw new DirectoryException(
-                             ResultCode.INVALID_DN_SYNTAX, message);
-            }
-          }
-          else
-          {
-            LocalizableMessage message =
-                ERR_ATTR_SYNTAX_DN_HEX_VALUE_TOO_SHORT.get(dnString);
-            throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                         message);
-          }
-        }
-        else if (c == ' ' || c == ',' || c == ';')
-        {
-          // This denotes the end of the value.
-          pos--;
-          break;
-        }
-        else
-        {
-          LocalizableMessage message =
-              ERR_ATTR_SYNTAX_DN_INVALID_HEX_DIGIT.get(dnString, c);
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                       message);
-        }
-      }
-
-
-      // At this point, we should have a valid hex string.  Convert it
-      // to a byte array and set that as the value of the provided
-      // octet string.
-      try
-      {
-        attributeValue.appendBytes(hexStringToByteArray(hexString.toString()));
-        return pos;
-      }
-      catch (Exception e)
-      {
-        logger.traceException(e);
-
-        throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-            ERR_ATTR_SYNTAX_DN_ATTR_VALUE_DECODE_FAILURE.get(dnString, e));
-      }
-    }
-
-
-    // If the first character is a quotation mark, then the value
-    // should continue until the corresponding closing quotation mark.
-    else if (c == '"')
-    {
-      // Keep reading until we find an unescaped closing quotation mark.
-      boolean escaped = false;
-      StringBuilder valueString = new StringBuilder();
-      while (true)
-      {
-        if (pos >= length)
-        {
-          // We hit the end of the DN before the closing quote.
-          // That's an error.
-          LocalizableMessage message =
-              ERR_ATTR_SYNTAX_DN_UNMATCHED_QUOTE.get(dnString);
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                       message);
-        }
-
-        c = dnString.charAt(pos++);
-        if (escaped)
-        {
-          // The previous character was an escape, so we'll take this
-          // one no matter what.
-          valueString.append(c);
-          escaped = false;
-        }
-        else if (c == '\\')
-        {
-          // The next character is escaped.  Set a flag to denote
-          // this, but don't include the backslash.
-          escaped = true;
-        }
-        else if (c == '"')
-        {
-          // This is the end of the value.
-          break;
-        }
-        else
-        {
-          // This is just a regular character that should be in the value.
-          valueString.append(c);
-        }
-      }
-
-      attributeValue.appendUtf8(valueString.toString());
-      return pos;
-    }
-    else if(c == '+' || c == ',')
-    {
-      //We don't allow an empty attribute value. So do not allow the
-      // first character to be a '+' or ',' since it is not escaped
-      // by the user.
-      LocalizableMessage message =
-             ERR_ATTR_SYNTAX_DN_INVALID_REQUIRES_ESCAPE_CHAR.get(
-                      dnString,pos);
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                       message);
-    }
-
-
-    // Otherwise, use general parsing to find the end of the value.
-    else
-    {
-      boolean escaped;
-      StringBuilder valueString = new StringBuilder();
-      StringBuilder hexChars    = new StringBuilder();
-
-      if (c == '\\')
-      {
-        escaped = true;
-      }
-      else
-      {
-        escaped = false;
-        valueString.append(c);
-      }
-
-
-      // Keep reading until we find an unescaped comma or plus sign or
-      // the end of the DN.
-      while (true)
-      {
-        if (pos >= length)
-        {
-          // This is the end of the DN and therefore the end of the
-          // value.  If there are any hex characters, then we need to
-          // deal with them accordingly.
-          appendHexChars(dnString, valueString, hexChars);
-          break;
-        }
-
-        c = dnString.charAt(pos++);
-        if (escaped)
-        {
-          // The previous character was an escape, so we'll take this
-          // one.  However, this could be a hex digit, and if that's
-          // the case then the escape would actually be in front of
-          // two hex digits that should be treated as a special
-          // character.
-          if (isHexDigit(c))
-          {
-            // It is a hexadecimal digit, so the next digit must be
-            // one too.  However, this could be just one in a series
-            // of escaped hex pairs that is used in a string
-            // containing one or more multi-byte UTF-8 characters so
-            // we can't just treat this byte in isolation.  Collect
-            // all the bytes together and make sure to take care of
-            // these hex bytes before appending anything else to the value.
-            if (pos >= length)
-            {
-              LocalizableMessage message =
-                ERR_ATTR_SYNTAX_DN_ESCAPED_HEX_VALUE_INVALID.
-                    get(dnString);
-              throw new DirectoryException(
-                             ResultCode.INVALID_DN_SYNTAX, message);
-            }
-            else
-            {
-              char c2 = dnString.charAt(pos++);
-              if (isHexDigit(c2))
-              {
-                hexChars.append(c);
-                hexChars.append(c2);
-              }
-              else
-              {
-                LocalizableMessage message =
-                  ERR_ATTR_SYNTAX_DN_ESCAPED_HEX_VALUE_INVALID.
-                      get(dnString);
-                throw new DirectoryException(
-                               ResultCode.INVALID_DN_SYNTAX, message);
-              }
-            }
-          }
-          else
-          {
-            appendHexChars(dnString, valueString, hexChars);
-            valueString.append(c);
-          }
-
-          escaped = false;
-        }
-        else if (c == '\\')
-        {
-          escaped = true;
-        }
-        else if (c == ',' || c == ';')
-        {
-          appendHexChars(dnString, valueString, hexChars);
-          pos--;
-          break;
-        }
-        else if (c == '+')
-        {
-          appendHexChars(dnString, valueString, hexChars);
-          pos--;
-          break;
-        }
-        else
-        {
-          appendHexChars(dnString, valueString, hexChars);
-          valueString.append(c);
-        }
-      }
-
-
-      // Strip off any unescaped spaces that may be at the end of the value.
-      if (pos > 2 && dnString.charAt(pos-1) == ' ' &&
-           dnString.charAt(pos-2) != '\\')
-      {
-        int lastPos = valueString.length() - 1;
-        while (lastPos > 0)
-        {
-          if (valueString.charAt(lastPos) == ' ')
-          {
-            valueString.delete(lastPos, lastPos+1);
-            lastPos--;
-          }
-          else
-          {
-            break;
-          }
-        }
-      }
-
-
-      attributeValue.appendUtf8(valueString.toString());
-      return pos;
-    }
-  }
-
-
-
-  /**
-   * Decodes a hexadecimal string from the provided
-   * <CODE>hexChars</CODE> buffer, converts it to a byte array, and
-   * then converts that to a UTF-8 string.  The resulting UTF-8 string
-   * will be appended to the provided <CODE>valueString</CODE> buffer,
-   * and the <CODE>hexChars</CODE> buffer will be cleared.
-   *
-   * @param  dnString     The DN string that is being decoded.
-   * @param  valueString  The buffer containing the value to which the
-   *                      decoded string should be appended.
-   * @param  hexChars     The buffer containing the hexadecimal
-   *                      characters to decode to a UTF-8 string.
-   *
-   * @throws  DirectoryException  If any problem occurs during the
-   *                              decoding process.
-   */
-  private static void appendHexChars(String dnString,
-                                     StringBuilder valueString,
-                                     StringBuilder hexChars)
-          throws DirectoryException
-  {
-    if (hexChars.length() == 0)
-    {
-      return;
-    }
-
-    try
-    {
-      byte[] hexBytes = hexStringToByteArray(hexChars.toString());
-      valueString.append(new String(hexBytes, "UTF-8"));
-      hexChars.delete(0, hexChars.length());
-    }
-    catch (Exception e)
-    {
-      logger.traceException(e);
-
-      throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-          ERR_ATTR_SYNTAX_DN_ATTR_VALUE_DECODE_FAILURE.get(dnString, e));
-    }
-  }
-
-
-
-  /**
-   * Indicates whether the provided object is equal to this DN.  In
-   * order for the object to be considered equal, it must be a DN with
-   * the same number of RDN components and each corresponding RDN
-   * component must be equal.
-   *
-   * @param  o  The object for which to make the determination.
-   *
-   * @return  <CODE>true</CODE> if the provided object is a DN that is
-   *          equal to this DN, or <CODE>false</CODE> if it is not.
-   */
-  @Override
-  public boolean equals(Object o)
-  {
-    if (this == o)
-    {
-      return true;
-    }
-
-    if (o instanceof DN)
-    {
-      DN otherDN = (DN) o;
-      return toNormalizedByteString().equals(otherDN.toNormalizedByteString());
-    }
-    return false;
-  }
-
-  /**
-   * Returns the hash code for this DN.
-   *
-   * @return  The hash code for this DN.
-   */
-  @Override
-  public int hashCode()
-  {
-     return toNormalizedByteString().hashCode();
-  }
-
-  /**
-   * Retrieves a string representation of this DN.
-   *
-   * @return  A string representation of this DN.
-   */
-  @Override
-  public String toString()
-  {
-    if (dnString == null)
-    {
-      if (numComponents == 0)
-      {
-        dnString = "";
-      }
-      else
-      {
-        StringBuilder buffer = new StringBuilder();
-        buffer.append(rdnComponents[0]);
-
-        for (int i=1; i < numComponents; i++)
-        {
-          buffer.append(",");
-          buffer.append(rdnComponents[i]);
-        }
-
-        dnString = buffer.toString();
-      }
-    }
-
-    return dnString;
-  }
-
-  /**
-   * Retrieves a normalized string representation of this DN.
-   * <p>
-   *
-   * This representation is safe to use in an URL or in a file name.
-   * However, it is not a valid DN and can't be reverted to a valid DN.
-   *
-   * @return  The normalized string representation of this DN.
-   */
-  public String toNormalizedUrlSafeString()
-  {
-    if (rdnComponents.length == 0)
-    {
-      return "";
-    }
-    StringBuilder buffer = new StringBuilder();
-    buffer.append(rdnComponents[numComponents - 1].toNormalizedUrlSafeString());
-    for (int i = numComponents - 2; i >= 0; i--)
-    {
-      buffer.append(',').append(rdnComponents[i].toNormalizedUrlSafeString());
-    }
-    return buffer.toString();
-  }
-
-  /**
-   * Retrieves a normalized byte string representation of this DN.
-   * <p>
-   * This representation is suitable for equality and comparisons, and for providing a
-   * natural hierarchical ordering.
-   * However, it is not a valid DN and can't be reverted to a valid DN.
-   *
-   * You should consider using a {@code CompactDn} as an alternative.
-   *
-   * @return  The normalized string representation of this DN.
-   */
-  public ByteString toNormalizedByteString()
-  {
-    if (normalizedDN == null)
-    {
-      if (numComponents == 0)
-      {
-        normalizedDN = ByteString.empty();
-      }
-      else
-      {
-        final ByteStringBuilder builder = new ByteStringBuilder();
-        rdnComponents[numComponents - 1].toNormalizedByteString(builder);
-        for (int i = numComponents - 2; i >= 0; i--)
-        {
-          builder.appendByte(NORMALIZED_RDN_SEPARATOR);
-          rdnComponents[i].toNormalizedByteString(builder);
-        }
-        normalizedDN = builder.toByteString();
-      }
-    }
-    return normalizedDN;
-  }
-
-  /**
-   * Compares this DN with the provided DN based on a natural order, as defined by
-   * the toNormalizedByteString() method.
-   *
-   * @param other
-   *          The DN against which to compare this DN.
-   * @return A negative integer if this DN should come before the provided DN, a
-   *         positive integer if this DN should come after the provided DN, or
-   *         zero if there is no difference with regard to ordering.
-   */
-  @Override
-  public int compareTo(DN other)
-  {
-    return toNormalizedByteString().compareTo(other.toNormalizedByteString());
-  }
-
-  @Override
-  public Iterator<RDN> iterator()
-  {
-    return Arrays.asList(rdnComponents).iterator();
-  }
-
-  /**
-   * Returns a UUID whose content is based on the normalized content of this DN. Two equivalent DNs
-   * subject to the same schema will always yield the same UUID.
-   *
-   * @return the UUID representing this DN
-   */
-  public UUID toUUID()
-  {
-    return UUID.nameUUIDFromBytes(toNormalizedByteString().toByteArray());
-  }
-}
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/types/RDN.java b/opendj-server-legacy/src/main/java/org/opends/server/types/RDN.java
deleted file mode 100644
index b3917e4..0000000
--- a/opendj-server-legacy/src/main/java/org/opends/server/types/RDN.java
+++ /dev/null
@@ -1,842 +0,0 @@
-/*
- * The contents of this file are subject to the terms of the Common Development and
- * Distribution License (the License). You may not use this file except in compliance with the
- * License.
- *
- * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
- * specific language governing permission and limitations under the License.
- *
- * When distributing Covered Software, include this CDDL Header Notice in each file and include
- * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
- * Header, with the fields enclosed by brackets [] replaced by your own identifying
- * information: "Portions Copyright [year] [name of copyright owner]".
- *
- * Copyright 2006-2010 Sun Microsystems, Inc.
- * Portions Copyright 2013-2016 ForgeRock AS.
- */
-package org.opends.server.types;
-
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
-import java.nio.CharBuffer;
-import java.nio.charset.Charset;
-import java.nio.charset.CharsetDecoder;
-import java.nio.charset.CodingErrorAction;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.SortedSet;
-import java.util.TreeSet;
-
-import org.forgerock.i18n.LocalizableMessage;
-import org.forgerock.opendj.ldap.AVA;
-import org.forgerock.opendj.ldap.ByteString;
-import org.forgerock.opendj.ldap.ByteStringBuilder;
-import org.forgerock.opendj.ldap.DecodeException;
-import org.forgerock.opendj.ldap.ResultCode;
-import org.forgerock.opendj.ldap.schema.AttributeType;
-import org.forgerock.opendj.ldap.schema.MatchingRule;
-import org.forgerock.util.Reject;
-import org.opends.server.core.DirectoryServer;
-
-import static org.opends.messages.CoreMessages.*;
-import static com.forgerock.opendj.util.StaticUtils.*;
-
-/**
- * This class defines a data structure for storing and interacting
- * with the relative distinguished names associated with entries in
- * the Directory Server.
- */
-@org.opends.server.types.PublicAPI(
-     stability=org.opends.server.types.StabilityLevel.UNCOMMITTED,
-     mayInstantiate=true,
-     mayExtend=false,
-     mayInvoke=true)
-public final class RDN
-       implements Comparable<RDN>, Iterable<AVA>
-{
-  /** The collection of AVAs for the elements in this RDN. */
-  private final List<AVA> avas;
-  /** Representation of the normalized form of this RDN. */
-  private ByteString normalizedRDN;
-
-
-  /**
-   * Creates a new RDN with the provided information.
-   *
-   * @param  attributeType   The attribute type for this RDN.  It must
-   *                         not be {@code null}.
-   * @param  attributeValue  The value for this RDN.  It must not be
-   *                         {@code null}.
-   */
-  public RDN(AttributeType attributeType, Object attributeValue)
-  {
-    Reject.ifNull(attributeType, attributeValue);
-    avas = new ArrayList<>(1);
-    avas.add(new AVA(attributeType, attributeValue));
-  }
-
-
-
-  /**
-   * Creates a new RDN with the provided information.
-   *
-   * @param  attributeType   The attribute type for this RDN.  It must
-   *                         not be {@code null}.
-   * @param  attributeName   The user-provided name for this RDN.  It
-   *                         must not be {@code null}.
-   * @param  attributeValue  The value for this RDN.  It must not be
-   *                         {@code null}.
-   */
-  public RDN(AttributeType attributeType, String attributeName, ByteString attributeValue)
-  {
-    Reject.ifNull(attributeType, attributeName, attributeValue);
-    avas = new ArrayList<>(1);
-    avas.add(new AVA(attributeType, attributeName, attributeValue));
-  }
-
-  /**
-   * Creates a new RDN with the provided {@link AVA}s.
-   *
-   * @param avas
-   *          The AVAs that will define the new RDN
-   */
-  public RDN(AVA... avas)
-  {
-    this(Arrays.asList(Reject.checkNotNull(avas, "avas must not be null")));
-  }
-
-  /**
-   * Creates a new RDN with the provided collection of {@link AVA}.
-   *
-   * @param avas
-   *          The collection of AVA that will define the new RDN
-   */
-  public RDN(Collection<AVA> avas)
-  {
-    Reject.ifNull(avas, "avas must not be null");
-    Reject.ifTrue(avas.isEmpty(), "avas must not be empty");
-    this.avas = new ArrayList<>(avas);
-  }
-
-  /**
-   * Retrieves the number of attribute-value pairs contained in this RDN.
-   *
-   * @return The number of attribute-value pairs contained in this RDN.
-   */
-  public int size()
-  {
-    return avas.size();
-  }
-
-  /**
-   * Indicates whether this RDN includes the specified attribute type.
-   *
-   * @param  attributeType  The attribute type for which to make the
-   *                        determination.
-   *
-   * @return  <CODE>true</CODE> if the RDN includes the specified
-   *          attribute type, or <CODE>false</CODE> if not.
-   */
-  public boolean hasAttributeType(AttributeType attributeType)
-  {
-    for (AVA ava : avas)
-    {
-      if (ava.getAttributeType().equals(attributeType))
-      {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  /**
-   * Retrieves the attribute value that is associated with the
-   * specified attribute type.
-   *
-   * @param  attributeType  The attribute type for which to retrieve
-   *                        the corresponding value.
-   *
-   * @return  The value for the requested attribute type, or
-   *          <CODE>null</CODE> if the specified attribute type is not
-   *          present in the RDN.
-   */
-  public ByteString getAttributeValue(AttributeType attributeType)
-  {
-    for (AVA ava : avas)
-    {
-      if (ava.getAttributeType().equals(attributeType))
-      {
-        return ava.getAttributeValue();
-      }
-    }
-    return null;
-  }
-
-  /**
-   * Indicates whether this RDN is multivalued.
-   *
-   * @return  <CODE>true</CODE> if this RDN is multivalued, or
-   *          <CODE>false</CODE> if not.
-   */
-  public boolean isMultiValued()
-  {
-    return avas.size() > 1;
-  }
-
-  /**
-   * Adds the provided type-value pair from this RDN.  Note that this
-   * is intended only for internal use when constructing DN values.
-   *
-   * @param  type   The attribute type of the pair to add.
-   * @param  name   The user-provided name of the pair to add.
-   * @param  value  The attribute value of the pair to add.
-   *
-   * @return  <CODE>true</CODE> if the type-value pair was added to
-   *          this RDN, or <CODE>false</CODE> if it was not (e.g., it
-   *          was already present).
-   */
-  boolean addValue(AttributeType type, String name, ByteString value)
-  {
-    for (AVA ava : avas)
-    {
-      if (ava.getAttributeType().equals(type) && ava.getAttributeValue().equals(value))
-      {
-        return false;
-      }
-    }
-    avas.add(new AVA(type, name, value));
-    return true;
-  }
-
-  /**
-   * Decodes the provided string as an RDN.
-   *
-   * @param rdnString
-   *          The string to decode as an RDN.
-   * @return The decoded RDN.
-   * @throws DirectoryException
-   *           If a problem occurs while trying to decode the provided
-   *           string as a RDN.
-   */
-  public static RDN valueOf(String rdnString) throws DirectoryException
-  {
-    // A null or empty RDN is not acceptable.
-    if (rdnString == null)
-    {
-      LocalizableMessage message = ERR_RDN_DECODE_NULL.get();
-      throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX, message);
-    }
-
-    int length = rdnString.length();
-    if (length == 0)
-    {
-      LocalizableMessage message = ERR_RDN_DECODE_NULL.get();
-      throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX, message);
-    }
-
-
-    // Iterate through the RDN string.  The first thing to do is to
-    // get rid of any leading spaces.
-    int pos = 0;
-    char c = rdnString.charAt(pos);
-    while (c == ' ')
-    {
-      pos++;
-      if (pos == length)
-      {
-        // This means that the RDN was completely comprised of spaces,
-        // which is not valid.
-        LocalizableMessage message = ERR_RDN_DECODE_NULL.get();
-        throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX, message);
-      }
-      else
-      {
-        c = rdnString.charAt(pos);
-      }
-    }
-
-
-    // We know that it's not an empty RDN, so we can do the real processing.
-    // First, parse the attribute name. We can borrow the DN code for this.
-    boolean allowExceptions = DirectoryServer.allowAttributeNameExceptions();
-    StringBuilder attributeName = new StringBuilder();
-    pos = DN.parseAttributeName(rdnString, pos, attributeName, allowExceptions);
-
-
-    // Make sure that we're not at the end of the RDN string because
-    // that would be invalid.
-    if (pos >= length)
-    {
-      throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-          ERR_RDN_END_WITH_ATTR_NAME.get(rdnString, attributeName));
-    }
-
-
-    // Skip over any spaces between the attribute name and its value.
-    c = rdnString.charAt(pos);
-    while (c == ' ')
-    {
-      pos++;
-      if (pos >= length)
-      {
-        // This means that we hit the end of the string before finding a '='.
-        // This is illegal because there is no attribute-value separator.
-        throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-            ERR_RDN_END_WITH_ATTR_NAME.get(rdnString, attributeName));
-      }
-      else
-      {
-        c = rdnString.charAt(pos);
-      }
-    }
-
-
-    // The next character must be an equal sign.  If it is not, then
-    // that's an error.
-    if (c == '=')
-    {
-      pos++;
-    }
-    else
-    {
-      throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-          ERR_RDN_NO_EQUAL.get(rdnString, attributeName, c));
-    }
-
-
-    // Skip over any spaces between the equal sign and the value.
-    while (pos < length && ((c = rdnString.charAt(pos)) == ' '))
-    {
-      pos++;
-    }
-
-
-    // If we are at the end of the RDN string, then that must mean
-    // that the attribute value was empty.
-    if (pos >= length)
-    {
-      String        name      = attributeName.toString();
-      String        lowerName = toLowerCase(name);
-      LocalizableMessage message = ERR_RDN_MISSING_ATTRIBUTE_VALUE.get(rdnString,
-             lowerName);
-      throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX, message);
-    }
-
-
-    // Parse the value for this RDN component.  This can be done using
-    // the DN code.
-    ByteStringBuilder parsedValue = new ByteStringBuilder(0);
-    pos = DN.parseAttributeValue(rdnString, pos, parsedValue);
-
-
-    // Create the new RDN with the provided information.  However,
-    // don't return it yet because this could be a multi-valued RDN.
-    String name            = attributeName.toString();
-
-    // If using default is a problem, it will be caught later either
-    // by not finding the target entry or by not allowing the entry
-    // to be added.
-    AttributeType attrType = DirectoryServer.getAttributeType(name);
-
-    RDN rdn = new RDN(attrType, name, parsedValue.toByteString());
-
-
-    // Skip over any spaces that might be after the attribute value.
-    while (pos < length && ((c = rdnString.charAt(pos)) == ' '))
-    {
-      pos++;
-    }
-
-
-    // Most likely, this is the end of the RDN.  If so, then return it.
-    if (pos >= length)
-    {
-      return rdn;
-    }
-
-
-    // If the next character is a comma or semicolon, then that is not
-    // allowed.  It would be legal for a DN but not an RDN.
-    if (c == ',' || c == ';')
-    {
-      LocalizableMessage message = ERR_RDN_UNEXPECTED_COMMA.get(rdnString, pos);
-      throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX, message);
-    }
-
-
-    // If the next character is anything but a plus sign, then it is illegal.
-    if (c != '+')
-    {
-      LocalizableMessage message = ERR_RDN_ILLEGAL_CHARACTER.get(rdnString, c, pos);
-      throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX, message);
-    }
-
-
-    // If we have gotten here, then it is a multi-valued RDN.  Parse
-    // the remaining attribute/value pairs and add them to the RDN
-    // that we've already created.
-    while (true)
-    {
-      // Skip over the plus sign and any spaces that may follow it
-      // before the next attribute name.
-      pos++;
-      while (pos < length && ((c = rdnString.charAt(pos)) == ' '))
-      {
-        pos++;
-      }
-
-
-      // Parse the attribute name.
-      attributeName = new StringBuilder();
-      pos = DN.parseAttributeName(rdnString, pos, attributeName,
-                                  allowExceptions);
-
-
-      // Make sure we're not at the end of the RDN.
-      if (pos >= length)
-      {
-        throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-            ERR_RDN_END_WITH_ATTR_NAME.get(rdnString, attributeName));
-      }
-
-
-      // Skip over any spaces between the attribute name and the equal sign.
-      c = rdnString.charAt(pos);
-      while (c == ' ')
-      {
-        pos++;
-        if (pos >= length)
-        {
-          // This means that we hit the end of the string before finding a '='.
-          // This is illegal because there is no attribute-value separator.
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-              ERR_RDN_END_WITH_ATTR_NAME.get(rdnString, attributeName));
-        }
-        else
-        {
-          c = rdnString.charAt(pos);
-        }
-      }
-
-
-      // The next character must be an equal sign.
-      if (c == '=')
-      {
-        pos++;
-      }
-      else
-      {
-        throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-            ERR_RDN_NO_EQUAL.get(rdnString, attributeName, c));
-      }
-
-
-      // Skip over any spaces after the equal sign.
-      while (pos < length && ((c = rdnString.charAt(pos)) == ' '))
-      {
-        pos++;
-      }
-
-
-      // If we are at the end of the RDN string, then that must mean
-      // that the attribute value was empty.  This will probably never
-      // happen in a real-world environment, but technically isn't
-      // illegal.  If it does happen, then go ahead and return the RDN.
-      if (pos >= length)
-      {
-        name      = attributeName.toString();
-        attrType = DirectoryServer.getAttributeType(name);
-
-        rdn.addValue(attrType, name, ByteString.empty());
-        return rdn;
-      }
-
-
-      // Parse the value for this RDN component.
-      parsedValue.clear();
-      pos = DN.parseAttributeValue(rdnString, pos, parsedValue);
-
-
-      // Update the RDN to include the new attribute/value.
-      name            = attributeName.toString();
-      // If using default is a problem, it will be caught later either
-      // by not finding the target entry or by not allowing the entry
-      // to be added.
-      attrType = DirectoryServer.getAttributeType(name);
-
-      rdn.addValue(attrType, name, parsedValue.toByteString());
-
-
-      // Skip over any spaces that might be after the attribute value.
-      while (pos < length && ((c = rdnString.charAt(pos)) == ' '))
-      {
-        pos++;
-      }
-
-
-      // If we're at the end of the string, then return the RDN.
-      if (pos >= length)
-      {
-        return rdn;
-      }
-
-
-      // If the next character is a comma or semicolon, then that is
-      // not allowed.  It would be legal for a DN but not an RDN.
-      if (c == ',' || c == ';')
-      {
-        LocalizableMessage message = ERR_RDN_UNEXPECTED_COMMA.get(rdnString, pos);
-        throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX, message);
-      }
-
-
-      // If the next character is anything but a plus sign, then it is illegal.
-      if (c != '+')
-      {
-        LocalizableMessage message = ERR_RDN_ILLEGAL_CHARACTER.get(rdnString, c, pos);
-        throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX, message);
-      }
-    }
-  }
-
-  /**
-   * Indicates whether the provided object is equal to this RDN.  It
-   * will only be considered equal if it is an RDN object that
-   * contains the same number of elements in the same order with the
-   * same types and normalized values.
-   *
-   * @param  o  The object for which to make the determination.
-   *
-   * @return  <CODE>true</CODE> if it is determined that the provided
-   *          object is equal to this RDN, or <CODE>false</CODE> if
-   *          not.
-   */
-  @Override
-  public boolean equals(Object o)
-  {
-    if (this == o)
-    {
-      return true;
-    }
-    if (o instanceof RDN)
-    {
-      RDN otherRDN = (RDN) o;
-      return toNormalizedByteString().equals(otherRDN.toNormalizedByteString());
-    }
-    return false;
-  }
-
-  /**
-   * Retrieves the hash code for this RDN.  It will be calculated as
-   * the sum of the hash codes of the types and values.
-   *
-   * @return  The hash code for this RDN.
-   */
-  @Override
-  public int hashCode()
-  {
-    return toNormalizedByteString().hashCode();
-  }
-
-  /** Returns normalized value for attribute at provided position. */
-  private ByteString getEqualityNormalizedValue(AVA ava)
-  {
-    final MatchingRule matchingRule = ava.getAttributeType().getEqualityMatchingRule();
-    ByteString attributeValue = ava.getAttributeValue();
-    if (matchingRule != null)
-    {
-      try
-      {
-        attributeValue = matchingRule.normalizeAttributeValue(attributeValue);
-      }
-      catch (final DecodeException de)
-      {
-        // Unable to normalize, use default
-        attributeValue = ava.getAttributeValue();
-      }
-    }
-    return attributeValue;
-  }
-
-
-
-  /**
-   * Retrieves a string representation of this RDN.
-   *
-   * @return  A string representation of this RDN.
-   */
-  @Override
-  public String toString()
-  {
-    StringBuilder buffer = new StringBuilder();
-    Iterator<AVA> it = avas.iterator();
-    buffer.append(it.next());
-    while (it.hasNext())
-    {
-      buffer.append("+");
-      buffer.append(it.next());
-    }
-    return buffer.toString();
-  }
-
-  /**
-  * Retrieves a normalized string representation of this RDN.
-  * <p>
-  *
-  * This representation is safe to use in an URL or in a file name.
-  * However, it is not a valid RDN and can't be reverted to a valid RDN.
-  *
-  * @return  The normalized string representation of this RDN.
-  */
-  String toNormalizedUrlSafeString()
-  {
-    final StringBuilder buffer = new StringBuilder();
-    if (avas.size() == 1)
-    {
-      normalizeAVAToUrlSafeString(getFirstAVA(), buffer);
-    }
-    else
-    {
-      // Normalization sorts RDNs alphabetically
-      SortedSet<String> avaStrings = new TreeSet<>();
-      for (AVA ava : avas)
-      {
-        StringBuilder builder = new StringBuilder();
-        normalizeAVAToUrlSafeString(ava, builder);
-        avaStrings.add(builder.toString());
-      }
-
-      Iterator<String> iterator = avaStrings.iterator();
-      buffer.append(iterator.next());
-      while (iterator.hasNext())
-      {
-        buffer.append('+');
-        buffer.append(iterator.next());
-      }
-    }
-    return buffer.toString();
-  }
-
-  private ByteString toNormalizedByteString()
-  {
-    if (normalizedRDN == null)
-    {
-      computeNormalizedByteString(new ByteStringBuilder());
-    }
-    return normalizedRDN;
-  }
-
-  /**
-   * Adds a normalized byte string representation of this RDN to the provided builder.
-   * <p>
-   * The representation is suitable for equality and comparisons, and for providing a
-   * natural hierarchical ordering.
-   * However, it is not a valid RDN and can't be reverted to a valid RDN.
-   *
-   * @param builder
-   *           Builder to add this representation to.
-   * @return the builder
-   */
-  public ByteStringBuilder toNormalizedByteString(ByteStringBuilder builder)
-  {
-    if (normalizedRDN != null)
-    {
-      return builder.appendBytes(normalizedRDN);
-    }
-    return computeNormalizedByteString(builder);
-  }
-
-  private ByteStringBuilder computeNormalizedByteString(ByteStringBuilder builder)
-  {
-    final int startPos = builder.length();
-
-    if (avas.size() == 1)
-    {
-      normalizeAVAToByteString(getFirstAVA(), builder);
-    }
-    else
-    {
-      // Normalization sorts RDNs
-      SortedSet<ByteString> avaStrings = new TreeSet<>();
-      for (AVA ava : avas)
-      {
-        ByteStringBuilder b = new ByteStringBuilder();
-        normalizeAVAToByteString(ava, b);
-        avaStrings.add(b.toByteString());
-      }
-
-      Iterator<ByteString> iterator = avaStrings.iterator();
-      builder.appendBytes(iterator.next());
-      while (iterator.hasNext())
-      {
-        builder.appendByte(DN.NORMALIZED_AVA_SEPARATOR);
-        builder.appendBytes(iterator.next());
-      }
-    }
-
-    if (normalizedRDN == null)
-    {
-      normalizedRDN = builder.subSequence(startPos, builder.length()).toByteString();
-    }
-
-    return builder;
-  }
-
-  /**
-   * Adds a normalized byte string representation of the AVA corresponding
-   * to provided position in this RDN to the provided builder.
-   *
-   * @param position
-   *           Position of AVA in this RDN.
-   * @param builder
-   *           Builder to add the representation to.
-   * @return the builder
-   */
-  private ByteStringBuilder normalizeAVAToByteString(AVA ava, final ByteStringBuilder builder)
-  {
-    builder.appendUtf8(ava.getAttributeType().getNormalizedNameOrOID());
-    builder.appendUtf8("=");
-    final ByteString value = getEqualityNormalizedValue(ava);
-    if (value.length() > 0)
-    {
-      builder.appendBytes(escapeBytes(value));
-    }
-    return builder;
-  }
-
-  /**
-   * Return a new byte string with bytes 0x00, 0x01 and 0x02 escaped.
-   * <p>
-   * These bytes are reserved to represent respectively the RDN separator, the
-   * AVA separator and the escape byte in a normalized byte string.
-   */
-  private ByteString escapeBytes(final ByteString value)
-  {
-    if (!needEscaping(value))
-    {
-      return value;
-    }
-
-    final ByteStringBuilder builder = new ByteStringBuilder();
-    for (int i = 0; i < value.length(); i++)
-    {
-      final byte b = value.byteAt(i);
-      if (isByteToEscape(b))
-      {
-        builder.appendByte(DN.NORMALIZED_ESC_BYTE);
-      }
-      builder.appendByte(b);
-    }
-    return builder.toByteString();
-  }
-
-  private boolean needEscaping(final ByteString value)
-  {
-    for (int i = 0; i < value.length(); i++)
-    {
-      if (isByteToEscape(value.byteAt(i)))
-      {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  private boolean isByteToEscape(final byte b)
-  {
-    return b == DN.NORMALIZED_RDN_SEPARATOR || b == DN.NORMALIZED_AVA_SEPARATOR || b == DN.NORMALIZED_ESC_BYTE;
-  }
-
-
-  /**
-   * Appends a normalized string representation of this RDN to the
-   * provided buffer.
-   *
-   * @param  position  The position of the attribute type and value to
-   *              retrieve.
-   * @param  builder  The buffer to which to append the information.
-   * @return the builder
-   */
-  private StringBuilder normalizeAVAToUrlSafeString(AVA ava, StringBuilder builder)
-  {
-    AttributeType attrType = ava.getAttributeType();
-    builder.append(attrType.getNormalizedNameOrOID());
-      builder.append('=');
-
-    ByteString value = getEqualityNormalizedValue(ava);
-      if (value.length() == 0)
-      {
-        return builder;
-      }
-    final boolean hasAttributeName = !attrType.getNames().isEmpty();
-    final boolean isHumanReadable = attrType.getSyntax().isHumanReadable();
-      if (!hasAttributeName || !isHumanReadable)
-      {
-        builder.append(value.toPercentHexString());
-      }
-      else
-      {
-        // try to decode value as UTF-8 string
-        final CharBuffer buffer = CharBuffer.allocate(value.length());
-        final CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder()
-            .onMalformedInput(CodingErrorAction.REPORT)
-            .onUnmappableCharacter(CodingErrorAction.REPORT);
-        if (value.copyTo(buffer, decoder))
-        {
-          buffer.flip();
-          try
-          {
-            // URL encoding encodes space char as '+' instead of using hex code
-            final String val = URLEncoder.encode(buffer.toString(), "UTF-8").replaceAll("\\+", "%20");
-            builder.append(val);
-          }
-          catch (UnsupportedEncodingException e)
-          {
-            // should never happen
-            builder.append(value.toPercentHexString());
-          }
-        }
-        else
-        {
-          builder.append(value.toPercentHexString());
-        }
-      }
-      return builder;
-  }
-
-  /**
-   * Compares this RDN with the provided RDN based on natural ordering defined
-   * by the toNormalizedByteString() method.
-   *
-   * @param  rdn  The RDN against which to compare this RDN.
-   *
-   * @return  A negative integer if this RDN should come before the
-   *          provided RDN, a positive integer if this RDN should come
-   *          after the provided RDN, or zero if there is no
-   *          difference with regard to ordering.
-   */
-  @Override
-  public int compareTo(RDN rdn)
-  {
-    return toNormalizedByteString().compareTo(rdn.toNormalizedByteString());
-  }
-
-  /**
-   * Returns the first AVA of this {@link RDN}.
-   *
-   * @return the first AVA of this {@link RDN}.
-   */
-  public AVA getFirstAVA()
-  {
-    return avas.get(0);
-  }
-
-  @Override
-  public Iterator<AVA> iterator()
-  {
-    return avas.iterator();
-  }
-}
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/types/TestDN.java b/opendj-server-legacy/src/test/java/org/opends/server/types/TestDN.java
index 0ed30a9..67ca277 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/types/TestDN.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/types/TestDN.java
@@ -25,12 +25,10 @@
 
 import org.forgerock.i18n.LocalizedIllegalArgumentException;
 import org.forgerock.opendj.ldap.ByteString;
-import org.forgerock.opendj.ldap.ByteStringBuilder;
 import org.forgerock.opendj.ldap.DN;
 import org.forgerock.opendj.ldap.RDN;
 import org.forgerock.opendj.ldap.schema.AttributeType;
 import org.opends.server.TestCaseUtils;
-import org.opends.server.backends.pluggable.DnKeyFormat;
 import org.opends.server.core.DirectoryServer;
 import org.testng.Assert;
 import org.testng.annotations.BeforeClass;
@@ -188,32 +186,11 @@
    *           If the test failed unexpectedly.
    */
   @Test
-  public void testCreateWithMultipleRDNs1() throws Exception {
+  public void testCreateWithMultipleRDNs() throws Exception {
     DN dn = DN.rootDN().child(RDN.valueOf("dc=org")).child(RDN.valueOf("dc=opends")).child(RDN.valueOf("dc=foo"));
     assertEquals(dn, DN.valueOf("dc=foo,dc=opends,dc=org"));
   }
 
-
-
-  /**
-   * Tests the create method.
-   *
-   * @throws Exception
-   *           If the test failed unexpectedly.
-   */
-  @Test
-  public void testCreateWithMultipleRDNs2() throws Exception {
-    ArrayList<RDN> rdnList = new ArrayList<>();
-    rdnList.add(RDN.valueOf("dc=foo"));
-    rdnList.add(RDN.valueOf("dc=opends"));
-    rdnList.add(RDN.valueOf("dc=org"));
-    DN dn = new DN(rdnList);
-
-    assertEquals(dn, DN.valueOf("dc=foo,dc=opends,dc=org"));
-  }
-
-
-
   /**
    * Tests the <CODE>valueOf</CODE> method which takes a String
    * argument.
@@ -283,12 +260,8 @@
    *           If the test failed unexpectedly.
    */
   @Test
-  public void testToNormalizedString() throws Exception {
+  public void testToNormalizedUrlSafeString() throws Exception {
     DN dn = DN.valueOf("dc=example,dc=com");
-
-    assertEquals(dn.toNormalizedByteString(),
-        new ByteStringBuilder().appendUtf8("dc=com").appendByte(DnKeyFormat.NORMALIZED_RDN_SEPARATOR)
-                               .appendUtf8("dc=example").toByteString());
     assertEquals(dn.toNormalizedUrlSafeString(), "dc=com,dc=example");
   }
 
@@ -900,7 +873,7 @@
       AssertionError.class })
   public void testIsAncestorOfException() throws Exception {
     DN dn = DN.valueOf("dc=com");
-    dn.isSuperiorOrEqualTo(null);
+    dn.isSuperiorOrEqualTo((DN) null);
   }
 
 
@@ -970,7 +943,7 @@
       AssertionError.class })
   public void testIsDescendantOfException() throws Exception {
     DN dn = DN.valueOf("dc=com");
-    dn.isSubordinateOrEqualTo(null);
+    dn.isSubordinateOrEqualTo((DN) null);
   }
 
 
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/types/TestRDN.java b/opendj-server-legacy/src/test/java/org/opends/server/types/TestRDN.java
index b0ebc0f..f983980 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/types/TestRDN.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/types/TestRDN.java
@@ -102,7 +102,7 @@
    */
   @Test
   public void testConstructorWithName() throws Exception {
-    RDN rdn = new RDN(AT_DC, "domainComponent", AV_DC_ORG);
+    RDN rdn = new RDN(new AVA(AT_DC, "domainComponent", AV_DC_ORG));
 
     assertEquals(rdn.size(), 1);
     AVA ava = rdn.getFirstAVA();
@@ -221,28 +221,6 @@
         { "O=\"Sue, Grabbit and Runn\"", "o=sue%2C%20grabbit%20and%20runn", "O=Sue\\, Grabbit and Runn" }, };
   }
 
-
-
-  /**
-   * Test RDN string decoder.
-   *
-   * @param rawRDN
-   *          Raw RDN string representation.
-   * @param normRDN
-   *          Normalized RDN string representation.
-   * @param stringRDN
-   *          String representation.
-   * @throws Exception
-   *           If the test failed unexpectedly.
-   */
-  @Test(dataProvider = "testRDNs")
-  public void testNormalizationToSafeUrlString(String rawRDN, String normRDN, String stringRDN) throws Exception {
-    RDN rdn = RDN.valueOf(rawRDN);
-    assertEquals(rdn.toNormalizedUrlSafeString(), normRDN);
-  }
-
-
-
   /**
    * Illegal RDN test data provider.
    *
@@ -251,8 +229,8 @@
   @DataProvider(name = "illegalRDNs")
   public Object[][] createIllegalData() {
     return new Object[][] { { null }, { "" }, { " " }, { "=" }, { "manager" },
-        { "manager " }, { "cn+"}, { "cn+Jim" }, { "cn=Jim+" }, { "cn=Jim +" },
-        { "cn=Jim+ " }, /* FIXME activate { "cn=Jim+cn=John" }, */ { "cn=Jim+sn" }, { "cn=Jim+sn " },
+        { "manager " }, { "cn+"}, { "cn+Jim" }, { "cn="}, { "cn=Jim+" }, { "cn=Jim +" },
+        { "cn=Jim+ " }, { "cn=Jim+cn=John" }, { "cn=Jim+sn" }, { "cn=Jim+sn " },
         { "cn=Jim+sn equals" }, { "cn=Jim," }, { "cn=Jim;" }, { "cn=Jim,  " },
         { "cn=Jim+sn=a," }, { "cn=Jim, sn=Jam " }, { "cn+uid=Jim" },
         { "-cn=Jim" }, { "/tmp=a" }, { "\\tmp=a" }, { "cn;lang-en=Jim" },
@@ -356,8 +334,8 @@
     RDN rdn = new RDN(AT_DC, AV_DC_ORG);
     assertEquals(rdn.size(), 1);
 
-    rdn.addValue(AT_CN, AT_CN.getNameOrOID(), AV_CN);
-    assertEquals(rdn.size(), 2);
+    RDN rdn2 = new RDN(new AVA(AT_DC, AV_DC_ORG), new AVA(AT_CN, AV_CN));
+    assertEquals(rdn2.size(), 2);
   }
 
   /**
@@ -369,28 +347,13 @@
   @Test
   public void testIsMultiValued() throws Exception {
     RDN rdn = new RDN(AT_DC, AV_DC_ORG);
-    assertEquals(rdn.size(), 1);
     assertFalse(rdn.isMultiValued());
 
-    rdn.addValue(AT_CN, AT_CN.getNameOrOID(), AV_CN);
-    assertTrue(rdn.isMultiValued());
+    RDN rdn2 = new RDN(new AVA(AT_DC, AV_DC_ORG), new AVA(AT_CN, AV_CN));
+    assertTrue(rdn2.isMultiValued());
   }
 
   /**
-   * Tests addValue with a duplicate value.
-   *
-   * @throws Exception
-   *           If the test failed unexpectedly.
-   */
-  @Test
-  public void testAddDuplicateValue() throws Exception {
-    RDN rdn = new RDN(AT_DC, AV_DC_ORG);
-    assertFalse(rdn.addValue(AT_DC, AT_DC.getNameOrOID(), AV_DC_ORG));
-  }
-
-
-
-  /**
    * Test RDN string decoder.
    *
    * @param rawRDN

--
Gitblit v1.10.0