mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Matthew Swift
05.47.2011 5d745a56a15b894ef0ca33538ea6e67170f96f96
Fix OPENDJ-376: Add isInScopeOf, localName, and rename methods to DN class
2 files modified
352 ■■■■■ changed files
opendj3/opendj-ldap-sdk/src/main/java/org/forgerock/opendj/ldap/DN.java 170 ●●●●● patch | view | raw | blame | history
opendj3/opendj-ldap-sdk/src/test/java/org/forgerock/opendj/ldap/DNTestCase.java 182 ●●●●● patch | view | raw | blame | history
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.
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));
  }
}