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

matthew_swift
07.51.2008 e02c878b0c0f152b87656ce7b2a170302ccb1e91
Fix issue 2482. Improve client side referential integrity checks in admin framework. Also renamed aggregation tests so that they are more easily differentiated and removed "slow" tags from certain aggregation tests now that they perform much quicker.
2 files renamed
4 files modified
400 ■■■■■ changed files
opends/src/server/org/opends/server/admin/AbstractManagedObjectDefinition.java 74 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/AggregationPropertyDefinition.java 225 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/AbstractManagedObjectDefinitionTest.java 68 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/client/ldap/AggregationClientTest.java 10 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/client/ldap/MockLDAPConnection.java 7 ●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/AggregationServerTest.java 16 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/AbstractManagedObjectDefinition.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 *      Portions Copyright 2007-2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
@@ -82,6 +82,10 @@
  // definition.
  private final Map<String, RelationDefinition<?, ?>> relationDefinitions;
  // The set of relation definitions directly referencing this managed
  // object definition.
  private final Set<RelationDefinition<C, S>> reverseRelationDefinitions;
  // The set of all property definitions associated with this managed
  // object definition including inherited property definitions.
  private final Map<String, PropertyDefinition<?>> allPropertyDefinitions;
@@ -120,6 +124,7 @@
    this.constraints = new LinkedList<Constraint>();
    this.propertyDefinitions = new HashMap<String, PropertyDefinition<?>>();
    this.relationDefinitions = new HashMap<String, RelationDefinition<?,?>>();
    this.reverseRelationDefinitions = new HashSet<RelationDefinition<C,S>>();
    this.allPropertyDefinitions = new HashMap<String, PropertyDefinition<?>>();
    this.allRelationDefinitions =
      new HashMap<String, RelationDefinition<?, ?>>();
@@ -182,7 +187,7 @@
   */
  public final Collection<Constraint> getAllConstraints() {
    // This method does not used a cached set of constraints because
    // constraints may be updated after child definitions haved been
    // constraints may be updated after child definitions have been
    // defined.
    List<Constraint> allConstraints = new LinkedList<Constraint>();
@@ -228,6 +233,35 @@
  /**
   * Get all the relation definitions which refer to this managed
   * object definition. The returned collection will contain relation
   * definitions which refer to parents of this managed object
   * definition.
   *
   * @return Returns a collection containing all the relation
   *         definitions which refer to this managed object
   *         definition. The caller is free to modify the collection
   *         if required.
   */
  public final Collection<RelationDefinition<? super C, ? super S>>
  getAllReverseRelationDefinitions() {
    // This method does not used a cached set of relations because
    // relations may be updated after child definitions have been
    // defined.
    List<RelationDefinition<? super C, ? super S>> rdlist =
      new LinkedList<RelationDefinition<? super C, ? super S>>();
    if (parent != null) {
      rdlist.addAll(parent.getAllReverseRelationDefinitions());
    }
    rdlist.addAll(reverseRelationDefinitions);
    return rdlist;
  }
  /**
   * Get all the tags associated with this type of managed object. The
   * returned collection will contain inherited tags.
   *
@@ -473,6 +507,23 @@
  /**
   * Get the relation definitions which refer directly to this managed
   * object definition. The returned collection will not contain
   * relation definitions which refer to parents of this managed
   * object definition.
   *
   * @return Returns an unmodifiable collection containing the
   *         relation definitions which refer directly to this managed
   *         object definition.
   */
  public final Collection<RelationDefinition<C, S>>
      getReverseRelationDefinitions() {
    return Collections.unmodifiableCollection(reverseRelationDefinitions);
  }
  /**
   * Gets the synopsis of this managed object definition in the
   * default locale.
   *
@@ -815,10 +866,15 @@
   *          The relation definition to be registered.
   */
  protected final void registerRelationDefinition(RelationDefinition<?, ?> d) {
    // Register the relation in this managed object definition.
    String name = d.getName();
    relationDefinitions.put(name, d);
    allRelationDefinitions.put(name, d);
    // Now register the relation in the referenced managed object
    // definition for reverse lookups.
    registerReverseRelationDefinition(d);
  }
@@ -880,9 +936,14 @@
   */
  final void deregisterRelationDefinition(
      RelationDefinition<?, ?> d) {
   // Deregister the relation from this managed object definition.
    String name = d.getName();
    relationDefinitions.remove(name);
    allRelationDefinitions.remove(name);
    // Now deregister the relation from the referenced managed object
    // definition for reverse lookups.
    d.getChildDefinition().reverseRelationDefinitions.remove(d);
  }
@@ -901,6 +962,15 @@
  // Register a relation definition in the referenced managed object
  // definition's reverse lookup table.
  private <CC extends ConfigurationClient, SS extends Configuration>
  void registerReverseRelationDefinition(RelationDefinition<CC, SS> rd) {
    rd.getChildDefinition().reverseRelationDefinitions.add(rd);
  }
  // Recursively descend definition hierarchy to find the best match definition.
  private AbstractManagedObjectDefinition<? extends C, ? extends S>
      resolveManagedObjectDefinitionAux(
opends/src/server/org/opends/server/admin/AggregationPropertyDefinition.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 *      Portions Copyright 2007-2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
@@ -36,6 +36,7 @@
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@@ -55,6 +56,7 @@
import org.opends.server.admin.server.ServerConstraintHandler;
import org.opends.server.admin.server.ServerManagedObject;
import org.opends.server.admin.server.ServerManagementContext;
import org.opends.server.admin.std.meta.RootCfgDefn;
import org.opends.server.config.ConfigException;
import org.opends.server.loggers.ErrorLogger;
import org.opends.server.loggers.debug.DebugTracer;
@@ -650,130 +652,6 @@
  private class TargetClientHandler extends ClientConstraintHandler {
    /**
     * Instances of this class are used to search for all managed
     * objects that contain a reference to the named managed object.
     */
    private class Finder implements
        RelationDefinitionVisitor<Void, ManagedObject<?>> {
      // Any authorization exceptions that were encountered.
      private AuthorizationException ae = null;
      // Any communication exceptions that were encountered.
      private CommunicationException ce = null;
      // The name of the managed object being deleted or modified.
      private final String name;
      // The collected list of referencing managed objects.
      private final Collection<ManagedObject<?>> references;
      // Private constructor.
      private Finder(String name, Collection<ManagedObject<?>> references) {
        this.name = name;
        this.references = references;
      }
      /**
       * {@inheritDoc}
       */
      public <CC extends ConfigurationClient, SS extends Configuration>
          Void visitInstantiable(
          InstantiableRelationDefinition<CC, SS> rd, ManagedObject<?> p) {
        try {
          for (String childName : p.listChildren(rd)) {
            find(p.getChild(rd, childName));
          }
        } catch (AuthorizationException e) {
          ae = e;
        } catch (CommunicationException e) {
          ce = e;
        } catch (OperationsException e) {
          // Ignore all other types of exception.
        }
        return null;
      }
      /**
       * {@inheritDoc}
       */
      public <CC extends ConfigurationClient, SS extends Configuration>
          Void visitOptional(
          OptionalRelationDefinition<CC, SS> rd, ManagedObject<?> p) {
        try {
          find(p.getChild(rd));
        } catch (AuthorizationException e) {
          ae = e;
        } catch (CommunicationException e) {
          ce = e;
        } catch (OperationsException e) {
          // Ignore all other types of exception.
        }
        return null;
      }
      /**
       * {@inheritDoc}
       */
      public <CC extends ConfigurationClient, SS extends Configuration>
          Void visitSingleton(
          SingletonRelationDefinition<CC, SS> rd, ManagedObject<?> p) {
        try {
          find(p.getChild(rd));
        } catch (AuthorizationException e) {
          ae = e;
        } catch (CommunicationException e) {
          ce = e;
        } catch (OperationsException e) {
          // Ignore all other types of exception.
        }
        return null;
      }
      private void find(ManagedObject<?> current)
          throws AuthorizationException, CommunicationException {
        // First check the current managed object to see if it
        // contains a reference.
        ManagedObjectDefinition<?, ?> mod = current
            .getManagedObjectDefinition();
        if (mod.isChildOf(getManagedObjectDefinition())) {
          for (String value : current
              .getPropertyValues(AggregationPropertyDefinition.this)) {
            if (compare(value, name) == 0) {
              references.add(current);
            }
          }
        }
        // Now check its children.
        for (RelationDefinition<?, ?> rd : mod.getAllRelationDefinitions()) {
          rd.accept(this, current);
          if (ae != null) {
            throw ae;
          }
          if (ce != null) {
            throw ce;
          }
        }
      }
    }
    /**
     * {@inheritDoc}
     */
    @Override
@@ -783,7 +661,8 @@
      // Any references to the deleted managed object should cause a
      // constraint violation.
      boolean isAcceptable = true;
      for (ManagedObject<?> mo : findReferences(context, path.getName())) {
      for (ManagedObject<?> mo : findReferences(context,
          getManagedObjectDefinition(), path.getName())) {
        String name = mo.getManagedObjectPath().getName();
        if (name == null) {
          Message msg = ERR_CLIENT_REFINT_CANNOT_DELETE_WITHOUT_NAME.get(
@@ -819,8 +698,9 @@
      // The referenced managed object is disabled. Need to check for
      // active references.
      boolean isAcceptable = true;
      for (ManagedObject<?> mo : findReferences(context, managedObject
          .getManagedObjectPath().getName())) {
      for (ManagedObject<?> mo : findReferences(context,
          getManagedObjectDefinition(), managedObject.getManagedObjectPath()
              .getName())) {
        if (targetNeedsEnablingCondition.evaluate(context, mo)) {
          String name = mo.getManagedObjectPath().getName();
          if (name == null) {
@@ -846,16 +726,91 @@
    // Find all managed objects which reference the named managed
    // object using this property.
    private Collection<ManagedObject<?>> findReferences(
        ManagementContext context, String name) throws AuthorizationException,
        CommunicationException {
      List<ManagedObject<?>> references = new LinkedList<ManagedObject<?>>();
      Finder finder = new Finder(name, references);
      finder.find(context.getRootConfigurationManagedObject());
      return references;
    private <CC extends ConfigurationClient>
        List<ManagedObject<? extends CC>> findReferences(
        ManagementContext context, AbstractManagedObjectDefinition<CC, ?> mod,
        String name) throws AuthorizationException, CommunicationException {
      List<ManagedObject<? extends CC>> instances = findInstances(context, mod);
      Iterator<ManagedObject<? extends CC>> i = instances.iterator();
      while (i.hasNext()) {
        ManagedObject<? extends CC> mo = i.next();
        boolean hasReference = false;
        for (String value : mo
            .getPropertyValues(AggregationPropertyDefinition.this)) {
          if (compare(value, name) == 0) {
            hasReference = true;
            break;
          }
        }
        if (!hasReference) {
          i.remove();
        }
      }
      return instances;
    }
    // Find all instances of a specific type of managed object.
    @SuppressWarnings("unchecked")
    private <CC extends ConfigurationClient>
        List<ManagedObject<? extends CC>> findInstances(
        ManagementContext context, AbstractManagedObjectDefinition<CC, ?> mod)
        throws AuthorizationException, CommunicationException {
      List<ManagedObject<? extends CC>> instances =
        new LinkedList<ManagedObject<? extends CC>>();
      if (mod == RootCfgDefn.getInstance()) {
        instances.add((ManagedObject<? extends CC>) context
            .getRootConfigurationManagedObject());
      } else {
        for (RelationDefinition<? super CC, ?> rd : mod
            .getAllReverseRelationDefinitions()) {
          for (ManagedObject<?> parent : findInstances(context, rd
              .getParentDefinition())) {
            try {
              if (rd instanceof SingletonRelationDefinition) {
                SingletonRelationDefinition<? super CC, ?> srd =
                  (SingletonRelationDefinition<? super CC, ?>) rd;
                ManagedObject<?> mo = parent.getChild(srd);
                if (mo.getManagedObjectDefinition().isChildOf(mod)) {
                  instances.add((ManagedObject<? extends CC>) mo);
                }
              } else if (rd instanceof OptionalRelationDefinition) {
                OptionalRelationDefinition<? super CC, ?> ord =
                  (OptionalRelationDefinition<? super CC, ?>) rd;
                ManagedObject<?> mo = parent.getChild(ord);
                if (mo.getManagedObjectDefinition().isChildOf(mod)) {
                  instances.add((ManagedObject<? extends CC>) mo);
                }
              } else if (rd instanceof InstantiableRelationDefinition) {
                InstantiableRelationDefinition<? super CC, ?> ird =
                  (InstantiableRelationDefinition<? super CC, ?>) rd;
                for (String name : parent.listChildren(ird)) {
                  ManagedObject<?> mo = parent.getChild(ird, name);
                  if (mo.getManagedObjectDefinition().isChildOf(mod)) {
                    instances.add((ManagedObject<? extends CC>) mo);
                  }
                }
              }
            } catch (OperationsException e) {
              // Ignore all operations exceptions.
            }
          }
        }
      }
      return instances;
    }
  }
  /**
   * The tracer object for the debug logger.
   */
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/AbstractManagedObjectDefinitionTest.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 *      Portions Copyright 2007-2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
@@ -39,6 +39,7 @@
import org.opends.server.admin.std.meta.ConnectionHandlerCfgDefn;
import org.opends.server.admin.std.meta.JMXConnectionHandlerCfgDefn;
import org.opends.server.admin.std.meta.LDAPConnectionHandlerCfgDefn;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
@@ -96,6 +97,17 @@
    // This test suite depends on having the schema available, so
    // we'll start the server.
    TestCaseUtils.startServer();
    TestCfg.setUp();
  }
  /**
   * Tears down test environment.
   */
  @AfterClass
  public void tearDown() {
    TestCfg.cleanup();
  }
@@ -300,4 +312,58 @@
    assertEquals(ddbp.getDefaultValues(), Collections
        .singleton("org.opends.server.protocols.jmx.JmxConnectionHandler"));
  }
  /**
   * Tests that the getReverseRelationDefinitions() method returns
   * relations referring to a managed object.
   */
  @Test
  public void testGetReverseRelationDefinitions() {
    Collection<RelationDefinition<TestParentCfgClient, TestParentCfg>> rdlist1 = TestParentCfgDefn
        .getInstance().getReverseRelationDefinitions();
    assertEquals(rdlist1.size(), 2);
    assertTrue(rdlist1.contains(TestCfg
        .getTestOneToManyParentRelationDefinition()));
    assertTrue(rdlist1.contains(TestCfg
        .getTestOneToZeroOrOneParentRelationDefinition()));
    Collection<RelationDefinition<TestChildCfgClient, TestChildCfg>> rdlist2 = TestChildCfgDefn
        .getInstance().getReverseRelationDefinitions();
    assertEquals(rdlist2.size(), 2);
    assertTrue(rdlist2.contains(TestParentCfgDefn.getInstance()
        .getTestChildrenRelationDefinition()));
    assertTrue(rdlist2.contains(TestParentCfgDefn.getInstance()
        .getOptionalTestChildRelationDefinition()));
  }
  /**
   * Tests that the getAllReverseRelationDefinitions() method returns
   * all relations referring to a managed object.
   */
  @Test
  public void testGetAllReverseRelationDefinitions() {
    Collection<RelationDefinition<? super TestParentCfgClient, ? super TestParentCfg>> rdlist1 = TestParentCfgDefn
        .getInstance().getAllReverseRelationDefinitions();
    assertEquals(rdlist1.size(), 2);
    assertTrue(rdlist1.contains(TestCfg
        .getTestOneToManyParentRelationDefinition()));
    assertTrue(rdlist1.contains(TestCfg
        .getTestOneToZeroOrOneParentRelationDefinition()));
    Collection<RelationDefinition<? super TestChildCfgClient, ? super TestChildCfg>> rdlist2 = TestChildCfgDefn
        .getInstance().getAllReverseRelationDefinitions();
    assertEquals(rdlist2.size(), 2);
    assertTrue(rdlist2.contains(TestParentCfgDefn.getInstance()
        .getTestChildrenRelationDefinition()));
    assertTrue(rdlist2.contains(TestParentCfgDefn.getInstance()
        .getOptionalTestChildRelationDefinition()));
  }
}
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/client/ldap/AggregationClientTest.java
File was renamed from opends/tests/unit-tests-testng/src/server/org/opends/server/admin/client/ldap/AggregationTest.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 *      Portions Copyright 2007-2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin.client.ldap;
@@ -63,7 +63,7 @@
 * Test cases for aggregations on the client-side.
 */
@Test(sequential = true)
public class AggregationTest extends AdminTestCase {
public class AggregationClientTest extends AdminTestCase {
  // Test LDIF.
  private static final String[] TEST_LDIF = new String[] {
@@ -186,10 +186,8 @@
  @BeforeClass
  public void setUp() throws Exception {
    // This test suite depends on having the schema available, so
    // we'll start the server. In addition this test is sensitive to
    // having lots of junk left over from previous tests, so we
    // restart the server to clean out the config (issue 2482).
    TestCaseUtils.restartServer();
    // we'll start the server.
    TestCaseUtils.startServer();
    TestCfg.setUp();
  }
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/client/ldap/MockLDAPConnection.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 *      Portions Copyright 2007-2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin.client.ldap;
@@ -355,6 +355,11 @@
    return entries.get(name);
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public void unbind() {
    // nothing to do
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/AggregationServerTest.java
File was renamed from opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/AggregationTest.java
@@ -22,7 +22,7 @@
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 *      Portions Copyright 2007-2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin.server;
@@ -74,7 +74,7 @@
 * Test cases for aggregations on the server-side.
 */
@Test(sequential = true)
public final class AggregationTest extends AdminTestCase {
public final class AggregationServerTest extends AdminTestCase {
  /**
   * Dummy change listener for triggering change constraint
@@ -443,7 +443,7 @@
   * @throws Exception
   *           If the test unexpectedly fails.
   */
  @Test(groups="slow")
  @Test
  public void testAggregationDisabledReference1() throws Exception {
    // Add the entry and the connection handler.
    TestCaseUtils.addEntry(TEST_CHILD_6);
@@ -504,7 +504,7 @@
   * @throws Exception
   *           If the test unexpectedly fails.
   */
  @Test(groups="slow")
  @Test
  public void testAggregationDisabledReference2() throws Exception {
    // Add the entry.
    TestCaseUtils.addEntry(TEST_CHILD_7);
@@ -566,7 +566,7 @@
   * @throws Exception
   *           If the test unexpectedly fails.
   */
  @Test(groups="slow")
  @Test
  public void testAggregationDisabledReference3() throws Exception {
    // Add the entry.
    TestCaseUtils.addEntry(TEST_CHILD_6);
@@ -629,7 +629,7 @@
   * @throws Exception
   *           If the test unexpectedly fails.
   */
  @Test(groups="slow")
  @Test
  public void testAggregationDisabledReference4() throws Exception {
    // Add the entry.
    TestCaseUtils.addEntry(TEST_CHILD_7);
@@ -745,7 +745,7 @@
   * @throws Exception
   *           If the test unexpectedly fails.
   */
  @Test(groups="slow")
  @Test
  public void testCannotDeleteReferencedComponent() throws Exception {
    // Add the entry.
    TestCaseUtils.addEntry(TEST_CHILD_7);
@@ -819,7 +819,7 @@
   * @throws Exception
   *           If the test unexpectedly fails.
   */
  @Test(groups="slow")
  @Test
  public void testCannotDisableReferencedComponent() throws Exception {
    // Add the entry.
    TestCaseUtils.addEntry(TEST_CHILD_7);