From d782e4facdae0897de52f560e4ebbf30bd800318 Mon Sep 17 00:00:00 2001
From: matthew_swift <matthew_swift@localhost>
Date: Tue, 15 Jun 2010 14:39:37 +0000
Subject: [PATCH] DN normalization enhancements:

---
 sdk/src/org/opends/sdk/schema/DistinguishedNameEqualityMatchingRuleImpl.java |  276 ++++++++++++++++++++++++++++--------------------------
 1 files changed, 143 insertions(+), 133 deletions(-)

diff --git a/sdk/src/org/opends/sdk/schema/DistinguishedNameEqualityMatchingRuleImpl.java b/sdk/src/org/opends/sdk/schema/DistinguishedNameEqualityMatchingRuleImpl.java
index 83ae0ca..eb0a820 100644
--- a/sdk/src/org/opends/sdk/schema/DistinguishedNameEqualityMatchingRuleImpl.java
+++ b/sdk/src/org/opends/sdk/schema/DistinguishedNameEqualityMatchingRuleImpl.java
@@ -22,17 +22,18 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2009 Sun Microsystems, Inc.
+ *      Copyright 2009-2010 Sun Microsystems, Inc.
  */
 package org.opends.sdk.schema;
 
 
 
-import java.util.Arrays;
-import java.util.Comparator;
+import java.util.TreeSet;
+import java.util.Iterator;
 
 import org.opends.sdk.*;
-
+import com.sun.opends.sdk.util.StaticUtils;
+import static com.sun.opends.sdk.util.StaticUtils.getBytes;
 
 
 /**
@@ -42,166 +43,175 @@
 final class DistinguishedNameEqualityMatchingRuleImpl extends
     AbstractMatchingRuleImpl
 {
-  private static final Comparator<AVA> ATV_COMPARATOR = new Comparator<AVA>()
-  {
-    public int compare(final AVA o1, final AVA o2)
-    {
-      return o1.getAttributeType().compareTo(o2.getAttributeType());
-    }
-  };
-
-
-
-  @Override
-  public Assertion getAssertion(final Schema schema, final ByteSequence value)
-      throws DecodeException
-  {
-    DN assertion;
-    try
-    {
-      assertion = DN.valueOf(value.toString(), schema);
-    }
-    catch (final LocalizedIllegalArgumentException e)
-    {
-      throw DecodeException.error(e.getMessageObject());
-    }
-
-    final DN finalAssertion = assertion;
-    return new Assertion()
-    {
-      public ConditionResult matches(final ByteSequence attributeValue)
-      {
-        try
-        {
-          final DN attribute = DN.valueOf(attributeValue.toString(), schema);
-          return matchDNs(finalAssertion, attribute);
-        }
-        catch (final LocalizedIllegalArgumentException e)
-        {
-          return ConditionResult.UNDEFINED;
-        }
-      }
-    };
-  }
-
-
-
+  /**
+   * {@inheritDoc}
+   */
   public ByteString normalizeAttributeValue(final Schema schema,
       final ByteSequence value) throws DecodeException
   {
     try
     {
-      return ByteString.valueOf(DN.valueOf(value.toString(), schema)
-          .toNormalizedString());
+      DN dn = DN.valueOf(value.toString(), schema.nonStrict());
+      StringBuilder builder = new StringBuilder(value.length());
+      return ByteString.valueOf(normalizeDN(builder, dn));
     }
     catch (final LocalizedIllegalArgumentException e)
     {
       throw DecodeException.error(e.getMessageObject());
     }
-  }
-
-
-
-  private ConditionResult matchAVAs(final AVA ava1, final AVA ava2)
-  {
-    final AttributeType type = ava1.getAttributeType();
-
-    if (!type.equals(ava2.getAttributeType()))
+    catch (final Exception e)
     {
-      return ConditionResult.FALSE;
-    }
-
-    final MatchingRule matchingRule = type.getEqualityMatchingRule();
-    if (matchingRule != null)
-    {
-      try
-      {
-        final ByteString nv1 = matchingRule.normalizeAttributeValue(ava1
-            .getAttributeValue());
-        final ByteString nv2 = matchingRule.normalizeAttributeValue(ava2
-            .getAttributeValue());
-        return nv1.equals(nv2) ? ConditionResult.TRUE : ConditionResult.FALSE;
-      }
-      catch (final DecodeException de)
-      {
-        return ConditionResult.UNDEFINED;
-      }
-    }
-
-    return ConditionResult.UNDEFINED;
-  }
-
-
-
-  private ConditionResult matchDNs(final DN dn1, final DN dn2)
-  {
-    final int sz1 = dn1.size();
-    final int sz2 = dn2.size();
-
-    if (sz1 != sz2)
-    {
-      return ConditionResult.FALSE;
-    }
-    else
-    {
-      final RDN rdn1 = dn1.rdn();
-      final RDN rdn2 = dn2.rdn();
-      while (rdn1 != null)
-      {
-        final ConditionResult result = matchRDNs(rdn1, rdn2);
-        if (result != ConditionResult.TRUE)
-        {
-          return result;
-        }
-      }
-      return ConditionResult.TRUE;
+      throw DecodeException.error(LocalizableMessage.raw(e.toString()));
     }
   }
 
-
-
-  private ConditionResult matchRDNs(final RDN rdn1, final RDN rdn2)
+  /**
+   * Returns the normalized string representation of a DN.
+   *
+   * @param builder The StringBuilder to use to construct the normalized string.
+   * @param dn The DN.
+   * @return The normalized string representation of the provided DN.
+   */
+  private static StringBuilder normalizeDN(final StringBuilder builder,
+                                          final DN dn)
   {
-    final int sz1 = rdn1.size();
-    final int sz2 = rdn2.size();
-
-    if (sz1 != sz2)
+    if(dn.rdn() == null)
     {
-      return ConditionResult.FALSE;
+      return builder;
     }
-    else if (sz1 == 1)
+
+    int i = dn.size() - 1;
+    normalizeRDN(builder, dn.parent(i).rdn());
+    for (i--; i >= 0; i--)
     {
-      return matchAVAs(rdn1.getFirstAVA(), rdn2.getFirstAVA());
+      builder.append('\u0000');
+      normalizeRDN(builder, dn.parent(i).rdn());
+    }
+    return builder;
+  }
+
+  /**
+   * Returns the normalized string representation of a RDN.
+   *
+   * @param builder The StringBuilder to use to construct the normalized string.
+   * @param rdn The RDN.
+   * @return The normalized string representation of the provided RDN.
+   */
+  private static StringBuilder normalizeRDN(final StringBuilder builder,
+                                           final RDN rdn)
+  {
+    final int sz = rdn.size();
+    if (sz == 1)
+    {
+      return normalizeAVA(builder, rdn.getFirstAVA());
     }
     else
     {
       // Need to sort the AVAs before comparing.
-      final AVA[] a1 = new AVA[sz1];
-      int i = 0;
-      for (final AVA ava : rdn1)
+      TreeSet<AVA> a = new TreeSet<AVA>();
+      for(AVA ava : rdn)
       {
-        a1[i++] = ava;
+        a.add(ava);
       }
-      Arrays.sort(a1, ATV_COMPARATOR);
-
-      final AVA[] a2 = new AVA[sz1];
-      i = 0;
-      for (final AVA ava : rdn2)
+      Iterator<AVA> i = a.iterator();
+      // Normalize the first AVA.
+      normalizeAVA(builder, i.next());
+      while(i.hasNext())
       {
-        a2[i++] = ava;
+        builder.append('\u0001');
+        normalizeAVA(builder, i.next());
       }
-      Arrays.sort(a2, ATV_COMPARATOR);
 
-      for (i = 0; i < sz1; i++)
+      return builder;
+    }
+  }
+
+  /**
+   * Returns the normalized string representation of an AVA.
+   *
+   * @param builder The StringBuilder to use to construct the normalized string.
+   * @param ava The AVA.
+   * @return The normalized string representation of the provided AVA.
+   */
+  private static StringBuilder normalizeAVA(final StringBuilder builder,
+                                           final AVA ava)
+  {
+    ByteString value = ava.getAttributeValue();
+    final MatchingRule matchingRule =
+        ava.getAttributeType().getEqualityMatchingRule();
+    if (matchingRule != null)
+    {
+      try
       {
-        final ConditionResult result = matchAVAs(a1[i], a2[i]);
-        if (result != ConditionResult.TRUE)
+        value =
+            matchingRule.normalizeAttributeValue(ava.getAttributeValue());
+      }
+      catch (final DecodeException de)
+      {
+        // Ignore - we'll drop back to the user provided value.
+      }
+    }
+
+    if (!ava.getAttributeType().getNames().iterator().hasNext())
+    {
+      builder.append(ava.getAttributeType().getOID());
+      builder.append("=#");
+      StaticUtils.toHex(value, builder);
+    }
+    else
+    {
+      final String name = ava.getAttributeType().getNameOrOID();
+      // Normalizing.
+      StaticUtils.toLowerCase(name, builder);
+
+      builder.append("=");
+
+      final Syntax syntax = ava.getAttributeType().getSyntax();
+      if (!syntax.isHumanReadable())
+      {
+        builder.append("#");
+        StaticUtils.toHex(value, builder);
+      }
+      else
+      {
+        final String str = value.toString();
+        if (str.length() == 0)
         {
-          return result;
+          return builder;
+        }
+        char c = str.charAt(0);
+        int startPos = 0;
+        if ((c == ' ') || (c == '#'))
+        {
+          builder.append('\\');
+          builder.append(c);
+          startPos = 1;
+        }
+        final int length = str.length();
+        for (int si = startPos; si < length; si++)
+        {
+          c = str.charAt(si);
+          if (c < ' ')
+          {
+            for (final byte b : getBytes(String.valueOf(c)))
+            {
+              builder.append('\\');
+              builder.append(StaticUtils.byteToLowerHex(b));
+            }
+          }
+          else
+          {
+            if ((c == ' ' && si == length - 1)
+                || (c == '"' || c == '+' || c == ',' || c == ';' || c == '<'
+                    || c == '=' || c == '>' || c == '\\' || c == '\u0000'))
+            {
+              builder.append('\\');
+            }
+            builder.append(c);
+          }
         }
       }
-
-      return ConditionResult.TRUE;
     }
+    return builder;
   }
 }

--
Gitblit v1.10.0