From 60f3502563cd2c71a751b74f0b34bfe2f5d17330 Mon Sep 17 00:00:00 2001
From: Violette Roche-Montane <violette.roche-montane@forgerock.com>
Date: Thu, 08 Nov 2012 15:40:09 +0000
Subject: [PATCH] Fix OPENDJ-619 : Reduce the memory utilization of LDIF.diff(EntryReader, EntryReader) in the SDK

---
 opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/DN.java |  136 +++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 136 insertions(+), 0 deletions(-)

diff --git a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/DN.java b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/DN.java
index e2ed752..a32ce02 100644
--- a/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/DN.java
+++ b/opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/DN.java
@@ -27,19 +27,24 @@
 
 package org.forgerock.opendj.ldap;
 
+import static com.forgerock.opendj.util.StaticUtils.getBytes;
 import static org.forgerock.opendj.ldap.CoreMessages.ERR_DN_TYPE_NOT_FOUND;
 
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.NoSuchElementException;
+import java.util.TreeSet;
 import java.util.WeakHashMap;
 
 import org.forgerock.i18n.LocalizableMessage;
 import org.forgerock.i18n.LocalizedIllegalArgumentException;
+import org.forgerock.opendj.ldap.schema.MatchingRule;
 import org.forgerock.opendj.ldap.schema.Schema;
+import org.forgerock.opendj.ldap.schema.Syntax;
 import org.forgerock.opendj.ldap.schema.UnknownSchemaElementException;
 
+import com.forgerock.opendj.util.StaticUtils;
 import com.forgerock.opendj.util.SubstringReader;
 import com.forgerock.opendj.util.Validator;
 
@@ -799,4 +804,135 @@
         }
         return stringValue;
     }
+
+    /**
+     * Returns the normalized string representation of a DN.
+     *
+     * @return The normalized string representation of the provided DN.
+     */
+    public String toNormalizedString() {
+        final StringBuilder builder = new StringBuilder(this.size());
+        if (rdn() == null) {
+            return builder.toString();
+        }
+
+        int i = this.size() - 1;
+        normalizeRDN(builder, parent(i).rdn());
+        for (i--; i >= 0; i--) {
+            final RDN rdn = parent(i).rdn();
+            // Only add a separator if the RDN is not RDN.maxValue().
+            if (rdn.size() != 0) {
+                builder.append('\u0000');
+            }
+            normalizeRDN(builder, rdn);
+        }
+        return builder.toString();
+    }
+
+    /**
+     * 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();
+        switch (sz) {
+        case 0:
+            // Handle RDN.maxValue().
+            builder.append('\u0001');
+            break;
+        case 1:
+            normalizeAVA(builder, rdn.getFirstAVA());
+            break;
+        default:
+            // Need to sort the AVAs before comparing.
+            TreeSet<AVA> a = new TreeSet<AVA>();
+            for (AVA ava : rdn) {
+                a.add(ava);
+            }
+            Iterator<AVA> i = a.iterator();
+            // Normalize the first AVA.
+            normalizeAVA(builder, i.next());
+            while (i.hasNext()) {
+                builder.append('\u0001');
+                normalizeAVA(builder, i.next());
+            }
+            break;
+        }
+        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 {
+                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 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 builder;
+    }
+
 }

--
Gitblit v1.10.0