From 5d745a56a15b894ef0ca33538ea6e67170f96f96 Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Mon, 05 Dec 2011 17:47:17 +0000
Subject: [PATCH] Fix OPENDJ-376: Add isInScopeOf, localName, and rename methods to DN class
---
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/DNTestCase.java | 182 ++++++++++++++++++++++++++++++
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/DN.java | 170 +++++++++++++++++++++++++++-
2 files changed, 345 insertions(+), 7 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 008528d..1176c4e 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
@@ -23,6 +23,7 @@
*
*
* Copyright 2009-2010 Sun Microsystems, Inc.
+ * Portions copyright 2011 ForgeRock AS.
*/
package org.forgerock.opendj.ldap;
@@ -269,7 +270,7 @@
parent = ROOT_DN;
}
- return new DN(rdn, parent, dnString);
+ return new DN(parent, rdn, dnString);
}
@@ -299,7 +300,7 @@
private final RDN rdn;
- private final DN parent;
+ private DN parent;
private final int size;
@@ -310,12 +311,21 @@
// Private constructor.
- private DN(final RDN rdn, final DN parent, final String stringValue)
+ private DN(final DN parent, final RDN rdn, final String stringValue)
{
- this.rdn = rdn;
+ this(parent, rdn, stringValue, parent != null ? parent.size + 1 : 0);
+ }
+
+
+
+ // Private constructor.
+ private DN(final DN parent, final RDN rdn, final String stringValue,
+ final int size)
+ {
this.parent = parent;
+ this.rdn = rdn;
this.stringValue = stringValue;
- this.size = parent != null ? parent.size + 1 : 0;
+ this.size = size;
}
@@ -353,7 +363,7 @@
DN newDN = this;
for (i = 0; i < rdns.length; i++)
{
- newDN = new DN(rdns[i], newDN, null);
+ newDN = new DN(newDN, rdns[i], null);
}
return newDN;
}
@@ -374,7 +384,7 @@
public DN child(final RDN rdn) throws NullPointerException
{
Validator.ensureNotNull(rdn);
- return new DN(rdn, this, null);
+ return new DN(this, rdn, null);
}
@@ -501,6 +511,73 @@
/**
+ * Returns {@code true} if this DN matches the provided base DN and search
+ * scope.
+ *
+ * @param dn
+ * The base DN.
+ * @param scope
+ * The search scope.
+ * @return {@code true} if this DN matches the provided base DN and search
+ * scope, otherwise {@code false}.
+ * @throws NullPointerException
+ * If {@code dn} or {@code scope} was {@code null}.
+ */
+ public boolean isInScopeOf(DN dn, SearchScope scope)
+ {
+ if (scope == SearchScope.BASE_OBJECT)
+ {
+ // The base DN must equal this DN.
+ return equals(dn);
+ }
+ else if (scope == SearchScope.SINGLE_LEVEL)
+ {
+ // The parent DN must equal the base DN.
+ return isChildOf(dn);
+ }
+ else if (scope == SearchScope.SUBORDINATES)
+ {
+ // This DN must be a descendant of the provided base DN, but
+ // not equal to it.
+ return isSubordinateOrEqualTo(dn) && !equals(dn);
+ }
+ else if (scope == SearchScope.WHOLE_SUBTREE)
+ {
+ // This DN must be a descendant of the provided base DN.
+ return isSubordinateOrEqualTo(dn);
+ }
+ else
+ {
+ // This is a scope that we don't recognize.
+ return false;
+ }
+ }
+
+
+
+ /**
+ * Returns {@code true} if this DN matches the provided base DN and search
+ * scope.
+ *
+ * @param dn
+ * The base DN.
+ * @param scope
+ * The search scope.
+ * @return {@code true} if this DN matches the provided base DN and search
+ * scope, otherwise {@code false}.
+ * @throws LocalizedIllegalArgumentException
+ * If {@code dn} is not a valid LDAP string representation of a DN.
+ * @throws NullPointerException
+ * If {@code dn} or {@code scope} was {@code null}.
+ */
+ public boolean isInScopeOf(String dn, SearchScope scope)
+ {
+ return isInScopeOf(valueOf(dn), scope);
+ }
+
+
+
+ /**
* Returns {@code true} if this DN is the immediate parent of the provided DN.
*
* @param dn
@@ -702,6 +779,52 @@
/**
+ * Returns the DN whose content is the specified number of RDNs from this DN.
+ * The following equivalences hold:
+ *
+ * <pre>
+ * dn.localName(0).isRootDN();
+ * dn.localName(1).equals(rootDN.child(dn.rdn()));
+ * dn.localName(dn.size()).equals(dn);
+ * </pre>
+ *
+ * @param index
+ * The number of RDNs to be included in the local name.
+ * @return The DN whose content is the specified number of RDNs from this DN.
+ * @throws IllegalArgumentException
+ * If {@code index} is less than zero.
+ */
+ public DN localName(final int index) throws IllegalArgumentException
+ {
+ Validator.ensureTrue(index >= 0, "index less than zero");
+
+ if (index == 0)
+ {
+ return ROOT_DN;
+ }
+ else if (index >= size)
+ {
+ return this;
+ }
+ else
+ {
+ final DN localName = new DN(null, rdn, null, index);
+ DN nextLocalName = localName;
+ DN lastDN = parent;
+ for (int i = index - 1; i > 0; i--)
+ {
+ nextLocalName.parent = new DN(null, lastDN.rdn, null, i);
+ nextLocalName = nextLocalName.parent;
+ lastDN = lastDN.parent;
+ }
+ nextLocalName.parent = ROOT_DN;
+ return localName;
+ }
+ }
+
+
+
+ /**
* Returns the DN which is the immediate parent of this DN, or {@code null} if
* this DN is the Root DN.
* <p>
@@ -762,6 +885,39 @@
/**
+ * 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.
+ * @throws NullPointerException
+ * If {@code fromDN} or {@code toDN} was {@code null}.
+ */
+ public DN rename(final DN fromDN, final DN toDN) throws NullPointerException
+ {
+ Validator.ensureNotNull(fromDN, toDN);
+
+ if (!isSubordinateOrEqualTo(fromDN))
+ {
+ return this;
+ }
+ else if (equals(fromDN))
+ {
+ return toDN;
+ }
+ else
+ {
+ return toDN.child(localName(size - fromDN.size));
+ }
+ }
+
+
+
+ /**
* Returns the number of RDN components in this DN.
*
* @return The number of RDN components in this DN.
diff --git a/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/DNTestCase.java b/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/DNTestCase.java
index 654370a..ccfd20b 100644
--- a/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/DNTestCase.java
+++ b/opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/DNTestCase.java
@@ -981,4 +981,186 @@
final DN string = DN.valueOf(stringDN);
assertEquals(raw, string);
}
+
+
+
+ /**
+ * Test data for testInScopeOf tests.
+ *
+ * @return Test data.
+ */
+ @DataProvider
+ public Object[][] createIsInScopeOfTestData()
+ {
+ // @formatter:off
+ return new Object[][]
+ {
+ { "dc=x,dc=y", "dc=x,dc=y", SearchScope.BASE_OBJECT, true },
+ { "dc=x,dc=y", "dc=z,dc=y", SearchScope.BASE_OBJECT, false },
+ { "dc=x,dc=z", "dc=x,dc=y", SearchScope.BASE_OBJECT, false },
+ { "dc=x,dc=y", "dc=y", SearchScope.BASE_OBJECT, false },
+ { "dc=y", "dc=x,dc=y", SearchScope.BASE_OBJECT, false },
+
+ { "dc=x,dc=y", "dc=x,dc=y", SearchScope.SINGLE_LEVEL, false },
+ { "dc=x,dc=y", "dc=y", SearchScope.SINGLE_LEVEL, true },
+ { "dc=z,dc=x,dc=y", "dc=y", SearchScope.SINGLE_LEVEL, false },
+ { "dc=y", "dc=x,dc=y", SearchScope.SINGLE_LEVEL, false },
+ { "dc=x,dc=z", "dc=y", SearchScope.SINGLE_LEVEL, false },
+
+ { "dc=x,dc=y", "dc=x,dc=y", SearchScope.SUBORDINATES, false },
+ { "dc=x,dc=y", "dc=y", SearchScope.SUBORDINATES, true },
+ { "dc=z,dc=x,dc=y", "dc=y", SearchScope.SUBORDINATES, true },
+ { "dc=y", "dc=x,dc=y", SearchScope.SUBORDINATES, false },
+ { "dc=x,dc=z", "dc=y", SearchScope.SUBORDINATES, false },
+
+ { "dc=x,dc=y", "dc=x,dc=y", SearchScope.WHOLE_SUBTREE, true },
+ { "dc=x,dc=y", "dc=y", SearchScope.WHOLE_SUBTREE, true },
+ { "dc=z,dc=x,dc=y", "dc=y", SearchScope.WHOLE_SUBTREE, true },
+ { "dc=y", "dc=x,dc=y", SearchScope.WHOLE_SUBTREE, false },
+ { "dc=x,dc=z", "dc=y", SearchScope.WHOLE_SUBTREE, false },
+ };
+ // @formatter:on
+ }
+
+
+
+ /**
+ * Tests {@link DN#isInScopeOf(String, SearchScope)}.
+ *
+ * @param dn
+ * The target DN.
+ * @param baseDN
+ * The scope base DN.
+ * @param scope
+ * The search scope.
+ * @param expectedResult
+ * The expected result.
+ */
+ @Test(dataProvider="createIsInScopeOfTestData")
+ public void testIsInScopeOfString(final String dn, final String baseDN,
+ final SearchScope scope, final boolean expectedResult)
+ {
+ assertEquals(DN.valueOf(dn).isInScopeOf(baseDN, scope), expectedResult);
+ }
+
+
+
+ /**
+ * Tests {@link DN#isInScopeOf(DN, SearchScope)}.
+ *
+ * @param dn
+ * The target DN.
+ * @param baseDN
+ * The scope base DN.
+ * @param scope
+ * The search scope.
+ * @param expectedResult
+ * The expected result.
+ */
+ @Test(dataProvider = "createIsInScopeOfTestData")
+ public void testIsInScopeOfDN(final String dn, final String baseDN,
+ final SearchScope scope, final boolean expectedResult)
+ {
+ assertEquals(DN.valueOf(dn).isInScopeOf(DN.valueOf(baseDN), scope),
+ expectedResult);
+ }
+
+
+
+ /**
+ * Test data for testLocalName tests.
+ *
+ * @return Test data.
+ */
+ @DataProvider
+ public Object[][] createLocalNameTestData()
+ {
+ // @formatter:off
+ return new Object[][]
+ {
+ { "", 0, "" },
+ { "", 1, "" },
+
+ { "dc=x", 0, "" },
+ { "dc=x", 1, "dc=x" },
+ { "dc=x", 2, "dc=x" },
+
+ { "dc=x,dc=y", 0, "" },
+ { "dc=x,dc=y", 1, "dc=x" },
+ { "dc=x,dc=y", 2, "dc=x,dc=y" },
+ { "dc=x,dc=y", 3, "dc=x,dc=y" },
+
+ { "dc=x,dc=y,dc=z", 0, "" },
+ { "dc=x,dc=y,dc=z", 1, "dc=x" },
+ { "dc=x,dc=y,dc=z", 2, "dc=x,dc=y" },
+ { "dc=x,dc=y,dc=z", 3, "dc=x,dc=y,dc=z" },
+ { "dc=x,dc=y,dc=z", 4, "dc=x,dc=y,dc=z" },
+ };
+ // @formatter:on
+ }
+
+
+
+ /**
+ * Tests {@link DN#localName(int)}.
+ *
+ * @param dn
+ * The DN whose local name is to be obtained.
+ * @param index
+ * The number of RDNs in the local name.
+ * @param expectedDN
+ * The expected local name.
+ */
+ @Test(dataProvider = "createLocalNameTestData")
+ public void testLocalName(final String dn, final int index,
+ final String expectedDN)
+ {
+ assertEquals(DN.valueOf(dn).localName(index), DN.valueOf(expectedDN));
+ }
+
+
+
+ /**
+ * Test data for testLocalName tests.
+ *
+ * @return Test data.
+ */
+ @DataProvider
+ public Object[][] createRenameTestData()
+ {
+ // @formatter:off
+ return new Object[][]
+ {
+ { "", "", "", "" },
+ { "", "", "dc=x", "dc=x" },
+ { "dc=x", "", "dc=y", "dc=x,dc=y" },
+ { "dc=x", "dc=x", "dc=y", "dc=y" },
+ { "dc=x,dc=y", "dc=y", "dc=z", "dc=x,dc=z" },
+ { "dc=x,dc=y", "dc=x,dc=y", "dc=z", "dc=z" },
+ { "dc=x,dc=y", "dc=x", "dc=z", "dc=x,dc=y" },
+ };
+ // @formatter:on
+ }
+
+
+
+ /**
+ * Tests {@link DN#rename(DN, DN)}.
+ *
+ * @param dn
+ * The DN to be renamed.
+ * @param fromDN
+ * The source DN.
+ * @param toDN
+ * The destination DN.
+ * @param expectedDN
+ * The expected result.
+ */
+ @Test(dataProvider = "createRenameTestData")
+ public void testRename(final String dn, final String fromDN,
+ final String toDN, final String expectedDN)
+ {
+ assertEquals(DN.valueOf(dn).rename(DN.valueOf(fromDN), DN.valueOf(toDN)),
+ DN.valueOf(expectedDN));
+ }
}
--
Gitblit v1.10.0