DN normalization enhancements:
* don't expose toNormalizedString since applications should not depend on the normalized representation (and they invariably will mis-use it)
* change normalized form to be big-endian and replace "," and "+" separators with \u0000 and \u0001 respectively in order to provide a more intuitive ordering, especially in the presence of multiple AVAs.
1 files added
6 files modified
| | |
| | | |
| | | |
| | | |
| | | StringBuilder toNormalizedString(final StringBuilder builder) |
| | | { |
| | | return toString(builder, true); |
| | | } |
| | | |
| | | |
| | | |
| | | StringBuilder toString(final StringBuilder builder) |
| | | { |
| | | return toString(builder, false); |
| | | } |
| | | |
| | | |
| | | |
| | | private ByteString getNormalizeValue() |
| | | { |
| | | final MatchingRule matchingRule = attributeType.getEqualityMatchingRule(); |
| | |
| | | |
| | | |
| | | |
| | | private StringBuilder toString(final StringBuilder builder, |
| | | final boolean normalize) |
| | | StringBuilder toString(final StringBuilder builder) |
| | | { |
| | | final ByteString value = normalize ? getNormalizeValue() : attributeValue; |
| | | |
| | | if (!attributeType.getNames().iterator().hasNext()) |
| | | { |
| | | builder.append(attributeType.getOID()); |
| | | builder.append("=#"); |
| | | StaticUtils.toHex(value, builder); |
| | | StaticUtils.toHex(attributeValue, builder); |
| | | } |
| | | else |
| | | { |
| | | final String name = attributeType.getNameOrOID(); |
| | | if (normalize) |
| | | { |
| | | // Normalizing. |
| | | StaticUtils.toLowerCase(name, builder); |
| | | } |
| | | else |
| | | { |
| | | builder.append(name); |
| | | } |
| | | |
| | | builder.append("="); |
| | | |
| | | final Syntax syntax = attributeType.getSyntax(); |
| | | if (!syntax.isHumanReadable()) |
| | | { |
| | | builder.append("#"); |
| | | StaticUtils.toHex(value, builder); |
| | | StaticUtils.toHex(attributeValue, builder); |
| | | } |
| | | else |
| | | { |
| | | final String str = value.toString(); |
| | | final String str = attributeValue.toString(); |
| | | if (str.length() == 0) |
| | | { |
| | | return builder; |
| | |
| | | |
| | | |
| | | |
| | | /** |
| | | * Compares the provided DN values to determine their relative order in a |
| | | * sorted list. |
| | | * |
| | | * @param dn1 |
| | | * The first DN to be compared. It must not be {@code null}. |
| | | * @param dn2 |
| | | * The second DN to be compared. It must not be {@code null}. |
| | | * @return A negative integer if the first DN should come before the second DN |
| | | * in a sorted list, a positive integer if the first DN should come |
| | | * after the second DN in a sorted list, or zero if the two DN values |
| | | * can be considered equal. |
| | | */ |
| | | private static int compareTo(final DN dn1, final DN dn2) |
| | | { |
| | | // Quickly check if we are comparing against root dse. |
| | | if (dn1.isRootDN()) |
| | | { |
| | | if (dn2.isRootDN()) |
| | | { |
| | | // both are equal. |
| | | return 0; |
| | | } |
| | | else |
| | | { |
| | | // dn1 comes before dn2. |
| | | return -1; |
| | | } |
| | | } |
| | | |
| | | if (dn2.isRootDN()) |
| | | { |
| | | // dn1 comes after dn2. |
| | | return 1; |
| | | } |
| | | |
| | | int dn1Size = dn1.size - 1; |
| | | int dn2Size = dn2.size - 1; |
| | | while (dn1Size >= 0 && dn2Size >= 0) |
| | | { |
| | | final DN dn1Parent = dn1.parent(dn1Size--); |
| | | final DN dn2Parent = dn2.parent(dn2Size--); |
| | | if (dn1Parent.isRootDN()) |
| | | { |
| | | if (dn2Parent.isRootDN()) |
| | | { |
| | | break; |
| | | } |
| | | return -1; |
| | | } |
| | | |
| | | if (dn2Parent.isRootDN()) |
| | | { |
| | | return 1; |
| | | } |
| | | |
| | | final int result = dn1Parent.rdn.compareTo(dn2Parent.rdn); |
| | | if (result > 0) |
| | | { |
| | | return 1; |
| | | } |
| | | else if (result < 0) |
| | | { |
| | | return -1; |
| | | } |
| | | } |
| | | |
| | | // What do we have here? |
| | | if (dn1Size > dn2Size) |
| | | { |
| | | return 1; |
| | | } |
| | | else if (dn1Size < dn2Size) |
| | | { |
| | | return -1; |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | |
| | | |
| | | // Decodes a DN using the provided reader and schema. |
| | | private static DN decode(final String dnString, final SubstringReader reader, |
| | | final Schema schema, final Map<String, DN> cache) |
| | |
| | | // preserve the original whitespace. |
| | | private String stringValue; |
| | | |
| | | private String normalizedStringValue = null; |
| | | |
| | | |
| | | |
| | | // Private constructor. |
| | |
| | | |
| | | |
| | | /** |
| | | * Compares the provided DN values to determine their relative order in a |
| | | * sorted list. |
| | | * |
| | | * @param dn1 |
| | | * The first DN to be compared. It must not be {@code null}. |
| | | * @param dn2 |
| | | * The second DN to be compared. It must not be {@code null}. |
| | | * @return A negative integer if the first DN should come before the second DN |
| | | * in a sorted list, a positive integer if the first DN should come |
| | | * after the second DN in a sorted list, or zero if the two DN values |
| | | * can be considered equal. |
| | | */ |
| | | public int compareTo(final DN dn1, final DN dn2) |
| | | { |
| | | // Quicly check if we are comparing against root dse. |
| | | if (dn1.isRootDN()) |
| | | { |
| | | if (dn2.isRootDN()) |
| | | { |
| | | // both are equal. |
| | | return 0; |
| | | } |
| | | else |
| | | { |
| | | // dn1 comes before dn2. |
| | | return -1; |
| | | } |
| | | } |
| | | |
| | | if (dn2.isRootDN()) |
| | | { |
| | | // dn1 comes after dn2. |
| | | return 1; |
| | | } |
| | | |
| | | int dn1Size = dn1.size - 1; |
| | | int dn2Size = dn2.size - 1; |
| | | while (dn1Size >= 0 && dn2Size >= 0) |
| | | { |
| | | final DN dn1Parent = dn1.parent(dn1Size--); |
| | | final DN dn2Parent = dn2.parent(dn2Size--); |
| | | if (dn1Parent.isRootDN()) |
| | | { |
| | | if (dn2Parent.isRootDN()) |
| | | { |
| | | break; |
| | | } |
| | | return -1; |
| | | } |
| | | |
| | | if (dn2Parent.isRootDN()) |
| | | { |
| | | return 1; |
| | | } |
| | | |
| | | final int result = dn1Parent.rdn.compareTo(dn2Parent.rdn); |
| | | if (result > 0) |
| | | { |
| | | return 1; |
| | | } |
| | | else if (result < 0) |
| | | { |
| | | return -1; |
| | | } |
| | | } |
| | | // What do we have here? |
| | | if (dn1Size > dn2Size) |
| | | { |
| | | return 1; |
| | | } |
| | | else if (dn1Size < dn2Size) |
| | | { |
| | | return -1; |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | |
| | | } |
| | | else if (obj instanceof DN) |
| | | { |
| | | final String s1 = toNormalizedString(); |
| | | final String s2 = ((DN) obj).toNormalizedString(); |
| | | return s1.equals(s2); |
| | | } |
| | | else |
| | | DN other = (DN)obj; |
| | | if(size == other.size()) |
| | | { |
| | | return false; |
| | | if(size == 0) |
| | | { |
| | | return true; |
| | | } |
| | | |
| | | if(rdn.equals(other.rdn)) |
| | | { |
| | | return parent.equals(other.parent); |
| | | } |
| | | } |
| | | } |
| | | |
| | | return false; |
| | | } |
| | | |
| | | |
| | |
| | | @Override |
| | | public int hashCode() |
| | | { |
| | | final String s = toNormalizedString(); |
| | | return s.hashCode(); |
| | | if (size == 0) |
| | | { |
| | | return 0; |
| | | } |
| | | else |
| | | { |
| | | return 31 * parent.hashCode() + rdn.hashCode(); |
| | | } |
| | | } |
| | | |
| | | |
| | |
| | | |
| | | |
| | | /** |
| | | * Returns the normalized string representation of this DN. |
| | | * |
| | | * @return The normalized string representation of this DN. |
| | | */ |
| | | public String toNormalizedString() |
| | | { |
| | | if (rdn == null) |
| | | { |
| | | return "".intern(); |
| | | } |
| | | if (normalizedStringValue == null) |
| | | { |
| | | final StringBuilder builder = new StringBuilder(); |
| | | rdn.toNormalizedString(builder); |
| | | if (!parent.isRootDN()) |
| | | { |
| | | builder.append(','); |
| | | builder.append(parent.toNormalizedString()); |
| | | } |
| | | normalizedStringValue = builder.toString(); |
| | | } |
| | | return normalizedStringValue; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Returns the RFC 4514 string representation of this DN. |
| | | * |
| | | * @return The RFC 4514 string representation of this DN. |
| | |
| | | |
| | | |
| | | |
| | | StringBuilder toNormalizedString(final StringBuilder builder) |
| | | { |
| | | final int sz = avas.length; |
| | | if (sz == 1) |
| | | { |
| | | return avas[0].toNormalizedString(builder); |
| | | } |
| | | else |
| | | { |
| | | // Need to sort the AVAs before comparing. |
| | | final AVA[] a = new AVA[sz]; |
| | | System.arraycopy(avas, 0, a, 0, sz); |
| | | Arrays.sort(a); |
| | | // Normalize the first AVA. |
| | | a[0].toNormalizedString(builder); |
| | | for (int i = 1; i < sz; i++) |
| | | { |
| | | builder.append('+'); |
| | | a[i].toNormalizedString(builder); |
| | | } |
| | | |
| | | return builder; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | StringBuilder toString(final StringBuilder builder) |
| | | { |
| | | return builder.append(toString()); |
| | |
| | | * 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; |
| | | |
| | | |
| | | /** |
| | |
| | | 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) |
| | | catch (final Exception e) |
| | | { |
| | | final AttributeType type = ava1.getAttributeType(); |
| | | |
| | | if (!type.equals(ava2.getAttributeType())) |
| | | { |
| | | 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; |
| | | throw DecodeException.error(LocalizableMessage.raw(e.toString())); |
| | | } |
| | | } |
| | | |
| | | return ConditionResult.UNDEFINED; |
| | | /** |
| | | * 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) |
| | | { |
| | | if(dn.rdn() == null) |
| | | { |
| | | return builder; |
| | | } |
| | | |
| | | |
| | | |
| | | private ConditionResult matchDNs(final DN dn1, final DN dn2) |
| | | int i = dn.size() - 1; |
| | | normalizeRDN(builder, dn.parent(i).rdn()); |
| | | for (i--; i >= 0; i--) |
| | | { |
| | | final int sz1 = dn1.size(); |
| | | final int sz2 = dn2.size(); |
| | | |
| | | if (sz1 != sz2) |
| | | { |
| | | return ConditionResult.FALSE; |
| | | builder.append('\u0000'); |
| | | normalizeRDN(builder, dn.parent(i).rdn()); |
| | | } |
| | | 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; |
| | | } |
| | | return builder; |
| | | } |
| | | |
| | | |
| | | |
| | | private ConditionResult matchRDNs(final RDN rdn1, final RDN rdn2) |
| | | /** |
| | | * 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 sz1 = rdn1.size(); |
| | | final int sz2 = rdn2.size(); |
| | | |
| | | if (sz1 != sz2) |
| | | final int sz = rdn.size(); |
| | | if (sz == 1) |
| | | { |
| | | return ConditionResult.FALSE; |
| | | } |
| | | else if (sz1 == 1) |
| | | { |
| | | return matchAVAs(rdn1.getFirstAVA(), rdn2.getFirstAVA()); |
| | | 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++) |
| | | { |
| | | final ConditionResult result = matchAVAs(a1[i], a2[i]); |
| | | if (result != ConditionResult.TRUE) |
| | | { |
| | | return result; |
| | | return builder; |
| | | } |
| | | } |
| | | |
| | | return ConditionResult.TRUE; |
| | | /** |
| | | * 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; |
| | | } |
| | | } |
| | |
| | | assertEquals(c, e); |
| | | assertEquals(c.hashCode(), e.hashCode()); |
| | | |
| | | assertEquals(c.toNormalizedString(), e.toNormalizedString()); |
| | | assertEquals(c.toString(), e.toString()); |
| | | |
| | | assertEquals(c.rdn(), RDN.valueOf("dc=foo")); |
| | |
| | | assertEquals(p, e); |
| | | assertEquals(p.hashCode(), e.hashCode()); |
| | | |
| | | assertEquals(p.toNormalizedString(), e.toNormalizedString()); |
| | | assertEquals(p.toString(), e.toString()); |
| | | |
| | | assertEquals(p.rdn(), RDN.valueOf("dc=bar")); |
| | |
| | | final DN nullDN = DN.rootDN(); |
| | | assertTrue(nullDN.isRootDN()); |
| | | assertTrue(nullDN.size() == 0); |
| | | assertEquals(nullDN.toNormalizedString(), ""); |
| | | } |
| | | |
| | | |
| | |
| | | |
| | | |
| | | /** |
| | | * Tests the toNoramlizedString methods. |
| | | * |
| | | * @throws Exception |
| | | * If the test failed unexpectedly. |
| | | */ |
| | | @Test |
| | | public void testToNormalizedString() throws Exception |
| | | { |
| | | final DN dn = DN.valueOf("dc=example,dc=com"); |
| | | assertEquals(dn.toNormalizedString(), "dc=example,dc=com"); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Test the RFC 4514 string representation of the DN. |
| | | * |
| | | * @param rawDN |
| | |
| | | public void testValueOfString(final String rawDN, final String normDN, |
| | | final String stringDN) throws Exception |
| | | { |
| | | final DN dn = DN.valueOf(rawDN); |
| | | final StringBuilder buffer = new StringBuilder(); |
| | | buffer.append(normDN); |
| | | Platform.normalize(buffer); |
| | | assertEquals(dn.toNormalizedString(), buffer.toString()); |
| | | final DN raw = DN.valueOf(rawDN); |
| | | final DN string = DN.valueOf(stringDN); |
| | | assertEquals(raw, string); |
| | | } |
| | | } |
| | |
| | | final String stringRDN) throws Exception |
| | | { |
| | | final RDN rdn = RDN.valueOf(rawRDN); |
| | | final StringBuilder buffer = new StringBuilder(); |
| | | buffer.append(normRDN); |
| | | Platform.normalize(buffer); |
| | | final StringBuilder normalBuffer = new StringBuilder(); |
| | | rdn.toNormalizedString(normalBuffer); |
| | | assertEquals(normalBuffer.toString(), buffer.toString()); |
| | | final RDN string = RDN.valueOf(stringRDN); |
| | | assertEquals(rdn, string); |
| | | } |
| | | |
| | | |
| New file |
| | |
| | | /* |
| | | * CDDL HEADER START |
| | | * |
| | | * The contents of this file are subject to the terms of the |
| | | * Common Development and Distribution License, Version 1.0 only |
| | | * (the "License"). You may not use this file except in compliance |
| | | * with the License. |
| | | * |
| | | * You can obtain a copy of the license at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE |
| | | * or https://OpenDS.dev.java.net/OpenDS.LICENSE. |
| | | * See the License for the specific language governing permissions |
| | | * and limitations under the License. |
| | | * |
| | | * When distributing Covered Code, include this CDDL HEADER in each |
| | | * file and include the License file at |
| | | * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, |
| | | * add the following below this CDDL HEADER, with the fields enclosed |
| | | * by brackets "[]" replaced with your own identifying information: |
| | | * Portions Copyright [yyyy] [name of copyright owner] |
| | | * |
| | | * CDDL HEADER END |
| | | * |
| | | * |
| | | * Copyright 2009-2010 Sun Microsystems, Inc. |
| | | */ |
| | | |
| | | package org.opends.sdk.schema; |
| | | |
| | | import org.testng.annotations.Test; |
| | | import org.testng.annotations.DataProvider; |
| | | import static org.testng.Assert.assertEquals; |
| | | import org.opends.sdk.ConditionResult; |
| | | import org.opends.sdk.ByteString; |
| | | import static org.opends.sdk.schema.SchemaConstants.EMR_DN_OID; |
| | | import com.sun.opends.sdk.util.Platform; |
| | | |
| | | /** |
| | | * Test the DistinguishedNameEqualityMatchingRule |
| | | */ |
| | | public class DistinguishedNameEqualityMatchingRuleTest extends MatchingRuleTest |
| | | { |
| | | @DataProvider(name = "matchingRuleInvalidAttributeValues") |
| | | public Object[][] createMatchingRuleInvalidAttributeValues() |
| | | { |
| | | return new Object[][] { { "manager" }, { "manager " }, { "=Jim" }, |
| | | { " =Jim" }, { "= Jim" }, |
| | | { " = Jim" }, |
| | | { "cn+Jim" }, |
| | | { "cn + Jim" }, |
| | | { "cn=Jim+" }, |
| | | { "cn=Jim+manager" }, |
| | | { "cn=Jim+manager " }, |
| | | { "cn=Jim+manager," },// { "cn=Jim," }, { "cn=Jim, " }, { "c[n]=Jim" }, |
| | | { "_cn=Jim" }, { "c_n=Jim" }, { "cn\"=Jim" }, { "c\"n=Jim" }, |
| | | { "1cn=Jim" }, { "cn+uid=Jim" }, { "-cn=Jim" }, { "/tmp=a" }, |
| | | { "\\tmp=a" }, { "cn;lang-en=Jim" }, { "@cn=Jim" }, |
| | | { "_name_=Jim" }, |
| | | { "\u03c0=pi" }, |
| | | { "v1.0=buggy" },// { "1.=buggy" }, { ".1=buggy" }, |
| | | { "oid.1." }, { "1.3.6.1.4.1.1466..0=#04024869" }, { "cn=#a" }, |
| | | { "cn=#ag" }, { "cn=#ga" }, { "cn=#abcdefgh" }, |
| | | { "cn=a\\b" }, // { "cn=a\\bg" }, { "cn=\"hello" }, |
| | | { "cn=+mail=,dc=example,dc=com" }, { "cn=xyz+sn=,dc=example,dc=com" }, |
| | | { "cn=,dc=example,dc=com" } }; |
| | | } |
| | | |
| | | @DataProvider(name = "matchingrules") |
| | | public Object[][] createMatchingRuleTest() |
| | | { |
| | | return new Object[][] { |
| | | { "", "", ConditionResult.TRUE }, |
| | | { " ", "", ConditionResult.TRUE }, |
| | | { "cn=", "cn=", ConditionResult.TRUE }, |
| | | { "cn= ", "cn=", ConditionResult.TRUE }, |
| | | { "cn =", "cn=", ConditionResult.TRUE }, |
| | | { "cn = ", "cn=", ConditionResult.TRUE }, |
| | | { "dc=com", "dc=com", ConditionResult.TRUE }, |
| | | { "dc=com+o=com", "dc=com+o=com", ConditionResult.TRUE }, |
| | | { "DC=COM", "dc=com", ConditionResult.TRUE }, |
| | | { "dc = com", "dc=com", ConditionResult.TRUE }, |
| | | { " dc = com ", "dc=com", ConditionResult.TRUE }, |
| | | { "dc=example,dc=com", "dc=example,dc=com", ConditionResult.TRUE }, |
| | | { "dc=example, dc=com", "dc=example,dc=com", ConditionResult.TRUE }, |
| | | { "dc=example ,dc=com", "dc=example,dc=com", ConditionResult.TRUE }, |
| | | { "dc =example , dc = com", "dc=example,dc=com", |
| | | ConditionResult.TRUE }, |
| | | { "givenName=John+cn=Doe,ou=People,dc=example,dc=com", |
| | | "cn=doe+givenname=john,ou=people,dc=example,dc=com", |
| | | ConditionResult.TRUE }, |
| | | { "givenName=John\\+cn=Doe,ou=People,dc=example,dc=com", |
| | | "givenname=john\\+cn\\=doe,ou=people,dc=example,dc=com", |
| | | ConditionResult.TRUE }, |
| | | { "cn=Doe\\, John,ou=People,dc=example,dc=com", |
| | | "cn=doe\\, john,ou=people,dc=example,dc=com", ConditionResult.TRUE }, |
| | | { "UID=jsmith,DC=example,DC=net", "uid=jsmith,dc=example,dc=net", |
| | | ConditionResult.TRUE }, |
| | | { "OU=Sales+CN=J. Smith,DC=example,DC=net", |
| | | "cn=j. smith+ou=sales,dc=example,dc=net", ConditionResult.TRUE }, |
| | | { "CN=James \\\"Jim\\\" Smith\\, III,DC=example,DC=net", |
| | | "cn=james \\\"jim\\\" smith\\, iii,dc=example,dc=net", |
| | | ConditionResult.TRUE }, |
| | | { "CN=John Smith\\2C III,DC=example,DC=net", |
| | | "cn=john smith\\, iii,dc=example,dc=net", ConditionResult.TRUE }, |
| | | { "CN=\\23John Smith\\20,DC=example,DC=net", |
| | | "cn=\\#john smith,dc=example,dc=net", ConditionResult.TRUE }, |
| | | { |
| | | "CN=Before\\0dAfter,DC=example,DC=net", |
| | | // \0d is a hex representation of Carriage return. It is mapped |
| | | // to a SPACE as defined in the MAP ( RFC 4518) |
| | | "cn=before after,dc=example,dc=net", ConditionResult.TRUE }, |
| | | { "2.5.4.3=#04024869", |
| | | // Unicode codepoints from 0000-0008 are mapped to nothing. |
| | | "cn=hi", ConditionResult.TRUE }, |
| | | { "1.1.1=", "1.1.1=", ConditionResult.TRUE }, |
| | | { "CN=Lu\\C4\\8Di\\C4\\87", "cn=lu\u010di\u0107", |
| | | ConditionResult.TRUE }, |
| | | { "ou=\\e5\\96\\b6\\e6\\a5\\ad\\e9\\83\\a8,o=Airius", |
| | | "ou=\u55b6\u696d\u90e8,o=airius", ConditionResult.TRUE }, |
| | | { "photo=\\ john \\ ,dc=com", "photo=\\ john \\ ,dc=com", |
| | | ConditionResult.TRUE }, |
| | | { "AB-global=", "ab-global=", ConditionResult.TRUE }, |
| | | { "OU= Sales + CN = J. Smith ,DC=example,DC=net", |
| | | "cn=j. smith+ou=sales,dc=example,dc=net", ConditionResult.TRUE }, |
| | | { "cn=John+a=Doe", "a=Doe+cn=john", ConditionResult.TRUE }, |
| | | { "O=\"Sue, Grabbit and Runn\",C=US", "o=sue\\, grabbit and runn,c=us", |
| | | ConditionResult.TRUE }, }; |
| | | } |
| | | |
| | | /** |
| | | * DN test data provider. |
| | | * |
| | | * @return The array of test DN strings. |
| | | */ |
| | | @DataProvider(name = "testDNs") |
| | | public Object[][] createData() |
| | | { |
| | | return new Object[][] { |
| | | { "", ""}, |
| | | { " ", ""}, |
| | | { "cn=", "cn="}, |
| | | { "cn= ", "cn="}, |
| | | { "cn =", "cn="}, |
| | | { "cn = ", "cn="}, |
| | | { "dc=com", "dc=com"}, |
| | | { "dc=com+o=com", "dc=com\u0001o=com"}, |
| | | { "DC=COM", "dc=com"}, |
| | | { "dc = com", "dc=com"}, |
| | | { " dc = com ", "dc=com"}, |
| | | { "dc=example,dc=com", "dc=com\u0000dc=example"}, |
| | | { "dc=example, dc=com", "dc=com\u0000dc=example"}, |
| | | { "dc=example ,dc=com", "dc=com\u0000dc=example"}, |
| | | { "dc =example , dc = com", "dc=com\u0000dc=example"}, |
| | | { "givenName=John+cn=Doe,ou=People,dc=example,dc=com", |
| | | "dc=com\u0000dc=example\u0000ou=people\u0000cn=doe\u0001givenname=john"}, |
| | | { "givenName=John\\+cn=Doe,ou=People,dc=example,dc=com", |
| | | "dc=com\u0000dc=example\u0000ou=people\u0000givenname=john\\+cn\\=doe"}, |
| | | { "cn=Doe\\, John,ou=People,dc=example,dc=com", |
| | | "dc=com\u0000dc=example\u0000ou=people\u0000cn=doe\\, john"}, |
| | | { "UID=jsmith,DC=example,DC=net", "dc=net\u0000dc=example\u0000uid=jsmith"}, |
| | | { "OU=Sales+CN=J. Smith,DC=example,DC=net", |
| | | "dc=net\u0000dc=example\u0000cn=j. smith\u0001ou=sales"}, |
| | | { "CN=James \\\"Jim\\\" Smith\\, III,DC=example,DC=net", |
| | | "dc=net\u0000dc=example\u0000cn=james \\\"jim\\\" smith\\, iii"}, |
| | | { "CN=John Smith\\2C III,DC=example,DC=net", |
| | | "dc=net\u0000dc=example\u0000cn=john smith\\, iii"}, |
| | | { "CN=\\23John Smith\\20,DC=example,DC=net", |
| | | "dc=net\u0000dc=example\u0000cn=\\#john smith"}, |
| | | { |
| | | "CN=Before\\0dAfter,DC=example,DC=net", |
| | | // \0d is a hex representation of Carriage return. It is mapped |
| | | // to a SPACE as defined in the MAP ( RFC 4518) |
| | | "dc=net\u0000dc=example\u0000cn=before after"}, |
| | | { "2.5.4.3=#04024869", |
| | | // Unicode codepoints from 0000-0008 are mapped to nothing. |
| | | "cn=hi"}, |
| | | { "1.1.1=", "1.1.1="}, |
| | | { "CN=Lu\\C4\\8Di\\C4\\87", "cn=lu\u010di\u0107"}, |
| | | { "ou=\\e5\\96\\b6\\e6\\a5\\ad\\e9\\83\\a8,o=Airius", |
| | | "o=airius\u0000ou=\u55b6\u696d\u90e8"}, |
| | | { "photo=\\ john \\ ,dc=com", "dc=com\u0000photo=\\ john \\ "}, |
| | | { "AB-global=", "ab-global="}, |
| | | { "OU= Sales + CN = J. Smith ,DC=example,DC=net", |
| | | "dc=net\u0000dc=example\u0000cn=j. smith\u0001ou=sales"}, |
| | | { "cn=John+a=", "a=\u0001cn=john"}, |
| | | { "O=\"Sue, Grabbit and Runn\",C=US", |
| | | "c=us\u0000o=sue\\, grabbit and runn" }, }; |
| | | } |
| | | |
| | | protected MatchingRule getRule() |
| | | { |
| | | return Schema.getCoreSchema().getMatchingRule(EMR_DN_OID); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Test the normalized values |
| | | */ |
| | | @Test(dataProvider = "testDNs") |
| | | public void matchingRules(final String value1, final String value2) |
| | | throws Exception |
| | | { |
| | | final MatchingRule rule = getRule(); |
| | | |
| | | final ByteString normalizedValue1 = rule.normalizeAttributeValue(ByteString |
| | | .valueOf(value1)); |
| | | StringBuilder buffer = new StringBuilder(value2); |
| | | Platform.normalize(buffer); |
| | | final ByteString expectedValue = ByteString.valueOf(buffer); |
| | | assertEquals(normalizedValue1, expectedValue); |
| | | } |
| | | } |