From 218b2a22d685fef5602021786334a4d78a2460e2 Mon Sep 17 00:00:00 2001
From: ludovicp <ludovicp@localhost>
Date: Fri, 25 Jun 2010 09:40:08 +0000
Subject: [PATCH] Resolves an issue in Import due to entries with multiple RDNs. This patch changes the key format used by the DN2ID database. Rebuilding the index is required.

---
 opends/src/server/org/opends/server/backends/jeb/JebFormat.java |  144 +++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 143 insertions(+), 1 deletions(-)

diff --git a/opends/src/server/org/opends/server/backends/jeb/JebFormat.java b/opends/src/server/org/opends/server/backends/jeb/JebFormat.java
index c9f375d..34f0692 100644
--- a/opends/src/server/org/opends/server/backends/jeb/JebFormat.java
+++ b/opends/src/server/org/opends/server/backends/jeb/JebFormat.java
@@ -22,12 +22,20 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2010 Sun Microsystems, Inc.
  */
 package org.opends.server.backends.jeb;
 
 import static org.opends.server.loggers.debug.DebugLogger.*;
 import org.opends.server.loggers.debug.DebugTracer;
+import org.opends.server.types.DN;
+import org.opends.server.types.RDN;
+import org.opends.server.types.ByteStringBuilder;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.util.StaticUtils;
+
+import java.util.TreeSet;
+import java.util.Iterator;
 
 /**
  * Handles the disk representation of LDAP data.
@@ -227,4 +235,138 @@
 
     return bytes;
   }
+
+  /**
+   * Decode a DN value from its database key representation.
+   *
+   * @param dnKey The database key value of the DN.
+   * @param offset Starting position in the database key data.
+   * @param length The length of the database key data.
+   * @param prefix The DN to prefix the deocded DN value.
+   * @return The decoded DN value.
+   * @throws DirectoryException if an error occurs while decoding the DN value.
+   */
+  public static DN dnFromDNKey(byte[] dnKey, int offset, int length, DN prefix)
+      throws DirectoryException
+  {
+    DN dn = prefix;
+    int start = offset;
+    boolean escaped = false;
+    ByteStringBuilder buffer = new ByteStringBuilder();
+    for(int i = start; i < length; i++)
+    {
+      if(dnKey[i] == 0x5C)
+      {
+        escaped = true;
+        continue;
+      }
+      else if(!escaped && dnKey[i] == 0x01)
+      {
+        buffer.append(0x01);
+        escaped = false;
+        continue;
+      }
+      else if(!escaped && dnKey[i] == 0x00)
+      {
+        if(buffer.length() > 0)
+        {
+          dn = dn.concat(RDN.decode(buffer.toString()));
+          buffer.clear();
+        }
+      }
+      else
+      {
+        if(escaped)
+        {
+          buffer.append(0x5C);
+          escaped = false;
+        }
+        buffer.append(dnKey[i]);
+      }
+    }
+
+    if(buffer.length() > 0)
+    {
+      dn = dn.concat(RDN.decode(buffer.toString()));
+    }
+
+    return dn;
+  }
+
+  /**
+   * Find the length of bytes that represents the superior DN of the given
+   * DN key. The superior DN is represented by the initial bytes of the DN key.
+   *
+   * @param dnKey The database key value of the DN.
+   * @param offset Starting position in the database key data.
+   * @param length The length of the database key data.
+   * @return The length of the superior DN or -1 if the given dn is the
+   *         root DN or 0 if the superior DN is removed.
+   */
+  public static int findDNKeyParent(byte[] dnKey, int offset, int length)
+  {
+    if(length == 0)
+    {
+      // This is the root or base DN
+      return -1;
+    }
+
+    // We will walk backwords through the buffer and find the first
+    // unescaped comma
+    for(int i = offset+length - 1; i >= offset; i--)
+    {
+      if(dnKey[i] == 0x00 && i-1 >= offset && dnKey[i-1] != 0x5C)
+      {
+        return i;
+      }
+    }
+    return offset;
+  }
+
+  /**
+   * Create a DN database key from an entry DN.
+   * @param dn The entry DN.
+   * @param prefixRDNs The number of prefix RDNs to remove from the encoded
+   *                   representation.
+   * @return A DatabaseEntry containing the key.
+   */
+  public static byte[] dnToDNKey(DN dn, int prefixRDNs)
+  {
+    StringBuilder buffer = new StringBuilder();
+    for (int i = dn.getNumComponents() - prefixRDNs - 1; i >= 0; i--)
+    {
+      buffer.append('\u0000');
+      formatRDNKey(dn.getRDN(i), buffer);
+    }
+
+    return StaticUtils.getBytes(buffer.toString());
+  }
+
+  private static void formatRDNKey(RDN rdn, StringBuilder buffer)
+  {
+    if (!rdn.isMultiValued())
+    {
+      rdn.toNormalizedString(buffer);
+    }
+    else
+    {
+      TreeSet<String> rdnElementStrings = new TreeSet<String>();
+
+      for (int i=0; i < rdn.getNumValues(); i++)
+      {
+        StringBuilder b2 = new StringBuilder();
+        rdn.getAVAString(i, b2);
+        rdnElementStrings.add(b2.toString());
+      }
+
+      Iterator<String> iterator = rdnElementStrings.iterator();
+      buffer.append(iterator.next().replace("\u0001", "\\\u0001"));
+
+      while (iterator.hasNext())
+      {
+        buffer.append('\u0001');
+        buffer.append(iterator.next().replace("\u0001", "\\\u0001"));
+      }
+    }
+  }
 }

--
Gitblit v1.10.0