From 2fef5aa0046548cb88034553f522d907195a19f7 Mon Sep 17 00:00:00 2001
From: Nicolas Capponi <nicolas.capponi@forgerock.com>
Date: Mon, 02 Dec 2013 10:47:18 +0000
Subject: [PATCH] OpenDJ 3 : config framework

---
 opendj-admin/src/main/java/org/opends/server/admin/AggregationPropertyDefinition.java | 2014 ++++++++++++++++++++++++++--------------------------------
 1 files changed, 915 insertions(+), 1,099 deletions(-)

diff --git a/opendj-admin/src/main/java/org/opends/server/admin/AggregationPropertyDefinition.java b/opendj-admin/src/main/java/org/opends/server/admin/AggregationPropertyDefinition.java
index a028505..33d3c7b 100644
--- a/opendj-admin/src/main/java/org/opends/server/admin/AggregationPropertyDefinition.java
+++ b/opendj-admin/src/main/java/org/opends/server/admin/AggregationPropertyDefinition.java
@@ -26,12 +26,6 @@
  */
 package org.opends.server.admin;
 
-
-
-import static org.opends.messages.AdminMessages.*;
-import static org.opends.server.loggers.debug.DebugLogger.*;
-import static org.opends.server.util.Validator.*;
-
 import java.util.Collection;
 import java.util.Collections;
 import java.util.EnumSet;
@@ -44,7 +38,6 @@
 import java.util.MissingResourceException;
 import java.util.SortedSet;
 
-import org.opends.messages.Message;
 import org.opends.server.admin.client.AuthorizationException;
 import org.opends.server.admin.client.ClientConstraintHandler;
 import org.opends.server.admin.client.CommunicationException;
@@ -58,1147 +51,970 @@
 import org.opends.server.admin.server.ServerManagedObject;
 import org.opends.server.admin.server.ServerManagedObjectChangeListener;
 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;
 import org.opends.server.types.ConfigChangeResult;
+import org.forgerock.i18n.LocalizableMessage;
 import org.forgerock.opendj.ldap.DN;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.ResultCode;
-import org.opends.server.util.StaticUtils;
-
-
+import org.forgerock.opendj.ldap.ResultCode;
 
 /**
  * Aggregation property definition.
  * <p>
- * An aggregation property names one or more managed objects which are
- * required by the managed object associated with this property. An
- * aggregation property definition takes care to perform referential
- * integrity checks: referenced managed objects cannot be deleted. Nor
- * can an aggregation reference non-existent managed objects.
- * Referential integrity checks are <b>not</b> performed during value
- * validation. Instead they are performed when changes to the managed
- * object are committed.
+ * An aggregation property names one or more managed objects which are required
+ * by the managed object associated with this property. An aggregation property
+ * definition takes care to perform referential integrity checks: referenced
+ * managed objects cannot be deleted. Nor can an aggregation reference
+ * non-existent managed objects. Referential integrity checks are <b>not</b>
+ * performed during value validation. Instead they are performed when changes to
+ * the managed object are committed.
  * <p>
- * An aggregation property definition can optionally identify two
- * properties:
+ * An aggregation property definition can optionally identify two properties:
  * <ul>
- * <li>an <code>enabled</code> property in the aggregated managed
- * object - the property must be a {@link BooleanPropertyDefinition}
- * and indicate whether the aggregated managed object is enabled or
- * not. If specified, the administration framework will prevent the
- * aggregated managed object from being disabled while it is
- * referenced
- * <li>an <code>enabled</code> property in this property's managed
- * object - the property must be a {@link BooleanPropertyDefinition}
- * and indicate whether this property's managed object is enabled or
- * not. If specified, and as long as there is an equivalent
- * <code>enabled</code> property defined for the aggregated managed
- * object, the <code>enabled</code> property in the aggregated
- * managed object will only be checked when this property is true.
+ * <li>an <code>enabled</code> property in the aggregated managed object - the
+ * property must be a {@link BooleanPropertyDefinition} and indicate whether the
+ * aggregated managed object is enabled or not. If specified, the administration
+ * framework will prevent the aggregated managed object from being disabled
+ * while it is referenced
+ * <li>an <code>enabled</code> property in this property's managed object - the
+ * property must be a {@link BooleanPropertyDefinition} and indicate whether
+ * this property's managed object is enabled or not. If specified, and as long
+ * as there is an equivalent <code>enabled</code> property defined for the
+ * aggregated managed object, the <code>enabled</code> property in the
+ * aggregated managed object will only be checked when this property is true.
  * </ul>
- * In other words, these properties can be used to make sure that
- * referenced managed objects are not disabled while they are
- * referenced.
+ * In other words, these properties can be used to make sure that referenced
+ * managed objects are not disabled while they are referenced.
  *
  * @param <C>
- *          The type of client managed object configuration that this
- *          aggregation property definition refers to.
+ *            The type of client managed object configuration that this
+ *            aggregation property definition refers to.
  * @param <S>
- *          The type of server managed object configuration that this
- *          aggregation property definition refers to.
+ *            The type of server managed object configuration that this
+ *            aggregation property definition refers to.
  */
-public final class AggregationPropertyDefinition
-    <C extends ConfigurationClient, S extends Configuration>
-    extends PropertyDefinition<String> {
+public final class AggregationPropertyDefinition<C extends ConfigurationClient, S extends Configuration> extends
+        PropertyDefinition<String> {
 
-  /**
-   * An interface for incrementally constructing aggregation property
-   * definitions.
-   *
-   * @param <C>
-   *          The type of client managed object configuration that
-   *          this aggregation property definition refers to.
-   * @param <S>
-   *          The type of server managed object configuration that
-   *          this aggregation property definition refers to.
-   */
-  public static class Builder
-      <C extends ConfigurationClient, S extends Configuration>
-      extends AbstractBuilder<String, AggregationPropertyDefinition<C, S>> {
+    /**
+     * An interface for incrementally constructing aggregation property
+     * definitions.
+     *
+     * @param <C>
+     *            The type of client managed object configuration that this
+     *            aggregation property definition refers to.
+     * @param <S>
+     *            The type of server managed object configuration that this
+     *            aggregation property definition refers to.
+     */
+    public static class Builder<C extends ConfigurationClient, S extends Configuration> extends
+            AbstractBuilder<String, AggregationPropertyDefinition<C, S>> {
+
+        // The string representation of the managed object path specifying
+        // the parent of the aggregated managed objects.
+        private String parentPathString = null;
+
+        // The name of a relation in the parent managed object which
+        // contains the aggregated managed objects.
+        private String rdName = null;
+
+        // The condition which is used to determine if a referenced
+        // managed object is enabled.
+        private Condition targetIsEnabledCondition = Conditions.TRUE;
+
+        // The condition which is used to determine whether or not
+        // referenced managed objects need to be enabled.
+        private Condition targetNeedsEnablingCondition = Conditions.TRUE;
+
+        // Private constructor
+        private Builder(AbstractManagedObjectDefinition<?, ?> d, String propertyName) {
+            super(d, propertyName);
+        }
+
+        /**
+         * Sets the name of the managed object which is the parent of the
+         * aggregated managed objects.
+         * <p>
+         * This must be defined before the property definition can be built.
+         *
+         * @param pathString
+         *            The string representation of the managed object path
+         *            specifying the parent of the aggregated managed objects.
+         */
+        public final void setParentPath(String pathString) {
+            this.parentPathString = pathString;
+        }
+
+        /**
+         * Sets the relation in the parent managed object which contains the
+         * aggregated managed objects.
+         * <p>
+         * This must be defined before the property definition can be built.
+         *
+         * @param rdName
+         *            The name of a relation in the parent managed object which
+         *            contains the aggregated managed objects.
+         */
+        public final void setRelationDefinition(String rdName) {
+            this.rdName = rdName;
+        }
+
+        /**
+         * Sets the condition which is used to determine if a referenced managed
+         * object is enabled. By default referenced managed objects are assumed
+         * to always be enabled.
+         *
+         * @param condition
+         *            The condition which is used to determine if a referenced
+         *            managed object is enabled.
+         */
+        public final void setTargetIsEnabledCondition(Condition condition) {
+            this.targetIsEnabledCondition = condition;
+        }
+
+        /**
+         * Sets the condition which is used to determine whether or not
+         * referenced managed objects need to be enabled. By default referenced
+         * managed objects must always be enabled.
+         *
+         * @param condition
+         *            The condition which is used to determine whether or not
+         *            referenced managed objects need to be enabled.
+         */
+        public final void setTargetNeedsEnablingCondition(Condition condition) {
+            this.targetNeedsEnablingCondition = condition;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        protected AggregationPropertyDefinition<C, S> buildInstance(AbstractManagedObjectDefinition<?, ?> d,
+                String propertyName, EnumSet<PropertyOption> options, AdministratorAction adminAction,
+                DefaultBehaviorProvider<String> defaultBehavior) {
+            // Make sure that the parent path has been defined.
+            if (parentPathString == null) {
+                throw new IllegalStateException("Parent path undefined");
+            }
+
+            // Make sure that the relation definition has been defined.
+            if (rdName == null) {
+                throw new IllegalStateException("Relation definition undefined");
+            }
+
+            return new AggregationPropertyDefinition<C, S>(d, propertyName, options, adminAction, defaultBehavior,
+                    parentPathString, rdName, targetNeedsEnablingCondition, targetIsEnabledCondition);
+        }
+
+    }
+
+    /**
+     * A change listener which prevents the named component from being disabled.
+     */
+    private class ReferentialIntegrityChangeListener implements ServerManagedObjectChangeListener<S> {
+
+        // The error message which should be returned if an attempt is
+        // made to disable the referenced component.
+        private final LocalizableMessage message;
+
+        // The path of the referenced component.
+        private final ManagedObjectPath<C, S> path;
+
+        // Creates a new referential integrity delete listener.
+        private ReferentialIntegrityChangeListener(ManagedObjectPath<C, S> path, LocalizableMessage message) {
+            this.path = path;
+            this.message = message;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public ConfigChangeResult applyConfigurationChange(ServerManagedObject<? extends S> mo) {
+            try {
+                if (targetIsEnabledCondition.evaluate(mo)) {
+                    return new ConfigChangeResult(ResultCode.SUCCESS, false);
+                }
+            } catch (ConfigException e) {
+                // This should not happen - ignore it and throw an exception
+                // anyway below.
+            }
+
+            // This should not happen - the previous call-back should have
+            // trapped this.
+            throw new IllegalStateException("Attempting to disable a referenced "
+                    + relationDefinition.getChildDefinition().getUserFriendlyName());
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public boolean isConfigurationChangeAcceptable(ServerManagedObject<? extends S> mo,
+                List<LocalizableMessage> unacceptableReasons) {
+            // Always prevent the referenced component from being
+            // disabled.
+            try {
+                if (!targetIsEnabledCondition.evaluate(mo)) {
+                    unacceptableReasons.add(message);
+                    return false;
+                } else {
+                    return true;
+                }
+            } catch (ConfigException e) {
+                // The condition could not be evaluated.
+                if (debugEnabled()) {
+                    TRACER.debugCaught(DebugLogLevel.ERROR, e);
+                }
+
+                LocalizableMessage message = ERR_REFINT_UNABLE_TO_EVALUATE_TARGET_CONDITION.get(mo.getManagedObjectDefinition()
+                        .getUserFriendlyName(), String.valueOf(mo.getDN()), StaticUtils.getExceptionLocalizableMessage(e));
+                ErrorLogger.logError(message);
+                unacceptableReasons.add(message);
+                return false;
+            }
+        }
+
+        // Gets the path associated with this listener.
+        private ManagedObjectPath<C, S> getManagedObjectPath() {
+            return path;
+        }
+
+    }
+
+    /**
+     * A delete listener which prevents the named component from being deleted.
+     */
+    private class ReferentialIntegrityDeleteListener implements ConfigurationDeleteListener<S> {
+
+        // The DN of the referenced configuration entry.
+        private final DN dn;
+
+        // The error message which should be returned if an attempt is
+        // made to delete the referenced component.
+        private final LocalizableMessage message;
+
+        // Creates a new referential integrity delete listener.
+        private ReferentialIntegrityDeleteListener(DN dn, LocalizableMessage message) {
+            this.dn = dn;
+            this.message = message;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public ConfigChangeResult applyConfigurationDelete(S configuration) {
+            // This should not happen - the
+            // isConfigurationDeleteAcceptable() call-back should have
+            // trapped this.
+            if (configuration.dn().equals(dn)) {
+                // This should not happen - the
+                // isConfigurationDeleteAcceptable() call-back should have
+                // trapped this.
+                throw new IllegalStateException("Attempting to delete a referenced "
+                        + relationDefinition.getChildDefinition().getUserFriendlyName());
+            } else {
+                return new ConfigChangeResult(ResultCode.SUCCESS, false);
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public boolean isConfigurationDeleteAcceptable(S configuration, List<LocalizableMessage> unacceptableReasons) {
+            if (configuration.dn().equals(dn)) {
+                // Always prevent deletion of the referenced component.
+                unacceptableReasons.add(message);
+                return false;
+            }
+
+            return true;
+        }
+
+    }
+
+    /**
+     * The server-side constraint handler implementation.
+     */
+    private class ServerHandler extends ServerConstraintHandler {
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public boolean isUsable(ServerManagedObject<?> managedObject, Collection<LocalizableMessage> unacceptableReasons)
+                throws ConfigException {
+            SortedSet<String> names = managedObject.getPropertyValues(AggregationPropertyDefinition.this);
+            ServerManagementContext context = ServerManagementContext.getInstance();
+            LocalizableMessage thisUFN = managedObject.getManagedObjectDefinition().getUserFriendlyName();
+            String thisDN = managedObject.getDN().toString();
+            LocalizableMessage thatUFN = getRelationDefinition().getUserFriendlyName();
+
+            boolean isUsable = true;
+            boolean needsEnabling = targetNeedsEnablingCondition.evaluate(managedObject);
+            for (String name : names) {
+                ManagedObjectPath<C, S> path = getChildPath(name);
+                String thatDN = path.toDN().toString();
+
+                if (!context.managedObjectExists(path)) {
+                    LocalizableMessage msg = ERR_SERVER_REFINT_DANGLING_REFERENCE.get(name, getName(), thisUFN, thisDN, thatUFN,
+                            thatDN);
+                    unacceptableReasons.add(msg);
+                    isUsable = false;
+                } else if (needsEnabling) {
+                    // Check that the referenced component is enabled if
+                    // required.
+                    ServerManagedObject<? extends S> ref = context.getManagedObject(path);
+                    if (!targetIsEnabledCondition.evaluate(ref)) {
+                        LocalizableMessage msg = ERR_SERVER_REFINT_TARGET_DISABLED.get(name, getName(), thisUFN, thisDN, thatUFN,
+                                thatDN);
+                        unacceptableReasons.add(msg);
+                        isUsable = false;
+                    }
+                }
+            }
+
+            return isUsable;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public void performPostAdd(ServerManagedObject<?> managedObject) throws ConfigException {
+            // First make sure existing listeners associated with this
+            // managed object are removed. This is required in order to
+            // prevent multiple change listener registrations from
+            // occurring, for example if this call-back is invoked multiple
+            // times after the same add event.
+            performPostDelete(managedObject);
+
+            // Add change and delete listeners against all referenced
+            // components.
+            LocalizableMessage thisUFN = managedObject.getManagedObjectDefinition().getUserFriendlyName();
+            String thisDN = managedObject.getDN().toString();
+            LocalizableMessage thatUFN = getRelationDefinition().getUserFriendlyName();
+
+            // Referenced managed objects will only need a change listener
+            // if they have can be disabled.
+            boolean needsChangeListeners = targetNeedsEnablingCondition.evaluate(managedObject);
+
+            // Delete listeners need to be registered against the parent
+            // entry of the referenced components.
+            ServerManagementContext context = ServerManagementContext.getInstance();
+            ManagedObjectPath<?, ?> parentPath = getParentPath();
+            ServerManagedObject<?> parent = context.getManagedObject(parentPath);
+
+            // Create entries in the listener tables.
+            List<ReferentialIntegrityDeleteListener> dlist = new LinkedList<ReferentialIntegrityDeleteListener>();
+            deleteListeners.put(managedObject.getDN(), dlist);
+
+            List<ReferentialIntegrityChangeListener> clist = new LinkedList<ReferentialIntegrityChangeListener>();
+            changeListeners.put(managedObject.getDN(), clist);
+
+            for (String name : managedObject.getPropertyValues(AggregationPropertyDefinition.this)) {
+                ManagedObjectPath<C, S> path = getChildPath(name);
+                DN dn = path.toDN();
+                String thatDN = dn.toString();
+
+                // Register the delete listener.
+                LocalizableMessage msg = ERR_SERVER_REFINT_CANNOT_DELETE.get(thatUFN, thatDN, getName(), thisUFN, thisDN);
+                ReferentialIntegrityDeleteListener dl = new ReferentialIntegrityDeleteListener(dn, msg);
+                parent.registerDeleteListener(getRelationDefinition(), dl);
+                dlist.add(dl);
+
+                // Register the change listener if required.
+                if (needsChangeListeners) {
+                    ServerManagedObject<? extends S> ref = context.getManagedObject(path);
+                    msg = ERR_SERVER_REFINT_CANNOT_DISABLE.get(thatUFN, thatDN, getName(), thisUFN, thisDN);
+                    ReferentialIntegrityChangeListener cl = new ReferentialIntegrityChangeListener(path, msg);
+                    ref.registerChangeListener(cl);
+                    clist.add(cl);
+                }
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public void performPostDelete(ServerManagedObject<?> managedObject) throws ConfigException {
+            // Remove any registered delete and change listeners.
+            ServerManagementContext context = ServerManagementContext.getInstance();
+            DN dn = managedObject.getDN();
+
+            // Delete listeners need to be deregistered against the parent
+            // entry of the referenced components.
+            ManagedObjectPath<?, ?> parentPath = getParentPath();
+            ServerManagedObject<?> parent = context.getManagedObject(parentPath);
+            if (deleteListeners.containsKey(dn)) {
+                for (ReferentialIntegrityDeleteListener dl : deleteListeners.get(dn)) {
+                    parent.deregisterDeleteListener(getRelationDefinition(), dl);
+                }
+                deleteListeners.remove(dn);
+            }
+
+            // Change listeners need to be deregistered from their
+            // associated referenced component.
+            if (changeListeners.containsKey(dn)) {
+                for (ReferentialIntegrityChangeListener cl : changeListeners.get(dn)) {
+                    ManagedObjectPath<C, S> path = cl.getManagedObjectPath();
+                    ServerManagedObject<? extends S> ref = context.getManagedObject(path);
+                    ref.deregisterChangeListener(cl);
+                }
+                changeListeners.remove(dn);
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public void performPostModify(ServerManagedObject<?> managedObject) throws ConfigException {
+            // Remove all the constraints associated with this managed
+            // object and then re-register them.
+            performPostDelete(managedObject);
+            performPostAdd(managedObject);
+        }
+    }
+
+    /**
+     * The client-side constraint handler implementation which enforces
+     * referential integrity when aggregating managed objects are added or
+     * modified.
+     */
+    private class SourceClientHandler extends ClientConstraintHandler {
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public boolean isAddAcceptable(ManagementContext context, ManagedObject<?> managedObject,
+                Collection<LocalizableMessage> unacceptableReasons) throws AuthorizationException, CommunicationException {
+            // If all of this managed object's "enabled" properties are true
+            // then any referenced managed objects must also be enabled.
+            boolean needsEnabling = targetNeedsEnablingCondition.evaluate(context, managedObject);
+
+            // Check the referenced managed objects exist and, if required,
+            // are enabled.
+            boolean isAcceptable = true;
+            LocalizableMessage ufn = getRelationDefinition().getUserFriendlyName();
+            for (String name : managedObject.getPropertyValues(AggregationPropertyDefinition.this)) {
+                // Retrieve the referenced managed object and make sure it
+                // exists.
+                ManagedObjectPath<?, ?> path = getChildPath(name);
+                ManagedObject<?> ref;
+                try {
+                    ref = context.getManagedObject(path);
+                } catch (DefinitionDecodingException e) {
+                    LocalizableMessage msg = ERR_CLIENT_REFINT_TARGET_INVALID.get(ufn, name, getName(), e.getLocalizableMessageObject());
+                    unacceptableReasons.add(msg);
+                    isAcceptable = false;
+                    continue;
+                } catch (ManagedObjectDecodingException e) {
+                    LocalizableMessage msg = ERR_CLIENT_REFINT_TARGET_INVALID.get(ufn, name, getName(), e.getLocalizableMessageObject());
+                    unacceptableReasons.add(msg);
+                    isAcceptable = false;
+                    continue;
+                } catch (ManagedObjectNotFoundException e) {
+                    LocalizableMessage msg = ERR_CLIENT_REFINT_TARGET_DANGLING_REFERENCE.get(ufn, name, getName());
+                    unacceptableReasons.add(msg);
+                    isAcceptable = false;
+                    continue;
+                }
+
+                // Make sure the reference managed object is enabled.
+                if (needsEnabling) {
+                    if (!targetIsEnabledCondition.evaluate(context, ref)) {
+                        LocalizableMessage msg = ERR_CLIENT_REFINT_TARGET_DISABLED.get(ufn, name, getName());
+                        unacceptableReasons.add(msg);
+                        isAcceptable = false;
+                    }
+                }
+            }
+            return isAcceptable;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public boolean isModifyAcceptable(ManagementContext context, ManagedObject<?> managedObject,
+                Collection<LocalizableMessage> unacceptableReasons) throws AuthorizationException, CommunicationException {
+            // The same constraint applies as for adds.
+            return isAddAcceptable(context, managedObject, unacceptableReasons);
+        }
+
+    }
+
+    /**
+     * The client-side constraint handler implementation which enforces
+     * referential integrity when aggregated managed objects are deleted or
+     * modified.
+     */
+    private class TargetClientHandler extends ClientConstraintHandler {
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public boolean isDeleteAcceptable(ManagementContext context, ManagedObjectPath<?, ?> path,
+                Collection<LocalizableMessage> unacceptableReasons) throws AuthorizationException, CommunicationException {
+            // Any references to the deleted managed object should cause a
+            // constraint violation.
+            boolean isAcceptable = true;
+            for (ManagedObject<?> mo : findReferences(context, getManagedObjectDefinition(), path.getName())) {
+                String name = mo.getManagedObjectPath().getName();
+                if (name == null) {
+                    LocalizableMessage msg = ERR_CLIENT_REFINT_CANNOT_DELETE_WITHOUT_NAME.get(getName(), mo
+                            .getManagedObjectDefinition().getUserFriendlyName(), getManagedObjectDefinition()
+                            .getUserFriendlyName());
+                    unacceptableReasons.add(msg);
+                } else {
+                    LocalizableMessage msg = ERR_CLIENT_REFINT_CANNOT_DELETE_WITH_NAME.get(getName(), mo
+                            .getManagedObjectDefinition().getUserFriendlyName(), name, getManagedObjectDefinition()
+                            .getUserFriendlyName());
+                    unacceptableReasons.add(msg);
+                }
+                isAcceptable = false;
+            }
+            return isAcceptable;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public boolean isModifyAcceptable(ManagementContext context, ManagedObject<?> managedObject,
+                Collection<LocalizableMessage> unacceptableReasons) throws AuthorizationException, CommunicationException {
+            // If the modified managed object is disabled and there are some
+            // active references then refuse the change.
+            if (targetIsEnabledCondition.evaluate(context, managedObject)) {
+                return true;
+            }
+
+            // The referenced managed object is disabled. Need to check for
+            // active references.
+            boolean isAcceptable = true;
+            for (ManagedObject<?> mo : findReferences(context, getManagedObjectDefinition(), managedObject
+                    .getManagedObjectPath().getName())) {
+                if (targetNeedsEnablingCondition.evaluate(context, mo)) {
+                    String name = mo.getManagedObjectPath().getName();
+                    if (name == null) {
+                        LocalizableMessage msg = ERR_CLIENT_REFINT_CANNOT_DISABLE_WITHOUT_NAME.get(managedObject
+                                .getManagedObjectDefinition().getUserFriendlyName(), getName(), mo
+                                .getManagedObjectDefinition().getUserFriendlyName());
+                        unacceptableReasons.add(msg);
+                    } else {
+                        LocalizableMessage msg = ERR_CLIENT_REFINT_CANNOT_DISABLE_WITH_NAME.get(managedObject
+                                .getManagedObjectDefinition().getUserFriendlyName(), getName(), mo
+                                .getManagedObjectDefinition().getUserFriendlyName(), name);
+                        unacceptableReasons.add(msg);
+                    }
+                    isAcceptable = false;
+                }
+            }
+            return isAcceptable;
+        }
+
+        // Find all managed objects which reference the named managed
+        // object using this property.
+        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.
+     */
+    private static final DebugTracer TRACER = getTracer();
+
+    /**
+     * Creates an aggregation property definition builder.
+     *
+     * @param <C>
+     *            The type of client managed object configuration that this
+     *            aggregation property definition refers to.
+     * @param <S>
+     *            The type of server managed object configuration that this
+     *            aggregation property definition refers to.
+     * @param d
+     *            The managed object definition associated with this property
+     *            definition.
+     * @param propertyName
+     *            The property name.
+     * @return Returns the new aggregation property definition builder.
+     */
+    public static <C extends ConfigurationClient, S extends Configuration> Builder<C, S> createBuilder(
+            AbstractManagedObjectDefinition<?, ?> d, String propertyName) {
+        return new Builder<C, S>(d, propertyName);
+    }
+
+    // The active server-side referential integrity change listeners
+    // associated with this property.
+    private final Map<DN, List<ReferentialIntegrityChangeListener>> changeListeners = new HashMap<DN, List<ReferentialIntegrityChangeListener>>();
+
+    // The active server-side referential integrity delete listeners
+    // associated with this property.
+    private final Map<DN, List<ReferentialIntegrityDeleteListener>> deleteListeners = new HashMap<DN, List<ReferentialIntegrityDeleteListener>>();
+
+    // The name of the managed object which is the parent of the
+    // aggregated managed objects.
+    private ManagedObjectPath<?, ?> parentPath;
 
     // The string representation of the managed object path specifying
     // the parent of the aggregated managed objects.
-    private String parentPathString = null;
+    private final String parentPathString;
 
     // The name of a relation in the parent managed object which
     // contains the aggregated managed objects.
-    private String rdName = null;
+    private final String rdName;
 
-    // The condition which is used to determine if a referenced
-    // managed object is enabled.
-    private Condition targetIsEnabledCondition = Conditions.TRUE;
+    // The relation in the parent managed object which contains the
+    // aggregated managed objects.
+    private InstantiableRelationDefinition<C, S> relationDefinition;
+
+    // The source constraint.
+    private final Constraint sourceConstraint;
+
+    // The condition which is used to determine if a referenced managed
+    // object is enabled.
+    private final Condition targetIsEnabledCondition;
 
     // The condition which is used to determine whether or not
     // referenced managed objects need to be enabled.
-    private Condition targetNeedsEnablingCondition = Conditions.TRUE;
+    private final Condition targetNeedsEnablingCondition;
 
+    // Private constructor.
+    private AggregationPropertyDefinition(AbstractManagedObjectDefinition<?, ?> d, String propertyName,
+            EnumSet<PropertyOption> options, AdministratorAction adminAction,
+            DefaultBehaviorProvider<String> defaultBehavior, String parentPathString, String rdName,
+            Condition targetNeedsEnablingCondition, Condition targetIsEnabledCondition) {
+        super(d, String.class, propertyName, options, adminAction, defaultBehavior);
 
+        this.parentPathString = parentPathString;
+        this.rdName = rdName;
+        this.targetNeedsEnablingCondition = targetNeedsEnablingCondition;
+        this.targetIsEnabledCondition = targetIsEnabledCondition;
+        this.sourceConstraint = new Constraint() {
 
-    // Private constructor
-    private Builder(AbstractManagedObjectDefinition<?, ?> d,
-        String propertyName) {
-      super(d, propertyName);
-    }
-
-
-
-    /**
-     * Sets the name of the managed object which is the parent of the
-     * aggregated managed objects.
-     * <p>
-     * This must be defined before the property definition can be
-     * built.
-     *
-     * @param pathString
-     *          The string representation of the managed object path
-     *          specifying the parent of the aggregated managed
-     *          objects.
-     */
-    public final void setParentPath(String pathString) {
-      this.parentPathString = pathString;
-    }
-
-
-
-    /**
-     * Sets the relation in the parent managed object which contains
-     * the aggregated managed objects.
-     * <p>
-     * This must be defined before the property definition can be
-     * built.
-     *
-     * @param rdName
-     *          The name of a relation in the parent managed object
-     *          which contains the aggregated managed objects.
-     */
-    public final void setRelationDefinition(String rdName) {
-      this.rdName = rdName;
-    }
-
-
-
-    /**
-     * Sets the condition which is used to determine if a referenced
-     * managed object is enabled. By default referenced managed
-     * objects are assumed to always be enabled.
-     *
-     * @param condition
-     *          The condition which is used to determine if a
-     *          referenced managed object is enabled.
-     */
-    public final void setTargetIsEnabledCondition(Condition condition) {
-      this.targetIsEnabledCondition = condition;
-    }
-
-
-
-    /**
-     * Sets the condition which is used to determine whether or not
-     * referenced managed objects need to be enabled. By default
-     * referenced managed objects must always be enabled.
-     *
-     * @param condition
-     *          The condition which is used to determine whether or
-     *          not referenced managed objects need to be enabled.
-     */
-    public final void setTargetNeedsEnablingCondition(Condition condition) {
-      this.targetNeedsEnablingCondition = condition;
-    }
-
-
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    protected AggregationPropertyDefinition<C, S> buildInstance(
-        AbstractManagedObjectDefinition<?, ?> d, String propertyName,
-        EnumSet<PropertyOption> options, AdministratorAction adminAction,
-        DefaultBehaviorProvider<String> defaultBehavior) {
-      // Make sure that the parent path has been defined.
-      if (parentPathString == null) {
-        throw new IllegalStateException("Parent path undefined");
-      }
-
-      // Make sure that the relation definition has been defined.
-      if (rdName == null) {
-        throw new IllegalStateException("Relation definition undefined");
-      }
-
-      return new AggregationPropertyDefinition<C, S>(d, propertyName, options,
-          adminAction, defaultBehavior, parentPathString, rdName,
-          targetNeedsEnablingCondition, targetIsEnabledCondition);
-    }
-
-  }
-
-
-
-  /**
-   * A change listener which prevents the named component from being
-   * disabled.
-   */
-  private class ReferentialIntegrityChangeListener implements
-      ServerManagedObjectChangeListener<S> {
-
-    // The error message which should be returned if an attempt is
-    // made to disable the referenced component.
-    private final Message message;
-
-    // The path of the referenced component.
-    private final ManagedObjectPath<C, S> path;
-
-
-
-    // Creates a new referential integrity delete listener.
-    private ReferentialIntegrityChangeListener(ManagedObjectPath<C, S> path,
-        Message message) {
-      this.path = path;
-      this.message = message;
-    }
-
-
-
-    /**
-     * {@inheritDoc}
-     */
-    public ConfigChangeResult applyConfigurationChange(
-        ServerManagedObject<? extends S> mo) {
-      try {
-        if (targetIsEnabledCondition.evaluate(mo)) {
-          return new ConfigChangeResult(ResultCode.SUCCESS, false);
-        }
-      } catch (ConfigException e) {
-        // This should not happen - ignore it and throw an exception
-        // anyway below.
-      }
-
-      // This should not happen - the previous call-back should have
-      // trapped this.
-      throw new IllegalStateException("Attempting to disable a referenced "
-          + relationDefinition.getChildDefinition().getUserFriendlyName());
-    }
-
-
-
-    /**
-     * {@inheritDoc}
-     */
-    public boolean isConfigurationChangeAcceptable(
-        ServerManagedObject<? extends S> mo,
-        List<Message> unacceptableReasons) {
-      // Always prevent the referenced component from being
-      // disabled.
-      try {
-        if (!targetIsEnabledCondition.evaluate(mo)) {
-          unacceptableReasons.add(message);
-          return false;
-        } else {
-          return true;
-        }
-      } catch (ConfigException e) {
-        // The condition could not be evaluated.
-        if (debugEnabled()) {
-          TRACER.debugCaught(DebugLogLevel.ERROR, e);
-        }
-
-        Message message = ERR_REFINT_UNABLE_TO_EVALUATE_TARGET_CONDITION.get(mo
-            .getManagedObjectDefinition().getUserFriendlyName(), String
-            .valueOf(mo.getDN()), StaticUtils.getExceptionMessage(e));
-        ErrorLogger.logError(message);
-        unacceptableReasons.add(message);
-        return false;
-      }
-    }
-
-
-
-    // Gets the path associated with this listener.
-    private ManagedObjectPath<C, S> getManagedObjectPath() {
-      return path;
-    }
-
-  }
-
-
-
-  /**
-   * A delete listener which prevents the named component from being
-   * deleted.
-   */
-  private class ReferentialIntegrityDeleteListener implements
-      ConfigurationDeleteListener<S> {
-
-    // The DN of the referenced configuration entry.
-    private final DN dn;
-
-    // The error message which should be returned if an attempt is
-    // made to delete the referenced component.
-    private final Message message;
-
-
-
-    // Creates a new referential integrity delete listener.
-    private ReferentialIntegrityDeleteListener(DN dn, Message message) {
-      this.dn = dn;
-      this.message = message;
-    }
-
-
-
-    /**
-     * {@inheritDoc}
-     */
-    public ConfigChangeResult applyConfigurationDelete(S configuration) {
-      // This should not happen - the
-      // isConfigurationDeleteAcceptable() call-back should have
-      // trapped this.
-      if (configuration.dn().equals(dn)) {
-        // This should not happen - the
-        // isConfigurationDeleteAcceptable() call-back should have
-        // trapped this.
-        throw new IllegalStateException("Attempting to delete a referenced "
-            + relationDefinition.getChildDefinition().getUserFriendlyName());
-      } else {
-        return new ConfigChangeResult(ResultCode.SUCCESS, false);
-      }
-    }
-
-
-
-    /**
-     * {@inheritDoc}
-     */
-    public boolean isConfigurationDeleteAcceptable(S configuration,
-        List<Message> unacceptableReasons) {
-      if (configuration.dn().equals(dn)) {
-        // Always prevent deletion of the referenced component.
-        unacceptableReasons.add(message);
-        return false;
-      }
-
-      return true;
-    }
-
-  }
-
-
-
-  /**
-   * The server-side constraint handler implementation.
-   */
-  private class ServerHandler extends ServerConstraintHandler {
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public boolean isUsable(ServerManagedObject<?> managedObject,
-        Collection<Message> unacceptableReasons) throws ConfigException {
-      SortedSet<String> names = managedObject
-          .getPropertyValues(AggregationPropertyDefinition.this);
-      ServerManagementContext context = ServerManagementContext.getInstance();
-      Message thisUFN = managedObject.getManagedObjectDefinition()
-          .getUserFriendlyName();
-      String thisDN = managedObject.getDN().toString();
-      Message thatUFN = getRelationDefinition().getUserFriendlyName();
-
-      boolean isUsable = true;
-      boolean needsEnabling = targetNeedsEnablingCondition
-          .evaluate(managedObject);
-      for (String name : names) {
-        ManagedObjectPath<C, S> path = getChildPath(name);
-        String thatDN = path.toDN().toString();
-
-        if (!context.managedObjectExists(path)) {
-          Message msg = ERR_SERVER_REFINT_DANGLING_REFERENCE.get(name,
-              getName(), thisUFN, thisDN, thatUFN, thatDN);
-          unacceptableReasons.add(msg);
-          isUsable = false;
-        } else if (needsEnabling) {
-          // Check that the referenced component is enabled if
-          // required.
-          ServerManagedObject<? extends S> ref = context.getManagedObject(path);
-          if (!targetIsEnabledCondition.evaluate(ref)) {
-            Message msg = ERR_SERVER_REFINT_TARGET_DISABLED.get(name,
-                getName(), thisUFN, thisDN, thatUFN, thatDN);
-            unacceptableReasons.add(msg);
-            isUsable = false;
-          }
-        }
-      }
-
-      return isUsable;
-    }
-
-
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void performPostAdd(ServerManagedObject<?> managedObject)
-        throws ConfigException {
-      // First make sure existing listeners associated with this
-      // managed object are removed. This is required in order to
-      // prevent multiple change listener registrations from
-      // occurring, for example if this call-back is invoked multiple
-      // times after the same add event.
-      performPostDelete(managedObject);
-
-      // Add change and delete listeners against all referenced
-      // components.
-      Message thisUFN = managedObject.getManagedObjectDefinition()
-          .getUserFriendlyName();
-      String thisDN = managedObject.getDN().toString();
-      Message thatUFN = getRelationDefinition().getUserFriendlyName();
-
-      // Referenced managed objects will only need a change listener
-      // if they have can be disabled.
-      boolean needsChangeListeners = targetNeedsEnablingCondition
-          .evaluate(managedObject);
-
-      // Delete listeners need to be registered against the parent
-      // entry of the referenced components.
-      ServerManagementContext context = ServerManagementContext.getInstance();
-      ManagedObjectPath<?, ?> parentPath = getParentPath();
-      ServerManagedObject<?> parent = context.getManagedObject(parentPath);
-
-      // Create entries in the listener tables.
-      List<ReferentialIntegrityDeleteListener> dlist =
-        new LinkedList<ReferentialIntegrityDeleteListener>();
-      deleteListeners.put(managedObject.getDN(), dlist);
-
-      List<ReferentialIntegrityChangeListener> clist =
-        new LinkedList<ReferentialIntegrityChangeListener>();
-      changeListeners.put(managedObject.getDN(), clist);
-
-      for (String name : managedObject
-          .getPropertyValues(AggregationPropertyDefinition.this)) {
-        ManagedObjectPath<C, S> path = getChildPath(name);
-        DN dn = path.toDN();
-        String thatDN = dn.toString();
-
-        // Register the delete listener.
-        Message msg = ERR_SERVER_REFINT_CANNOT_DELETE.get(thatUFN, thatDN,
-            getName(), thisUFN, thisDN);
-        ReferentialIntegrityDeleteListener dl =
-          new ReferentialIntegrityDeleteListener(dn, msg);
-        parent.registerDeleteListener(getRelationDefinition(), dl);
-        dlist.add(dl);
-
-        // Register the change listener if required.
-        if (needsChangeListeners) {
-          ServerManagedObject<? extends S> ref = context.getManagedObject(path);
-          msg = ERR_SERVER_REFINT_CANNOT_DISABLE.get(thatUFN, thatDN,
-              getName(), thisUFN, thisDN);
-          ReferentialIntegrityChangeListener cl =
-            new ReferentialIntegrityChangeListener(path, msg);
-          ref.registerChangeListener(cl);
-          clist.add(cl);
-        }
-      }
-    }
-
-
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void performPostDelete(ServerManagedObject<?> managedObject)
-        throws ConfigException {
-      // Remove any registered delete and change listeners.
-      ServerManagementContext context = ServerManagementContext.getInstance();
-      DN dn = managedObject.getDN();
-
-      // Delete listeners need to be deregistered against the parent
-      // entry of the referenced components.
-      ManagedObjectPath<?, ?> parentPath = getParentPath();
-      ServerManagedObject<?> parent = context.getManagedObject(parentPath);
-      if (deleteListeners.containsKey(dn)) {
-        for (ReferentialIntegrityDeleteListener dl : deleteListeners.get(dn)) {
-          parent.deregisterDeleteListener(getRelationDefinition(), dl);
-        }
-        deleteListeners.remove(dn);
-      }
-
-      // Change listeners need to be deregistered from their
-      // associated referenced component.
-      if (changeListeners.containsKey(dn)) {
-        for (ReferentialIntegrityChangeListener cl : changeListeners.get(dn)) {
-          ManagedObjectPath<C, S> path = cl.getManagedObjectPath();
-          ServerManagedObject<? extends S> ref = context.getManagedObject(path);
-          ref.deregisterChangeListener(cl);
-        }
-        changeListeners.remove(dn);
-      }
-    }
-
-
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void performPostModify(ServerManagedObject<?> managedObject)
-        throws ConfigException {
-      // Remove all the constraints associated with this managed
-      // object and then re-register them.
-      performPostDelete(managedObject);
-      performPostAdd(managedObject);
-    }
-  }
-
-
-
-  /**
-   * The client-side constraint handler implementation which enforces
-   * referential integrity when aggregating managed objects are added
-   * or modified.
-   */
-  private class SourceClientHandler extends ClientConstraintHandler {
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public boolean isAddAcceptable(ManagementContext context,
-        ManagedObject<?> managedObject, Collection<Message> unacceptableReasons)
-        throws AuthorizationException, CommunicationException {
-      // If all of this managed object's "enabled" properties are true
-      // then any referenced managed objects must also be enabled.
-      boolean needsEnabling = targetNeedsEnablingCondition.evaluate(context,
-          managedObject);
-
-      // Check the referenced managed objects exist and, if required,
-      // are enabled.
-      boolean isAcceptable = true;
-      Message ufn = getRelationDefinition().getUserFriendlyName();
-      for (String name : managedObject
-          .getPropertyValues(AggregationPropertyDefinition.this)) {
-        // Retrieve the referenced managed object and make sure it
-        // exists.
-        ManagedObjectPath<?, ?> path = getChildPath(name);
-        ManagedObject<?> ref;
-        try {
-          ref = context.getManagedObject(path);
-        } catch (DefinitionDecodingException e) {
-          Message msg = ERR_CLIENT_REFINT_TARGET_INVALID.get(ufn, name,
-              getName(), e.getMessageObject());
-          unacceptableReasons.add(msg);
-          isAcceptable = false;
-          continue;
-        } catch (ManagedObjectDecodingException e) {
-          Message msg = ERR_CLIENT_REFINT_TARGET_INVALID.get(ufn, name,
-              getName(), e.getMessageObject());
-          unacceptableReasons.add(msg);
-          isAcceptable = false;
-          continue;
-        } catch (ManagedObjectNotFoundException e) {
-          Message msg = ERR_CLIENT_REFINT_TARGET_DANGLING_REFERENCE.get(ufn,
-              name, getName());
-          unacceptableReasons.add(msg);
-          isAcceptable = false;
-          continue;
-        }
-
-        // Make sure the reference managed object is enabled.
-        if (needsEnabling) {
-          if (!targetIsEnabledCondition.evaluate(context, ref)) {
-            Message msg = ERR_CLIENT_REFINT_TARGET_DISABLED.get(ufn, name,
-                getName());
-            unacceptableReasons.add(msg);
-            isAcceptable = false;
-          }
-        }
-      }
-      return isAcceptable;
-    }
-
-
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public boolean isModifyAcceptable(ManagementContext context,
-        ManagedObject<?> managedObject, Collection<Message> unacceptableReasons)
-        throws AuthorizationException, CommunicationException {
-      // The same constraint applies as for adds.
-      return isAddAcceptable(context, managedObject, unacceptableReasons);
-    }
-
-  }
-
-
-
-  /**
-   * The client-side constraint handler implementation which enforces
-   * referential integrity when aggregated managed objects are deleted
-   * or modified.
-   */
-  private class TargetClientHandler extends ClientConstraintHandler {
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public boolean isDeleteAcceptable(ManagementContext context,
-        ManagedObjectPath<?, ?> path, Collection<Message> unacceptableReasons)
-        throws AuthorizationException, CommunicationException {
-      // Any references to the deleted managed object should cause a
-      // constraint violation.
-      boolean isAcceptable = true;
-      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(
-              getName(), mo.getManagedObjectDefinition().getUserFriendlyName(),
-              getManagedObjectDefinition().getUserFriendlyName());
-          unacceptableReasons.add(msg);
-        } else {
-          Message msg = ERR_CLIENT_REFINT_CANNOT_DELETE_WITH_NAME.get(
-              getName(), mo.getManagedObjectDefinition().getUserFriendlyName(),
-              name, getManagedObjectDefinition().getUserFriendlyName());
-          unacceptableReasons.add(msg);
-        }
-        isAcceptable = false;
-      }
-      return isAcceptable;
-    }
-
-
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public boolean isModifyAcceptable(ManagementContext context,
-        ManagedObject<?> managedObject, Collection<Message> unacceptableReasons)
-        throws AuthorizationException, CommunicationException {
-      // If the modified managed object is disabled and there are some
-      // active references then refuse the change.
-      if (targetIsEnabledCondition.evaluate(context, managedObject)) {
-        return true;
-      }
-
-      // The referenced managed object is disabled. Need to check for
-      // active references.
-      boolean isAcceptable = true;
-      for (ManagedObject<?> mo : findReferences(context,
-          getManagedObjectDefinition(), managedObject.getManagedObjectPath()
-              .getName())) {
-        if (targetNeedsEnablingCondition.evaluate(context, mo)) {
-          String name = mo.getManagedObjectPath().getName();
-          if (name == null) {
-            Message msg = ERR_CLIENT_REFINT_CANNOT_DISABLE_WITHOUT_NAME.get(
-                managedObject.getManagedObjectDefinition()
-                    .getUserFriendlyName(), getName(), mo
-                    .getManagedObjectDefinition().getUserFriendlyName());
-            unacceptableReasons.add(msg);
-          } else {
-            Message msg = ERR_CLIENT_REFINT_CANNOT_DISABLE_WITH_NAME.get(
-                managedObject.getManagedObjectDefinition()
-                    .getUserFriendlyName(), getName(), mo
-                    .getManagedObjectDefinition().getUserFriendlyName(), name);
-            unacceptableReasons.add(msg);
-          }
-          isAcceptable = false;
-        }
-      }
-      return isAcceptable;
-    }
-
-
-
-    // Find all managed objects which reference the named managed
-    // object using this property.
-    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.
+            /**
+             * {@inheritDoc}
+             */
+            public Collection<ClientConstraintHandler> getClientConstraintHandlers() {
+                ClientConstraintHandler handler = new SourceClientHandler();
+                return Collections.singleton(handler);
             }
-          }
+
+            /**
+             * {@inheritDoc}
+             */
+            public Collection<ServerConstraintHandler> getServerConstraintHandlers() {
+                ServerConstraintHandler handler = new ServerHandler();
+                return Collections.singleton(handler);
+            }
+        };
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public <R, P> R accept(PropertyDefinitionVisitor<R, P> v, P p) {
+        return v.visitAggregation(this, p);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public <R, P> R accept(PropertyValueVisitor<R, P> v, String value, P p) {
+        return v.visitAggregation(this, value, p);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String decodeValue(String value) throws IllegalPropertyValueStringException {
+        ensureNotNull(value);
+
+        try {
+            validateValue(value);
+            return value;
+        } catch (IllegalPropertyValueException e) {
+            throw new IllegalPropertyValueStringException(this, value);
         }
-      }
-
-      return instances;
     }
-  }
 
-
-
-  /**
-   * The tracer object for the debug logger.
-   */
-  private static final DebugTracer TRACER = getTracer();
-
-
-
-  /**
-   * Creates an aggregation property definition builder.
-   *
-   * @param <C>
-   *          The type of client managed object configuration that
-   *          this aggregation property definition refers to.
-   * @param <S>
-   *          The type of server managed object configuration that
-   *          this aggregation property definition refers to.
-   * @param d
-   *          The managed object definition associated with this
-   *          property definition.
-   * @param propertyName
-   *          The property name.
-   * @return Returns the new aggregation property definition builder.
-   */
-  public static <C extends ConfigurationClient, S extends Configuration>
-      Builder<C, S> createBuilder(
-      AbstractManagedObjectDefinition<?, ?> d, String propertyName) {
-    return new Builder<C, S>(d, propertyName);
-  }
-
-  // The active server-side referential integrity change listeners
-  // associated with this property.
-  private final Map<DN, List<ReferentialIntegrityChangeListener>>
-    changeListeners = new HashMap<DN,
-      List<ReferentialIntegrityChangeListener>>();
-
-  // The active server-side referential integrity delete listeners
-  // associated with this property.
-  private final Map<DN, List<ReferentialIntegrityDeleteListener>>
-    deleteListeners = new HashMap<DN,
-      List<ReferentialIntegrityDeleteListener>>();
-
-  // The name of the managed object which is the parent of the
-  // aggregated managed objects.
-  private ManagedObjectPath<?, ?> parentPath;
-
-  // The string representation of the managed object path specifying
-  // the parent of the aggregated managed objects.
-  private final String parentPathString;
-
-  // The name of a relation in the parent managed object which
-  // contains the aggregated managed objects.
-  private final String rdName;
-
-  // The relation in the parent managed object which contains the
-  // aggregated managed objects.
-  private InstantiableRelationDefinition<C, S> relationDefinition;
-
-  // The source constraint.
-  private final Constraint sourceConstraint;
-
-  // The condition which is used to determine if a referenced managed
-  // object is enabled.
-  private final Condition targetIsEnabledCondition;
-
-  // The condition which is used to determine whether or not
-  // referenced managed objects need to be enabled.
-  private final Condition targetNeedsEnablingCondition;
-
-
-
-  // Private constructor.
-  private AggregationPropertyDefinition(
-      AbstractManagedObjectDefinition<?, ?> d, String propertyName,
-      EnumSet<PropertyOption> options, AdministratorAction adminAction,
-      DefaultBehaviorProvider<String> defaultBehavior, String parentPathString,
-      String rdName, Condition targetNeedsEnablingCondition,
-      Condition targetIsEnabledCondition) {
-    super(d, String.class, propertyName, options, adminAction, defaultBehavior);
-
-    this.parentPathString = parentPathString;
-    this.rdName = rdName;
-    this.targetNeedsEnablingCondition = targetNeedsEnablingCondition;
-    this.targetIsEnabledCondition = targetIsEnabledCondition;
-    this.sourceConstraint = new Constraint() {
-
-      /**
-       * {@inheritDoc}
-       */
-      public Collection<ClientConstraintHandler> getClientConstraintHandlers() {
-        ClientConstraintHandler handler = new SourceClientHandler();
-        return Collections.singleton(handler);
-      }
-
-
-
-      /**
-       * {@inheritDoc}
-       */
-      public Collection<ServerConstraintHandler> getServerConstraintHandlers() {
-        ServerConstraintHandler handler = new ServerHandler();
-        return Collections.singleton(handler);
-      }
-    };
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override
-  public <R, P> R accept(PropertyDefinitionVisitor<R, P> v, P p) {
-    return v.visitAggregation(this, p);
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override
-  public <R, P> R accept(PropertyValueVisitor<R, P> v, String value, P p) {
-    return v.visitAggregation(this, value, p);
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override
-  public String decodeValue(String value)
-      throws IllegalPropertyValueStringException {
-    ensureNotNull(value);
-
-    try {
-      validateValue(value);
-      return value;
-    } catch (IllegalPropertyValueException e) {
-      throw new IllegalPropertyValueStringException(this, value);
+    /**
+     * Constructs a DN for a referenced managed object having the provided name.
+     * This method is implemented by first calling {@link #getChildPath(String)}
+     * and then invoking {@code ManagedObjectPath.toDN()} on the returned path.
+     *
+     * @param name
+     *            The name of the child managed object.
+     * @return Returns a DN for a referenced managed object having the provided
+     *         name.
+     */
+    public final DN getChildDN(String name) {
+        return getChildPath(name).toDN();
     }
-  }
 
-
-
-  /**
-   * Constructs a DN for a referenced managed object having the
-   * provided name. This method is implemented by first calling
-   * {@link #getChildPath(String)} and then invoking
-   * {@code ManagedObjectPath.toDN()} on the returned path.
-   *
-   * @param name
-   *          The name of the child managed object.
-   * @return Returns a DN for a referenced managed object having the
-   *         provided name.
-   */
-  public final DN getChildDN(String name) {
-    return getChildPath(name).toDN();
-  }
-
-
-
-  /**
-   * Constructs a managed object path for a referenced managed object
-   * having the provided name.
-   *
-   * @param name
-   *          The name of the child managed object.
-   * @return Returns a managed object path for a referenced managed
-   *         object having the provided name.
-   */
-  public final ManagedObjectPath<C, S> getChildPath(String name) {
-    return parentPath.child(relationDefinition, name);
-  }
-
-
-
-  /**
-   * Gets the name of the managed object which is the parent of the
-   * aggregated managed objects.
-   *
-   * @return Returns the name of the managed object which is the
-   *         parent of the aggregated managed objects.
-   */
-  public final ManagedObjectPath<?, ?> getParentPath() {
-    return parentPath;
-  }
-
-
-
-  /**
-   * Gets the relation in the parent managed object which contains the
-   * aggregated managed objects.
-   *
-   * @return Returns the relation in the parent managed object which
-   *         contains the aggregated managed objects.
-   */
-  public final InstantiableRelationDefinition<C, S> getRelationDefinition() {
-    return relationDefinition;
-  }
-
-
-
-  /**
-   * Gets the constraint which should be enforced on the aggregating
-   * managed object.
-   *
-   * @return Returns the constraint which should be enforced on the
-   *         aggregating managed object.
-   */
-  public final Constraint getSourceConstraint() {
-    return sourceConstraint;
-  }
-
-
-
-  /**
-   * Gets the optional constraint synopsis of this aggregation
-   * property definition in the default locale. The constraint
-   * synopsis describes when and how referenced managed objects must
-   * be enabled. When there are no constraints between the source
-   * managed object and the objects it references through this
-   * aggregation, <code>null</code> is returned.
-   *
-   * @return Returns the optional constraint synopsis of this
-   *         aggregation property definition in the default locale, or
-   *         <code>null</code> if there is no constraint synopsis.
-   */
-  public final Message getSourceConstraintSynopsis() {
-    return getSourceConstraintSynopsis(Locale.getDefault());
-  }
-
-
-
-  /**
-   * Gets the optional constraint synopsis of this aggregation
-   * property definition in the specified locale.The constraint
-   * synopsis describes when and how referenced managed objects must
-   * be enabled. When there are no constraints between the source
-   * managed object and the objects it references through this
-   * aggregation, <code>null</code> is returned.
-   *
-   * @param locale
-   *          The locale.
-   * @return Returns the optional constraint synopsis of this
-   *         aggregation property definition in the specified locale,
-   *         or <code>null</code> if there is no constraint
-   *         synopsis.
-   */
-  public final Message getSourceConstraintSynopsis(Locale locale) {
-    ManagedObjectDefinitionI18NResource resource =
-      ManagedObjectDefinitionI18NResource.getInstance();
-    String property = "property." + getName()
-        + ".syntax.aggregation.constraint-synopsis";
-    try {
-      return resource
-          .getMessage(getManagedObjectDefinition(), property, locale);
-    } catch (MissingResourceException e) {
-      return null;
+    /**
+     * Constructs a managed object path for a referenced managed object having
+     * the provided name.
+     *
+     * @param name
+     *            The name of the child managed object.
+     * @return Returns a managed object path for a referenced managed object
+     *         having the provided name.
+     */
+    public final ManagedObjectPath<C, S> getChildPath(String name) {
+        return parentPath.child(relationDefinition, name);
     }
-  }
 
-
-
-  /**
-   * Gets the condition which is used to determine if a referenced
-   * managed object is enabled.
-   *
-   * @return Returns the condition which is used to determine if a
-   *         referenced managed object is enabled.
-   */
-  public final Condition getTargetIsEnabledCondition() {
-    return targetIsEnabledCondition;
-  }
-
-
-
-  /**
-   * Gets the condition which is used to determine whether or not
-   * referenced managed objects need to be enabled.
-   *
-   * @return Returns the condition which is used to determine whether
-   *         or not referenced managed objects need to be enabled.
-   */
-  public final Condition getTargetNeedsEnablingCondition() {
-    return targetNeedsEnablingCondition;
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override
-  public String normalizeValue(String value)
-      throws IllegalPropertyValueException {
-    try {
-      Reference<C, S> reference = Reference.parseName(parentPath,
-          relationDefinition, value);
-      return reference.getNormalizedName();
-    } catch (IllegalArgumentException e) {
-      throw new IllegalPropertyValueException(this, value);
+    /**
+     * Gets the name of the managed object which is the parent of the aggregated
+     * managed objects.
+     *
+     * @return Returns the name of the managed object which is the parent of the
+     *         aggregated managed objects.
+     */
+    public final ManagedObjectPath<?, ?> getParentPath() {
+        return parentPath;
     }
-  }
 
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override
-  public void toString(StringBuilder builder) {
-    super.toString(builder);
-
-    builder.append(" parentPath=");
-    builder.append(parentPath);
-
-    builder.append(" relationDefinition=");
-    builder.append(relationDefinition.getName());
-
-    builder.append(" targetNeedsEnablingCondition=");
-    builder.append(String.valueOf(targetNeedsEnablingCondition));
-
-    builder.append(" targetIsEnabledCondition=");
-    builder.append(String.valueOf(targetIsEnabledCondition));
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override
-  public void validateValue(String value) throws IllegalPropertyValueException {
-    try {
-      Reference.parseName(parentPath, relationDefinition, value);
-    } catch (IllegalArgumentException e) {
-      throw new IllegalPropertyValueException(this, value);
+    /**
+     * Gets the relation in the parent managed object which contains the
+     * aggregated managed objects.
+     *
+     * @return Returns the relation in the parent managed object which contains
+     *         the aggregated managed objects.
+     */
+    public final InstantiableRelationDefinition<C, S> getRelationDefinition() {
+        return relationDefinition;
     }
-  }
 
+    /**
+     * Gets the constraint which should be enforced on the aggregating managed
+     * object.
+     *
+     * @return Returns the constraint which should be enforced on the
+     *         aggregating managed object.
+     */
+    public final Constraint getSourceConstraint() {
+        return sourceConstraint;
+    }
 
+    /**
+     * Gets the optional constraint synopsis of this aggregation property
+     * definition in the default locale. The constraint synopsis describes when
+     * and how referenced managed objects must be enabled. When there are no
+     * constraints between the source managed object and the objects it
+     * references through this aggregation, <code>null</code> is returned.
+     *
+     * @return Returns the optional constraint synopsis of this aggregation
+     *         property definition in the default locale, or <code>null</code>
+     *         if there is no constraint synopsis.
+     */
+    public final LocalizableMessage getSourceConstraintSynopsis() {
+        return getSourceConstraintSynopsis(Locale.getDefault());
+    }
 
-  /**
-   * {@inheritDoc}
-   */
-  @SuppressWarnings("unchecked")
-  @Override
-  public void initialize() throws Exception {
-    // Decode the path.
-    parentPath = ManagedObjectPath.valueOf(parentPathString);
+    /**
+     * Gets the optional constraint synopsis of this aggregation property
+     * definition in the specified locale.The constraint synopsis describes when
+     * and how referenced managed objects must be enabled. When there are no
+     * constraints between the source managed object and the objects it
+     * references through this aggregation, <code>null</code> is returned.
+     *
+     * @param locale
+     *            The locale.
+     * @return Returns the optional constraint synopsis of this aggregation
+     *         property definition in the specified locale, or <code>null</code>
+     *         if there is no constraint synopsis.
+     */
+    public final LocalizableMessage getSourceConstraintSynopsis(Locale locale) {
+        ManagedObjectDefinitionI18NResource resource = ManagedObjectDefinitionI18NResource.getInstance();
+        String property = "property." + getName() + ".syntax.aggregation.constraint-synopsis";
+        try {
+            return resource.getLocalizableMessage(getManagedObjectDefinition(), property, locale);
+        } catch (MissingResourceException e) {
+            return null;
+        }
+    }
 
-    // Decode the relation definition.
-    AbstractManagedObjectDefinition<?, ?> parent = parentPath
-        .getManagedObjectDefinition();
-    RelationDefinition<?, ?> rd = parent.getRelationDefinition(rdName);
-    relationDefinition = (InstantiableRelationDefinition<C, S>) rd;
+    /**
+     * Gets the condition which is used to determine if a referenced managed
+     * object is enabled.
+     *
+     * @return Returns the condition which is used to determine if a referenced
+     *         managed object is enabled.
+     */
+    public final Condition getTargetIsEnabledCondition() {
+        return targetIsEnabledCondition;
+    }
 
-    // Now decode the conditions.
-    targetNeedsEnablingCondition.initialize(getManagedObjectDefinition());
-    targetIsEnabledCondition.initialize(rd.getChildDefinition());
+    /**
+     * Gets the condition which is used to determine whether or not referenced
+     * managed objects need to be enabled.
+     *
+     * @return Returns the condition which is used to determine whether or not
+     *         referenced managed objects need to be enabled.
+     */
+    public final Condition getTargetNeedsEnablingCondition() {
+        return targetNeedsEnablingCondition;
+    }
 
-    // Register a client-side constraint with the referenced
-    // definition. This will be used to enforce referential integrity
-    // for actions performed against referenced managed objects.
-    Constraint constraint = new Constraint() {
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String normalizeValue(String value) throws IllegalPropertyValueException {
+        try {
+            Reference<C, S> reference = Reference.parseName(parentPath, relationDefinition, value);
+            return reference.getNormalizedName();
+        } catch (IllegalArgumentException e) {
+            throw new IllegalPropertyValueException(this, value);
+        }
+    }
 
-      /**
-       * {@inheritDoc}
-       */
-      public Collection<ClientConstraintHandler> getClientConstraintHandlers() {
-        ClientConstraintHandler handler = new TargetClientHandler();
-        return Collections.singleton(handler);
-      }
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void toString(StringBuilder builder) {
+        super.toString(builder);
 
+        builder.append(" parentPath=");
+        builder.append(parentPath);
 
+        builder.append(" relationDefinition=");
+        builder.append(relationDefinition.getName());
 
-      /**
-       * {@inheritDoc}
-       */
-      public Collection<ServerConstraintHandler> getServerConstraintHandlers() {
-        return Collections.emptyList();
-      }
-    };
+        builder.append(" targetNeedsEnablingCondition=");
+        builder.append(String.valueOf(targetNeedsEnablingCondition));
 
-    rd.getChildDefinition().registerConstraint(constraint);
-  }
+        builder.append(" targetIsEnabledCondition=");
+        builder.append(String.valueOf(targetIsEnabledCondition));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void validateValue(String value) throws IllegalPropertyValueException {
+        try {
+            Reference.parseName(parentPath, relationDefinition, value);
+        } catch (IllegalArgumentException e) {
+            throw new IllegalPropertyValueException(this, value);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public void initialize() throws Exception {
+        // Decode the path.
+        parentPath = ManagedObjectPath.valueOf(parentPathString);
+
+        // Decode the relation definition.
+        AbstractManagedObjectDefinition<?, ?> parent = parentPath.getManagedObjectDefinition();
+        RelationDefinition<?, ?> rd = parent.getRelationDefinition(rdName);
+        relationDefinition = (InstantiableRelationDefinition<C, S>) rd;
+
+        // Now decode the conditions.
+        targetNeedsEnablingCondition.initialize(getManagedObjectDefinition());
+        targetIsEnabledCondition.initialize(rd.getChildDefinition());
+
+        // Register a client-side constraint with the referenced
+        // definition. This will be used to enforce referential integrity
+        // for actions performed against referenced managed objects.
+        Constraint constraint = new Constraint() {
+
+            /**
+             * {@inheritDoc}
+             */
+            public Collection<ClientConstraintHandler> getClientConstraintHandlers() {
+                ClientConstraintHandler handler = new TargetClientHandler();
+                return Collections.singleton(handler);
+            }
+
+            /**
+             * {@inheritDoc}
+             */
+            public Collection<ServerConstraintHandler> getServerConstraintHandlers() {
+                return Collections.emptyList();
+            }
+        };
+
+        rd.getChildDefinition().registerConstraint(constraint);
+    }
 
 }

--
Gitblit v1.10.0