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

matthew_swift
08.01.2009 12d33c6a8ead4d8fbf8ef74fcf1b75152fa62057
Fix issue 3779 - merge with real attribute show only virtual attribute value.
2 files modified
437 ■■■■■ changed files
opends/src/server/org/opends/server/types/Entry.java 93 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/UserDefinedVirtualAttributeProviderTestCase.java 344 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/types/Entry.java
@@ -2865,13 +2865,13 @@
         new HashMap<AttributeType,List<Attribute>>(
              userAttributes.size());
    deepCopy(userAttributes, userAttrsCopy, false, false, false,
        true);
        true, false);
    HashMap<AttributeType,List<Attribute>> operationalAttrsCopy =
         new HashMap<AttributeType,List<Attribute>>(
                  operationalAttributes.size());
    deepCopy(operationalAttributes, operationalAttrsCopy, false,
        false, false, true);
        false, false, true, false);
    for (AttributeType t : suppressedAttributes.keySet())
    {
@@ -2917,17 +2917,22 @@
   *          Indicates whether to exclude real attributes.
   * @param omitVirtual
   *          Indicates whether to exclude virtual attributes.
   * @param mergeDuplicates
   *          Indicates whether duplicate attributes should be merged.
   */
  private void deepCopy(Map<AttributeType,List<Attribute>> source,
                        Map<AttributeType,List<Attribute>> target,
                        boolean omitValues,
                        boolean omitEmpty,
                        boolean omitReal,
                        boolean omitVirtual)
                        boolean omitVirtual,
                        boolean mergeDuplicates)
  {
    for (AttributeType t : source.keySet())
    for (Map.Entry<AttributeType, List<Attribute>> mapEntry :
      source.entrySet())
    {
      List<Attribute> sourceList = source.get(t);
      AttributeType t = mapEntry.getKey();
      List<Attribute> sourceList = mapEntry.getValue();
      ArrayList<Attribute> targetList =
           new ArrayList<Attribute>(sourceList.size());
@@ -2945,9 +2950,32 @@
        {
          continue;
        }
        else if (omitValues)
        if (omitValues)
        {
          targetList.add(Attributes.empty(a));
          a = Attributes.empty(a);
        }
        if (!targetList.isEmpty() && mergeDuplicates)
        {
          // Ensure that there is only one attribute with the same
          // type and options. This is not very efficient but will
          // occur very rarely.
          boolean found = false;
          for (int i = 0; i < targetList.size(); i++)
          {
            Attribute otherAttribute = targetList.get(i);
            if (otherAttribute.optionsEqual(a.getOptions()))
            {
              targetList.set(i, Attributes.merge(a, otherAttribute));
              found = true;
            }
          }
          if (!found)
          {
            targetList.add(a);
          }
        }
        else
        {
@@ -3266,30 +3294,10 @@
   */
  public void processVirtualAttributes()
  {
    processVirtualAttributes(true);
  }
  /**
   * Performs any necessary virtual attribute processing for this
   * entry.  This should only be called at the time the entry is
   * decoded or created within the backend.
   *
   * @param  includeOperational  Indicates whether to include
   *                             operational attributes.
   */
  public void processVirtualAttributes(boolean includeOperational)
  {
    for (VirtualAttributeRule rule :
         DirectoryServer.getVirtualAttributes(this))
    {
      AttributeType attributeType = rule.getAttributeType();
      if (attributeType.isOperational() && (! includeOperational))
      {
        continue;
      }
      List<Attribute> attrList = userAttributes.get(attributeType);
      if ((attrList == null) || attrList.isEmpty())
      {
@@ -4949,7 +4957,7 @@
      // Copy all user attributes.
      deepCopy(userAttributes, userAttrsCopy, omitValues, true,
          omitReal, omitVirtual);
          omitReal, omitVirtual, true);
    }
    else
    {
@@ -5008,7 +5016,7 @@
          // Copy all user attributes.
          deepCopy(userAttributes, userAttrsCopy, omitValues, true,
              omitReal, omitVirtual);
              omitReal, omitVirtual, true);
          continue;
        }
@@ -5017,7 +5025,7 @@
          // This is a special placeholder indicating that all
          // operational attributes should be returned.
          deepCopy(operationalAttributes, operationalAttrsCopy,
              omitValues, true, omitReal, omitVirtual);
              omitValues, true, omitReal, omitVirtual, true);
          continue;
        }
@@ -5264,19 +5272,32 @@
        }
        else
        {
          // The attribute may have already been put in the list
          // - lets replace it assuming that the previous version
          // was added using a wildcard and that this version has
          // a user provided name and/or options.
          // The attribute may have already been put in the list.
          //
          // This may occur in two cases:
          //
          // 1) The attribute is identified by more than one attribute
          //    type description in the attribute list (e.g. in a
          //    wildcard).
          //
          // 2) The attribute has both a real and virtual component.
          //
          boolean found = false;
          for (int i = 0; i < attrList.size(); i++)
          {
            if (attrList.get(i).optionsEqual(attribute.getOptions()))
            Attribute otherAttribute = attrList.get(i);
            if (otherAttribute.optionsEqual(attribute.getOptions()))
            {
              attrList.set(i, attribute);
              // Assume that wildcards appear first in an attribute
              // list with more specific attribute names afterwards:
              // let the attribute name and options from the later
              // attribute take preference.
              attrList.set(i, Attributes.merge(attribute,
                  otherAttribute));
              found = true;
            }
          }
          if (!found)
          {
            attrList.add(attribute);
opends/tests/unit-tests-testng/src/server/org/opends/server/extensions/UserDefinedVirtualAttributeProviderTestCase.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 *      Copyright 2008-2009 Sun Microsystems, Inc.
 */
package org.opends.server.extensions;
@@ -113,15 +113,20 @@
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    try
    {
    InternalSearchOperation searchOperation =
         new InternalSearchOperation(conn, conn.nextOperationID(),
                  conn.nextMessageID(), null, DN.decode(ruleDN),
          new InternalSearchOperation(conn, InternalClientConnection
              .nextOperationID(), InternalClientConnection
              .nextMessageID(), null, DN.decode(ruleDN),
                  SearchScope.BASE_OBJECT,
                  DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false,
                  SearchFilter.createFilterFromString("(objectClass=*)"), null,
                  null);
              SearchFilter.createFilterFromString("(objectClass=*)"),
              null, null);
    for (VirtualAttributeRule rule : DirectoryServer.getVirtualAttributes())
      for (VirtualAttributeRule rule : DirectoryServer
          .getVirtualAttributes())
    {
      if (rule.getAttributeType().equals(descriptionType))
      {
@@ -142,9 +147,14 @@
      }
    }
    DeleteOperation deleteOperation = conn.processDelete(DN.decode(ruleDN));
    }
    finally
    {
      DeleteOperation deleteOperation =
          conn.processDelete(DN.decode(ruleDN));
    assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
  }
  }
@@ -175,15 +185,20 @@
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    try
    {
    InternalSearchOperation searchOperation =
         new InternalSearchOperation(conn, conn.nextOperationID(),
                  conn.nextMessageID(), null, DN.decode(ruleDN),
          new InternalSearchOperation(conn, InternalClientConnection
              .nextOperationID(), InternalClientConnection
              .nextMessageID(), null, DN.decode(ruleDN),
                  SearchScope.BASE_OBJECT,
                  DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false,
                  SearchFilter.createFilterFromString("(objectClass=*)"), null,
                  null);
              SearchFilter.createFilterFromString("(objectClass=*)"),
              null, null);
    for (VirtualAttributeRule rule : DirectoryServer.getVirtualAttributes())
      for (VirtualAttributeRule rule : DirectoryServer
          .getVirtualAttributes())
    {
      if (rule.getAttributeType().equals(descriptionType))
      {
@@ -203,10 +218,14 @@
                     ResultCode.UNWILLING_TO_PERFORM);
      }
    }
    DeleteOperation deleteOperation = conn.processDelete(DN.decode(ruleDN));
    }
    finally
    {
      DeleteOperation deleteOperation =
          conn.processDelete(DN.decode(ruleDN));
    assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
  }
  }
@@ -252,9 +271,13 @@
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    try
    {
    InternalSearchOperation searchOperation =
         conn.processSearch(DN.decode(userDN), SearchScope.BASE_OBJECT,
              SearchFilter.createFilterFromString("(objectClass=*)"));
          conn.processSearch(DN.decode(userDN),
              SearchScope.BASE_OBJECT, SearchFilter
                  .createFilterFromString("(objectClass=*)"));
    List<Attribute> attrList =
         searchOperation.getSearchEntries().get(0).getAttribute(
@@ -264,11 +287,16 @@
    Attribute attr = attrList.get(0);
    assertEquals(attr.size(), 1);
    assertTrue(attr.contains(AttributeValues.create(descriptionType, value)));
    DeleteOperation deleteOperation = conn.processDelete(DN.decode(ruleDN));
      assertTrue(attr.contains(AttributeValues.create(descriptionType,
          value)));
    }
    finally
    {
      DeleteOperation deleteOperation =
          conn.processDelete(DN.decode(ruleDN));
    assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
  }
  }
@@ -316,9 +344,13 @@
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    try
    {
    InternalSearchOperation searchOperation =
         conn.processSearch(DN.decode(userDN), SearchScope.BASE_OBJECT,
              SearchFilter.createFilterFromString("(objectClass=*)"));
          conn.processSearch(DN.decode(userDN),
              SearchScope.BASE_OBJECT, SearchFilter
                  .createFilterFromString("(objectClass=*)"));
    List<Attribute> attrList =
         searchOperation.getSearchEntries().get(0).getAttribute(
@@ -328,12 +360,18 @@
    Attribute attr = attrList.get(0);
    assertEquals(attr.size(), 2);
    assertTrue(attr.contains(AttributeValues.create(descriptionType, value1)));
    assertTrue(attr.contains(AttributeValues.create(descriptionType, value2)));
    DeleteOperation deleteOperation = conn.processDelete(DN.decode(ruleDN));
      assertTrue(attr.contains(AttributeValues.create(descriptionType,
          value1)));
      assertTrue(attr.contains(AttributeValues.create(descriptionType,
          value2)));
    }
    finally
    {
      DeleteOperation deleteOperation =
          conn.processDelete(DN.decode(ruleDN));
    assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
  }
  }
@@ -381,9 +419,13 @@
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    try
    {
    InternalSearchOperation searchOperation =
         conn.processSearch(DN.decode(userDN), SearchScope.BASE_OBJECT,
              SearchFilter.createFilterFromString("(objectClass=*)"));
          conn.processSearch(DN.decode(userDN),
              SearchScope.BASE_OBJECT, SearchFilter
                  .createFilterFromString("(objectClass=*)"));
    List<Attribute> attrList =
         searchOperation.getSearchEntries().get(0).getAttribute(
@@ -393,11 +435,16 @@
    Attribute attr = attrList.get(0);
    assertEquals(attr.size(), 1);
    assertTrue(attr.contains(AttributeValues.create(descriptionType, realValue)));
    DeleteOperation deleteOperation = conn.processDelete(DN.decode(ruleDN));
      assertTrue(attr.contains(AttributeValues.create(descriptionType,
          realValue)));
    }
    finally
    {
      DeleteOperation deleteOperation =
          conn.processDelete(DN.decode(ruleDN));
    assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
  }
  }
@@ -445,9 +492,13 @@
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    try
    {
    InternalSearchOperation searchOperation =
         conn.processSearch(DN.decode(userDN), SearchScope.BASE_OBJECT,
              SearchFilter.createFilterFromString("(objectClass=*)"));
          conn.processSearch(DN.decode(userDN),
              SearchScope.BASE_OBJECT, SearchFilter
                  .createFilterFromString("(objectClass=*)"));
    List<Attribute> attrList =
         searchOperation.getSearchEntries().get(0).getAttribute(
@@ -459,10 +510,14 @@
    assertEquals(attr.size(), 1);
    assertTrue(attr.contains(AttributeValues.create(descriptionType,
                                                virtualValue)));
    DeleteOperation deleteOperation = conn.processDelete(DN.decode(ruleDN));
    }
    finally
    {
      DeleteOperation deleteOperation =
          conn.processDelete(DN.decode(ruleDN));
    assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
  }
  }
@@ -510,33 +565,121 @@
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    try
    {
    InternalSearchOperation searchOperation =
         conn.processSearch(DN.decode(userDN), SearchScope.BASE_OBJECT,
              SearchFilter.createFilterFromString("(objectClass=*)"));
          conn.processSearch(DN.decode(userDN),
              SearchScope.BASE_OBJECT, SearchFilter
                  .createFilterFromString("(objectClass=*)"));
    List<Attribute> attrList =
         searchOperation.getSearchEntries().get(0).getAttribute(
              descriptionType);
    assertNotNull(attrList);
    assertEquals(attrList.size(), 2);
      assertEquals(attrList.size(), 1);
    LinkedHashSet<AttributeValue> allValues =
         new LinkedHashSet<AttributeValue>();
    for (Attribute a : attrList)
      Attribute a = attrList.get(0);
      assertEquals(a.size(), 2);
      assertTrue(a.contains(AttributeValues.create(
          descriptionType, realValue)));
      assertTrue(a.contains(AttributeValues.create(
          descriptionType, virtualValue)));
    }
    finally
    {
      for (AttributeValue av : a) {
        allValues.add(av);
      }
    }
    assertTrue(allValues.contains(AttributeValues.create(descriptionType,
                                                     realValue)));
    assertTrue(allValues.contains(AttributeValues.create(descriptionType,
                                                     virtualValue)));
    DeleteOperation deleteOperation = conn.processDelete(DN.decode(ruleDN));
      DeleteOperation deleteOperation =
          conn.processDelete(DN.decode(ruleDN));
    assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
  }
  }
  /**
   * Tests the creation of a description virtual attribute when real and
   * virtual values should be merged and the entry has a real value.
   * <p>
   * Returning a subset of attributes is handled differently to all
   * attributes. This tests fix for issue 3779.
   *
   * @throws Exception
   *           If an unexpected problem occurs.
   */
  @Test()
  public void testSingleDescriptionMergeRealAndVirtualWithAttrList()
         throws Exception
  {
    TestCaseUtils.initializeTestBackend(true);
    String ruleDN = "cn=User-Defined Test,cn=Virtual Attributes,cn=config";
    String userDN = "uid=test.user,o=test";
    String virtualValue = "This is the virtual value";
    String realValue    = "This is the real value";
    TestCaseUtils.addEntries(
      "dn: " + ruleDN,
      "objectClass: top",
      "objectClass: ds-cfg-virtual-attribute",
      "objectClass: ds-cfg-user-defined-virtual-attribute",
      "cn: User-Defined Test",
      "ds-cfg-java-class: org.opends.server.extensions." +
           "UserDefinedVirtualAttributeProvider",
      "ds-cfg-enabled: true",
      "ds-cfg-attribute-type: description",
      "ds-cfg-conflict-behavior: merge-real-and-virtual",
      "ds-cfg-value: " + virtualValue,
      "",
      "dn: " + userDN,
      "objectClass: top",
      "objectClass: person",
      "objectClass: organizationalPerson",
      "objectClass: inetOrgPerson",
      "uid: test.user",
      "givenName: Test",
      "sn: User",
      "cn: Test User",
      "userPassword: test",
      "description: " + realValue);
    InternalClientConnection conn =
      InternalClientConnection.getRootConnection();
    try
    {
      LinkedHashSet<String> attributes = new LinkedHashSet<String>(1);
      attributes.add("description");
      InternalSearchOperation searchOperation =
          conn.processSearch(DN.decode(userDN),
              SearchScope.BASE_OBJECT,
              DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false,
              SearchFilter.createFilterFromString("(objectClass=*)"),
              attributes);
      List<Attribute> attrList =
          searchOperation.getSearchEntries().get(0).getAttribute(
              descriptionType);
      assertNotNull(attrList);
      assertEquals(attrList.size(), 1);
      Attribute a = attrList.get(0);
      assertEquals(a.size(), 2);
      assertTrue(a.contains(AttributeValues.create(
          descriptionType, realValue)));
      assertTrue(a.contains(AttributeValues.create(
          descriptionType, virtualValue)));
    }
    finally
    {
      DeleteOperation deleteOperation =
          conn.processDelete(DN.decode(ruleDN));
      assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
    }
  }
@@ -610,54 +753,48 @@
      "cn: Test User",
      "userPassword: test");
    String path1 = TestCaseUtils.createTempFile(
      "dn: " + userDN,
      "changetype: modify",
      "replace: userPassword",
    try
    {
      String path1 =
          TestCaseUtils.createTempFile("dn: " + userDN,
              "changetype: modify", "replace: userPassword",
      "userPassword: short");
    String[] args1 =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path1
    };
          { "-h", "127.0.0.1", "-p",
              String.valueOf(TestCaseUtils.getServerLdapPort()), "-D",
              "cn=Directory Manager", "-w", "password", "-f", path1 };
    assertFalse(LDAPModify.mainModify(args1, false, null, null) == 0);
    String path2 = TestCaseUtils.createTempFile(
      "dn: " + ruleDN,
      "changetype: modify",
      "replace: ds-cfg-enabled",
      String path2 =
          TestCaseUtils.createTempFile("dn: " + ruleDN,
              "changetype: modify", "replace: ds-cfg-enabled",
      "ds-cfg-enabled: false");
    String[] args2 = new String[]
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerAdminPort()),
      "-Z", "-X",
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path2
    };
      String[] args2 =
          new String[] { "-h", "127.0.0.1", "-p",
              String.valueOf(TestCaseUtils.getServerAdminPort()), "-Z",
              "-X", "-D", "cn=Directory Manager", "-w", "password",
              "-f", path2 };
    assertEquals(LDAPModify.mainModify(args2, false, null, null), 0);
    assertEquals(LDAPModify.mainModify(args1, false, null, null), 0);
    }
    finally
    {
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    DeleteOperation deleteOperation = conn.processDelete(DN.decode(ruleDN));
      DeleteOperation deleteOperation =
          conn.processDelete(DN.decode(ruleDN));
    assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
    deleteOperation = conn.processDelete(DN.decode(policyDN));
    assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
  }
  }
@@ -703,49 +840,44 @@
      "userPassword: password");
    String path1 = TestCaseUtils.createTempFile(
      "dn: o=test",
      "changetype: modify",
      "replace: description",
    try
    {
      String path1 =
          TestCaseUtils.createTempFile("dn: o=test",
              "changetype: modify", "replace: description",
      "description: foo");
    String[] args1 =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", userDN,
      "-w", "password",
      "-f", path1
    };
          { "-h", "127.0.0.1", "-p",
              String.valueOf(TestCaseUtils.getServerLdapPort()), "-D",
              userDN, "-w", "password", "-f", path1 };
    assertFalse(LDAPModify.mainModify(args1, false, null, null) == 0);
    String path2 = TestCaseUtils.createTempFile(
      "dn: " + ruleDN,
      "changetype: modify",
      "replace: ds-cfg-enabled",
      String path2 =
          TestCaseUtils.createTempFile("dn: " + ruleDN,
              "changetype: modify", "replace: ds-cfg-enabled",
      "ds-cfg-enabled: true");
    String[] args2 = new String[]
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerAdminPort()),
      "-Z", "-X",
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path2
    };
      String[] args2 =
          new String[] { "-h", "127.0.0.1", "-p",
              String.valueOf(TestCaseUtils.getServerAdminPort()), "-Z",
              "-X", "-D", "cn=Directory Manager", "-w", "password",
              "-f", path2 };
    assertEquals(LDAPModify.mainModify(args2, false, null, null), 0);
    assertEquals(LDAPModify.mainModify(args1, false, null, null), 0);
    }
    finally
    {
    InternalClientConnection conn =
         InternalClientConnection.getRootConnection();
    DeleteOperation deleteOperation = conn.processDelete(DN.decode(ruleDN));
      DeleteOperation deleteOperation =
          conn.processDelete(DN.decode(ruleDN));
    assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
  }
}
}