opends/resource/admin/property-types/aggregation.xsl
@@ -29,7 +29,8 @@ <!-- Templates for processing aggregation properties. --> <xsl:template match="adm:aggregation" mode="java-definition-imports"> <xsl:template match="adm:aggregation" mode="java-definition-imports"> <xsl:element name="import"> <xsl:call-template name="get-definition-package" /> <xsl:value-of select="'.client.'" /> @@ -99,6 +100,14 @@ normalize-space(@target-enabled-property-name), '");
')" /> </xsl:if> </xsl:template> <xsl:template match="adm:aggregation" mode="java-definition-post-ctor"> <xsl:value-of select="' INSTANCE.registerConstraint(PD_'" /> <xsl:call-template name="name-to-java-constant"> <xsl:with-param name="value" select="../../@name" /> </xsl:call-template> <xsl:value-of select="');
'" /> </xsl:template> <!-- Gets the Java client configuration interface for the referenced type. --> opends/src/messages/messages/admin.properties
@@ -259,3 +259,5 @@ constraint violation occurred: %s SEVERE_ERR_CONSTRAINT_VIOLATION_EXCEPTION_PLURAL_113=The following \ constraint violations occurred: %s SEVERE_ERR_SERVER_REFINT_DANGLING_REFERENCE_114=The value "%s" in \ property "%s" in the %s in entry "%s" refers to a non-existent %s at "%s" opends/src/server/org/opends/server/admin/AggregationPropertyDefinition.java
@@ -28,10 +28,20 @@ import static org.opends.messages.AdminMessages.*; import static org.opends.server.util.Validator.*; import java.util.Collection; import java.util.Collections; import java.util.EnumSet; import java.util.SortedSet; import org.opends.messages.Message; import org.opends.server.admin.client.ClientConstraintHandler; 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.config.ConfigException; import org.opends.server.types.DN; @@ -78,7 +88,7 @@ */ public final class AggregationPropertyDefinition <C extends ConfigurationClient, S extends Configuration> extends PropertyDefinition<String> { extends PropertyDefinition<String> implements Constraint { /** * An interface for incrementally constructing aggregation property @@ -95,6 +105,9 @@ <C extends ConfigurationClient, S extends Configuration> extends AbstractBuilder<String, AggregationPropertyDefinition<C, S>> { // The type of referenced managed objects. private AbstractManagedObjectDefinition<?, ?> cd = null; // The name of the managed object which is the parent of the // aggregated managed objects. private ManagedObjectPath<?, ?> p = null; @@ -103,9 +116,6 @@ // contains the aggregated managed objects. private String rdName = null; // The type of referenced managed objects. private AbstractManagedObjectDefinition<?, ?> cd = null; // The optional name of a boolean "enabled" property in this // managed object. When this property is true, the enabled // property in the aggregated managed object must also be true. @@ -127,6 +137,23 @@ /** * Sets the definition of the type of referenced managed objects. * <p> * This must be defined before the property definition can be * built. * * @param d * The definition of the type of referenced managed * objects. */ public final void setManagedObjectDefinition( AbstractManagedObjectDefinition<C, S> d) { this.cd = d; } /** * Sets the name of the managed object which is the parent of the * aggregated managed objects. * <p> @@ -161,23 +188,6 @@ /** * Sets the definition of the type of referenced managed objects. * <p> * This must be defined before the property definition can be * built. * * @param d * The definition of the type of referenced managed * objects. */ public final void setManagedObjectDefinition( AbstractManagedObjectDefinition<C, S> d) { this.cd = d; } /** * Sets the optional boolean "enabled" property in this managed * object. When this property is true, the enabled property in the * aggregated managed object must also be true. @@ -275,6 +285,54 @@ /** * The server-side constraint handler implementation. */ private static class ServerHandler <C extends ConfigurationClient, S extends Configuration> extends ServerConstraintHandler { // The associated property definition. private final AggregationPropertyDefinition<C, S> pd; // Creates a new server-side constraint handler. private ServerHandler(AggregationPropertyDefinition<C, S> pd) { this.pd = pd; } /** * {@inheritDoc} */ @Override public boolean isUsable(ServerManagedObject<?> managedObject, Collection<Message> unacceptableReasons) throws ConfigException { SortedSet<String> names = managedObject.getPropertyValues(pd); ServerManagementContext context = ServerManagementContext.getInstance(); boolean isUsable = true; for (String name : names) { ManagedObjectPath<C, S> path = pd.getChildPath(name); if (!context.managedObjectExists(path)) { Message msg = ERR_SERVER_REFINT_DANGLING_REFERENCE.get(name, pd .getName(), managedObject.getManagedObjectDefinition() .getUserFriendlyName(), managedObject.getDN().toString(), pd .getRelationDefinition().getUserFriendlyName(), path.toDN() .toString()); unacceptableReasons.add(msg); isUsable = false; } } return isUsable; } } /** * Creates an aggregation property definition builder. * * @param <C> @@ -405,6 +463,16 @@ /** * {@inheritDoc} */ public Collection<ClientConstraintHandler> getClientConstraintHandlers() { // TODO: not yet implemented. return Collections.emptyList(); } /** * Gets the name of the managed object which is the parent of the * aggregated managed objects. * @@ -431,6 +499,16 @@ /** * {@inheritDoc} */ public Collection<ServerConstraintHandler> getServerConstraintHandlers() { ServerConstraintHandler handler = new ServerHandler<C, S>(this); return Collections.singleton(handler); } /** * Gets the optional boolean "enabled" property in this managed * object. When this property is true, the enabled property in the * aggregated managed object must also be true. opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildCfgDefn.java
@@ -48,15 +48,15 @@ import org.opends.server.admin.client.AuthorizationException; import org.opends.server.admin.client.CommunicationException; import org.opends.server.admin.client.ConcurrentModificationException; import org.opends.server.admin.std.client.ConnectionHandlerCfgClient; import org.opends.server.admin.client.ManagedObject; import org.opends.server.admin.client.MissingMandatoryPropertiesException; import org.opends.server.admin.client.OperationRejectedException; import org.opends.server.admin.server.ConfigurationChangeListener; import org.opends.server.admin.server.ServerManagedObject; import org.opends.server.admin.std.client.ConnectionHandlerCfgClient; import org.opends.server.admin.TestChildCfgClient; import org.opends.server.admin.std.meta.ConnectionHandlerCfgDefn; import org.opends.server.admin.server.ConfigurationChangeListener; import org.opends.server.admin.std.server.ConnectionHandlerCfg; import org.opends.server.admin.server.ServerManagedObject; import org.opends.server.admin.TestChildCfg; import org.opends.server.types.AttributeType; import org.opends.server.types.DN; @@ -119,6 +119,7 @@ builder.setManagedObjectDefinition(ConnectionHandlerCfgDefn.getInstance()); PD_AGGREGATION_PROPERTY = builder.getInstance(); INSTANCE.registerPropertyDefinition(PD_AGGREGATION_PROPERTY); INSTANCE.registerConstraint(PD_AGGREGATION_PROPERTY); } opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/AggregationTest.java
@@ -34,6 +34,7 @@ import javax.naming.ldap.LdapName; import org.opends.messages.Message; import org.opends.server.TestCaseUtils; import org.opends.server.admin.AdminTestCase; import org.opends.server.admin.IllegalPropertyValueStringException; @@ -150,6 +151,23 @@ assertSetEquals(child.getAggregationProperty(), "LDAPS Connection Handler", "LDAP Connection Handler"); } // Test child 5 LDIF. private static final String[] TEST_CHILD_5 = new String[] { "dn: cn=test child 5,cn=test children,cn=test parent 1,cn=test parents,cn=config", "objectclass: top", "objectclass: ds-cfg-test-child-dummy", "cn: test child 5", "ds-cfg-virtual-attribute-enabled: true", "ds-cfg-virtual-attribute-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider", "ds-cfg-virtual-attribute-type: description", "ds-cfg-virtual-attribute-conflict-behavior: virtual-overrides-real", "ds-cfg-backend-base-dn: cn=BAD Connection Handler 1, cn=connection handlers, cn=config", "ds-cfg-backend-base-dn: cn=BAD Connection Handler 2, cn=connection handlers, cn=config", "ds-cfg-backend-base-dn: cn=LDAP Connection Handler, cn=connection handlers, cn=config" }; // Test LDIF. private static final String[] TEST_LDIF = new String[] { @@ -332,6 +350,41 @@ /** * Tests that aggregation is rejected by a constraint violation when * the DN values are dangling. * * @throws Exception * If the test unexpectedly fails. */ @Test public void testAggregationDanglingReference() throws Exception { // Add the entry. TestCaseUtils.addEntry(TEST_CHILD_5); try { TestParentCfg parent = getParent("test parent 1"); parent.getTestChild("test child 5"); Assert .fail("Unexpectedly added test child 5 when it had a dangling reference"); } catch (ConfigException e) { // Check that we have a constraint violation as the cause. Throwable cause = e.getCause(); if (cause instanceof ConstraintViolationException) { ConstraintViolationException cve = (ConstraintViolationException) cause; Collection<Message> causes = cve.getMessages(); Assert.assertEquals(causes.size(), 2); } else { // Got an unexpected cause. throw e; } } finally { deleteSubtree("cn=test child 5,cn=test children,cn=test parent 1,cn=test parents,cn=config"); } } // Asserts that the actual set of DNs contains the expected values. private void assertSetEquals(SortedSet<String> actual, String... expected) { SortedSet<String> values = new TreeSet<String>(TestChildCfgDefn