From e538344449d345daa6e5ecb9b05ceba5427408e9 Mon Sep 17 00:00:00 2001
From: Nicolas Capponi <nicolas.capponi@forgerock.com>
Date: Wed, 04 Dec 2013 14:13:59 +0000
Subject: [PATCH] OpenDJ 3 : config framework

---
 opendj-admin/src/main/java/org/opends/server/admin/server/DNBuilder.java                            |   79 
 opendj-admin/src/main/java/org/opends/server/admin/AdministratorAction.java                         |    2 
 opendj-admin/src/main/java/org/opends/server/admin/server/ConfigExceptionFactory.java               |  180 
 opendj-admin/src/main/java/org/opends/server/admin/server/ConfigAddListenerAdaptor.java             |   21 
 opendj-admin/pom.xml                                                                                |   58 
 opendj-admin/src/main/java/org/opends/server/admin/server/ConfigurationChangeListener.java          |   63 
 opendj-admin/src/main/java/org/opends/server/admin/server/ConfigurationDeleteListener.java          |   62 
 opendj-admin/src/main/java/org/opends/server/admin/server/ConstraintViolationException.java         |  213 -
 opendj-admin/src/main/java/org/opends/server/admin/server/ServerConstraintHandler.java              |  268 +-
 opendj-admin/src/main/java/org/opends/server/admin/server/ConfigDeleteListenerAdaptor.java          |  410 +-
 opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagedObjectDecodingException.java |  157 
 opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagedObject.java                  | 2894 +++++++++++-------------
 opendj-admin/src/main/java/org/opends/server/admin/server/DelayedConfigAddListener.java             |  243 -
 opendj-admin/src/main/java/org/opends/server/admin/server/ConfigChangeListenerAdaptor.java          |  712 ++---
 opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagementContext.java              | 1576 ++++++-------
 15 files changed, 3,107 insertions(+), 3,831 deletions(-)

diff --git a/opendj-admin/pom.xml b/opendj-admin/pom.xml
index 370aa07..0847aef 100644
--- a/opendj-admin/pom.xml
+++ b/opendj-admin/pom.xml
@@ -32,6 +32,10 @@
       <artifactId>i18n-core</artifactId>
     </dependency>
     <dependency>
+      <groupId>org.forgerock.commons</groupId>
+      <artifactId>i18n-slf4j</artifactId>
+    </dependency>
+    <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-api</artifactId>
     </dependency>
@@ -423,60 +427,6 @@
       </plugin>
     </plugins>
     <pluginManagement>
-      <plugins>
-        <!--This plugin's configuration is used to store Eclipse m2e settings 
-          only. It has no influence on the Maven build itself. -->
-        <plugin>
-          <groupId>org.eclipse.m2e</groupId>
-          <artifactId>lifecycle-mapping</artifactId>
-          <version>1.0.0</version>
-          <configuration>
-            <lifecycleMappingMetadata>
-              <pluginExecutions>
-                <pluginExecution>
-                  <pluginExecutionFilter>
-                    <groupId>org.codehaus.mojo</groupId>
-                    <artifactId>build-helper-maven-plugin</artifactId>
-                    <versionRange>[1.8,)</versionRange>
-                    <goals>
-                      <goal>parse-version</goal>
-                    </goals>
-                  </pluginExecutionFilter>
-                  <action>
-                    <ignore></ignore>
-                  </action>
-                </pluginExecution>
-                <pluginExecution>
-                  <pluginExecutionFilter>
-                    <groupId>org.codehaus.mojo</groupId>
-                    <artifactId>templating-maven-plugin</artifactId>
-                    <versionRange>[1.0-alpha-3,)</versionRange>
-                    <goals>
-                      <goal>filter-sources</goal>
-                    </goals>
-                  </pluginExecutionFilter>
-                  <action>
-                    <ignore></ignore>
-                  </action>
-                </pluginExecution>
-                <pluginExecution>
-                  <pluginExecutionFilter>
-                    <groupId>org.codehaus.mojo</groupId>
-                    <artifactId>xml-maven-plugin</artifactId>
-                    <versionRange>[1.0,)</versionRange>
-                    <goals>
-                      <goal>transform</goal>
-                    </goals>
-                  </pluginExecutionFilter>
-                  <action>
-                    <ignore></ignore>
-                  </action>
-                </pluginExecution>
-              </pluginExecutions>
-            </lifecycleMappingMetadata>
-          </configuration>
-        </plugin>
-      </plugins>
     </pluginManagement>
   </build>
   <reporting>
diff --git a/opendj-admin/src/main/java/org/opends/server/admin/AdministratorAction.java b/opendj-admin/src/main/java/org/opends/server/admin/AdministratorAction.java
index 192f076..92d3e5b 100644
--- a/opendj-admin/src/main/java/org/opends/server/admin/AdministratorAction.java
+++ b/opendj-admin/src/main/java/org/opends/server/admin/AdministratorAction.java
@@ -150,7 +150,7 @@
         ManagedObjectDefinitionI18NResource resource = ManagedObjectDefinitionI18NResource.getInstance();
         String property = "property." + propertyName + ".requires-admin-action.synopsis";
         try {
-            return resource.getLocalizableMessage(definition, property, locale);
+            return resource.getMessage(definition, property, locale);
         } catch (MissingResourceException e) {
             return null;
         }
diff --git a/opendj-admin/src/main/java/org/opends/server/admin/server/ConfigAddListenerAdaptor.java b/opendj-admin/src/main/java/org/opends/server/admin/server/ConfigAddListenerAdaptor.java
index 95418ae..305572a 100644
--- a/opendj-admin/src/main/java/org/opends/server/admin/server/ConfigAddListenerAdaptor.java
+++ b/opendj-admin/src/main/java/org/opends/server/admin/server/ConfigAddListenerAdaptor.java
@@ -28,8 +28,6 @@
 
 
 
-import static org.opends.server.loggers.debug.DebugLogger.*;
-
 import java.util.LinkedList;
 import java.util.List;
 
@@ -46,14 +44,12 @@
 import org.opends.server.admin.SetRelationDefinition;
 import org.opends.server.admin.DefinitionDecodingException.Reason;
 import org.opends.server.api.ConfigAddListener;
-import org.opends.server.config.ConfigEntry;
 import org.opends.server.config.ConfigException;
-import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.AttributeValue;
 import org.opends.server.types.ConfigChangeResult;
 import org.forgerock.opendj.ldap.DN;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.ResultCode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.forgerock.opendj.ldap.ResultCode;
 
 
 
@@ -68,10 +64,7 @@
 final class ConfigAddListenerAdaptor<S extends Configuration> extends
     AbstractConfigListenerAdaptor implements ConfigAddListener {
 
-  /**
-   * The tracer object for the debug logger.
-   */
-  private static final DebugTracer TRACER = getTracer();
+  private static final Logger debugLogger = LoggerFactory.getLogger(ConfigAddListenerAdaptor.class);
 
   // Cached managed object between accept/apply callbacks.
   private ServerManagedObject<? extends S> cachedManagedObject;
@@ -196,9 +189,7 @@
           try {
             handler.performPostAdd(cachedManagedObject);
           } catch (ConfigException e) {
-            if (debugEnabled()) {
-              TRACER.debugCaught(DebugLogLevel.ERROR, e);
-            }
+              debugLogger.trace("Unable to perform post add", e);
           }
         }
       }
@@ -257,7 +248,7 @@
     }
 
     // Let the add listener decide.
-    List<LocalizableMessage> reasons = new LinkedList<Message>();
+    List<LocalizableMessage> reasons = new LinkedList<LocalizableMessage>();
     if (listener.isConfigurationAddAcceptable(cachedManagedObject, reasons)) {
       return true;
     } else {
diff --git a/opendj-admin/src/main/java/org/opends/server/admin/server/ConfigChangeListenerAdaptor.java b/opendj-admin/src/main/java/org/opends/server/admin/server/ConfigChangeListenerAdaptor.java
index a71ed59..70a9e29 100644
--- a/opendj-admin/src/main/java/org/opends/server/admin/server/ConfigChangeListenerAdaptor.java
+++ b/opendj-admin/src/main/java/org/opends/server/admin/server/ConfigChangeListenerAdaptor.java
@@ -26,9 +26,7 @@
  */
 package org.opends.server.admin.server;
 
-
-
-import static org.opends.server.loggers.debug.DebugLogger.*;
+import static com.forgerock.opendj.ldap.AdminMessages.*;
 
 import java.util.Collection;
 import java.util.HashSet;
@@ -36,9 +34,12 @@
 import java.util.List;
 import java.util.Set;
 
-import org.opends.messages.AdminMessages;
+import com.forgerock.opendj.ldap.AdminMessages;
+import com.forgerock.opendj.util.StaticUtils;
+
 import org.forgerock.i18n.LocalizableMessage;
 import org.forgerock.i18n.LocalizableMessageBuilder;
+import org.forgerock.i18n.slf4j.LocalizedLogger;
 import org.opends.server.admin.AbsoluteInheritedDefaultBehaviorProvider;
 import org.opends.server.admin.AbstractManagedObjectDefinition;
 import org.opends.server.admin.AliasDefaultBehaviorProvider;
@@ -55,438 +56,367 @@
 import org.opends.server.admin.UndefinedDefaultBehaviorProvider;
 import org.opends.server.api.ConfigChangeListener;
 import org.opends.server.api.ConfigDeleteListener;
-import org.opends.server.config.ConfigEntry;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.loggers.ErrorLogger;
-import org.opends.server.loggers.debug.DebugTracer;
 import org.opends.server.types.ConfigChangeResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 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;
 
 /**
- * An adaptor class which converts {@link ConfigChangeListener}
- * call-backs to {@link ServerManagedObjectChangeListener}
- * call-backs.
+ * An adaptor class which converts {@link ConfigChangeListener} call-backs to
+ * {@link ServerManagedObjectChangeListener} call-backs.
  *
  * @param <S>
- *          The type of server configuration handled by the change
- *          listener.
+ *            The type of server configuration handled by the change listener.
  */
-final class ConfigChangeListenerAdaptor<S extends Configuration> extends
-    AbstractConfigListenerAdaptor implements ConfigChangeListener {
+final class ConfigChangeListenerAdaptor<S extends Configuration> extends AbstractConfigListenerAdaptor implements
+        ConfigChangeListener {
 
-  /**
-   * A default behavior visitor used for determining the set of
-   * dependencies.
-   *
-   * @param <T>
-   *          The type of property.
-   */
-  private static final class Visitor<T> implements
-      DefaultBehaviorProviderVisitor<T, Void, ManagedObjectPath<?, ?>> {
+    private static final Logger debugLogger = LoggerFactory.getLogger(ConfigChangeListenerAdaptor.class);
+    private static final LocalizedLogger adminLogger = LocalizedLogger.getLocalizedLogger(
+            ERR_ADMIN_MANAGED_OBJECT_DOES_NOT_EXIST.get("").resourceName());
 
     /**
-     * Finds the dependencies associated with the provided property
-     * definition.
+     * A default behavior visitor used for determining the set of dependencies.
      *
      * @param <T>
-     * @param path
-     *          The current base path used for relative name
-     *          resolution.
-     * @param pd
-     *          The property definition.
-     * @param dependencies
-     *          Add dependencies names to this collection.
+     *            The type of property.
      */
-    public static <T> void find(ManagedObjectPath<?, ?> path,
-        PropertyDefinition<T> pd, Collection<DN> dependencies) {
-      Visitor<T> v = new Visitor<T>(dependencies);
-      DefaultBehaviorProvider<T> db = pd.getDefaultBehaviorProvider();
-      db.accept(v, path);
+    private static final class Visitor<T> implements DefaultBehaviorProviderVisitor<T, Void, ManagedObjectPath<?, ?>> {
+
+        /**
+         * Finds the dependencies associated with the provided property
+         * definition.
+         *
+         * @param <T>
+         * @param path
+         *            The current base path used for relative name resolution.
+         * @param pd
+         *            The property definition.
+         * @param dependencies
+         *            Add dependencies names to this collection.
+         */
+        public static <T> void find(ManagedObjectPath<?, ?> path, PropertyDefinition<T> pd, Collection<DN> dependencies) {
+            Visitor<T> v = new Visitor<T>(dependencies);
+            DefaultBehaviorProvider<T> db = pd.getDefaultBehaviorProvider();
+            db.accept(v, path);
+        }
+
+        // The names of entries that this change listener depends on.
+        private final Collection<DN> dependencies;
+
+        // Prevent instantiation.
+        private Visitor(Collection<DN> dependencies) {
+            this.dependencies = dependencies;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public Void visitAbsoluteInherited(AbsoluteInheritedDefaultBehaviorProvider<T> d, ManagedObjectPath<?, ?> p) {
+            ManagedObjectPath<?, ?> next = d.getManagedObjectPath();
+            dependencies.add(DNBuilder.create(next));
+
+            // If the dependent property uses inherited defaults then
+            // recursively get those as well.
+            String propertyName = d.getPropertyName();
+            AbstractManagedObjectDefinition<?, ?> mod = d.getManagedObjectDefinition();
+            PropertyDefinition<?> pd = mod.getPropertyDefinition(propertyName);
+            find(next, pd, dependencies);
+
+            return null;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public Void visitAlias(AliasDefaultBehaviorProvider<T> d, ManagedObjectPath<?, ?> p) {
+            return null;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public Void visitDefined(DefinedDefaultBehaviorProvider<T> d, ManagedObjectPath<?, ?> p) {
+            return null;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public Void visitRelativeInherited(RelativeInheritedDefaultBehaviorProvider<T> d, ManagedObjectPath<?, ?> p) {
+            ManagedObjectPath<?, ?> next = d.getManagedObjectPath(p);
+            dependencies.add(DNBuilder.create(next));
+
+            // If the dependent property uses inherited defaults then
+            // recursively get those as well.
+            String propertyName = d.getPropertyName();
+            AbstractManagedObjectDefinition<?, ?> mod = d.getManagedObjectDefinition();
+            PropertyDefinition<?> pd = mod.getPropertyDefinition(propertyName);
+            find(next, pd, dependencies);
+
+            return null;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public Void visitUndefined(UndefinedDefaultBehaviorProvider<T> d, ManagedObjectPath<?, ?> p) {
+            return null;
+        }
     }
 
+    // Cached managed object between accept/apply call-backs.
+    private ServerManagedObject<? extends S> cachedManagedObject;
+
+    // The delete listener which is used to remove this listener and any
+    // dependencies.
+    private final ConfigDeleteListener cleanerListener;
+
     // The names of entries that this change listener depends on.
-    private final Collection<DN> dependencies;
+    private final Set<DN> dependencies;
 
+    // The listener used to notify this listener when dependency entries
+    // are modified.
+    private final ConfigChangeListener dependencyListener;
 
+    // The DN associated with this listener.
+    private final DN dn;
 
-    // Prevent instantiation.
-    private Visitor(Collection<DN> dependencies) {
-      this.dependencies = dependencies;
-    }
+    // The underlying change listener.
+    private final ServerManagedObjectChangeListener<? super S> listener;
 
-
+    // The managed object path.
+    private final ManagedObjectPath<?, S> path;
 
     /**
-     * {@inheritDoc}
+     * Create a new configuration change listener adaptor.
+     *
+     * @param path
+     *            The managed object path.
+     * @param listener
+     *            The underlying change listener.
      */
-    public Void visitAbsoluteInherited(
-        AbsoluteInheritedDefaultBehaviorProvider<T> d,
-        ManagedObjectPath<?, ?> p) {
-      ManagedObjectPath<?, ?> next = d.getManagedObjectPath();
-      dependencies.add(DNBuilder.create(next));
+    public ConfigChangeListenerAdaptor(ManagedObjectPath<?, S> path,
+            ServerManagedObjectChangeListener<? super S> listener) {
+        this.path = path;
+        this.dn = DNBuilder.create(path);
+        this.listener = listener;
+        this.cachedManagedObject = null;
 
-      // If the dependent property uses inherited defaults then
-      // recursively get those as well.
-      String propertyName = d.getPropertyName();
-      AbstractManagedObjectDefinition<?, ?> mod = d
-          .getManagedObjectDefinition();
-      PropertyDefinition<?> pd = mod.getPropertyDefinition(propertyName);
-      find(next, pd, dependencies);
+        // This change listener should be notified when dependent entries
+        // are modified. Determine the dependencies and register change
+        // listeners against them.
+        this.dependencies = new HashSet<DN>();
+        this.dependencyListener = new ConfigChangeListener() {
 
-      return null;
-    }
-
-
-
-    /**
-     * {@inheritDoc}
-     */
-    public Void visitAlias(AliasDefaultBehaviorProvider<T> d,
-        ManagedObjectPath<?, ?> p) {
-      return null;
-    }
-
-
-
-    /**
-     * {@inheritDoc}
-     */
-    public Void visitDefined(DefinedDefaultBehaviorProvider<T> d,
-        ManagedObjectPath<?, ?> p) {
-      return null;
-    }
-
-
-
-    /**
-     * {@inheritDoc}
-     */
-    public Void visitRelativeInherited(
-        RelativeInheritedDefaultBehaviorProvider<T> d,
-        ManagedObjectPath<?, ?> p) {
-      ManagedObjectPath<?, ?> next = d.getManagedObjectPath(p);
-      dependencies.add(DNBuilder.create(next));
-
-      // If the dependent property uses inherited defaults then
-      // recursively get those as well.
-      String propertyName = d.getPropertyName();
-      AbstractManagedObjectDefinition<?, ?> mod = d
-          .getManagedObjectDefinition();
-      PropertyDefinition<?> pd = mod.getPropertyDefinition(propertyName);
-      find(next, pd, dependencies);
-
-      return null;
-    }
-
-
-
-    /**
-     * {@inheritDoc}
-     */
-    public Void visitUndefined(UndefinedDefaultBehaviorProvider<T> d,
-        ManagedObjectPath<?, ?> p) {
-      return null;
-    }
-  }
-
-  /**
-   * The tracer object for the debug logger.
-   */
-  private static final DebugTracer TRACER = getTracer();
-
-  // Cached managed object between accept/apply call-backs.
-  private ServerManagedObject<? extends S> cachedManagedObject;
-
-  // The delete listener which is used to remove this listener and any
-  // dependencies.
-  private final ConfigDeleteListener cleanerListener;
-
-  // The names of entries that this change listener depends on.
-  private final Set<DN> dependencies;
-
-  // The listener used to notify this listener when dependency entries
-  // are modified.
-  private final ConfigChangeListener dependencyListener;
-
-  // The DN associated with this listener.
-  private final DN dn;
-
-  // The underlying change listener.
-  private final ServerManagedObjectChangeListener<? super S> listener;
-
-  // The managed object path.
-  private final ManagedObjectPath<?, S> path;
-
-
-
-  /**
-   * Create a new configuration change listener adaptor.
-   *
-   * @param path
-   *          The managed object path.
-   * @param listener
-   *          The underlying change listener.
-   */
-  public ConfigChangeListenerAdaptor(ManagedObjectPath<?, S> path,
-      ServerManagedObjectChangeListener<? super S> listener) {
-    this.path = path;
-    this.dn = DNBuilder.create(path);
-    this.listener = listener;
-    this.cachedManagedObject = null;
-
-    // This change listener should be notified when dependent entries
-    // are modified. Determine the dependencies and register change
-    // listeners against them.
-    this.dependencies = new HashSet<DN>();
-    this.dependencyListener = new ConfigChangeListener() {
-
-      public ConfigChangeResult applyConfigurationChange(
-          ConfigEntry configEntry) {
-        ConfigEntry dependentConfigEntry = getConfigEntry(dn);
-        if (dependentConfigEntry != null) {
-          return ConfigChangeListenerAdaptor.this
-              .applyConfigurationChange(dependentConfigEntry);
-        } else {
-          // The dependent entry was not found.
-          configEntry.deregisterChangeListener(this);
-          return new ConfigChangeResult(ResultCode.SUCCESS, false);
-        }
-      }
-
-
-
-      public boolean configChangeIsAcceptable(ConfigEntry configEntry,
-          LocalizableMessageBuilder unacceptableReason) {
-        ConfigEntry dependentConfigEntry = getConfigEntry(dn);
-        if (dependentConfigEntry != null) {
-          return ConfigChangeListenerAdaptor.this.configChangeIsAcceptable(
-              dependentConfigEntry, unacceptableReason, configEntry);
-        } else {
-          // The dependent entry was not found.
-          configEntry.deregisterChangeListener(this);
-          return true;
-        }
-      }
-
-    };
-
-    AbstractManagedObjectDefinition<?, ?> d = path.getManagedObjectDefinition();
-    for (PropertyDefinition<?> pd : d.getAllPropertyDefinitions()) {
-      Visitor.find(path, pd, dependencies);
-    }
-
-    for (DN entryDN : dependencies) {
-      // Be careful not to register listeners against the dependent
-      // entry itself.
-      if (!entryDN.equals(dn)) {
-        ConfigEntry configEntry = getConfigEntry(entryDN);
-        if (configEntry != null) {
-          configEntry.registerChangeListener(dependencyListener);
-        }
-      }
-    }
-
-    // Register a delete listener against the parent which will
-    // finalize this change listener when the monitored configuration
-    // entry is removed.
-    this.cleanerListener = new ConfigDeleteListener() {
-
-      public ConfigChangeResult applyConfigurationDelete(
-          ConfigEntry configEntry) {
-        // Perform finalization if the deleted entry is the monitored
-        // entry.
-        if (configEntry.getDN().equals(dn)) {
-          finalizeChangeListener();
-        }
-        return new ConfigChangeResult(ResultCode.SUCCESS, false);
-      }
-
-
-
-      public boolean configDeleteIsAcceptable(ConfigEntry configEntry,
-          LocalizableMessageBuilder unacceptableReason) {
-        // Always acceptable.
-        return true;
-      }
-
-    };
-
-    DN parent = dn.getParent();
-    if (parent != null) {
-      ConfigEntry configEntry = getConfigEntry(dn.getParent());
-      if (configEntry != null) {
-        configEntry.registerDeleteListener(cleanerListener);
-      }
-    }
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  public ConfigChangeResult applyConfigurationChange(ConfigEntry configEntry) {
-    // Looking at the ConfigFileHandler implementation reveals
-    // that this ConfigEntry will actually be a different object to
-    // the one passed in the previous call-back (it will have the same
-    // content though). This configuration entry has the correct
-    // listener lists.
-    cachedManagedObject.setConfigEntry(configEntry);
-
-    ConfigChangeResult result = listener
-        .applyConfigurationChange(cachedManagedObject);
-
-    // Now apply post constraint call-backs.
-    if (result.getResultCode() == ResultCode.SUCCESS) {
-      ManagedObjectDefinition<?, ?> d = cachedManagedObject
-          .getManagedObjectDefinition();
-      for (Constraint constraint : d.getAllConstraints()) {
-        for (ServerConstraintHandler handler : constraint
-            .getServerConstraintHandlers()) {
-          try {
-            handler.performPostModify(cachedManagedObject);
-          } catch (ConfigException e) {
-            if (debugEnabled()) {
-              TRACER.debugCaught(DebugLogLevel.ERROR, e);
+            public ConfigChangeResult applyConfigurationChange(ConfigEntry configEntry) {
+                ConfigEntry dependentConfigEntry = getConfigEntry(dn);
+                if (dependentConfigEntry != null) {
+                    return ConfigChangeListenerAdaptor.this.applyConfigurationChange(dependentConfigEntry);
+                } else {
+                    // The dependent entry was not found.
+                    configEntry.deregisterChangeListener(this);
+                    return new ConfigChangeResult(ResultCode.SUCCESS, false);
+                }
             }
-          }
+
+            public boolean configChangeIsAcceptable(ConfigEntry configEntry,
+                    LocalizableMessageBuilder unacceptableReason) {
+                ConfigEntry dependentConfigEntry = getConfigEntry(dn);
+                if (dependentConfigEntry != null) {
+                    return ConfigChangeListenerAdaptor.this.configChangeIsAcceptable(dependentConfigEntry,
+                            unacceptableReason, configEntry);
+                } else {
+                    // The dependent entry was not found.
+                    configEntry.deregisterChangeListener(this);
+                    return true;
+                }
+            }
+
+        };
+
+        AbstractManagedObjectDefinition<?, ?> d = path.getManagedObjectDefinition();
+        for (PropertyDefinition<?> pd : d.getAllPropertyDefinitions()) {
+            Visitor.find(path, pd, dependencies);
         }
-      }
+
+        for (DN entryDN : dependencies) {
+            // Be careful not to register listeners against the dependent
+            // entry itself.
+            if (!entryDN.equals(dn)) {
+                ConfigEntry configEntry = getConfigEntry(entryDN);
+                if (configEntry != null) {
+                    configEntry.registerChangeListener(dependencyListener);
+                }
+            }
+        }
+
+        // Register a delete listener against the parent which will
+        // finalize this change listener when the monitored configuration
+        // entry is removed.
+        this.cleanerListener = new ConfigDeleteListener() {
+
+            public ConfigChangeResult applyConfigurationDelete(ConfigEntry configEntry) {
+                // Perform finalization if the deleted entry is the monitored
+                // entry.
+                if (configEntry.getDN().equals(dn)) {
+                    finalizeChangeListener();
+                }
+                return new ConfigChangeResult(ResultCode.SUCCESS, false);
+            }
+
+            public boolean configDeleteIsAcceptable(ConfigEntry configEntry,
+                    LocalizableMessageBuilder unacceptableReason) {
+                // Always acceptable.
+                return true;
+            }
+
+        };
+
+        DN parent = dn.parent();
+        if (parent != null) {
+            ConfigEntry configEntry = getConfigEntry(dn.parent();
+            if (configEntry != null) {
+                configEntry.registerDeleteListener(cleanerListener);
+            }
+        }
     }
 
-    return result;
-  }
+    /**
+     * {@inheritDoc}
+     */
+    public ConfigChangeResult applyConfigurationChange(ConfigEntry configEntry) {
+        // Looking at the ConfigFileHandler implementation reveals
+        // that this ConfigEntry will actually be a different object to
+        // the one passed in the previous call-back (it will have the same
+        // content though). This configuration entry has the correct
+        // listener lists.
+        cachedManagedObject.setConfigEntry(configEntry);
 
+        ConfigChangeResult result = listener.applyConfigurationChange(cachedManagedObject);
 
+        // Now apply post constraint call-backs.
+        if (result.getResultCode() == ResultCode.SUCCESS) {
+            ManagedObjectDefinition<?, ?> d = cachedManagedObject.getManagedObjectDefinition();
+            for (Constraint constraint : d.getAllConstraints()) {
+                for (ServerConstraintHandler handler : constraint.getServerConstraintHandlers()) {
+                    try {
+                        handler.performPostModify(cachedManagedObject);
+                    } catch (ConfigException e) {
+                        debugLogger.trace("Unable to perform post modify", e);
+                    }
+                }
+            }
+        }
 
-  /**
-   * {@inheritDoc}
-   */
-  public boolean configChangeIsAcceptable(ConfigEntry configEntry,
-      LocalizableMessageBuilder unacceptableReason) {
-    return configChangeIsAcceptable(configEntry, unacceptableReason,
-        configEntry);
-  }
-
-
-
-  /**
-   * Indicates whether the configuration entry that will result from a
-   * proposed modification is acceptable to this change listener.
-   *
-   * @param configEntry
-   *          The configuration entry that will result from the
-   *          requested update.
-   * @param unacceptableReason
-   *          A buffer to which this method can append a
-   *          human-readable message explaining why the proposed
-   *          change is not acceptable.
-   * @param newConfigEntry
-   *          The configuration entry that caused the notification
-   *          (will be different from <code>configEntry</code> if a
-   *          dependency was modified).
-   * @return <CODE>true</CODE> if the proposed entry contains an
-   *         acceptable configuration, or <CODE>false</CODE> if it
-   *         does not.
-   */
-  public boolean configChangeIsAcceptable(ConfigEntry configEntry,
-      LocalizableMessageBuilder unacceptableReason, ConfigEntry newConfigEntry) {
-    try {
-      ServerManagementContext context = ServerManagementContext.getInstance();
-      cachedManagedObject = context.decode(path, configEntry, newConfigEntry);
-    } catch (DecodingException e) {
-      unacceptableReason.append(e.getMessageObject());
-      return false;
+        return result;
     }
 
-    // Give up immediately if a constraint violation occurs.
-    try {
-      cachedManagedObject.ensureIsUsable();
-    } catch (ConstraintViolationException e) {
-      generateUnacceptableReason(e.getMessages(), unacceptableReason);
-      return false;
+    /**
+     * {@inheritDoc}
+     */
+    public boolean configChangeIsAcceptable(ConfigEntry configEntry, LocalizableMessageBuilder unacceptableReason) {
+        return configChangeIsAcceptable(configEntry, unacceptableReason, configEntry);
     }
 
-    // Let the change listener decide.
-    List<LocalizableMessage> reasons = new LinkedList<Message>();
-    if (listener.isConfigurationChangeAcceptable(cachedManagedObject,reasons)) {
-      return true;
-    } else {
-      generateUnacceptableReason(reasons, unacceptableReason);
-      return false;
-    }
-  }
+    /**
+     * Indicates whether the configuration entry that will result from a
+     * proposed modification is acceptable to this change listener.
+     *
+     * @param configEntry
+     *            The configuration entry that will result from the requested
+     *            update.
+     * @param unacceptableReason
+     *            A buffer to which this method can append a human-readable
+     *            message explaining why the proposed change is not acceptable.
+     * @param newConfigEntry
+     *            The configuration entry that caused the notification (will be
+     *            different from <code>configEntry</code> if a dependency was
+     *            modified).
+     * @return <CODE>true</CODE> if the proposed entry contains an acceptable
+     *         configuration, or <CODE>false</CODE> if it does not.
+     */
+    public boolean configChangeIsAcceptable(ConfigEntry configEntry, LocalizableMessageBuilder unacceptableReason,
+            ConfigEntry newConfigEntry) {
+        try {
+            ServerManagementContext context = ServerManagementContext.getInstance();
+            cachedManagedObject = context.decode(path, configEntry, newConfigEntry);
+        } catch (DecodingException e) {
+            unacceptableReason.append(e.getMessageObject());
+            return false;
+        }
 
+        // Give up immediately if a constraint violation occurs.
+        try {
+            cachedManagedObject.ensureIsUsable();
+        } catch (ConstraintViolationException e) {
+            generateUnacceptableReason(e.getMessages(), unacceptableReason);
+            return false;
+        }
 
-
-  /**
-   * Finalizes this configuration change listener adaptor. This method
-   * must be called before this change listener is removed.
-   */
-  public void finalizeChangeListener() {
-    // Remove the dependency listeners.
-    for (DN dependency : dependencies) {
-      ConfigEntry listenerConfigEntry = getConfigEntry(dependency);
-      if (listenerConfigEntry != null) {
-        listenerConfigEntry.deregisterChangeListener(dependencyListener);
-      }
+        // Let the change listener decide.
+        List<LocalizableMessage> reasons = new LinkedList<LocalizableMessage>();
+        if (listener.isConfigurationChangeAcceptable(cachedManagedObject, reasons)) {
+            return true;
+        } else {
+            generateUnacceptableReason(reasons, unacceptableReason);
+            return false;
+        }
     }
 
-    // Now remove the cleaner listener as it will no longer be
-    // needed.
-    ConfigEntry parentConfigEntry = getConfigEntry(dn.getParent());
-    if (parentConfigEntry != null) {
-      parentConfigEntry.deregisterDeleteListener(cleanerListener);
+    /**
+     * Finalizes this configuration change listener adaptor. This method must be
+     * called before this change listener is removed.
+     */
+    public void finalizeChangeListener() {
+        // Remove the dependency listeners.
+        for (DN dependency : dependencies) {
+            ConfigEntry listenerConfigEntry = getConfigEntry(dependency);
+            if (listenerConfigEntry != null) {
+                listenerConfigEntry.deregisterChangeListener(dependencyListener);
+            }
+        }
+
+        // Now remove the cleaner listener as it will no longer be
+        // needed.
+        ConfigEntry parentConfigEntry = getConfigEntry(dn.parent();
+        if (parentConfigEntry != null) {
+            parentConfigEntry.deregisterDeleteListener(cleanerListener);
+        }
+
     }
 
-  }
-
-
-
-  /**
-   * Get the server managed object change listener associated with
-   * this adaptor.
-   *
-   * @return Returns the server managed object change listener
-   *         associated with this adaptor.
-   */
-  ServerManagedObjectChangeListener<? super S>
-  getServerManagedObjectChangeListener() {
-    return listener;
-  }
-
-
-
-  // Returns the named configuration entry or null if it could not be
-  // retrieved.
-  private ConfigEntry getConfigEntry(DN dn) {
-    try {
-      ConfigEntry configEntry = DirectoryServer.getConfigEntry(dn);
-      if (configEntry != null) {
-        return configEntry;
-      } else {
-        LocalizableMessage message = AdminMessages.ERR_ADMIN_MANAGED_OBJECT_DOES_NOT_EXIST
-            .get(String.valueOf(dn));
-        ErrorLogger.logError(message);
-      }
-    } catch (ConfigException e) {
-      // The dependent entry could not be retrieved.
-      if (debugEnabled()) {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      LocalizableMessage message = AdminMessages.ERR_ADMIN_CANNOT_GET_MANAGED_OBJECT.get(
-          String.valueOf(dn), StaticUtils.getExceptionMessage(e));
-      ErrorLogger.logError(message);
+    /**
+     * Get the server managed object change listener associated with this
+     * adaptor.
+     *
+     * @return Returns the server managed object change listener associated with
+     *         this adaptor.
+     */
+    ServerManagedObjectChangeListener<? super S> getServerManagedObjectChangeListener() {
+        return listener;
     }
 
-    return null;
-  }
+    // Returns the named configuration entry or null if it could not be
+    // retrieved.
+    private ConfigEntry getConfigEntry(DN dn) {
+        try {
+            ConfigEntry configEntry = DirectoryServer.getConfigEntry(dn);
+            if (configEntry != null) {
+                return configEntry;
+            } else {
+                adminLogger.error(ERR_ADMIN_MANAGED_OBJECT_DOES_NOT_EXIST, String.valueOf(dn));
+            }
+        } catch (ConfigException e) {
+            debugLogger.trace("The dependent entry could not be retrieved", e);
+            adminLogger.error(ERR_ADMIN_CANNOT_GET_MANAGED_OBJECT, String.valueOf(dn),
+                    StaticUtils.getExceptionMessage(e));
+        }
+
+        return null;
+    }
 
 }
diff --git a/opendj-admin/src/main/java/org/opends/server/admin/server/ConfigDeleteListenerAdaptor.java b/opendj-admin/src/main/java/org/opends/server/admin/server/ConfigDeleteListenerAdaptor.java
index 06d231f..958bbe7 100644
--- a/opendj-admin/src/main/java/org/opends/server/admin/server/ConfigDeleteListenerAdaptor.java
+++ b/opendj-admin/src/main/java/org/opends/server/admin/server/ConfigDeleteListenerAdaptor.java
@@ -26,16 +26,14 @@
  */
 package org.opends.server.admin.server;
 
-
-
 import static com.forgerock.opendj.ldap.AdminMessages.*;
-import static org.opends.server.loggers.debug.DebugLogger.*;
 
 import java.util.LinkedList;
 import java.util.List;
 
 import org.forgerock.i18n.LocalizableMessage;
 import org.forgerock.i18n.LocalizableMessageBuilder;
+import org.forgerock.i18n.slf4j.LocalizedLogger;
 import org.opends.server.admin.Configuration;
 import org.opends.server.admin.Constraint;
 import org.opends.server.admin.DecodingException;
@@ -47,256 +45,222 @@
 import org.opends.server.admin.SetRelationDefinition;
 import org.opends.server.admin.DefinitionDecodingException.Reason;
 import org.opends.server.api.ConfigDeleteListener;
-import org.opends.server.config.ConfigEntry;
 import org.opends.server.config.ConfigException;
-import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.AttributeValue;
 import org.opends.server.types.ConfigChangeResult;
 import org.forgerock.opendj.ldap.DN;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.ResultCode;
-
-
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.forgerock.opendj.ldap.ResultCode;
 
 /**
- * An adaptor class which converts {@link ConfigDeleteListener}
- * callbacks to {@link ServerManagedObjectDeleteListener} callbacks.
+ * An adaptor class which converts {@link ConfigDeleteListener} callbacks to
+ * {@link ServerManagedObjectDeleteListener} callbacks.
  *
  * @param <S>
- *          The type of server configuration handled by the delete
- *          listener.
+ *            The type of server configuration handled by the delete listener.
  */
-final class ConfigDeleteListenerAdaptor<S extends Configuration> extends
-    AbstractConfigListenerAdaptor implements ConfigDeleteListener {
+final class ConfigDeleteListenerAdaptor<S extends Configuration> extends AbstractConfigListenerAdaptor implements
+        ConfigDeleteListener {
 
-  /**
-   * The tracer object for the debug logger.
-   */
-  private static final DebugTracer TRACER = getTracer();
+    private static final Logger debugLogger = LoggerFactory.getLogger(ConfigDeleteListenerAdaptor.class);
 
-  // Cached managed object between accept/apply callbacks.
-  private ServerManagedObject<? extends S> cachedManagedObject;
+    // Cached managed object between accept/apply callbacks.
+    private ServerManagedObject<? extends S> cachedManagedObject;
 
-  // The instantiable relation.
-  private final InstantiableRelationDefinition<?, S> instantiableRelation;
+    // The instantiable relation.
+    private final InstantiableRelationDefinition<?, S> instantiableRelation;
 
-  // The set relation.
-  private final SetRelationDefinition<?, S> setRelation;
+    // The set relation.
+    private final SetRelationDefinition<?, S> setRelation;
 
-  // The underlying delete listener.
-  private final ServerManagedObjectDeleteListener<S> listener;
+    // The underlying delete listener.
+    private final ServerManagedObjectDeleteListener<S> listener;
 
-  // The optional relation.
-  private final OptionalRelationDefinition<?, S> optionalRelation;
+    // The optional relation.
+    private final OptionalRelationDefinition<?, S> optionalRelation;
 
-  // The managed object path of the parent.
-  private final ManagedObjectPath<?, ?> path;
+    // The managed object path of the parent.
+    private final ManagedObjectPath<?, ?> path;
 
-
-
-  /**
-   * Create a new configuration delete listener adaptor for an
-   * instantiable relation.
-   *
-   * @param path
-   *          The managed object path of the parent.
-   * @param relation
-   *          The instantiable relation.
-   * @param listener
-   *          The underlying delete listener.
-   */
-  public ConfigDeleteListenerAdaptor(ManagedObjectPath<?, ?> path,
-      InstantiableRelationDefinition<?, S> relation,
-      ServerManagedObjectDeleteListener<S> listener) {
-    this.path = path;
-    this.optionalRelation = null;
-    this.instantiableRelation = relation;
-    this.setRelation = null;
-    this.listener = listener;
-    this.cachedManagedObject = null;
-  }
-
-
-
-  /**
-   * Create a new configuration delete listener adaptor for an
-   * optional relation.
-   *
-   * @param path
-   *          The managed object path of the parent.
-   * @param relation
-   *          The optional relation.
-   * @param listener
-   *          The underlying delete listener.
-   */
-  public ConfigDeleteListenerAdaptor(ManagedObjectPath<?, ?> path,
-      OptionalRelationDefinition<?, S> relation,
-      ServerManagedObjectDeleteListener<S> listener) {
-    this.path = path;
-    this.optionalRelation = relation;
-    this.instantiableRelation = null;
-    this.setRelation = null;
-    this.listener = listener;
-    this.cachedManagedObject = null;
-  }
-
-
-
-  /**
-   * Create a new configuration delete listener adaptor for an
-   * set relation.
-   *
-   * @param path
-   *          The managed object path of the parent.
-   * @param relation
-   *          The set relation.
-   * @param listener
-   *          The underlying delete listener.
-   */
-  public ConfigDeleteListenerAdaptor(ManagedObjectPath<?, ?> path,
-      SetRelationDefinition<?, S> relation,
-      ServerManagedObjectDeleteListener<S> listener) {
-    this.path = path;
-    this.optionalRelation = null;
-    this.instantiableRelation = null;
-    this.setRelation = relation;
-    this.listener = listener;
-    this.cachedManagedObject = null;
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  public ConfigChangeResult applyConfigurationDelete(ConfigEntry configEntry) {
-    if (optionalRelation != null) {
-      // Optional managed objects are located directly beneath the
-      // parent and have a well-defined name. We need to make sure
-      // that we are handling the correct entry.
-      ManagedObjectPath<?, ?> childPath = path.child(optionalRelation);
-      DN expectedDN = DNBuilder.create(childPath);
-      if (!configEntry.getDN().equals(expectedDN)) {
-        // Doesn't apply to us.
-        return new ConfigChangeResult(ResultCode.SUCCESS, false);
-      }
+    /**
+     * Create a new configuration delete listener adaptor for an instantiable
+     * relation.
+     *
+     * @param path
+     *            The managed object path of the parent.
+     * @param relation
+     *            The instantiable relation.
+     * @param listener
+     *            The underlying delete listener.
+     */
+    public ConfigDeleteListenerAdaptor(ManagedObjectPath<?, ?> path, InstantiableRelationDefinition<?, S> relation,
+            ServerManagedObjectDeleteListener<S> listener) {
+        this.path = path;
+        this.optionalRelation = null;
+        this.instantiableRelation = relation;
+        this.setRelation = null;
+        this.listener = listener;
+        this.cachedManagedObject = null;
     }
 
-    // Cached objects are guaranteed to be from previous acceptable
-    // callback.
-    ConfigChangeResult result = listener
-        .applyConfigurationDelete(cachedManagedObject);
+    /**
+     * Create a new configuration delete listener adaptor for an optional
+     * relation.
+     *
+     * @param path
+     *            The managed object path of the parent.
+     * @param relation
+     *            The optional relation.
+     * @param listener
+     *            The underlying delete listener.
+     */
+    public ConfigDeleteListenerAdaptor(ManagedObjectPath<?, ?> path, OptionalRelationDefinition<?, S> relation,
+            ServerManagedObjectDeleteListener<S> listener) {
+        this.path = path;
+        this.optionalRelation = relation;
+        this.instantiableRelation = null;
+        this.setRelation = null;
+        this.listener = listener;
+        this.cachedManagedObject = null;
+    }
 
-    // Now apply post constraint call-backs.
-    if (result.getResultCode() == ResultCode.SUCCESS) {
-      ManagedObjectDefinition<?, ?> d = cachedManagedObject
-          .getManagedObjectDefinition();
-      for (Constraint constraint : d.getAllConstraints()) {
-        for (ServerConstraintHandler handler : constraint
-            .getServerConstraintHandlers()) {
-          try {
-            handler.performPostDelete(cachedManagedObject);
-          } catch (ConfigException e) {
-            if (debugEnabled()) {
-              TRACER.debugCaught(DebugLogLevel.ERROR, e);
+    /**
+     * Create a new configuration delete listener adaptor for an set relation.
+     *
+     * @param path
+     *            The managed object path of the parent.
+     * @param relation
+     *            The set relation.
+     * @param listener
+     *            The underlying delete listener.
+     */
+    public ConfigDeleteListenerAdaptor(ManagedObjectPath<?, ?> path, SetRelationDefinition<?, S> relation,
+            ServerManagedObjectDeleteListener<S> listener) {
+        this.path = path;
+        this.optionalRelation = null;
+        this.instantiableRelation = null;
+        this.setRelation = relation;
+        this.listener = listener;
+        this.cachedManagedObject = null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public ConfigChangeResult applyConfigurationDelete(ConfigEntry configEntry) {
+        if (optionalRelation != null) {
+            // Optional managed objects are located directly beneath the
+            // parent and have a well-defined name. We need to make sure
+            // that we are handling the correct entry.
+            ManagedObjectPath<?, ?> childPath = path.child(optionalRelation);
+            DN expectedDN = DNBuilder.create(childPath);
+            if (!configEntry.getDN().equals(expectedDN)) {
+                // Doesn't apply to us.
+                return new ConfigChangeResult(ResultCode.SUCCESS, false);
             }
-          }
         }
-      }
+
+        // Cached objects are guaranteed to be from previous acceptable
+        // callback.
+        ConfigChangeResult result = listener.applyConfigurationDelete(cachedManagedObject);
+
+        // Now apply post constraint call-backs.
+        if (result.getResultCode() == ResultCode.SUCCESS) {
+            ManagedObjectDefinition<?, ?> d = cachedManagedObject.getManagedObjectDefinition();
+            for (Constraint constraint : d.getAllConstraints()) {
+                for (ServerConstraintHandler handler : constraint.getServerConstraintHandlers()) {
+                    try {
+                        handler.performPostDelete(cachedManagedObject);
+                    } catch (ConfigException e) {
+                        debugLogger.trace("Unable to perform post delete", e);
+                    }
+                }
+            }
+        }
+
+        return result;
     }
 
-    return result;
-  }
+    /**
+     * {@inheritDoc}
+     */
+    public boolean configDeleteIsAcceptable(ConfigEntry configEntry, LocalizableMessageBuilder unacceptableReason) {
+        DN dn = configEntry.getDN();
+        AttributeValue av = dn.rdn().getAttributeValue(0);
+        String name = av.getValue().toString().trim();
 
-
-
-  /**
-   * {@inheritDoc}
-   */
-  public boolean configDeleteIsAcceptable(ConfigEntry configEntry,
-      LocalizableMessageBuilder unacceptableReason) {
-    DN dn = configEntry.getDN();
-    AttributeValue av = dn.getRDN().getAttributeValue(0);
-    String name = av.getValue().toString().trim();
-
-    try {
-      ManagedObjectPath<?, ? extends S> childPath;
-      if (instantiableRelation != null) {
-        childPath = path.child(instantiableRelation, name);
-      } else if (setRelation != null) {
         try {
-          childPath = path.child(setRelation, name);
-        } catch (IllegalArgumentException e) {
-          throw new DefinitionDecodingException(setRelation
-              .getChildDefinition(), Reason.WRONG_TYPE_INFORMATION);
+            ManagedObjectPath<?, ? extends S> childPath;
+            if (instantiableRelation != null) {
+                childPath = path.child(instantiableRelation, name);
+            } else if (setRelation != null) {
+                try {
+                    childPath = path.child(setRelation, name);
+                } catch (IllegalArgumentException e) {
+                    throw new DefinitionDecodingException(setRelation.getChildDefinition(),
+                            Reason.WRONG_TYPE_INFORMATION);
+                }
+            } else {
+                // Optional managed objects are located directly beneath the
+                // parent and have a well-defined name. We need to make sure
+                // that we are handling the correct entry.
+                childPath = path.child(optionalRelation);
+                DN expectedDN = DNBuilder.create(childPath);
+                if (!dn.equals(expectedDN)) {
+                    // Doesn't apply to us.
+                    return true;
+                }
+            }
+
+            ServerManagementContext context = ServerManagementContext.getInstance();
+            cachedManagedObject = context.decode(childPath, configEntry);
+        } catch (DecodingException e) {
+            unacceptableReason.append(e.getMessageObject());
+            return false;
         }
-      } else {
-        // Optional managed objects are located directly beneath the
-        // parent and have a well-defined name. We need to make sure
-        // that we are handling the correct entry.
-        childPath = path.child(optionalRelation);
-        DN expectedDN = DNBuilder.create(childPath);
-        if (!dn.equals(expectedDN)) {
-          // Doesn't apply to us.
-          return true;
+
+        List<LocalizableMessage> reasons = new LinkedList<LocalizableMessage>();
+
+        // Enforce any constraints.
+        boolean isDeleteAllowed = true;
+        ManagedObjectDefinition<?, ?> d = cachedManagedObject.getManagedObjectDefinition();
+        for (Constraint constraint : d.getAllConstraints()) {
+            for (ServerConstraintHandler handler : constraint.getServerConstraintHandlers()) {
+                try {
+                    if (!handler.isDeleteAllowed(cachedManagedObject, reasons)) {
+                        isDeleteAllowed = false;
+                    }
+                } catch (ConfigException e) {
+                    LocalizableMessage message = ERR_SERVER_CONSTRAINT_EXCEPTION.get(e.getMessageObject());
+                    reasons.add(message);
+                    isDeleteAllowed = false;
+                }
+            }
         }
-      }
 
-      ServerManagementContext context = ServerManagementContext.getInstance();
-      cachedManagedObject = context.decode(childPath, configEntry);
-    } catch (DecodingException e) {
-      unacceptableReason.append(e.getMessageObject());
-      return false;
-    }
-
-    List<LocalizableMessage> reasons = new LinkedList<Message>();
-
-    // Enforce any constraints.
-    boolean isDeleteAllowed = true;
-    ManagedObjectDefinition<?, ?> d = cachedManagedObject
-        .getManagedObjectDefinition();
-    for (Constraint constraint : d.getAllConstraints()) {
-      for (ServerConstraintHandler handler : constraint
-          .getServerConstraintHandlers()) {
-        try {
-          if (!handler.isDeleteAllowed(cachedManagedObject, reasons)) {
-            isDeleteAllowed = false;
-          }
-        } catch (ConfigException e) {
-          LocalizableMessage message = ERR_SERVER_CONSTRAINT_EXCEPTION.get(e
-              .getMessageObject());
-          reasons.add(message);
-          isDeleteAllowed = false;
+        // Give up immediately if a constraint violation occurs.
+        if (!isDeleteAllowed) {
+            generateUnacceptableReason(reasons, unacceptableReason);
+            return false;
         }
-      }
+
+        // Let the delete listener decide.
+        if (listener.isConfigurationDeleteAcceptable(cachedManagedObject, reasons)) {
+            return true;
+        } else {
+            generateUnacceptableReason(reasons, unacceptableReason);
+            return false;
+        }
     }
 
-    // Give up immediately if a constraint violation occurs.
-    if (!isDeleteAllowed) {
-      generateUnacceptableReason(reasons, unacceptableReason);
-      return false;
+    /**
+     * Get the server managed object delete listener associated with this
+     * adaptor.
+     *
+     * @return Returns the server managed object delete listener associated with
+     *         this adaptor.
+     */
+    ServerManagedObjectDeleteListener<S> getServerManagedObjectDeleteListener() {
+        return listener;
     }
-
-    // Let the delete listener decide.
-    if (listener.isConfigurationDeleteAcceptable(cachedManagedObject,
-        reasons)) {
-      return true;
-    } else {
-      generateUnacceptableReason(reasons, unacceptableReason);
-      return false;
-    }
-  }
-
-
-
-  /**
-   * Get the server managed object delete listener associated with
-   * this adaptor.
-   *
-   * @return Returns the server managed object delete listener
-   *         associated with this adaptor.
-   */
-  ServerManagedObjectDeleteListener<S> getServerManagedObjectDeleteListener() {
-    return listener;
-  }
 }
diff --git a/opendj-admin/src/main/java/org/opends/server/admin/server/ConfigExceptionFactory.java b/opendj-admin/src/main/java/org/opends/server/admin/server/ConfigExceptionFactory.java
index 738f0b9..7695bd8 100644
--- a/opendj-admin/src/main/java/org/opends/server/admin/server/ConfigExceptionFactory.java
+++ b/opendj-admin/src/main/java/org/opends/server/admin/server/ConfigExceptionFactory.java
@@ -25,124 +25,104 @@
  *      Copyright 2008 Sun Microsystems, Inc.
  */
 package org.opends.server.admin.server;
+
 import org.forgerock.i18n.LocalizableMessage;
 
-
-
-import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString;
+import static com.forgerock.opendj.util.StaticUtils.*;
 
 import org.opends.server.admin.DefinitionDecodingException;
 import org.opends.server.config.ConfigException;
-import org.opends.messages.AdminMessages;
+import org.opends.server.util.DynamicConstants;
+
+import com.forgerock.opendj.ldap.AdminMessages;
+
 import org.forgerock.opendj.ldap.DN;
 
-
-
 /**
  * A utility class for converting admin exceptions to config exceptions.
  */
 final class ConfigExceptionFactory {
 
-  // The singleton instance.
-  private static final ConfigExceptionFactory INSTANCE =
-    new ConfigExceptionFactory();
+    // The singleton instance.
+    private static final ConfigExceptionFactory INSTANCE = new ConfigExceptionFactory();
 
+    // Prevent instantiation.
+    private ConfigExceptionFactory() {
+        // Do nothing.
+    }
 
+    /**
+     * Get the configuration exception factory instance.
+     *
+     * @return Returns the configuration exception factory instance.
+     */
+    public static ConfigExceptionFactory getInstance() {
+        return INSTANCE;
+    }
 
-  // Prevent instantiation.
-  private ConfigExceptionFactory() {
-    // Do nothing.
-  }
+    /**
+     * Create a configuration exception from a definition decoding exception.
+     *
+     * @param dn
+     *            The dn of the configuration entry that could not be decoded.
+     * @param e
+     *            The definition decoding exception
+     * @return Returns the configuration exception.
+     */
+    public ConfigException createDecodingExceptionAdaptor(DN dn, DefinitionDecodingException e) {
+        LocalizableMessage message = AdminMessages.ERR_ADMIN_MANAGED_OBJECT_DECODING_PROBLEM.get(String.valueOf(dn),
+                stackTraceToSingleLineString(e, DynamicConstants.DEBUG_BUILD));
+        return new ConfigException(message, e);
+    }
 
+    /**
+     * Create a configuration exception from a server managed object decoding
+     * exception.
+     *
+     * @param e
+     *            The server managed object decoding exception.
+     * @return Returns the configuration exception.
+     */
 
+    public ConfigException createDecodingExceptionAdaptor(ServerManagedObjectDecodingException e) {
+        DN dn = e.getPartialManagedObject().getDN();
+        LocalizableMessage message = AdminMessages.ERR_ADMIN_MANAGED_OBJECT_DECODING_PROBLEM.get(String.valueOf(dn),
+                stackTraceToSingleLineString(e, DynamicConstants.DEBUG_BUILD));
+        return new ConfigException(message, e);
+    }
 
-  /**
-   * Get the configuration exception factory instance.
-   *
-   * @return Returns the configuration exception factory instance.
-   */
-  public static ConfigExceptionFactory getInstance() {
-    return INSTANCE;
-  }
+    /**
+     * Create a configuration exception from a constraints violation decoding
+     * exception.
+     *
+     * @param e
+     *            The constraints violation decoding exception.
+     * @return Returns the configuration exception.
+     */
+    public ConfigException createDecodingExceptionAdaptor(ConstraintViolationException e) {
+        DN dn = e.getManagedObject().getDN();
+        LocalizableMessage message = AdminMessages.ERR_ADMIN_MANAGED_OBJECT_DECODING_PROBLEM.get(String.valueOf(dn),
+                stackTraceToSingleLineString(e, DynamicConstants.DEBUG_BUILD));
+        return new ConfigException(message, e);
+    }
 
+    /**
+     * Create an exception that describes a problem that occurred when
+     * attempting to load and instantiate a class.
+     *
+     * @param dn
+     *            The dn of the configuration entry was being processed.
+     * @param className
+     *            The name of the class that could not be loaded or
+     *            instantiated.
+     * @param e
+     *            The exception that occurred.
+     * @return Returns the configuration exception.
+     */
 
-
-  /**
-   * Create a configuration exception from a definition decoding exception.
-   *
-   * @param dn
-   *          The dn of the configuration entry that could not be decoded.
-   * @param e
-   *          The definition decoding exception
-   * @return Returns the configuration exception.
-   */
-  public ConfigException createDecodingExceptionAdaptor(DN dn,
-      DefinitionDecodingException e) {
-    LocalizableMessage message = AdminMessages.ERR_ADMIN_MANAGED_OBJECT_DECODING_PROBLEM.
-        get(String.valueOf(dn), stackTraceToSingleLineString(e));
-    return new ConfigException(message, e);
-  }
-
-
-
-  /**
-   * Create a configuration exception from a server managed object decoding
-   * exception.
-   *
-   * @param e
-   *          The server managed object decoding exception.
-   * @return Returns the configuration exception.
-   */
-
-  public ConfigException createDecodingExceptionAdaptor(
-      ServerManagedObjectDecodingException e) {
-    DN dn = e.getPartialManagedObject().getDN();
-    LocalizableMessage message =
-            AdminMessages.ERR_ADMIN_MANAGED_OBJECT_DECODING_PROBLEM.get(
-                    String.valueOf(dn),
-        stackTraceToSingleLineString(e));
-    return new ConfigException(message, e);
-  }
-
-
-
-  /**
-   * Create a configuration exception from a constraints violation
-   * decoding exception.
-   *
-   * @param e
-   *          The constraints violation decoding exception.
-   * @return Returns the configuration exception.
-   */
-  public ConfigException createDecodingExceptionAdaptor(
-      ConstraintViolationException e) {
-    DN dn = e.getManagedObject().getDN();
-    LocalizableMessage message = AdminMessages.ERR_ADMIN_MANAGED_OBJECT_DECODING_PROBLEM
-        .get(String.valueOf(dn), stackTraceToSingleLineString(e));
-    return new ConfigException(message, e);
-  }
-
-
-
-  /**
-   * Create an exception that describes a problem that occurred when
-   * attempting to load and instantiate a class.
-   *
-   * @param dn
-   *          The dn of the configuration entry was being processed.
-   * @param className
-   *          The name of the class that could not be loaded or
-   *          instantiated.
-   * @param e
-   *          The exception that occurred.
-   * @return Returns the configuration exception.
-   */
-
-  public ConfigException createClassLoadingExceptionAdaptor(DN dn,
-      String className, Exception e) {
-    LocalizableMessage message = AdminMessages.ERR_ADMIN_CANNOT_INSTANTIATE_CLASS.
-        get(String.valueOf(className), String.valueOf(dn),
-            stackTraceToSingleLineString(e));
-    return new ConfigException(message, e);
-  }
+    public ConfigException createClassLoadingExceptionAdaptor(DN dn, String className, Exception e) {
+        LocalizableMessage message = AdminMessages.ERR_ADMIN_CANNOT_INSTANTIATE_CLASS.get(String.valueOf(className),
+                String.valueOf(dn), stackTraceToSingleLineString(e, DynamicConstants.DEBUG_BUILD));
+        return new ConfigException(message, e);
+    }
 }
diff --git a/opendj-admin/src/main/java/org/opends/server/admin/server/ConfigurationChangeListener.java b/opendj-admin/src/main/java/org/opends/server/admin/server/ConfigurationChangeListener.java
index dd85724..833439a 100644
--- a/opendj-admin/src/main/java/org/opends/server/admin/server/ConfigurationChangeListener.java
+++ b/opendj-admin/src/main/java/org/opends/server/admin/server/ConfigurationChangeListener.java
@@ -25,53 +25,46 @@
  *      Copyright 2007-2008 Sun Microsystems, Inc.
  */
 package org.opends.server.admin.server;
+
 import org.forgerock.i18n.LocalizableMessage;
 
-
-
 import java.util.List;
 
 import org.opends.server.admin.Configuration;
 import org.opends.server.types.ConfigChangeResult;
 
-
-
 /**
- * This interface defines the methods that a Directory Server
- * configurable component should implement if it wishes to be able to
- * receive notifications when a its associated configuration is
- * changed.
+ * This interface defines the methods that a Directory Server configurable
+ * component should implement if it wishes to be able to receive notifications
+ * when a its associated configuration is changed.
  *
  * @param <T>
- *          The type of configuration that this listener should be
- *          notified about.
+ *            The type of configuration that this listener should be notified
+ *            about.
  */
 public interface ConfigurationChangeListener<T extends Configuration> {
 
-  /**
-   * Indicates whether the proposed change to the configuration is
-   * acceptable to this change listener.
-   *
-   * @param configuration
-   *          The new configuration containing the changes.
-   * @param unacceptableReasons
-   *          A list that can be used to hold messages about why the
-   *          provided configuration is not acceptable.
-   * @return Returns <code>true</code> if the proposed change is
-   *         acceptable, or <code>false</code> if it is not.
-   */
-  public boolean isConfigurationChangeAcceptable(T configuration,
-      List<LocalizableMessage> unacceptableReasons);
+    /**
+     * Indicates whether the proposed change to the configuration is acceptable
+     * to this change listener.
+     *
+     * @param configuration
+     *            The new configuration containing the changes.
+     * @param unacceptableReasons
+     *            A list that can be used to hold messages about why the
+     *            provided configuration is not acceptable.
+     * @return Returns <code>true</code> if the proposed change is acceptable,
+     *         or <code>false</code> if it is not.
+     */
+    public boolean isConfigurationChangeAcceptable(T configuration, List<LocalizableMessage> unacceptableReasons);
 
-
-
-  /**
-   * Applies the configuration changes to this change listener.
-   *
-   * @param configuration
-   *          The new configuration containing the changes.
-   * @return Returns information about the result of changing the
-   *         configuration.
-   */
-  public ConfigChangeResult applyConfigurationChange(T configuration);
+    /**
+     * Applies the configuration changes to this change listener.
+     *
+     * @param configuration
+     *            The new configuration containing the changes.
+     * @return Returns information about the result of changing the
+     *         configuration.
+     */
+    public ConfigChangeResult applyConfigurationChange(T configuration);
 }
diff --git a/opendj-admin/src/main/java/org/opends/server/admin/server/ConfigurationDeleteListener.java b/opendj-admin/src/main/java/org/opends/server/admin/server/ConfigurationDeleteListener.java
index 0bb2290..28e7939 100644
--- a/opendj-admin/src/main/java/org/opends/server/admin/server/ConfigurationDeleteListener.java
+++ b/opendj-admin/src/main/java/org/opends/server/admin/server/ConfigurationDeleteListener.java
@@ -25,52 +25,46 @@
  *      Copyright 2007-2008 Sun Microsystems, Inc.
  */
 package org.opends.server.admin.server;
+
 import org.forgerock.i18n.LocalizableMessage;
 
-
-
 import java.util.List;
 
 import org.opends.server.admin.Configuration;
 import org.opends.server.types.ConfigChangeResult;
 
-
-
 /**
- * This interface defines the methods that a Directory Server
- * configurable component should implement if it wishes to be able to
- * receive notifications when an existing configuration is deleted.
+ * This interface defines the methods that a Directory Server configurable
+ * component should implement if it wishes to be able to receive notifications
+ * when an existing configuration is deleted.
  *
  * @param <T>
- *          The type of configuration that this listener should be
- *          notified about.
+ *            The type of configuration that this listener should be notified
+ *            about.
  */
 public interface ConfigurationDeleteListener<T extends Configuration> {
 
-  /**
-   * Indicates whether the proposed deletion of an existing
-   * configuration is acceptable to this delete listener.
-   *
-   * @param configuration
-   *          The configuration that will be deleted.
-   * @param unacceptableReasons
-   *          A list that can be used to hold messages about why the
-   *          provided configuration is not acceptable.
-   * @return Returns <code>true</code> if the proposed deletion is
-   *         acceptable, or <code>false</code> if it is not.
-   */
-  public boolean isConfigurationDeleteAcceptable(T configuration,
-      List<LocalizableMessage> unacceptableReasons);
+    /**
+     * Indicates whether the proposed deletion of an existing configuration is
+     * acceptable to this delete listener.
+     *
+     * @param configuration
+     *            The configuration that will be deleted.
+     * @param unacceptableReasons
+     *            A list that can be used to hold messages about why the
+     *            provided configuration is not acceptable.
+     * @return Returns <code>true</code> if the proposed deletion is acceptable,
+     *         or <code>false</code> if it is not.
+     */
+    public boolean isConfigurationDeleteAcceptable(T configuration, List<LocalizableMessage> unacceptableReasons);
 
-
-
-  /**
-   * Deletes an existing configuration from this delete listener.
-   *
-   * @param configuration
-   *          The existing configuration that will be deleted.
-   * @return Returns information about the result of deleting the
-   *         configuration.
-   */
-  public ConfigChangeResult applyConfigurationDelete(T configuration);
+    /**
+     * Deletes an existing configuration from this delete listener.
+     *
+     * @param configuration
+     *            The existing configuration that will be deleted.
+     * @return Returns information about the result of deleting the
+     *         configuration.
+     */
+    public ConfigChangeResult applyConfigurationDelete(T configuration);
 }
diff --git a/opendj-admin/src/main/java/org/opends/server/admin/server/ConstraintViolationException.java b/opendj-admin/src/main/java/org/opends/server/admin/server/ConstraintViolationException.java
index 71a2081..e75ac65 100644
--- a/opendj-admin/src/main/java/org/opends/server/admin/server/ConstraintViolationException.java
+++ b/opendj-admin/src/main/java/org/opends/server/admin/server/ConstraintViolationException.java
@@ -24,12 +24,10 @@
  *
  *      Copyright 2008 Sun Microsystems, Inc.
  */
-
 package org.opends.server.admin.server;
 
-
-
 import static com.forgerock.opendj.ldap.AdminMessages.*;
+import static com.forgerock.opendj.util.Validator.*;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -38,142 +36,115 @@
 import org.forgerock.i18n.LocalizableMessage;
 import org.forgerock.i18n.LocalizableMessageBuilder;
 import org.opends.server.admin.DecodingException;
-import static com.forgerock.opendj.util.Validator.*;
-
-
 
 /**
- * This exception is thrown when the server refuses to use or delete a
- * managed object due to one or more constraints that cannot be
- * satisfied.
+ * This exception is thrown when the server refuses to use or delete a managed
+ * object due to one or more constraints that cannot be satisfied.
  */
 public class ConstraintViolationException extends DecodingException {
 
-  /**
-   * Serialization ID.
-   */
-  private static final long serialVersionUID = -4902443848460011875L;
+    /**
+     * Serialization ID.
+     */
+    private static final long serialVersionUID = -4902443848460011875L;
 
-  // The server managed object.
-  private final ServerManagedObject<?> managedObject;
+    // The server managed object.
+    private final ServerManagedObject<?> managedObject;
 
+    // Gets the default message.
+    private static LocalizableMessage getDefaultMessage(Collection<LocalizableMessage> messages) {
+        ensureNotNull(messages);
+        ensureTrue(!messages.isEmpty(), "messages should not be empty");
 
-
-  // Gets the default message.
-  private static LocalizableMessage getDefaultMessage(Collection<Message> messages) {
-    Validator.ensureNotNull(messages);
-    Validator.ensureTrue(!messages.isEmpty());
-
-    if (messages.size() == 1) {
-      return ERR_CONSTRAINT_VIOLATION_EXCEPTION_SINGLE.get(messages.iterator()
-          .next());
-    } else {
-      return ERR_CONSTRAINT_VIOLATION_EXCEPTION_PLURAL
-          .get(getSingleMessage(messages));
-    }
-  }
-
-
-
-  // Merge the messages into a single message.
-  private static LocalizableMessage getSingleMessage(Collection<Message> messages) {
-    if (messages.size() == 1) {
-      return messages.iterator().next();
-    } else {
-      LocalizableMessageBuilder builder = new MessageBuilder();
-
-      boolean isFirst = true;
-      for (LocalizableMessage m : messages) {
-        if (!isFirst) {
-          builder.append(";  ");
+        if (messages.size() == 1) {
+            return ERR_CONSTRAINT_VIOLATION_EXCEPTION_SINGLE.get(messages.iterator().next());
+        } else {
+            return ERR_CONSTRAINT_VIOLATION_EXCEPTION_PLURAL.get(getSingleMessage(messages));
         }
-        builder.append(m);
-        isFirst = false;
-      }
-
-      return builder.toMessage();
     }
-  }
 
-  // The messages describing the constraint violations that occurred.
-  private final Collection<LocalizableMessage> messages;
+    // Merge the messages into a single message.
+    private static LocalizableMessage getSingleMessage(Collection<LocalizableMessage> messages) {
+        if (messages.size() == 1) {
+            return messages.iterator().next();
+        } else {
+            LocalizableMessageBuilder builder = new LocalizableMessageBuilder();
 
+            boolean isFirst = true;
+            for (LocalizableMessage m : messages) {
+                if (!isFirst) {
+                    builder.append(";  ");
+                }
+                builder.append(m);
+                isFirst = false;
+            }
 
+            return builder.toMessage();
+        }
+    }
 
-  /**
-   * Creates a new constraint violation exception with the provided
-   * messages.
-   *
-   * @param managedObject
-   *          The server managed object which caused the constraint
-   *          violations.
-   * @param messages
-   *          The messages describing the constraint violations that
-   *          occurred (must be non-<code>null</code> and
-   *          non-empty).
-   */
-  public ConstraintViolationException(ServerManagedObject<?> managedObject,
-      Collection<LocalizableMessage> messages) {
-    super(getDefaultMessage(messages));
+    // The messages describing the constraint violations that occurred.
+    private final Collection<LocalizableMessage> messages;
 
-    this.managedObject = managedObject;
-    this.messages = new ArrayList<LocalizableMessage>(messages);
-  }
+    /**
+     * Creates a new constraint violation exception with the provided messages.
+     *
+     * @param managedObject
+     *            The server managed object which caused the constraint
+     *            violations.
+     * @param messages
+     *            The messages describing the constraint violations that
+     *            occurred (must be non-<code>null</code> and non-empty).
+     */
+    public ConstraintViolationException(ServerManagedObject<?> managedObject, Collection<LocalizableMessage> messages) {
+        super(getDefaultMessage(messages));
 
+        this.managedObject = managedObject;
+        this.messages = new ArrayList<LocalizableMessage>(messages);
+    }
 
+    /**
+     * Creates a new constraint violation exception with the provided message.
+     *
+     * @param managedObject
+     *            The server managed object which caused the constraint
+     *            violations.
+     * @param message
+     *            The message describing the constraint violation that occurred.
+     */
+    public ConstraintViolationException(ServerManagedObject<?> managedObject, LocalizableMessage message) {
+        this(managedObject, Collections.singleton(message));
+    }
 
-  /**
-   * Creates a new constraint violation exception with the provided
-   * message.
-   *
-   * @param managedObject
-   *          The server managed object which caused the constraint
-   *          violations.
-   * @param message
-   *          The message describing the constraint violation that
-   *          occurred.
-   */
-  public ConstraintViolationException(ServerManagedObject<?> managedObject,
-      LocalizableMessage message) {
-    this(managedObject, Collections.singleton(message));
-  }
+    /**
+     * Gets an unmodifiable collection view of the messages describing the
+     * constraint violations that occurred.
+     *
+     * @return Returns an unmodifiable collection view of the messages
+     *         describing the constraint violations that occurred.
+     */
+    public Collection<LocalizableMessage> getMessages() {
+        return Collections.unmodifiableCollection(messages);
+    }
 
+    /**
+     * Creates a single message listing all the messages combined into a single
+     * list separated by semi-colons.
+     *
+     * @return Returns a single message listing all the messages combined into a
+     *         single list separated by semi-colons.
+     */
+    public LocalizableMessage getMessagesAsSingleMessage() {
+        return getSingleMessage(messages);
+    }
 
-
-  /**
-   * Gets an unmodifiable collection view of the messages describing
-   * the constraint violations that occurred.
-   *
-   * @return Returns an unmodifiable collection view of the messages
-   *         describing the constraint violations that occurred.
-   */
-  public Collection<LocalizableMessage> getMessages() {
-    return Collections.unmodifiableCollection(messages);
-  }
-
-
-
-  /**
-   * Creates a single message listing all the messages combined into a
-   * single list separated by semi-colons.
-   *
-   * @return Returns a single message listing all the messages
-   *         combined into a single list separated by semi-colons.
-   */
-  public LocalizableMessage getMessagesAsSingleMessage() {
-    return getSingleMessage(messages);
-  }
-
-
-
-  /**
-   * Gets the server managed object which caused the constraint
-   * violations.
-   *
-   * @return Returns the server managed object which caused the
-   *         constraint violations.
-   */
-  public ServerManagedObject<?> getManagedObject() {
-    return managedObject;
-  }
+    /**
+     * Gets the server managed object which caused the constraint violations.
+     *
+     * @return Returns the server managed object which caused the constraint
+     *         violations.
+     */
+    public ServerManagedObject<?> getManagedObject() {
+        return managedObject;
+    }
 }
diff --git a/opendj-admin/src/main/java/org/opends/server/admin/server/DNBuilder.java b/opendj-admin/src/main/java/org/opends/server/admin/server/DNBuilder.java
index b3c25c6..f7c4448 100644
--- a/opendj-admin/src/main/java/org/opends/server/admin/server/DNBuilder.java
+++ b/opendj-admin/src/main/java/org/opends/server/admin/server/DNBuilder.java
@@ -27,64 +27,47 @@
 
 package org.opends.server.admin.server;
 
-
-
 import org.forgerock.opendj.ldap.DN;
 import org.opends.server.admin.LDAPProfile;
 import org.opends.server.admin.ManagedObjectPath;
 import org.opends.server.admin.RelationDefinition;
-import org.opends.server.types.DirectoryException;
-
-
 
 /**
- * A factory class for creating <code>DN</code>s from managed
- * object paths.
+ * A factory class for creating <code>DN</code>s from managed object paths.
  */
 final class DNBuilder {
 
-  /**
-   * Creates a new DN representing the specified managed object path.
-   *
-   * @param path
-   *          The managed object path.
-   * @return Returns a new DN representing the specified managed
-   *         object path.
-   */
-  public static DN create(ManagedObjectPath<?, ?> path) {
-    return path.toDN();
-  }
-
-
-
-  /**
-   * Creates a new DN representing the specified managed object path
-   * and relation.
-   *
-   * @param path
-   *          The managed object path.
-   * @param relation
-   *          The child relation.
-   * @return Returns a new DN representing the specified managed
-   *         object path and relation.
-   */
-  public static DN create(ManagedObjectPath<?, ?> path,
-      RelationDefinition<?, ?> relation) {
-    DN dn = path.toDN();
-
-    try {
-      LDAPProfile profile = LDAPProfile.getInstance();
-      DN localName = DN.decode(profile.getRelationRDNSequence(relation));
-      return dn.concat(localName);
-    } catch (DirectoryException e) {
-      throw new RuntimeException(e);
+    /**
+     * Creates a new DN representing the specified managed object path.
+     *
+     * @param path
+     *            The managed object path.
+     * @return Returns a new DN representing the specified managed object path.
+     */
+    public static DN create(ManagedObjectPath<?, ?> path) {
+        return path.toDN();
     }
-  }
 
+    /**
+     * Creates a new DN representing the specified managed object path and
+     * relation.
+     *
+     * @param path
+     *            The managed object path.
+     * @param relation
+     *            The child relation.
+     * @return Returns a new DN representing the specified managed object path
+     *         and relation.
+     */
+    public static DN create(ManagedObjectPath<?, ?> path, RelationDefinition<?, ?> relation) {
+        DN dn = path.toDN();
+        LDAPProfile profile = LDAPProfile.getInstance();
+        DN localName = DN.valueOf(profile.getRelationRDNSequence(relation));
+        return dn.child(localName);
+    }
 
-
-  // Prevent instantiation.
-  private DNBuilder() {
-    // No implementation required.
-  }
+    // Prevent instantiation.
+    private DNBuilder() {
+        // No implementation required.
+    }
 }
diff --git a/opendj-admin/src/main/java/org/opends/server/admin/server/DelayedConfigAddListener.java b/opendj-admin/src/main/java/org/opends/server/admin/server/DelayedConfigAddListener.java
index cf32ac4..a4fba01 100644
--- a/opendj-admin/src/main/java/org/opends/server/admin/server/DelayedConfigAddListener.java
+++ b/opendj-admin/src/main/java/org/opends/server/admin/server/DelayedConfigAddListener.java
@@ -26,166 +26,139 @@
  */
 package org.opends.server.admin.server;
 
-
-
-import static org.opends.server.loggers.debug.DebugLogger.*;
-import org.opends.server.loggers.debug.DebugTracer;
-
 import org.opends.server.api.ConfigAddListener;
 import org.opends.server.api.ConfigDeleteListener;
-import org.opends.server.config.ConfigEntry;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
 import org.opends.server.types.ConfigChangeResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.forgerock.opendj.ldap.DN;
-import org.opends.server.types.DebugLogLevel;
-import org.opends.server.types.ResultCode;
+import org.forgerock.opendj.ldap.ResultCode;
 import org.forgerock.i18n.LocalizableMessageBuilder;
 
-
 /**
- * A configuration add listener which will monitor a parent entry to
- * see when a specified child entry has been added. When the child
- * entry is added the add listener will automatically register its
- * "delayed" add or delete listener.
+ * A configuration add listener which will monitor a parent entry to see when a
+ * specified child entry has been added. When the child entry is added the add
+ * listener will automatically register its "delayed" add or delete listener.
  */
 final class DelayedConfigAddListener implements ConfigAddListener {
 
-  /**
-   * The tracer object for the debug logger.
-   */
-  private static final DebugTracer TRACER = getTracer();
+    private static final Logger debugLogger = LoggerFactory.getLogger(DelayedConfigAddListener.class);
 
-  // The name of the parent entry.
-  private final DN parent;
+    // The name of the parent entry.
+    private final DN parent;
 
-  // The name of the subordinate entry which should have an add or
-  // delete listener registered with it when it is created.
-  private final DN child;
+    // The name of the subordinate entry which should have an add or
+    // delete listener registered with it when it is created.
+    private final DN child;
 
-  // The add listener to be registered with the subordinate entry when
-  // it is added (or null if a delete listener should be registered).
-  private final ConfigAddListener delayedAddListener;
+    // The add listener to be registered with the subordinate entry when
+    // it is added (or null if a delete listener should be registered).
+    private final ConfigAddListener delayedAddListener;
 
-  // The delete listener to be registered with the subordinate entry
-  // when it is added (or null if an add listener should be
-  // registered).
-  private final ConfigDeleteListener delayedDeleteListener;
+    // The delete listener to be registered with the subordinate entry
+    // when it is added (or null if an add listener should be
+    // registered).
+    private final ConfigDeleteListener delayedDeleteListener;
 
-
-
-  /**
-   * Create a new delayed add listener which will register an add
-   * listener with the specified entry when it is added.
-   *
-   * @param child
-   *          The name of the subordinate entry which should have an
-   *          add listener registered with it when it is created.
-   * @param addListener
-   *          The add listener to be added to the subordinate entry
-   *          when it is added.
-   */
-  public DelayedConfigAddListener(DN child, ConfigAddListener addListener) {
-    this.parent = child.getParent();
-    this.child = child;
-    this.delayedAddListener = addListener;
-    this.delayedDeleteListener = null;
-  }
-
-
-
-  /**
-   * Create a new delayed add listener which will register a delete
-   * listener with the specified entry when it is added.
-   *
-   * @param child
-   *          The name of the subordinate entry which should have a
-   *          delete listener registered with it when it is created.
-   * @param deleteListener
-   *          The delete listener to be added to the subordinate entry
-   *          when it is added.
-   */
-  public DelayedConfigAddListener(DN child,
-      ConfigDeleteListener deleteListener) {
-    this.parent = child.getParent();
-    this.child = child;
-    this.delayedAddListener = null;
-    this.delayedDeleteListener = deleteListener;
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  public ConfigChangeResult applyConfigurationAdd(ConfigEntry configEntry) {
-    if (configEntry.getDN().equals(child)) {
-      // The subordinate entry matched our criteria so register the
-      // listener(s).
-      if (delayedAddListener != null) {
-        configEntry.registerAddListener(delayedAddListener);
-      }
-
-      if (delayedDeleteListener != null) {
-        configEntry.registerDeleteListener(delayedDeleteListener);
-      }
-
-      // We are no longer needed.
-      try {
-        ConfigEntry myEntry = DirectoryServer.getConfigEntry(parent);
-        if (myEntry != null) {
-          myEntry.deregisterAddListener(this);
-        }
-      } catch (ConfigException e) {
-        if (debugEnabled()) {
-          TRACER.debugCaught(DebugLogLevel.ERROR, e);
-        }
-
-        // Ignore this error as it implies that this listener has
-        // already been deregistered.
-      }
+    /**
+     * Create a new delayed add listener which will register an add listener
+     * with the specified entry when it is added.
+     *
+     * @param child
+     *            The name of the subordinate entry which should have an add
+     *            listener registered with it when it is created.
+     * @param addListener
+     *            The add listener to be added to the subordinate entry when it
+     *            is added.
+     */
+    public DelayedConfigAddListener(DN child, ConfigAddListener addListener) {
+        this.parent = child.parent();
+        this.child = child;
+        this.delayedAddListener = addListener;
+        this.delayedDeleteListener = null;
     }
 
-    return new ConfigChangeResult(ResultCode.SUCCESS, false);
-  }
+    /**
+     * Create a new delayed add listener which will register a delete listener
+     * with the specified entry when it is added.
+     *
+     * @param child
+     *            The name of the subordinate entry which should have a delete
+     *            listener registered with it when it is created.
+     * @param deleteListener
+     *            The delete listener to be added to the subordinate entry when
+     *            it is added.
+     */
+    public DelayedConfigAddListener(DN child, ConfigDeleteListener deleteListener) {
+        this.parent = child.parent();
+        this.child = child;
+        this.delayedAddListener = null;
+        this.delayedDeleteListener = deleteListener;
+    }
 
+    /**
+     * {@inheritDoc}
+     */
+    public ConfigChangeResult applyConfigurationAdd(ConfigEntry configEntry) {
+        if (configEntry.getDN().equals(child)) {
+            // The subordinate entry matched our criteria so register the
+            // listener(s).
+            if (delayedAddListener != null) {
+                configEntry.registerAddListener(delayedAddListener);
+            }
 
+            if (delayedDeleteListener != null) {
+                configEntry.registerDeleteListener(delayedDeleteListener);
+            }
 
-  /**
-   * {@inheritDoc}
-   */
-  public boolean configAddIsAcceptable(ConfigEntry configEntry,
-      LocalizableMessageBuilder unacceptableReason) {
-    // Always acceptable.
-    return true;
-  }
+            // We are no longer needed.
+            try {
+                ConfigEntry myEntry = DirectoryServer.getConfigEntry(parent);
+                if (myEntry != null) {
+                    myEntry.deregisterAddListener(this);
+                }
+            } catch (ConfigException e) {
+                debugLogger.trace("Unable to deregister add listener", e);
+                // Ignore this error as it implies that this listener has
+                // already been deregistered.
+            }
+        }
 
+        return new ConfigChangeResult(ResultCode.SUCCESS, false);
+    }
 
+    /**
+     * {@inheritDoc}
+     */
+    public boolean configAddIsAcceptable(ConfigEntry configEntry, LocalizableMessageBuilder unacceptableReason) {
+        // Always acceptable.
+        return true;
+    }
 
-  /**
-   * Gets the delayed add listener.
-   * <p>
-   * This method is provided for unit-testing.
-   *
-   * @return Returns the delayed add listener, or <code>null</code>
-   *         if this listener is delaying a delete listener.
-   */
-  ConfigAddListener getDelayedAddListener() {
-    return delayedAddListener;
-  }
+    /**
+     * Gets the delayed add listener.
+     * <p>
+     * This method is provided for unit-testing.
+     *
+     * @return Returns the delayed add listener, or <code>null</code> if this
+     *         listener is delaying a delete listener.
+     */
+    ConfigAddListener getDelayedAddListener() {
+        return delayedAddListener;
+    }
 
-
-
-  /**
-   * Gets the delayed delete listener.
-   * <p>
-   * This method is provided for unit-testing.
-   *
-   * @return Returns the delayed delete listener, or <code>null</code>
-   *         if this listener is delaying a add listener.
-   */
-  ConfigDeleteListener getDelayedDeleteListener() {
-    return delayedDeleteListener;
-  }
+    /**
+     * Gets the delayed delete listener.
+     * <p>
+     * This method is provided for unit-testing.
+     *
+     * @return Returns the delayed delete listener, or <code>null</code> if this
+     *         listener is delaying a add listener.
+     */
+    ConfigDeleteListener getDelayedDeleteListener() {
+        return delayedDeleteListener;
+    }
 
 }
diff --git a/opendj-admin/src/main/java/org/opends/server/admin/server/ServerConstraintHandler.java b/opendj-admin/src/main/java/org/opends/server/admin/server/ServerConstraintHandler.java
index e2c19e9..b0de720 100644
--- a/opendj-admin/src/main/java/org/opends/server/admin/server/ServerConstraintHandler.java
+++ b/opendj-admin/src/main/java/org/opends/server/admin/server/ServerConstraintHandler.java
@@ -26,168 +26,146 @@
  */
 package org.opends.server.admin.server;
 
-
-
 import java.util.Collection;
 
 import org.forgerock.i18n.LocalizableMessage;
 import org.opends.server.config.ConfigException;
 
-
-
 /**
  * An interface for performing server-side constraint validation.
  * <p>
- * Constraints are evaluated immediately before and after write
- * operations are performed. Server-side constraints are evaluated in
- * two phases: the first phase determines if the proposed add, delete,
- * or modification is acceptable according to the constraint. If one
- * or more constraints fails, the write write operation is refused,
- * and the client will receive an
- * <code>OperationRejectedException</code> exception. The second
- * phase is invoked once the add, delete, or modification request has
- * been allowed and any changes applied. The second phase gives the
- * constraint handler a chance to register listener call-backs if
- * required.
+ * Constraints are evaluated immediately before and after write operations are
+ * performed. Server-side constraints are evaluated in two phases: the first
+ * phase determines if the proposed add, delete, or modification is acceptable
+ * according to the constraint. If one or more constraints fails, the write
+ * write operation is refused, and the client will receive an
+ * <code>OperationRejectedException</code> exception. The second phase is
+ * invoked once the add, delete, or modification request has been allowed and
+ * any changes applied. The second phase gives the constraint handler a chance
+ * to register listener call-backs if required.
  * <p>
- * A server constraint handler must override at least one of the
- * provided methods.
+ * A server constraint handler must override at least one of the provided
+ * methods.
  *
  * @see org.opends.server.admin.Constraint
  */
 public abstract class ServerConstraintHandler {
 
-  /**
-   * Creates a new server constraint handler.
-   */
-  protected ServerConstraintHandler() {
-    // No implementation required.
-  }
+    /**
+     * Creates a new server constraint handler.
+     */
+    protected ServerConstraintHandler() {
+        // No implementation required.
+    }
 
+    /**
+     * Determines whether or not the existing managed object can be deleted from
+     * the server's configuration. For example, an implementation might enforce
+     * referential integrity by preventing referenced managed objects from being
+     * deleted.
+     * <p>
+     * If the constraint is not satisfied, the implementation must return
+     * <code>false</code> and add a message describing why the managed object
+     * cannot be deleted.
+     * <p>
+     * The default implementation is to return <code>true</code>.
+     *
+     * @param managedObject
+     *            The managed object which is about to be deleted.
+     * @param unacceptableReasons
+     *            A list of messages to which error messages should be added.
+     * @return Returns <code>true</code> if this constraint is satisfied, or
+     *         <code>false</code> if it is not and the managed object cannot be
+     *         deleted.
+     * @throws ConfigException
+     *             If an configuration exception prevented this constraint from
+     *             being evaluated.
+     */
+    public boolean isDeleteAllowed(ServerManagedObject<?> managedObject,
+            Collection<LocalizableMessage> unacceptableReasons) throws ConfigException {
+        return true;
+    }
 
+    /**
+     * Determines whether or not the provided managed object can be used by the
+     * server. This method is invoked each time a managed object is decoded by
+     * the administration framework: when an attempt is made to add a new
+     * configuration, modify an existing configuration, or during server
+     * initialization. If the constraint is not satisfied the managed object
+     * will be rejected.
+     * <p>
+     * If the constraint is not satisfied, the implementation must return
+     * <code>false</code> and add a message describing why the managed object is
+     * not usable.
+     * <p>
+     * The default implementation is to return <code>true</code>.
+     *
+     * @param managedObject
+     *            The new managed object.
+     * @param unacceptableReasons
+     *            A list of messages to which error messages should be added.
+     * @return Returns <code>true</code> if this constraint is satisfied, or
+     *         <code>false</code> if it is not and the managed object cannot be
+     *         used.
+     * @throws ConfigException
+     *             If an configuration exception prevented this constraint from
+     *             being evaluated.
+     */
+    public boolean isUsable(ServerManagedObject<?> managedObject, Collection<LocalizableMessage> unacceptableReasons)
+            throws ConfigException {
+        return true;
+    }
 
-  /**
-   * Determines whether or not the existing managed object can be
-   * deleted from the server's configuration. For example, an
-   * implementation might enforce referential integrity by preventing
-   * referenced managed objects from being deleted.
-   * <p>
-   * If the constraint is not satisfied, the implementation must
-   * return <code>false</code> and add a message describing why the
-   * managed object cannot be deleted.
-   * <p>
-   * The default implementation is to return <code>true</code>.
-   *
-   * @param managedObject
-   *          The managed object which is about to be deleted.
-   * @param unacceptableReasons
-   *          A list of messages to which error messages should be
-   *          added.
-   * @return Returns <code>true</code> if this constraint is
-   *         satisfied, or <code>false</code> if it is not and the
-   *         managed object cannot be deleted.
-   * @throws ConfigException
-   *           If an configuration exception prevented this constraint
-   *           from being evaluated.
-   */
-  public boolean isDeleteAllowed(ServerManagedObject<?> managedObject,
-      Collection<LocalizableMessage> unacceptableReasons) throws ConfigException {
-    return true;
-  }
+    /**
+     * Performs any post-add processing required by this constraint. This method
+     * is invoked after a new managed object has been accepted for use by the
+     * administration framework. This might occur during initialization or when
+     * a managed object is added at run-time.
+     * <p>
+     * The default implementation is to do nothing.
+     *
+     * @param managedObject
+     *            The managed object which has just been added to the server's
+     *            configuration.
+     * @throws ConfigException
+     *             If the post-add processing fails due to a configuration
+     *             exception.
+     */
+    public void performPostAdd(ServerManagedObject<?> managedObject) throws ConfigException {
+        // Do nothing.
+    }
 
+    /**
+     * Performs any post-delete processing required by this constraint. This
+     * method is invoked after a managed object has been accepted for deletion
+     * from the server's configuration.
+     * <p>
+     * The default implementation is to do nothing.
+     *
+     * @param managedObject
+     *            The managed object which was deleted.
+     * @throws ConfigException
+     *             If the post-delete processing fails due to a configuration
+     *             exception.
+     */
+    public void performPostDelete(ServerManagedObject<?> managedObject) throws ConfigException {
+        // Do nothing.
+    }
 
-
-  /**
-   * Determines whether or not the provided managed object can be used
-   * by the server. This method is invoked each time a managed object
-   * is decoded by the administration framework: when an attempt is
-   * made to add a new configuration, modify an existing
-   * configuration, or during server initialization. If the constraint
-   * is not satisfied the managed object will be rejected.
-   * <p>
-   * If the constraint is not satisfied, the implementation must
-   * return <code>false</code> and add a message describing why the
-   * managed object is not usable.
-   * <p>
-   * The default implementation is to return <code>true</code>.
-   *
-   * @param managedObject
-   *          The new managed object.
-   * @param unacceptableReasons
-   *          A list of messages to which error messages should be
-   *          added.
-   * @return Returns <code>true</code> if this constraint is
-   *         satisfied, or <code>false</code> if it is not and the
-   *         managed object cannot be used.
-   * @throws ConfigException
-   *           If an configuration exception prevented this constraint
-   *           from being evaluated.
-   */
-  public boolean isUsable(ServerManagedObject<?> managedObject,
-      Collection<LocalizableMessage> unacceptableReasons) throws ConfigException {
-    return true;
-  }
-
-
-
-  /**
-   * Performs any post-add processing required by this constraint.
-   * This method is invoked after a new managed object has been
-   * accepted for use by the administration framework. This might
-   * occur during initialization or when a managed object is added at
-   * run-time.
-   * <p>
-   * The default implementation is to do nothing.
-   *
-   * @param managedObject
-   *          The managed object which has just been added to the
-   *          server's configuration.
-   * @throws ConfigException
-   *           If the post-add processing fails due to a configuration
-   *           exception.
-   */
-  public void performPostAdd(ServerManagedObject<?> managedObject)
-      throws ConfigException {
-    // Do nothing.
-  }
-
-
-
-  /**
-   * Performs any post-delete processing required by this constraint.
-   * This method is invoked after a managed object has been accepted
-   * for deletion from the server's configuration.
-   * <p>
-   * The default implementation is to do nothing.
-   *
-   * @param managedObject
-   *          The managed object which was deleted.
-   * @throws ConfigException
-   *           If the post-delete processing fails due to a
-   *           configuration exception.
-   */
-  public void performPostDelete(ServerManagedObject<?> managedObject)
-      throws ConfigException {
-    // Do nothing.
-  }
-
-
-
-  /**
-   * Performs any post-modify processing required by this constraint.
-   * This method is invoked after changes to an existing managed
-   * object have been accepted.
-   * <p>
-   * The default implementation is to do nothing.
-   *
-   * @param managedObject
-   *          The managed object which was modified.
-   * @throws ConfigException
-   *           If the post-modify processing fails due to a
-   *           configuration exception.
-   */
-  public void performPostModify(ServerManagedObject<?> managedObject)
-      throws ConfigException {
-    // Do nothing.
-  }
+    /**
+     * Performs any post-modify processing required by this constraint. This
+     * method is invoked after changes to an existing managed object have been
+     * accepted.
+     * <p>
+     * The default implementation is to do nothing.
+     *
+     * @param managedObject
+     *            The managed object which was modified.
+     * @throws ConfigException
+     *             If the post-modify processing fails due to a configuration
+     *             exception.
+     */
+    public void performPostModify(ServerManagedObject<?> managedObject) throws ConfigException {
+        // Do nothing.
+    }
 }
diff --git a/opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagedObject.java b/opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagedObject.java
index 431ac69..e31fb2c 100644
--- a/opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagedObject.java
+++ b/opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagedObject.java
@@ -27,7 +27,8 @@
 
 package org.opends.server.admin.server;
 
-
+import static com.forgerock.opendj.ldap.AdminMessages.*;
+import static com.forgerock.opendj.util.StaticUtils.*;
 
 import java.util.Collections;
 import java.util.LinkedList;
@@ -36,6 +37,7 @@
 import java.util.Set;
 import java.util.SortedSet;
 
+import org.forgerock.i18n.LocalizableMessage;
 import org.forgerock.opendj.ldap.DN;
 import org.opends.server.admin.Configuration;
 import org.opends.server.admin.Constraint;
@@ -52,1641 +54,1359 @@
 import org.opends.server.api.ConfigChangeListener;
 import org.opends.server.api.ConfigDeleteListener;
 import org.opends.server.config.ConfigException;
-
-
+import org.opends.server.util.DynamicConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * A server-side managed object.
  *
  * @param <S>
- *          The type of server configuration represented by the server
- *          managed object.
+ *            The type of server configuration represented by the server managed
+ *            object.
  */
-public final class ServerManagedObject<S extends Configuration> implements
-    PropertyProvider {
+public final class ServerManagedObject<S extends Configuration> implements PropertyProvider {
 
-  /**
-   * The tracer object for the debug logger.
-   */
-  private static final DebugTracer TRACER = getTracer();
+    private static final Logger logger = LoggerFactory.getLogger(ServerManagedObject.class);
 
-  // The configuration entry associated with this server managed
-  // object (null if root).
-  private ConfigEntry configEntry;
+    // The configuration entry associated with this server managed
+    // object (null if root).
+    private ConfigEntry configEntry;
 
-  // The management context.
-  private final ServerManagementContext context = ServerManagementContext
-      .getInstance();
+    // The management context.
+    private final ServerManagementContext context = ServerManagementContext.getInstance();
 
-  // The managed object's definition.
-  private final ManagedObjectDefinition<?, S> definition;
+    // The managed object's definition.
+    private final ManagedObjectDefinition<?, S> definition;
 
-  // The managed object path identifying this managed object's
-  // location.
-  private final ManagedObjectPath<?, S> path;
+    // The managed object path identifying this managed object's
+    // location.
+    private final ManagedObjectPath<?, S> path;
 
-  // The managed object's properties.
-  private final Map<PropertyDefinition<?>, SortedSet<?>> properties;
+    // The managed object's properties.
+    private final Map<PropertyDefinition<?>, SortedSet<?>> properties;
 
-
-
-  /**
-   * Creates an new server side managed object.
-   *
-   * @param path
-   *          The managed object path.
-   * @param d
-   *          The managed object definition.
-   * @param properties
-   *          The managed object's properties.
-   * @param configEntry
-   *          The configuration entry associated with the managed
-   *          object.
-   */
-  ServerManagedObject(ManagedObjectPath<?, S> path,
-      ManagedObjectDefinition<?, S> d,
-      Map<PropertyDefinition<?>, SortedSet<?>> properties,
-      ConfigEntry configEntry) {
-    this.definition = d;
-    this.path = path;
-    this.properties = properties;
-    this.configEntry = configEntry;
-  }
-
-
-
-  /**
-   * Deregisters an existing configuration add listener.
-   *
-   * @param <M>
-   *          The type of the child server configuration object.
-   * @param d
-   *          The instantiable relation definition.
-   * @param listener
-   *          The configuration add listener.
-   * @throws IllegalArgumentException
-   *           If the instantiable relation definition is not
-   *           associated with this managed object's definition.
-   */
-  public <M extends Configuration> void deregisterAddListener(
-      InstantiableRelationDefinition<?, M> d,
-      ConfigurationAddListener<M> listener) throws IllegalArgumentException {
-    validateRelationDefinition(d);
-
-    DN baseDN = DNBuilder.create(path, d);
-    deregisterAddListener(baseDN, listener);
-  }
-
-
-
-  /**
-   * Deregisters an existing server managed object add listener.
-   *
-   * @param <M>
-   *          The type of the child server configuration object.
-   * @param d
-   *          The instantiable relation definition.
-   * @param listener
-   *          The server managed object add listener.
-   * @throws IllegalArgumentException
-   *           If the instantiable relation definition is not
-   *           associated with this managed object's definition.
-   */
-  public <M extends Configuration> void deregisterAddListener(
-      InstantiableRelationDefinition<?, M> d,
-      ServerManagedObjectAddListener<M> listener)
-      throws IllegalArgumentException {
-    validateRelationDefinition(d);
-
-    DN baseDN = DNBuilder.create(path, d);
-    deregisterAddListener(baseDN, listener);
-  }
-
-
-
-  /**
-   * Deregisters an existing configuration add listener.
-   *
-   * @param <M>
-   *          The type of the child server configuration object.
-   * @param d
-   *          The optional relation definition.
-   * @param listener
-   *          The configuration add listener.
-   * @throws IllegalArgumentException
-   *           If the optional relation definition is not associated
-   *           with this managed object's definition.
-   */
-  public <M extends Configuration> void deregisterAddListener(
-      OptionalRelationDefinition<?, M> d, ConfigurationAddListener<M> listener)
-      throws IllegalArgumentException {
-    validateRelationDefinition(d);
-
-    DN baseDN = DNBuilder.create(path, d).getParent();
-    deregisterAddListener(baseDN, listener);
-  }
-
-
-
-  /**
-   * Deregisters an existing server managed object add listener.
-   *
-   * @param <M>
-   *          The type of the child server configuration object.
-   * @param d
-   *          The optional relation definition.
-   * @param listener
-   *          The server managed object add listener.
-   * @throws IllegalArgumentException
-   *           If the optional relation definition is not associated
-   *           with this managed object's definition.
-   */
-  public <M extends Configuration> void deregisterAddListener(
-      OptionalRelationDefinition<?, M> d,
-      ServerManagedObjectAddListener<M> listener)
-      throws IllegalArgumentException {
-    validateRelationDefinition(d);
-
-    DN baseDN = DNBuilder.create(path, d).getParent();
-    deregisterAddListener(baseDN, listener);
-  }
-
-
-
-  /**
-   * Deregisters an existing configuration add listener.
-   *
-   * @param <M>
-   *          The type of the child server configuration object.
-   * @param d
-   *          The set relation definition.
-   * @param listener
-   *          The configuration add listener.
-   * @throws IllegalArgumentException
-   *           If the set relation definition is not
-   *           associated with this managed object's definition.
-   */
-  public <M extends Configuration> void deregisterAddListener(
-      SetRelationDefinition<?, M> d,
-      ConfigurationAddListener<M> listener) throws IllegalArgumentException {
-    validateRelationDefinition(d);
-
-    DN baseDN = DNBuilder.create(path, d);
-    deregisterAddListener(baseDN, listener);
-  }
-
-
-
-  /**
-   * Deregisters an existing server managed object add listener.
-   *
-   * @param <M>
-   *          The type of the child server configuration object.
-   * @param d
-   *          The set relation definition.
-   * @param listener
-   *          The server managed object add listener.
-   * @throws IllegalArgumentException
-   *           If the set relation definition is not
-   *           associated with this managed object's definition.
-   */
-  public <M extends Configuration> void deregisterAddListener(
-      SetRelationDefinition<?, M> d,
-      ServerManagedObjectAddListener<M> listener)
-      throws IllegalArgumentException {
-    validateRelationDefinition(d);
-
-    DN baseDN = DNBuilder.create(path, d);
-    deregisterAddListener(baseDN, listener);
-  }
-
-
-
-  /**
-   * Deregisters an existing configuration change listener.
-   *
-   * @param listener
-   *          The configuration change listener.
-   */
-  public void deregisterChangeListener(
-      ConfigurationChangeListener<? super S> listener) {
-    for (ConfigChangeListener l : configEntry.getChangeListeners()) {
-      if (l instanceof ConfigChangeListenerAdaptor) {
-        ConfigChangeListenerAdaptor<?> adaptor =
-          (ConfigChangeListenerAdaptor<?>) l;
-        ServerManagedObjectChangeListener<?> l2 = adaptor
-            .getServerManagedObjectChangeListener();
-        if (l2 instanceof ServerManagedObjectChangeListenerAdaptor<?>) {
-          ServerManagedObjectChangeListenerAdaptor<?> adaptor2 =
-            (ServerManagedObjectChangeListenerAdaptor<?>) l2;
-          if (adaptor2.getConfigurationChangeListener() == listener) {
-            adaptor.finalizeChangeListener();
-            configEntry.deregisterChangeListener(adaptor);
-          }
-        }
-      }
-    }
-  }
-
-
-
-  /**
-   * Deregisters an existing server managed object change listener.
-   *
-   * @param listener
-   *          The server managed object change listener.
-   */
-  public void deregisterChangeListener(
-      ServerManagedObjectChangeListener<? super S> listener) {
-    for (ConfigChangeListener l : configEntry.getChangeListeners()) {
-      if (l instanceof ConfigChangeListenerAdaptor) {
-        ConfigChangeListenerAdaptor<?> adaptor =
-          (ConfigChangeListenerAdaptor<?>) l;
-        if (adaptor.getServerManagedObjectChangeListener() == listener) {
-          adaptor.finalizeChangeListener();
-          configEntry.deregisterChangeListener(adaptor);
-        }
-      }
-    }
-  }
-
-
-
-  /**
-   * Deregisters an existing configuration delete listener.
-   *
-   * @param <M>
-   *          The type of the child server configuration object.
-   * @param d
-   *          The instantiable relation definition.
-   * @param listener
-   *          The configuration delete listener.
-   * @throws IllegalArgumentException
-   *           If the instantiable relation definition is not
-   *           associated with this managed object's definition.
-   */
-  public <M extends Configuration> void deregisterDeleteListener(
-      InstantiableRelationDefinition<?, M> d,
-      ConfigurationDeleteListener<M> listener) throws IllegalArgumentException {
-    validateRelationDefinition(d);
-
-    DN baseDN = DNBuilder.create(path, d);
-    deregisterDeleteListener(baseDN, listener);
-  }
-
-
-
-  /**
-   * Deregisters an existing server managed object delete listener.
-   *
-   * @param <M>
-   *          The type of the child server configuration object.
-   * @param d
-   *          The instantiable relation definition.
-   * @param listener
-   *          The server managed object delete listener.
-   * @throws IllegalArgumentException
-   *           If the instantiable relation definition is not
-   *           associated with this managed object's definition.
-   */
-  public <M extends Configuration> void deregisterDeleteListener(
-      InstantiableRelationDefinition<?, M> d,
-      ServerManagedObjectDeleteListener<M> listener)
-      throws IllegalArgumentException {
-    validateRelationDefinition(d);
-
-    DN baseDN = DNBuilder.create(path, d);
-    deregisterDeleteListener(baseDN, listener);
-  }
-
-
-
-  /**
-   * Deregisters an existing configuration delete listener.
-   *
-   * @param <M>
-   *          The type of the child server configuration object.
-   * @param d
-   *          The optional relation definition.
-   * @param listener
-   *          The configuration delete listener.
-   * @throws IllegalArgumentException
-   *           If the optional relation definition is not associated
-   *           with this managed object's definition.
-   */
-  public <M extends Configuration> void deregisterDeleteListener(
-      OptionalRelationDefinition<?, M> d,
-      ConfigurationDeleteListener<M> listener) throws IllegalArgumentException {
-    validateRelationDefinition(d);
-
-    DN baseDN = DNBuilder.create(path, d).getParent();
-    deregisterDeleteListener(baseDN, listener);
-  }
-
-
-
-  /**
-   * Deregisters an existing server managed object delete listener.
-   *
-   * @param <M>
-   *          The type of the child server configuration object.
-   * @param d
-   *          The optional relation definition.
-   * @param listener
-   *          The server managed object delete listener.
-   * @throws IllegalArgumentException
-   *           If the optional relation definition is not associated
-   *           with this managed object's definition.
-   */
-  public <M extends Configuration> void deregisterDeleteListener(
-      OptionalRelationDefinition<?, M> d,
-      ServerManagedObjectDeleteListener<M> listener)
-      throws IllegalArgumentException {
-    validateRelationDefinition(d);
-
-    DN baseDN = DNBuilder.create(path, d).getParent();
-    deregisterDeleteListener(baseDN, listener);
-  }
-
-
-
-  /**
-   * Deregisters an existing configuration delete listener.
-   *
-   * @param <M>
-   *          The type of the child server configuration object.
-   * @param d
-   *          The set relation definition.
-   * @param listener
-   *          The configuration delete listener.
-   * @throws IllegalArgumentException
-   *           If the set relation definition is not
-   *           associated with this managed object's definition.
-   */
-  public <M extends Configuration> void deregisterDeleteListener(
-      SetRelationDefinition<?, M> d,
-      ConfigurationDeleteListener<M> listener) throws IllegalArgumentException {
-    validateRelationDefinition(d);
-
-    DN baseDN = DNBuilder.create(path, d);
-    deregisterDeleteListener(baseDN, listener);
-  }
-
-
-
-  /**
-   * Deregisters an existing server managed object delete listener.
-   *
-   * @param <M>
-   *          The type of the child server configuration object.
-   * @param d
-   *          The set relation definition.
-   * @param listener
-   *          The server managed object delete listener.
-   * @throws IllegalArgumentException
-   *           If the set relation definition is not
-   *           associated with this managed object's definition.
-   */
-  public <M extends Configuration> void deregisterDeleteListener(
-      SetRelationDefinition<?, M> d,
-      ServerManagedObjectDeleteListener<M> listener)
-      throws IllegalArgumentException {
-    validateRelationDefinition(d);
-
-    DN baseDN = DNBuilder.create(path, d);
-    deregisterDeleteListener(baseDN, listener);
-  }
-
-
-
-  /**
-   * Retrieve an instantiable child managed object.
-   *
-   * @param <M>
-   *          The requested type of the child server managed object
-   *          configuration.
-   * @param d
-   *          The instantiable relation definition.
-   * @param name
-   *          The name of the child managed object.
-   * @return Returns the instantiable child managed object.
-   * @throws IllegalArgumentException
-   *           If the relation definition is not associated with this
-   *           managed object's definition.
-   * @throws ConfigException
-   *           If the child managed object could not be found or if it
-   *           could not be decoded.
-   */
-  public <M extends Configuration> ServerManagedObject<? extends M> getChild(
-      InstantiableRelationDefinition<?, M> d, String name)
-      throws IllegalArgumentException, ConfigException {
-    validateRelationDefinition(d);
-    return context.getManagedObject(path.child(d, name));
-  }
-
-
-
-  /**
-   * Retrieve an optional child managed object.
-   *
-   * @param <M>
-   *          The requested type of the child server managed object
-   *          configuration.
-   * @param d
-   *          The optional relation definition.
-   * @return Returns the optional child managed object.
-   * @throws IllegalArgumentException
-   *           If the optional relation definition is not associated
-   *           with this managed object's definition.
-   * @throws ConfigException
-   *           If the child managed object could not be found or if it
-   *           could not be decoded.
-   */
-  public <M extends Configuration> ServerManagedObject<? extends M> getChild(
-      OptionalRelationDefinition<?, M> d) throws IllegalArgumentException,
-      ConfigException {
-    validateRelationDefinition(d);
-    return context.getManagedObject(path.child(d));
-  }
-
-
-
-  /**
-   * Retrieve a set child managed object.
-   *
-   * @param <M>
-   *          The requested type of the child server managed object
-   *          configuration.
-   * @param d
-   *          The set relation definition.
-   * @param name
-   *          The name of the child managed object.
-   * @return Returns the set child managed object.
-   * @throws IllegalArgumentException
-   *           If the relation definition is not associated with this
-   *           managed object's definition or if {@code name} specifies
-   *           a managed object definition which is not a sub-type of
-   *           the relation's child definition.
-   * @throws ConfigException
-   *           If the child managed object could not be found or if it
-   *           could not be decoded.
-   */
-  public <M extends Configuration> ServerManagedObject<? extends M> getChild(
-      SetRelationDefinition<?, M> d, String name)
-      throws IllegalArgumentException, ConfigException
-  {
-    validateRelationDefinition(d);
-
-    return context.getManagedObject(path.child(d, name));
-  }
-
-
-
-  /**
-   * Retrieve a singleton child managed object.
-   *
-   * @param <M>
-   *          The requested type of the child server managed object
-   *          configuration.
-   * @param d
-   *          The singleton relation definition.
-   * @return Returns the singleton child managed object.
-   * @throws IllegalArgumentException
-   *           If the relation definition is not associated with this
-   *           managed object's definition.
-   * @throws ConfigException
-   *           If the child managed object could not be found or if it
-   *           could not be decoded.
-   */
-  public <M extends Configuration> ServerManagedObject<? extends M> getChild(
-      SingletonRelationDefinition<?, M> d) throws IllegalArgumentException,
-      ConfigException {
-    validateRelationDefinition(d);
-    return context.getManagedObject(path.child(d));
-  }
-
-
-
-  /**
-   * Creates a server configuration view of this managed object.
-   *
-   * @return Returns the server configuration view of this managed
-   *         object.
-   */
-  public S getConfiguration() {
-    return definition.createServerConfiguration(this);
-  }
-
-
-
-  /**
-   * Get the DN of the LDAP entry associated with this server managed
-   * object.
-   *
-   * @return Returns the DN of the LDAP entry associated with this
-   *         server managed object, or an null DN if this is the root
-   *         managed object.
-   */
-  public DN getDN() {
-    if (configEntry != null) {
-      return configEntry.getDN();
-    } else {
-      return DN.nullDN();
-    }
-  }
-
-
-
-  /**
-   * Get the definition associated with this server managed object.
-   *
-   * @return Returns the definition associated with this server
-   *         managed object.
-   */
-  public ManagedObjectDefinition<?, S> getManagedObjectDefinition() {
-    return definition;
-  }
-
-
-
-  /**
-   * Get the path of this server managed object.
-   *
-   * @return Returns the path of this server managed object.
-   */
-  public ManagedObjectPath<?, S> getManagedObjectPath() {
-    return path;
-  }
-
-
-
-  /**
-   * Get the effective value of the specified property. If the
-   * property is multi-valued then just the first value is returned.
-   * If the property does not have a value then its default value is
-   * returned if it has one, or <code>null</code> indicating that
-   * any default behavior is applicable.
-   *
-   * @param <T>
-   *          The type of the property to be retrieved.
-   * @param d
-   *          The property to be retrieved.
-   * @return Returns the property's effective value, or
-   *         <code>null</code> indicating that any default behavior
-   *         is applicable.
-   * @throws IllegalArgumentException
-   *           If the property definition is not associated with this
-   *           managed object's definition.
-   */
-  public <T> T getPropertyValue(PropertyDefinition<T> d)
-      throws IllegalArgumentException {
-    Set<T> values = getPropertyValues(d);
-    if (values.isEmpty()) {
-      return null;
-    } else {
-      return values.iterator().next();
-    }
-  }
-
-
-
-  /**
-   * Get the effective values of the specified property. If the
-   * property does not have any values then its default values are
-   * returned if it has any, or an empty set indicating that any
-   * default behavior is applicable.
-   *
-   * @param <T>
-   *          The type of the property to be retrieved.
-   * @param d
-   *          The property to be retrieved.
-   * @return Returns an unmodifiable set containing the property's
-   *         effective values. An empty set indicates that the
-   *         property has no default values defined and any default
-   *         behavior is applicable.
-   * @throws IllegalArgumentException
-   *           If the property definition is not associated with this
-   *           managed object's definition.
-   */
-  @SuppressWarnings("unchecked")
-  public <T> SortedSet<T> getPropertyValues(PropertyDefinition<T> d)
-      throws IllegalArgumentException {
-    if (!properties.containsKey(d)) {
-      throw new IllegalArgumentException("Unknown property " + d.getName());
-    }
-    return Collections.unmodifiableSortedSet((SortedSet<T>) properties.get(d));
-  }
-
-
-
-  /**
-   * Determines whether or not the optional managed object associated
-   * with the specified optional relations exists.
-   *
-   * @param d
-   *          The optional relation definition.
-   * @return Returns <code>true</code> if the optional managed
-   *         object exists, <code>false</code> otherwise.
-   * @throws IllegalArgumentException
-   *           If the optional relation definition is not associated
-   *           with this managed object's definition.
-   */
-  public boolean hasChild(OptionalRelationDefinition<?, ?> d)
-      throws IllegalArgumentException {
-    validateRelationDefinition(d);
-    return context.managedObjectExists(path.child(d));
-  }
-
-
-
-  /**
-   * Lists the child managed objects associated with the specified
-   * instantiable relation.
-   *
-   * @param d
-   *          The instantiable relation definition.
-   * @return Returns the names of the child managed objects.
-   * @throws IllegalArgumentException
-   *           If the relation definition is not associated with this
-   *           managed object's definition.
-   */
-  public String[] listChildren(InstantiableRelationDefinition<?, ?> d)
-      throws IllegalArgumentException {
-    validateRelationDefinition(d);
-    return context.listManagedObjects(path, d);
-  }
-
-
-
-  /**
-   * Lists the child managed objects associated with the specified
-   * set relation.
-   *
-   * @param d
-   *          The set relation definition.
-   * @return Returns the names of the child managed objects.
-   * @throws IllegalArgumentException
-   *           If the relation definition is not associated with this
-   *           managed object's definition.
-   */
-  public String[] listChildren(SetRelationDefinition<?, ?> d)
-      throws IllegalArgumentException {
-    validateRelationDefinition(d);
-    return context.listManagedObjects(path, d);
-  }
-
-
-
-  /**
-   * Register to be notified when new child configurations are added
-   * beneath an instantiable relation.
-   *
-   * @param <M>
-   *          The type of the child server configuration object.
-   * @param d
-   *          The instantiable relation definition.
-   * @param listener
-   *          The configuration add listener.
-   * @throws IllegalArgumentException
-   *           If the instantiable relation definition is not
-   *           associated with this managed object's definition.
-   * @throws ConfigException
-   *           If the configuration entry associated with the
-   *           instantiable relation could not be retrieved.
-   */
-  public <M extends Configuration> void registerAddListener(
-      InstantiableRelationDefinition<?, M> d,
-      ConfigurationAddListener<M> listener) throws IllegalArgumentException,
-      ConfigException {
-    registerAddListener(d, new ServerManagedObjectAddListenerAdaptor<M>(
-        listener));
-  }
-
-
-
-  /**
-   * Register to be notified when new child server managed object are
-   * added beneath an instantiable relation.
-   *
-   * @param <M>
-   *          The type of the child server configuration object.
-   * @param d
-   *          The instantiable relation definition.
-   * @param listener
-   *          The server managed object add listener.
-   * @throws IllegalArgumentException
-   *           If the instantiable relation definition is not
-   *           associated with this managed object's definition.
-   * @throws ConfigException
-   *           If the configuration entry associated with the
-   *           instantiable relation could not be retrieved.
-   */
-  public <M extends Configuration> void registerAddListener(
-      InstantiableRelationDefinition<?, M> d,
-      ServerManagedObjectAddListener<M> listener)
-      throws IllegalArgumentException, ConfigException {
-    validateRelationDefinition(d);
-    DN baseDN = DNBuilder.create(path, d);
-    ConfigAddListener adaptor = new ConfigAddListenerAdaptor<M>(path, d,
-        listener);
-    registerAddListener(baseDN, adaptor);
-  }
-
-
-
-  /**
-   * Register to be notified when a new child configurations is added
-   * beneath an optional relation.
-   *
-   * @param <M>
-   *          The type of the child server configuration object.
-   * @param d
-   *          The optional relation definition.
-   * @param listener
-   *          The configuration add listener.
-   * @throws IllegalArgumentException
-   *           If the optional relation definition is not associated
-   *           with this managed object's definition.
-   * @throws ConfigException
-   *           If the configuration entry associated with the optional
-   *           relation could not be retrieved.
-   */
-  public <M extends Configuration> void registerAddListener(
-      OptionalRelationDefinition<?, M> d, ConfigurationAddListener<M> listener)
-      throws IllegalArgumentException, ConfigException {
-    registerAddListener(d, new ServerManagedObjectAddListenerAdaptor<M>(
-        listener));
-  }
-
-
-
-  /**
-   * Register to be notified when a new child server managed object is
-   * added beneath an optional relation.
-   *
-   * @param <M>
-   *          The type of the child server configuration object.
-   * @param d
-   *          The optional relation definition.
-   * @param listener
-   *          The server managed object add listener.
-   * @throws IllegalArgumentException
-   *           If the optional relation definition is not associated
-   *           with this managed object's definition.
-   * @throws ConfigException
-   *           If the configuration entry associated with the optional
-   *           relation could not be retrieved.
-   */
-  public <M extends Configuration> void registerAddListener(
-      OptionalRelationDefinition<?, M> d,
-      ServerManagedObjectAddListener<M> listener)
-      throws IllegalArgumentException, ConfigException {
-    validateRelationDefinition(d);
-    DN baseDN = DNBuilder.create(path, d).getParent();
-    ConfigAddListener adaptor = new ConfigAddListenerAdaptor<M>(path, d,
-        listener);
-    registerAddListener(baseDN, adaptor);
-  }
-
-
-
-  /**
-   * Register to be notified when new child configurations are added
-   * beneath a set relation.
-   *
-   * @param <M>
-   *          The type of the child server configuration object.
-   * @param d
-   *          The set relation definition.
-   * @param listener
-   *          The configuration add listener.
-   * @throws IllegalArgumentException
-   *           If the set relation definition is not
-   *           associated with this managed object's definition.
-   * @throws ConfigException
-   *           If the configuration entry associated with the
-   *           set relation could not be retrieved.
-   */
-  public <M extends Configuration> void registerAddListener(
-      SetRelationDefinition<?, M> d,
-      ConfigurationAddListener<M> listener) throws IllegalArgumentException,
-      ConfigException {
-    registerAddListener(d, new ServerManagedObjectAddListenerAdaptor<M>(
-        listener));
-  }
-
-
-
-  /**
-   * Register to be notified when new child server managed object are
-   * added beneath a set relation.
-   *
-   * @param <M>
-   *          The type of the child server configuration object.
-   * @param d
-   *          The set relation definition.
-   * @param listener
-   *          The server managed object add listener.
-   * @throws IllegalArgumentException
-   *           If the set relation definition is not
-   *           associated with this managed object's definition.
-   * @throws ConfigException
-   *           If the configuration entry associated with the
-   *           set relation could not be retrieved.
-   */
-  public <M extends Configuration> void registerAddListener(
-      SetRelationDefinition<?, M> d,
-      ServerManagedObjectAddListener<M> listener)
-      throws IllegalArgumentException, ConfigException {
-    validateRelationDefinition(d);
-    DN baseDN = DNBuilder.create(path, d);
-    ConfigAddListener adaptor = new ConfigAddListenerAdaptor<M>(path, d,
-        listener);
-    registerAddListener(baseDN, adaptor);
-  }
-
-
-
-  /**
-   * Register to be notified when this server managed object is
-   * changed.
-   *
-   * @param listener
-   *          The configuration change listener.
-   */
-  public void registerChangeListener(
-      ConfigurationChangeListener<? super S> listener) {
-    registerChangeListener(new ServerManagedObjectChangeListenerAdaptor<S>(
-        listener));
-  }
-
-
-
-  /**
-   * Register to be notified when this server managed object is
-   * changed.
-   *
-   * @param listener
-   *          The server managed object change listener.
-   */
-  public void registerChangeListener(
-      ServerManagedObjectChangeListener<? super S> listener) {
-    ConfigChangeListener adaptor = new ConfigChangeListenerAdaptor<S>(path,
-        listener);
-    configEntry.registerChangeListener(adaptor);
-
-    // Change listener registration usually signifies that a managed
-    // object has been accepted and added to the server configuration
-    // during initialization post-add.
-
-    // FIXME: we should prevent multiple invocations in the case where
-    // multiple change listeners are registered for the same object.
-    for (Constraint constraint : definition.getAllConstraints()) {
-      for (ServerConstraintHandler handler : constraint
-          .getServerConstraintHandlers()) {
-        try {
-          handler.performPostAdd(this);
-        } catch (ConfigException e) {
-          if (debugEnabled()) {
-            TRACER.debugCaught(DebugLogLevel.ERROR, e);
-          }
-        }
-      }
-    }
-  }
-
-
-
-  /**
-   * Register to be notified when existing child configurations are
-   * deleted beneath an instantiable relation.
-   *
-   * @param <M>
-   *          The type of the child server configuration object.
-   * @param d
-   *          The instantiable relation definition.
-   * @param listener
-   *          The configuration delete listener.
-   * @throws IllegalArgumentException
-   *           If the instantiable relation definition is not
-   *           associated with this managed object's definition.
-   * @throws ConfigException
-   *           If the configuration entry associated with the
-   *           instantiable relation could not be retrieved.
-   */
-  public <M extends Configuration> void registerDeleteListener(
-      InstantiableRelationDefinition<?, M> d,
-      ConfigurationDeleteListener<M> listener) throws IllegalArgumentException,
-      ConfigException {
-    registerDeleteListener(d, new ServerManagedObjectDeleteListenerAdaptor<M>(
-        listener));
-  }
-
-
-
-  /**
-   * Register to be notified when existing child server managed
-   * objects are deleted beneath an instantiable relation.
-   *
-   * @param <M>
-   *          The type of the child server configuration object.
-   * @param d
-   *          The instantiable relation definition.
-   * @param listener
-   *          The server managed objects delete listener.
-   * @throws IllegalArgumentException
-   *           If the instantiable relation definition is not
-   *           associated with this managed object's definition.
-   * @throws ConfigException
-   *           If the configuration entry associated with the
-   *           instantiable relation could not be retrieved.
-   */
-  public <M extends Configuration> void registerDeleteListener(
-      InstantiableRelationDefinition<?, M> d,
-      ServerManagedObjectDeleteListener<M> listener)
-      throws IllegalArgumentException, ConfigException {
-    validateRelationDefinition(d);
-    DN baseDN = DNBuilder.create(path, d);
-    ConfigDeleteListener adaptor = new ConfigDeleteListenerAdaptor<M>(path, d,
-        listener);
-    registerDeleteListener(baseDN, adaptor);
-  }
-
-
-
-  /**
-   * Register to be notified when an existing child configuration is
-   * deleted beneath an optional relation.
-   *
-   * @param <M>
-   *          The type of the child server configuration object.
-   * @param d
-   *          The optional relation definition.
-   * @param listener
-   *          The configuration delete listener.
-   * @throws IllegalArgumentException
-   *           If the optional relation definition is not associated
-   *           with this managed object's definition.
-   * @throws ConfigException
-   *           If the configuration entry associated with the optional
-   *           relation could not be retrieved.
-   */
-  public <M extends Configuration> void registerDeleteListener(
-      OptionalRelationDefinition<?, M> d,
-      ConfigurationDeleteListener<M> listener) throws IllegalArgumentException,
-      ConfigException {
-    registerDeleteListener(d, new ServerManagedObjectDeleteListenerAdaptor<M>(
-        listener));
-  }
-
-
-
-  /**
-   * Register to be notified when an existing child server managed
-   * object is deleted beneath an optional relation.
-   *
-   * @param <M>
-   *          The type of the child server configuration object.
-   * @param d
-   *          The optional relation definition.
-   * @param listener
-   *          The server managed object delete listener.
-   * @throws IllegalArgumentException
-   *           If the optional relation definition is not associated
-   *           with this managed object's definition.
-   * @throws ConfigException
-   *           If the configuration entry associated with the optional
-   *           relation could not be retrieved.
-   */
-  public <M extends Configuration> void registerDeleteListener(
-      OptionalRelationDefinition<?, M> d,
-      ServerManagedObjectDeleteListener<M> listener)
-      throws IllegalArgumentException, ConfigException {
-    validateRelationDefinition(d);
-    DN baseDN = DNBuilder.create(path, d).getParent();
-    ConfigDeleteListener adaptor = new ConfigDeleteListenerAdaptor<M>(path, d,
-        listener);
-    registerDeleteListener(baseDN, adaptor);
-  }
-
-
-
-  /**
-   * Register to be notified when existing child configurations are
-   * deleted beneath a set relation.
-   *
-   * @param <M>
-   *          The type of the child server configuration object.
-   * @param d
-   *          The set relation definition.
-   * @param listener
-   *          The configuration delete listener.
-   * @throws IllegalArgumentException
-   *           If the set relation definition is not
-   *           associated with this managed object's definition.
-   * @throws ConfigException
-   *           If the configuration entry associated with the
-   *           set relation could not be retrieved.
-   */
-  public <M extends Configuration> void registerDeleteListener(
-      SetRelationDefinition<?, M> d,
-      ConfigurationDeleteListener<M> listener) throws IllegalArgumentException,
-      ConfigException {
-    registerDeleteListener(d, new ServerManagedObjectDeleteListenerAdaptor<M>(
-        listener));
-  }
-
-
-
-  /**
-   * Register to be notified when existing child server managed
-   * objects are deleted beneath a set relation.
-   *
-   * @param <M>
-   *          The type of the child server configuration object.
-   * @param d
-   *          The set relation definition.
-   * @param listener
-   *          The server managed objects delete listener.
-   * @throws IllegalArgumentException
-   *           If the set relation definition is not
-   *           associated with this managed object's definition.
-   * @throws ConfigException
-   *           If the configuration entry associated with the
-   *           set relation could not be retrieved.
-   */
-  public <M extends Configuration> void registerDeleteListener(
-      SetRelationDefinition<?, M> d,
-      ServerManagedObjectDeleteListener<M> listener)
-      throws IllegalArgumentException, ConfigException {
-    validateRelationDefinition(d);
-    DN baseDN = DNBuilder.create(path, d);
-    ConfigDeleteListener adaptor = new ConfigDeleteListenerAdaptor<M>(path, d,
-        listener);
-    registerDeleteListener(baseDN, adaptor);
-  }
-
-
-
-  /**
-   * {@inheritDoc}
-   */
-  @Override
-  public String toString() {
-    StringBuilder builder = new StringBuilder();
-
-    builder.append("{ TYPE=");
-    builder.append(definition.getName());
-    builder.append(", DN=\"");
-    builder.append(getDN());
-    builder.append('\"');
-    for (Map.Entry<PropertyDefinition<?>, SortedSet<?>> value : properties
-        .entrySet()) {
-      builder.append(", ");
-      builder.append(value.getKey().getName());
-      builder.append('=');
-      builder.append(value.getValue());
-    }
-    builder.append(" }");
-
-    return builder.toString();
-  }
-
-
-
-  /**
-   * Determines whether or not this managed object can be used by the
-   * server.
-   *
-   * @throws ConstraintViolationException
-   *           If one or more constraints determined that this managed
-   *           object cannot be used by the server.
-   */
-  void ensureIsUsable() throws ConstraintViolationException {
-    // Enforce any constraints.
-    boolean isUsable = true;
-    List<LocalizableMessage> reasons = new LinkedList<Message>();
-    for (Constraint constraint : definition.getAllConstraints()) {
-      for (ServerConstraintHandler handler : constraint
-          .getServerConstraintHandlers()) {
-        try {
-          if (!handler.isUsable(this, reasons)) {
-            isUsable = false;
-          }
-        } catch (ConfigException e) {
-          LocalizableMessage message = ERR_SERVER_CONSTRAINT_EXCEPTION.get(e
-              .getMessageObject());
-          reasons.add(message);
-          isUsable = false;
-        }
-      }
+    /**
+     * Creates an new server side managed object.
+     *
+     * @param path
+     *            The managed object path.
+     * @param d
+     *            The managed object definition.
+     * @param properties
+     *            The managed object's properties.
+     * @param configEntry
+     *            The configuration entry associated with the managed object.
+     */
+    ServerManagedObject(ManagedObjectPath<?, S> path, ManagedObjectDefinition<?, S> d,
+            Map<PropertyDefinition<?>, SortedSet<?>> properties, ConfigEntry configEntry) {
+        this.definition = d;
+        this.path = path;
+        this.properties = properties;
+        this.configEntry = configEntry;
     }
 
-    if (!isUsable) {
-      throw new ConstraintViolationException(this, reasons);
-    }
-  }
+    /**
+     * Deregisters an existing configuration add listener.
+     *
+     * @param <M>
+     *            The type of the child server configuration object.
+     * @param d
+     *            The instantiable relation definition.
+     * @param listener
+     *            The configuration add listener.
+     * @throws IllegalArgumentException
+     *             If the instantiable relation definition is not associated
+     *             with this managed object's definition.
+     */
+    public <M extends Configuration> void deregisterAddListener(InstantiableRelationDefinition<?, M> d,
+            ConfigurationAddListener<M> listener) throws IllegalArgumentException {
+        validateRelationDefinition(d);
 
-
-
-  /**
-   * Update the config entry associated with this server managed
-   * object. This is only intended to be used by change listener call
-   * backs in order to update the managed object with the correct
-   * config entry.
-   *
-   * @param configEntry
-   *          The configuration entry.
-   */
-  void setConfigEntry(ConfigEntry configEntry) {
-    this.configEntry = configEntry;
-  }
-
-
-
-  // Deregister an add listener.
-  private <M extends Configuration> void deregisterAddListener(DN baseDN,
-      ConfigurationAddListener<M> listener) {
-    try {
-      ConfigEntry configEntry = getListenerConfigEntry(baseDN);
-      if (configEntry != null) {
-        for (ConfigAddListener l : configEntry.getAddListeners()) {
-          if (l instanceof ConfigAddListenerAdaptor) {
-            ConfigAddListenerAdaptor<?> adaptor =
-              (ConfigAddListenerAdaptor<?>) l;
-            ServerManagedObjectAddListener<?> l2 = adaptor
-                .getServerManagedObjectAddListener();
-            if (l2 instanceof ServerManagedObjectAddListenerAdaptor<?>) {
-              ServerManagedObjectAddListenerAdaptor<?> adaptor2 =
-                (ServerManagedObjectAddListenerAdaptor<?>) l2;
-              if (adaptor2.getConfigurationAddListener() == listener) {
-                configEntry.deregisterAddListener(adaptor);
-              }
-            }
-          }
-        }
-      }
-      else
-      {
-        // The relation entry does not exist so check for and deregister
-        // delayed add listener.
-        deregisterDelayedAddListener(baseDN, listener);
-      }
-    } catch (ConfigException e) {
-      // Ignore the exception since this implies deregistration.
-      if (debugEnabled()) {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-    }
-  }
-
-
-
-  // Deregister an add listener.
-  private <M extends Configuration> void deregisterAddListener(DN baseDN,
-      ServerManagedObjectAddListener<M> listener) {
-    try {
-      ConfigEntry configEntry = getListenerConfigEntry(baseDN);
-      if (configEntry != null) {
-        for (ConfigAddListener l : configEntry.getAddListeners()) {
-          if (l instanceof ConfigAddListenerAdaptor) {
-            ConfigAddListenerAdaptor<?> adaptor =
-              (ConfigAddListenerAdaptor<?>) l;
-            if (adaptor.getServerManagedObjectAddListener() == listener) {
-              configEntry.deregisterAddListener(adaptor);
-            }
-          }
-        }
-      }
-      else
-      {
-        // The relation entry does not exist so check for and deregister
-        // delayed add listener.
-        deregisterDelayedAddListener(baseDN, listener);
-      }
-    } catch (ConfigException e) {
-      // Ignore the exception since this implies deregistration.
-      if (debugEnabled()) {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-    }
-  }
-
-
-
-  // Deregister a delete listener.
-  private <M extends Configuration> void deregisterDeleteListener(DN baseDN,
-      ConfigurationDeleteListener<M> listener) {
-    try {
-      ConfigEntry configEntry = getListenerConfigEntry(baseDN);
-      if (configEntry != null) {
-        for (ConfigDeleteListener l : configEntry.getDeleteListeners()) {
-          if (l instanceof ConfigDeleteListenerAdaptor) {
-            ConfigDeleteListenerAdaptor<?> adaptor =
-              (ConfigDeleteListenerAdaptor<?>) l;
-            ServerManagedObjectDeleteListener<?> l2 = adaptor
-                .getServerManagedObjectDeleteListener();
-            if (l2 instanceof ServerManagedObjectDeleteListenerAdaptor<?>) {
-              ServerManagedObjectDeleteListenerAdaptor<?> adaptor2 =
-                (ServerManagedObjectDeleteListenerAdaptor<?>) l2;
-              if (adaptor2.getConfigurationDeleteListener() == listener) {
-                configEntry.deregisterDeleteListener(adaptor);
-              }
-            }
-          }
-        }
-      }
-      else
-      {
-        // The relation entry does not exist so check for and deregister
-        // delayed add listener.
-        deregisterDelayedDeleteListener(baseDN, listener);
-      }
-    } catch (ConfigException e) {
-      // Ignore the exception since this implies deregistration.
-      if (debugEnabled()) {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-    }
-  }
-
-
-
-  // Deregister a delete listener.
-  private <M extends Configuration> void deregisterDeleteListener(DN baseDN,
-      ServerManagedObjectDeleteListener<M> listener) {
-    try {
-      ConfigEntry configEntry = getListenerConfigEntry(baseDN);
-      if (configEntry != null) {
-        for (ConfigDeleteListener l : configEntry.getDeleteListeners()) {
-          if (l instanceof ConfigDeleteListenerAdaptor) {
-            ConfigDeleteListenerAdaptor<?> adaptor =
-              (ConfigDeleteListenerAdaptor<?>) l;
-            if (adaptor.getServerManagedObjectDeleteListener() == listener) {
-              configEntry.deregisterDeleteListener(adaptor);
-            }
-          }
-        }
-      }
-      else
-      {
-        // The relation entry does not exist so check for and deregister
-        // delayed add listener.
-        deregisterDelayedDeleteListener(baseDN, listener);
-      }
-    } catch (ConfigException e) {
-      // Ignore the exception since this implies deregistration.
-      if (debugEnabled()) {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-    }
-  }
-
-
-
-  // Gets a config entry required for a listener and throws a config
-  // exception on failure or returns null if the entry does not exist.
-  private ConfigEntry getListenerConfigEntry(DN dn) throws ConfigException {
-    // Attempt to retrieve the listener base entry.
-    ConfigEntry configEntry;
-    try {
-      configEntry = DirectoryServer.getConfigEntry(dn);
-    } catch (ConfigException e) {
-      if (debugEnabled()) {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      LocalizableMessage message = ERR_ADMIN_CANNOT_GET_LISTENER_BASE.get(
-          String.valueOf(dn), stackTraceToSingleLineString(e));
-      throw new ConfigException(message, e);
+        DN baseDN = DNBuilder.create(path, d);
+        deregisterAddListener(baseDN, listener);
     }
 
-    return configEntry;
-  }
+    /**
+     * Deregisters an existing server managed object add listener.
+     *
+     * @param <M>
+     *            The type of the child server configuration object.
+     * @param d
+     *            The instantiable relation definition.
+     * @param listener
+     *            The server managed object add listener.
+     * @throws IllegalArgumentException
+     *             If the instantiable relation definition is not associated
+     *             with this managed object's definition.
+     */
+    public <M extends Configuration> void deregisterAddListener(InstantiableRelationDefinition<?, M> d,
+            ServerManagedObjectAddListener<M> listener) throws IllegalArgumentException {
+        validateRelationDefinition(d);
 
-
-
-  // Register an instantiable or optional relation add listener.
-  private void registerAddListener(DN baseDN, ConfigAddListener adaptor)
-      throws IllegalArgumentException, ConfigException {
-    ConfigEntry relationEntry = getListenerConfigEntry(baseDN);
-
-    if (relationEntry != null) {
-      relationEntry.registerAddListener(adaptor);
-    } else {
-      // The relation entry does not exist yet so register a delayed
-      // add listener.
-      ConfigAddListener delayedListener = new DelayedConfigAddListener(baseDN,
-          adaptor);
-      registerDelayedListener(baseDN, delayedListener);
-    }
-  }
-
-
-
-  // Register a delayed listener with the nearest existing parent
-  // entry to the provided base DN.
-  private void registerDelayedListener(DN baseDN,
-      ConfigAddListener delayedListener) throws ConfigException {
-    DN parentDN = baseDN.getParent();
-    while (parentDN != null) {
-      ConfigEntry relationEntry = getListenerConfigEntry(parentDN);
-      if (relationEntry == null) {
-        delayedListener = new DelayedConfigAddListener(parentDN,
-            delayedListener);
-        parentDN = parentDN.getParent();
-      } else {
-        relationEntry.registerAddListener(delayedListener);
-        return;
-      }
+        DN baseDN = DNBuilder.create(path, d);
+        deregisterAddListener(baseDN, listener);
     }
 
-    // No parent entry could be found.
-    LocalizableMessage message = ERR_ADMIN_UNABLE_TO_REGISTER_LISTENER
-        .get(String.valueOf(baseDN));
-    throw new ConfigException(message);
-  }
+    /**
+     * Deregisters an existing configuration add listener.
+     *
+     * @param <M>
+     *            The type of the child server configuration object.
+     * @param d
+     *            The optional relation definition.
+     * @param listener
+     *            The configuration add listener.
+     * @throws IllegalArgumentException
+     *             If the optional relation definition is not associated with
+     *             this managed object's definition.
+     */
+    public <M extends Configuration> void deregisterAddListener(OptionalRelationDefinition<?, M> d,
+            ConfigurationAddListener<M> listener) throws IllegalArgumentException {
+        validateRelationDefinition(d);
 
-  // Deregister a delayed listener with the nearest existing parent
-  // entry to the provided base DN.
-  private <M extends Configuration> void deregisterDelayedAddListener(DN baseDN,
-      ConfigurationAddListener<M> listener) throws ConfigException {
-    DN parentDN = baseDN.getParent();
-    int delayWrappers = 0;
-    while (parentDN != null) {
-      ConfigEntry relationEntry = getListenerConfigEntry(parentDN);
-      if (relationEntry == null) {
-        parentDN = parentDN.getParent();
-        delayWrappers++;
-      } else {
-        for (ConfigAddListener l : relationEntry.getAddListeners()) {
-          if(l instanceof DelayedConfigAddListener)
-          {
-            DelayedConfigAddListener delayListener =
-                (DelayedConfigAddListener) l;
-            ConfigAddListener wrappedListener;
+        DN baseDN = DNBuilder.create(path, d).parent();
+        deregisterAddListener(baseDN, listener);
+    }
 
-            int i = delayWrappers;
-            for(; i > 0; i--)
-            {
-              wrappedListener = delayListener.getDelayedAddListener();
-              if(wrappedListener != null &&
-                  wrappedListener instanceof DelayedConfigAddListener)
-              {
-                delayListener = (DelayedConfigAddListener) l;
-              }
-              else
-              {
-                break;
-              }
-            }
+    /**
+     * Deregisters an existing server managed object add listener.
+     *
+     * @param <M>
+     *            The type of the child server configuration object.
+     * @param d
+     *            The optional relation definition.
+     * @param listener
+     *            The server managed object add listener.
+     * @throws IllegalArgumentException
+     *             If the optional relation definition is not associated with
+     *             this managed object's definition.
+     */
+    public <M extends Configuration> void deregisterAddListener(OptionalRelationDefinition<?, M> d,
+            ServerManagedObjectAddListener<M> listener) throws IllegalArgumentException {
+        validateRelationDefinition(d);
 
-            if(i > 0)
-            {
-              // There are not enough level of wrapping so this can't be
-              // the listener we are looking for.
-              continue;
-            }
+        DN baseDN = DNBuilder.create(path, d).parent();
+        deregisterAddListener(baseDN, listener);
+    }
 
-            ConfigAddListener delayedListener =
-                delayListener.getDelayedAddListener();
+    /**
+     * Deregisters an existing configuration add listener.
+     *
+     * @param <M>
+     *            The type of the child server configuration object.
+     * @param d
+     *            The set relation definition.
+     * @param listener
+     *            The configuration add listener.
+     * @throws IllegalArgumentException
+     *             If the set relation definition is not associated with this
+     *             managed object's definition.
+     */
+    public <M extends Configuration> void deregisterAddListener(SetRelationDefinition<?, M> d,
+            ConfigurationAddListener<M> listener) throws IllegalArgumentException {
+        validateRelationDefinition(d);
 
-            if (delayedListener != null &&
-                 delayedListener instanceof ConfigAddListenerAdaptor) {
-              ConfigAddListenerAdaptor<?> adaptor =
-                  (ConfigAddListenerAdaptor<?>) delayedListener;
-              ServerManagedObjectAddListener<?> l2 = adaptor
-                  .getServerManagedObjectAddListener();
-              if (l2 instanceof ServerManagedObjectAddListenerAdaptor<?>) {
-                ServerManagedObjectAddListenerAdaptor<?> adaptor2 =
-                    (ServerManagedObjectAddListenerAdaptor<?>) l2;
-                if (adaptor2.getConfigurationAddListener() == listener) {
-                  relationEntry.deregisterAddListener(l);
+        DN baseDN = DNBuilder.create(path, d);
+        deregisterAddListener(baseDN, listener);
+    }
+
+    /**
+     * Deregisters an existing server managed object add listener.
+     *
+     * @param <M>
+     *            The type of the child server configuration object.
+     * @param d
+     *            The set relation definition.
+     * @param listener
+     *            The server managed object add listener.
+     * @throws IllegalArgumentException
+     *             If the set relation definition is not associated with this
+     *             managed object's definition.
+     */
+    public <M extends Configuration> void deregisterAddListener(SetRelationDefinition<?, M> d,
+            ServerManagedObjectAddListener<M> listener) throws IllegalArgumentException {
+        validateRelationDefinition(d);
+
+        DN baseDN = DNBuilder.create(path, d);
+        deregisterAddListener(baseDN, listener);
+    }
+
+    /**
+     * Deregisters an existing configuration change listener.
+     *
+     * @param listener
+     *            The configuration change listener.
+     */
+    public void deregisterChangeListener(ConfigurationChangeListener<? super S> listener) {
+        for (ConfigChangeListener l : configEntry.getChangeListeners()) {
+            if (l instanceof ConfigChangeListenerAdaptor) {
+                ConfigChangeListenerAdaptor<?> adaptor = (ConfigChangeListenerAdaptor<?>) l;
+                ServerManagedObjectChangeListener<?> l2 = adaptor.getServerManagedObjectChangeListener();
+                if (l2 instanceof ServerManagedObjectChangeListenerAdaptor<?>) {
+                    ServerManagedObjectChangeListenerAdaptor<?> adaptor2 =
+                            (ServerManagedObjectChangeListenerAdaptor<?>) l2;
+                    if (adaptor2.getConfigurationChangeListener() == listener) {
+                        adaptor.finalizeChangeListener();
+                        configEntry.deregisterChangeListener(adaptor);
+                    }
                 }
-              }
             }
-          }
         }
-        return;
-      }
     }
-  }
 
-
-  // Deregister a delayed listener with the nearest existing parent
-  // entry to the provided base DN.
-  private <M extends Configuration> void deregisterDelayedDeleteListener(
-      DN baseDN, ConfigurationDeleteListener<M> listener)
-      throws ConfigException {
-    DN parentDN = baseDN.getParent();
-    int delayWrappers = 0;
-    while (parentDN != null) {
-      ConfigEntry relationEntry = getListenerConfigEntry(parentDN);
-      if (relationEntry == null) {
-        parentDN = parentDN.getParent();
-        delayWrappers++;
-      } else {
-        for (ConfigAddListener l : relationEntry.getAddListeners()) {
-          if(l instanceof DelayedConfigAddListener)
-          {
-            DelayedConfigAddListener delayListener =
-                (DelayedConfigAddListener) l;
-            ConfigAddListener wrappedListener;
-
-            int i = delayWrappers;
-            for(; i > 0; i--)
-            {
-              wrappedListener = delayListener.getDelayedAddListener();
-              if(wrappedListener != null &&
-                  wrappedListener instanceof DelayedConfigAddListener)
-              {
-                delayListener = (DelayedConfigAddListener) l;
-              }
-              else
-              {
-                break;
-              }
-            }
-
-            if(i > 0)
-            {
-              // There are not enough level of wrapping so this can't be
-              // the listener we are looking for.
-              continue;
-            }
-
-            ConfigDeleteListener delayedListener =
-                delayListener.getDelayedDeleteListener();
-
-            if (delayedListener != null &&
-                delayedListener instanceof ConfigDeleteListenerAdaptor) {
-              ConfigDeleteListenerAdaptor<?> adaptor =
-                  (ConfigDeleteListenerAdaptor<?>) delayedListener;
-              ServerManagedObjectDeleteListener<?> l2 = adaptor
-                  .getServerManagedObjectDeleteListener();
-              if (l2 instanceof ServerManagedObjectDeleteListenerAdaptor<?>) {
-                ServerManagedObjectDeleteListenerAdaptor<?> adaptor2 =
-                    (ServerManagedObjectDeleteListenerAdaptor<?>) l2;
-                if (adaptor2.getConfigurationDeleteListener() == listener) {
-                  relationEntry.deregisterAddListener(l);
+    /**
+     * Deregisters an existing server managed object change listener.
+     *
+     * @param listener
+     *            The server managed object change listener.
+     */
+    public void deregisterChangeListener(ServerManagedObjectChangeListener<? super S> listener) {
+        for (ConfigChangeListener l : configEntry.getChangeListeners()) {
+            if (l instanceof ConfigChangeListenerAdaptor) {
+                ConfigChangeListenerAdaptor<?> adaptor = (ConfigChangeListenerAdaptor<?>) l;
+                if (adaptor.getServerManagedObjectChangeListener() == listener) {
+                    adaptor.finalizeChangeListener();
+                    configEntry.deregisterChangeListener(adaptor);
                 }
-              }
             }
-          }
         }
-        return;
-      }
     }
-  }
 
-  // Deregister a delayed listener with the nearest existing parent
-  // entry to the provided base DN.
-  private <M extends Configuration> void deregisterDelayedAddListener(DN baseDN,
-      ServerManagedObjectAddListener<M> listener) throws ConfigException {
-    DN parentDN = baseDN.getParent();
-    int delayWrappers = 0;
-    while (parentDN != null) {
-      ConfigEntry relationEntry = getListenerConfigEntry(parentDN);
-      if (relationEntry == null) {
-        parentDN = parentDN.getParent();
-        delayWrappers++;
-      } else {
-        for (ConfigAddListener l : relationEntry.getAddListeners()) {
-          if(l instanceof DelayedConfigAddListener)
-          {
-            DelayedConfigAddListener delayListener =
-                (DelayedConfigAddListener) l;
-            ConfigAddListener wrappedListener;
+    /**
+     * Deregisters an existing configuration delete listener.
+     *
+     * @param <M>
+     *            The type of the child server configuration object.
+     * @param d
+     *            The instantiable relation definition.
+     * @param listener
+     *            The configuration delete listener.
+     * @throws IllegalArgumentException
+     *             If the instantiable relation definition is not associated
+     *             with this managed object's definition.
+     */
+    public <M extends Configuration> void deregisterDeleteListener(InstantiableRelationDefinition<?, M> d,
+            ConfigurationDeleteListener<M> listener) throws IllegalArgumentException {
+        validateRelationDefinition(d);
 
-            int i = delayWrappers;
-            for(; i > 0; i--)
-            {
-              wrappedListener = delayListener.getDelayedAddListener();
-              if(wrappedListener != null &&
-                  wrappedListener instanceof DelayedConfigAddListener)
-              {
-                delayListener = (DelayedConfigAddListener) l;
-              }
-              else
-              {
-                break;
-              }
-            }
+        DN baseDN = DNBuilder.create(path, d);
+        deregisterDeleteListener(baseDN, listener);
+    }
 
-            if(i > 0)
-            {
-              // There are not enough level of wrapping so this can't be
-              // the listener we are looking for.
-              continue;
-            }
+    /**
+     * Deregisters an existing server managed object delete listener.
+     *
+     * @param <M>
+     *            The type of the child server configuration object.
+     * @param d
+     *            The instantiable relation definition.
+     * @param listener
+     *            The server managed object delete listener.
+     * @throws IllegalArgumentException
+     *             If the instantiable relation definition is not associated
+     *             with this managed object's definition.
+     */
+    public <M extends Configuration> void deregisterDeleteListener(InstantiableRelationDefinition<?, M> d,
+            ServerManagedObjectDeleteListener<M> listener) throws IllegalArgumentException {
+        validateRelationDefinition(d);
 
-            ConfigAddListener delayedListener =
-                delayListener.getDelayedAddListener();
+        DN baseDN = DNBuilder.create(path, d);
+        deregisterDeleteListener(baseDN, listener);
+    }
 
-            if (delayedListener != null &&
-                 delayedListener instanceof ConfigAddListenerAdaptor) {
-              ConfigAddListenerAdaptor<?> adaptor =
-                  (ConfigAddListenerAdaptor<?>) delayedListener;
-              if (adaptor.getServerManagedObjectAddListener() == listener) {
-                relationEntry.deregisterAddListener(l);
-              }
-            }
-          }
+    /**
+     * Deregisters an existing configuration delete listener.
+     *
+     * @param <M>
+     *            The type of the child server configuration object.
+     * @param d
+     *            The optional relation definition.
+     * @param listener
+     *            The configuration delete listener.
+     * @throws IllegalArgumentException
+     *             If the optional relation definition is not associated with
+     *             this managed object's definition.
+     */
+    public <M extends Configuration> void deregisterDeleteListener(OptionalRelationDefinition<?, M> d,
+            ConfigurationDeleteListener<M> listener) throws IllegalArgumentException {
+        validateRelationDefinition(d);
+
+        DN baseDN = DNBuilder.create(path, d).parent();
+        deregisterDeleteListener(baseDN, listener);
+    }
+
+    /**
+     * Deregisters an existing server managed object delete listener.
+     *
+     * @param <M>
+     *            The type of the child server configuration object.
+     * @param d
+     *            The optional relation definition.
+     * @param listener
+     *            The server managed object delete listener.
+     * @throws IllegalArgumentException
+     *             If the optional relation definition is not associated with
+     *             this managed object's definition.
+     */
+    public <M extends Configuration> void deregisterDeleteListener(OptionalRelationDefinition<?, M> d,
+            ServerManagedObjectDeleteListener<M> listener) throws IllegalArgumentException {
+        validateRelationDefinition(d);
+
+        DN baseDN = DNBuilder.create(path, d).parent();
+        deregisterDeleteListener(baseDN, listener);
+    }
+
+    /**
+     * Deregisters an existing configuration delete listener.
+     *
+     * @param <M>
+     *            The type of the child server configuration object.
+     * @param d
+     *            The set relation definition.
+     * @param listener
+     *            The configuration delete listener.
+     * @throws IllegalArgumentException
+     *             If the set relation definition is not associated with this
+     *             managed object's definition.
+     */
+    public <M extends Configuration> void deregisterDeleteListener(SetRelationDefinition<?, M> d,
+            ConfigurationDeleteListener<M> listener) throws IllegalArgumentException {
+        validateRelationDefinition(d);
+
+        DN baseDN = DNBuilder.create(path, d);
+        deregisterDeleteListener(baseDN, listener);
+    }
+
+    /**
+     * Deregisters an existing server managed object delete listener.
+     *
+     * @param <M>
+     *            The type of the child server configuration object.
+     * @param d
+     *            The set relation definition.
+     * @param listener
+     *            The server managed object delete listener.
+     * @throws IllegalArgumentException
+     *             If the set relation definition is not associated with this
+     *             managed object's definition.
+     */
+    public <M extends Configuration> void deregisterDeleteListener(SetRelationDefinition<?, M> d,
+            ServerManagedObjectDeleteListener<M> listener) throws IllegalArgumentException {
+        validateRelationDefinition(d);
+
+        DN baseDN = DNBuilder.create(path, d);
+        deregisterDeleteListener(baseDN, listener);
+    }
+
+    /**
+     * Retrieve an instantiable child managed object.
+     *
+     * @param <M>
+     *            The requested type of the child server managed object
+     *            configuration.
+     * @param d
+     *            The instantiable relation definition.
+     * @param name
+     *            The name of the child managed object.
+     * @return Returns the instantiable child managed object.
+     * @throws IllegalArgumentException
+     *             If the relation definition is not associated with this
+     *             managed object's definition.
+     * @throws ConfigException
+     *             If the child managed object could not be found or if it could
+     *             not be decoded.
+     */
+    public <M extends Configuration> ServerManagedObject<? extends M> getChild(InstantiableRelationDefinition<?, M> d,
+            String name) throws IllegalArgumentException, ConfigException {
+        validateRelationDefinition(d);
+        return context.getManagedObject(path.child(d, name));
+    }
+
+    /**
+     * Retrieve an optional child managed object.
+     *
+     * @param <M>
+     *            The requested type of the child server managed object
+     *            configuration.
+     * @param d
+     *            The optional relation definition.
+     * @return Returns the optional child managed object.
+     * @throws IllegalArgumentException
+     *             If the optional relation definition is not associated with
+     *             this managed object's definition.
+     * @throws ConfigException
+     *             If the child managed object could not be found or if it could
+     *             not be decoded.
+     */
+    public <M extends Configuration> ServerManagedObject<? extends M> getChild(OptionalRelationDefinition<?, M> d)
+            throws IllegalArgumentException, ConfigException {
+        validateRelationDefinition(d);
+        return context.getManagedObject(path.child(d));
+    }
+
+    /**
+     * Retrieve a set child managed object.
+     *
+     * @param <M>
+     *            The requested type of the child server managed object
+     *            configuration.
+     * @param d
+     *            The set relation definition.
+     * @param name
+     *            The name of the child managed object.
+     * @return Returns the set child managed object.
+     * @throws IllegalArgumentException
+     *             If the relation definition is not associated with this
+     *             managed object's definition or if {@code name} specifies a
+     *             managed object definition which is not a sub-type of the
+     *             relation's child definition.
+     * @throws ConfigException
+     *             If the child managed object could not be found or if it could
+     *             not be decoded.
+     */
+    public <M extends Configuration> ServerManagedObject<? extends M> getChild(SetRelationDefinition<?, M> d,
+            String name) throws IllegalArgumentException, ConfigException {
+        validateRelationDefinition(d);
+
+        return context.getManagedObject(path.child(d, name));
+    }
+
+    /**
+     * Retrieve a singleton child managed object.
+     *
+     * @param <M>
+     *            The requested type of the child server managed object
+     *            configuration.
+     * @param d
+     *            The singleton relation definition.
+     * @return Returns the singleton child managed object.
+     * @throws IllegalArgumentException
+     *             If the relation definition is not associated with this
+     *             managed object's definition.
+     * @throws ConfigException
+     *             If the child managed object could not be found or if it could
+     *             not be decoded.
+     */
+    public <M extends Configuration> ServerManagedObject<? extends M> getChild(SingletonRelationDefinition<?, M> d)
+            throws IllegalArgumentException, ConfigException {
+        validateRelationDefinition(d);
+        return context.getManagedObject(path.child(d));
+    }
+
+    /**
+     * Creates a server configuration view of this managed object.
+     *
+     * @return Returns the server configuration view of this managed object.
+     */
+    public S getConfiguration() {
+        return definition.createServerConfiguration(this);
+    }
+
+    /**
+     * Get the DN of the LDAP entry associated with this server managed object.
+     *
+     * @return Returns the DN of the LDAP entry associated with this server
+     *         managed object, or an null DN if this is the root managed object.
+     */
+    public DN getDN() {
+        if (configEntry != null) {
+            return configEntry.getDN();
+        } else {
+            return DN.rootDN();
         }
-        return;
-      }
     }
-  }
 
+    /**
+     * Get the definition associated with this server managed object.
+     *
+     * @return Returns the definition associated with this server managed
+     *         object.
+     */
+    public ManagedObjectDefinition<?, S> getManagedObjectDefinition() {
+        return definition;
+    }
 
-  // Deregister a delayed listener with the nearest existing parent
-  // entry to the provided base DN.
-  private <M extends Configuration> void deregisterDelayedDeleteListener(
-      DN baseDN, ServerManagedObjectDeleteListener<M> listener)
-      throws ConfigException {
-    DN parentDN = baseDN.getParent();
-    int delayWrappers = 0;
-    while (parentDN != null) {
-      ConfigEntry relationEntry = getListenerConfigEntry(parentDN);
-      if (relationEntry == null) {
-        parentDN = parentDN.getParent();
-        delayWrappers++;
-      } else {
-        for (ConfigAddListener l : relationEntry.getAddListeners()) {
-          if(l instanceof DelayedConfigAddListener)
-          {
-            DelayedConfigAddListener delayListener =
-                (DelayedConfigAddListener) l;
-            ConfigAddListener wrappedListener;
+    /**
+     * Get the path of this server managed object.
+     *
+     * @return Returns the path of this server managed object.
+     */
+    public ManagedObjectPath<?, S> getManagedObjectPath() {
+        return path;
+    }
 
-            int i = delayWrappers;
-            for(; i > 0; i--)
-            {
-              wrappedListener = delayListener.getDelayedAddListener();
-              if(wrappedListener != null &&
-                  wrappedListener instanceof DelayedConfigAddListener)
-              {
-                delayListener = (DelayedConfigAddListener) l;
-              }
-              else
-              {
-                break;
-              }
-            }
-
-            if(i > 0)
-            {
-              // There are not enough level of wrapping so this can't be
-              // the listener we are looking for.
-              continue;
-            }
-
-            ConfigDeleteListener delayedListener =
-                delayListener.getDelayedDeleteListener();
-
-            if (delayedListener != null &&
-                 delayedListener instanceof ConfigDeleteListenerAdaptor) {
-              ConfigDeleteListenerAdaptor<?> adaptor =
-                  (ConfigDeleteListenerAdaptor<?>) delayedListener;
-              if (adaptor.getServerManagedObjectDeleteListener() == listener) {
-                relationEntry.deregisterAddListener(l);
-              }
-            }
-          }
+    /**
+     * Get the effective value of the specified property. If the property is
+     * multi-valued then just the first value is returned. If the property does
+     * not have a value then its default value is returned if it has one, or
+     * <code>null</code> indicating that any default behavior is applicable.
+     *
+     * @param <T>
+     *            The type of the property to be retrieved.
+     * @param d
+     *            The property to be retrieved.
+     * @return Returns the property's effective value, or <code>null</code>
+     *         indicating that any default behavior is applicable.
+     * @throws IllegalArgumentException
+     *             If the property definition is not associated with this
+     *             managed object's definition.
+     */
+    public <T> T getPropertyValue(PropertyDefinition<T> d) throws IllegalArgumentException {
+        Set<T> values = getPropertyValues(d);
+        if (values.isEmpty()) {
+            return null;
+        } else {
+            return values.iterator().next();
         }
-        return;
-      }
     }
-  }
 
-
-  // Register an instantiable or optional relation delete listener.
-  private void registerDeleteListener(DN baseDN, ConfigDeleteListener adaptor)
-      throws ConfigException {
-    ConfigEntry relationEntry = getListenerConfigEntry(baseDN);
-
-    if (relationEntry != null) {
-      relationEntry.registerDeleteListener(adaptor);
-    } else {
-      // The relation entry does not exist yet so register a delayed
-      // add listener.
-      ConfigAddListener delayedListener = new DelayedConfigAddListener(baseDN,
-          adaptor);
-      registerDelayedListener(baseDN, delayedListener);
+    /**
+     * Get the effective values of the specified property. If the property does
+     * not have any values then its default values are returned if it has any,
+     * or an empty set indicating that any default behavior is applicable.
+     *
+     * @param <T>
+     *            The type of the property to be retrieved.
+     * @param d
+     *            The property to be retrieved.
+     * @return Returns an unmodifiable set containing the property's effective
+     *         values. An empty set indicates that the property has no default
+     *         values defined and any default behavior is applicable.
+     * @throws IllegalArgumentException
+     *             If the property definition is not associated with this
+     *             managed object's definition.
+     */
+    @SuppressWarnings("unchecked")
+    public <T> SortedSet<T> getPropertyValues(PropertyDefinition<T> d) throws IllegalArgumentException {
+        if (!properties.containsKey(d)) {
+            throw new IllegalArgumentException("Unknown property " + d.getName());
+        }
+        return Collections.unmodifiableSortedSet((SortedSet<T>) properties.get(d));
     }
-  }
 
-
-
-  // Validate that a relation definition belongs to this managed
-  // object.
-  private void validateRelationDefinition(RelationDefinition<?, ?> rd)
-      throws IllegalArgumentException {
-    RelationDefinition<?, ?> tmp = definition.getRelationDefinition(rd
-        .getName());
-    if (tmp != rd) {
-      throw new IllegalArgumentException("The relation " + rd.getName()
-          + " is not associated with a " + definition.getName());
+    /**
+     * Determines whether or not the optional managed object associated with the
+     * specified optional relations exists.
+     *
+     * @param d
+     *            The optional relation definition.
+     * @return Returns <code>true</code> if the optional managed object exists,
+     *         <code>false</code> otherwise.
+     * @throws IllegalArgumentException
+     *             If the optional relation definition is not associated with
+     *             this managed object's definition.
+     */
+    public boolean hasChild(OptionalRelationDefinition<?, ?> d) throws IllegalArgumentException {
+        validateRelationDefinition(d);
+        return context.managedObjectExists(path.child(d));
     }
-  }
+
+    /**
+     * Lists the child managed objects associated with the specified
+     * instantiable relation.
+     *
+     * @param d
+     *            The instantiable relation definition.
+     * @return Returns the names of the child managed objects.
+     * @throws IllegalArgumentException
+     *             If the relation definition is not associated with this
+     *             managed object's definition.
+     */
+    public String[] listChildren(InstantiableRelationDefinition<?, ?> d) throws IllegalArgumentException {
+        validateRelationDefinition(d);
+        return context.listManagedObjects(path, d);
+    }
+
+    /**
+     * Lists the child managed objects associated with the specified set
+     * relation.
+     *
+     * @param d
+     *            The set relation definition.
+     * @return Returns the names of the child managed objects.
+     * @throws IllegalArgumentException
+     *             If the relation definition is not associated with this
+     *             managed object's definition.
+     */
+    public String[] listChildren(SetRelationDefinition<?, ?> d) throws IllegalArgumentException {
+        validateRelationDefinition(d);
+        return context.listManagedObjects(path, d);
+    }
+
+    /**
+     * Register to be notified when new child configurations are added beneath
+     * an instantiable relation.
+     *
+     * @param <M>
+     *            The type of the child server configuration object.
+     * @param d
+     *            The instantiable relation definition.
+     * @param listener
+     *            The configuration add listener.
+     * @throws IllegalArgumentException
+     *             If the instantiable relation definition is not associated
+     *             with this managed object's definition.
+     * @throws ConfigException
+     *             If the configuration entry associated with the instantiable
+     *             relation could not be retrieved.
+     */
+    public <M extends Configuration> void registerAddListener(InstantiableRelationDefinition<?, M> d,
+            ConfigurationAddListener<M> listener) throws IllegalArgumentException, ConfigException {
+        registerAddListener(d, new ServerManagedObjectAddListenerAdaptor<M>(listener));
+    }
+
+    /**
+     * Register to be notified when new child server managed object are added
+     * beneath an instantiable relation.
+     *
+     * @param <M>
+     *            The type of the child server configuration object.
+     * @param d
+     *            The instantiable relation definition.
+     * @param listener
+     *            The server managed object add listener.
+     * @throws IllegalArgumentException
+     *             If the instantiable relation definition is not associated
+     *             with this managed object's definition.
+     * @throws ConfigException
+     *             If the configuration entry associated with the instantiable
+     *             relation could not be retrieved.
+     */
+    public <M extends Configuration> void registerAddListener(InstantiableRelationDefinition<?, M> d,
+            ServerManagedObjectAddListener<M> listener) throws IllegalArgumentException, ConfigException {
+        validateRelationDefinition(d);
+        DN baseDN = DNBuilder.create(path, d);
+        ConfigAddListener adaptor = new ConfigAddListenerAdaptor<M>(path, d, listener);
+        registerAddListener(baseDN, adaptor);
+    }
+
+    /**
+     * Register to be notified when a new child configurations is added beneath
+     * an optional relation.
+     *
+     * @param <M>
+     *            The type of the child server configuration object.
+     * @param d
+     *            The optional relation definition.
+     * @param listener
+     *            The configuration add listener.
+     * @throws IllegalArgumentException
+     *             If the optional relation definition is not associated with
+     *             this managed object's definition.
+     * @throws ConfigException
+     *             If the configuration entry associated with the optional
+     *             relation could not be retrieved.
+     */
+    public <M extends Configuration> void registerAddListener(OptionalRelationDefinition<?, M> d,
+            ConfigurationAddListener<M> listener) throws IllegalArgumentException, ConfigException {
+        registerAddListener(d, new ServerManagedObjectAddListenerAdaptor<M>(listener));
+    }
+
+    /**
+     * Register to be notified when a new child server managed object is added
+     * beneath an optional relation.
+     *
+     * @param <M>
+     *            The type of the child server configuration object.
+     * @param d
+     *            The optional relation definition.
+     * @param listener
+     *            The server managed object add listener.
+     * @throws IllegalArgumentException
+     *             If the optional relation definition is not associated with
+     *             this managed object's definition.
+     * @throws ConfigException
+     *             If the configuration entry associated with the optional
+     *             relation could not be retrieved.
+     */
+    public <M extends Configuration> void registerAddListener(OptionalRelationDefinition<?, M> d,
+            ServerManagedObjectAddListener<M> listener) throws IllegalArgumentException, ConfigException {
+        validateRelationDefinition(d);
+        DN baseDN = DNBuilder.create(path, d).parent();
+        ConfigAddListener adaptor = new ConfigAddListenerAdaptor<M>(path, d, listener);
+        registerAddListener(baseDN, adaptor);
+    }
+
+    /**
+     * Register to be notified when new child configurations are added beneath a
+     * set relation.
+     *
+     * @param <M>
+     *            The type of the child server configuration object.
+     * @param d
+     *            The set relation definition.
+     * @param listener
+     *            The configuration add listener.
+     * @throws IllegalArgumentException
+     *             If the set relation definition is not associated with this
+     *             managed object's definition.
+     * @throws ConfigException
+     *             If the configuration entry associated with the set relation
+     *             could not be retrieved.
+     */
+    public <M extends Configuration> void registerAddListener(SetRelationDefinition<?, M> d,
+            ConfigurationAddListener<M> listener) throws IllegalArgumentException, ConfigException {
+        registerAddListener(d, new ServerManagedObjectAddListenerAdaptor<M>(listener));
+    }
+
+    /**
+     * Register to be notified when new child server managed object are added
+     * beneath a set relation.
+     *
+     * @param <M>
+     *            The type of the child server configuration object.
+     * @param d
+     *            The set relation definition.
+     * @param listener
+     *            The server managed object add listener.
+     * @throws IllegalArgumentException
+     *             If the set relation definition is not associated with this
+     *             managed object's definition.
+     * @throws ConfigException
+     *             If the configuration entry associated with the set relation
+     *             could not be retrieved.
+     */
+    public <M extends Configuration> void registerAddListener(SetRelationDefinition<?, M> d,
+            ServerManagedObjectAddListener<M> listener) throws IllegalArgumentException, ConfigException {
+        validateRelationDefinition(d);
+        DN baseDN = DNBuilder.create(path, d);
+        ConfigAddListener adaptor = new ConfigAddListenerAdaptor<M>(path, d, listener);
+        registerAddListener(baseDN, adaptor);
+    }
+
+    /**
+     * Register to be notified when this server managed object is changed.
+     *
+     * @param listener
+     *            The configuration change listener.
+     */
+    public void registerChangeListener(ConfigurationChangeListener<? super S> listener) {
+        registerChangeListener(new ServerManagedObjectChangeListenerAdaptor<S>(listener));
+    }
+
+    /**
+     * Register to be notified when this server managed object is changed.
+     *
+     * @param listener
+     *            The server managed object change listener.
+     */
+    public void registerChangeListener(ServerManagedObjectChangeListener<? super S> listener) {
+        ConfigChangeListener adaptor = new ConfigChangeListenerAdaptor<S>(path, listener);
+        configEntry.registerChangeListener(adaptor);
+
+        // Change listener registration usually signifies that a managed
+        // object has been accepted and added to the server configuration
+        // during initialization post-add.
+
+        // FIXME: we should prevent multiple invocations in the case where
+        // multiple change listeners are registered for the same object.
+        for (Constraint constraint : definition.getAllConstraints()) {
+            for (ServerConstraintHandler handler : constraint.getServerConstraintHandlers()) {
+                try {
+                    handler.performPostAdd(this);
+                } catch (ConfigException e) {
+                    logger.trace("Unable to perform post add", e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Register to be notified when existing child configurations are deleted
+     * beneath an instantiable relation.
+     *
+     * @param <M>
+     *            The type of the child server configuration object.
+     * @param d
+     *            The instantiable relation definition.
+     * @param listener
+     *            The configuration delete listener.
+     * @throws IllegalArgumentException
+     *             If the instantiable relation definition is not associated
+     *             with this managed object's definition.
+     * @throws ConfigException
+     *             If the configuration entry associated with the instantiable
+     *             relation could not be retrieved.
+     */
+    public <M extends Configuration> void registerDeleteListener(InstantiableRelationDefinition<?, M> d,
+            ConfigurationDeleteListener<M> listener) throws IllegalArgumentException, ConfigException {
+        registerDeleteListener(d, new ServerManagedObjectDeleteListenerAdaptor<M>(listener));
+    }
+
+    /**
+     * Register to be notified when existing child server managed objects are
+     * deleted beneath an instantiable relation.
+     *
+     * @param <M>
+     *            The type of the child server configuration object.
+     * @param d
+     *            The instantiable relation definition.
+     * @param listener
+     *            The server managed objects delete listener.
+     * @throws IllegalArgumentException
+     *             If the instantiable relation definition is not associated
+     *             with this managed object's definition.
+     * @throws ConfigException
+     *             If the configuration entry associated with the instantiable
+     *             relation could not be retrieved.
+     */
+    public <M extends Configuration> void registerDeleteListener(InstantiableRelationDefinition<?, M> d,
+            ServerManagedObjectDeleteListener<M> listener) throws IllegalArgumentException, ConfigException {
+        validateRelationDefinition(d);
+        DN baseDN = DNBuilder.create(path, d);
+        ConfigDeleteListener adaptor = new ConfigDeleteListenerAdaptor<M>(path, d, listener);
+        registerDeleteListener(baseDN, adaptor);
+    }
+
+    /**
+     * Register to be notified when an existing child configuration is deleted
+     * beneath an optional relation.
+     *
+     * @param <M>
+     *            The type of the child server configuration object.
+     * @param d
+     *            The optional relation definition.
+     * @param listener
+     *            The configuration delete listener.
+     * @throws IllegalArgumentException
+     *             If the optional relation definition is not associated with
+     *             this managed object's definition.
+     * @throws ConfigException
+     *             If the configuration entry associated with the optional
+     *             relation could not be retrieved.
+     */
+    public <M extends Configuration> void registerDeleteListener(OptionalRelationDefinition<?, M> d,
+            ConfigurationDeleteListener<M> listener) throws IllegalArgumentException, ConfigException {
+        registerDeleteListener(d, new ServerManagedObjectDeleteListenerAdaptor<M>(listener));
+    }
+
+    /**
+     * Register to be notified when an existing child server managed object is
+     * deleted beneath an optional relation.
+     *
+     * @param <M>
+     *            The type of the child server configuration object.
+     * @param d
+     *            The optional relation definition.
+     * @param listener
+     *            The server managed object delete listener.
+     * @throws IllegalArgumentException
+     *             If the optional relation definition is not associated with
+     *             this managed object's definition.
+     * @throws ConfigException
+     *             If the configuration entry associated with the optional
+     *             relation could not be retrieved.
+     */
+    public <M extends Configuration> void registerDeleteListener(OptionalRelationDefinition<?, M> d,
+            ServerManagedObjectDeleteListener<M> listener) throws IllegalArgumentException, ConfigException {
+        validateRelationDefinition(d);
+        DN baseDN = DNBuilder.create(path, d).parent();
+        ConfigDeleteListener adaptor = new ConfigDeleteListenerAdaptor<M>(path, d, listener);
+        registerDeleteListener(baseDN, adaptor);
+    }
+
+    /**
+     * Register to be notified when existing child configurations are deleted
+     * beneath a set relation.
+     *
+     * @param <M>
+     *            The type of the child server configuration object.
+     * @param d
+     *            The set relation definition.
+     * @param listener
+     *            The configuration delete listener.
+     * @throws IllegalArgumentException
+     *             If the set relation definition is not associated with this
+     *             managed object's definition.
+     * @throws ConfigException
+     *             If the configuration entry associated with the set relation
+     *             could not be retrieved.
+     */
+    public <M extends Configuration> void registerDeleteListener(SetRelationDefinition<?, M> d,
+            ConfigurationDeleteListener<M> listener) throws IllegalArgumentException, ConfigException {
+        registerDeleteListener(d, new ServerManagedObjectDeleteListenerAdaptor<M>(listener));
+    }
+
+    /**
+     * Register to be notified when existing child server managed objects are
+     * deleted beneath a set relation.
+     *
+     * @param <M>
+     *            The type of the child server configuration object.
+     * @param d
+     *            The set relation definition.
+     * @param listener
+     *            The server managed objects delete listener.
+     * @throws IllegalArgumentException
+     *             If the set relation definition is not associated with this
+     *             managed object's definition.
+     * @throws ConfigException
+     *             If the configuration entry associated with the set relation
+     *             could not be retrieved.
+     */
+    public <M extends Configuration> void registerDeleteListener(SetRelationDefinition<?, M> d,
+            ServerManagedObjectDeleteListener<M> listener) throws IllegalArgumentException, ConfigException {
+        validateRelationDefinition(d);
+        DN baseDN = DNBuilder.create(path, d);
+        ConfigDeleteListener adaptor = new ConfigDeleteListenerAdaptor<M>(path, d, listener);
+        registerDeleteListener(baseDN, adaptor);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+
+        builder.append("{ TYPE=");
+        builder.append(definition.getName());
+        builder.append(", DN=\"");
+        builder.append(getDN());
+        builder.append('\"');
+        for (Map.Entry<PropertyDefinition<?>, SortedSet<?>> value : properties.entrySet()) {
+            builder.append(", ");
+            builder.append(value.getKey().getName());
+            builder.append('=');
+            builder.append(value.getValue());
+        }
+        builder.append(" }");
+
+        return builder.toString();
+    }
+
+    /**
+     * Determines whether or not this managed object can be used by the server.
+     *
+     * @throws ConstraintViolationException
+     *             If one or more constraints determined that this managed
+     *             object cannot be used by the server.
+     */
+    void ensureIsUsable() throws ConstraintViolationException {
+        // Enforce any constraints.
+        boolean isUsable = true;
+        List<LocalizableMessage> reasons = new LinkedList<LocalizableMessage>();
+        for (Constraint constraint : definition.getAllConstraints()) {
+            for (ServerConstraintHandler handler : constraint.getServerConstraintHandlers()) {
+                try {
+                    if (!handler.isUsable(this, reasons)) {
+                        isUsable = false;
+                    }
+                } catch (ConfigException e) {
+                    LocalizableMessage message = ERR_SERVER_CONSTRAINT_EXCEPTION.get(e.getMessageObject());
+                    reasons.add(message);
+                    isUsable = false;
+                }
+            }
+        }
+
+        if (!isUsable) {
+            throw new ConstraintViolationException(this, reasons);
+        }
+    }
+
+    /**
+     * Update the config entry associated with this server managed object. This
+     * is only intended to be used by change listener call backs in order to
+     * update the managed object with the correct config entry.
+     *
+     * @param configEntry
+     *            The configuration entry.
+     */
+    void setConfigEntry(ConfigEntry configEntry) {
+        this.configEntry = configEntry;
+    }
+
+    // Deregister an add listener.
+    private <M extends Configuration> void deregisterAddListener(DN baseDN, ConfigurationAddListener<M> listener) {
+        try {
+            ConfigEntry configEntry = getListenerConfigEntry(baseDN);
+            if (configEntry != null) {
+                for (ConfigAddListener l : configEntry.getAddListeners()) {
+                    if (l instanceof ConfigAddListenerAdaptor) {
+                        ConfigAddListenerAdaptor<?> adaptor = (ConfigAddListenerAdaptor<?>) l;
+                        ServerManagedObjectAddListener<?> l2 = adaptor.getServerManagedObjectAddListener();
+                        if (l2 instanceof ServerManagedObjectAddListenerAdaptor<?>) {
+                            ServerManagedObjectAddListenerAdaptor<?> adaptor2 =
+                                    (ServerManagedObjectAddListenerAdaptor<?>) l2;
+                            if (adaptor2.getConfigurationAddListener() == listener) {
+                                configEntry.deregisterAddListener(adaptor);
+                            }
+                        }
+                    }
+                }
+            } else {
+                // The relation entry does not exist so check for and deregister
+                // delayed add listener.
+                deregisterDelayedAddListener(baseDN, listener);
+            }
+        } catch (ConfigException e) {
+            // Ignore the exception since this implies deregistration.
+            logger.trace("Unable to deregister add listener", e);
+        }
+    }
+
+    // Deregister an add listener.
+    private <M extends Configuration> void deregisterAddListener(DN baseDN,
+            ServerManagedObjectAddListener<M> listener) {
+        try {
+            ConfigEntry configEntry = getListenerConfigEntry(baseDN);
+            if (configEntry != null) {
+                for (ConfigAddListener l : configEntry.getAddListeners()) {
+                    if (l instanceof ConfigAddListenerAdaptor) {
+                        ConfigAddListenerAdaptor<?> adaptor = (ConfigAddListenerAdaptor<?>) l;
+                        if (adaptor.getServerManagedObjectAddListener() == listener) {
+                            configEntry.deregisterAddListener(adaptor);
+                        }
+                    }
+                }
+            } else {
+                // The relation entry does not exist so check for and deregister
+                // delayed add listener.
+                deregisterDelayedAddListener(baseDN, listener);
+            }
+        } catch (ConfigException e) {
+            // Ignore the exception since this implies deregistration.
+            logger.trace("Unable to deregister add listener", e);
+        }
+    }
+
+    // Deregister a delete listener.
+    private <M extends Configuration> void deregisterDeleteListener(DN baseDN,
+            ConfigurationDeleteListener<M> listener) {
+        try {
+            ConfigEntry configEntry = getListenerConfigEntry(baseDN);
+            if (configEntry != null) {
+                for (ConfigDeleteListener l : configEntry.getDeleteListeners()) {
+                    if (l instanceof ConfigDeleteListenerAdaptor) {
+                        ConfigDeleteListenerAdaptor<?> adaptor = (ConfigDeleteListenerAdaptor<?>) l;
+                        ServerManagedObjectDeleteListener<?> l2 = adaptor.getServerManagedObjectDeleteListener();
+                        if (l2 instanceof ServerManagedObjectDeleteListenerAdaptor<?>) {
+                            ServerManagedObjectDeleteListenerAdaptor<?> adaptor2 =
+                                    (ServerManagedObjectDeleteListenerAdaptor<?>) l2;
+                            if (adaptor2.getConfigurationDeleteListener() == listener) {
+                                configEntry.deregisterDeleteListener(adaptor);
+                            }
+                        }
+                    }
+                }
+            } else {
+                // The relation entry does not exist so check for and deregister
+                // delayed add listener.
+                deregisterDelayedDeleteListener(baseDN, listener);
+            }
+        } catch (ConfigException e) {
+            // Ignore the exception since this implies deregistration.
+            logger.trace("Unable to deregister delete listener", e);
+        }
+    }
+
+    // Deregister a delete listener.
+    private <M extends Configuration> void deregisterDeleteListener(DN baseDN,
+            ServerManagedObjectDeleteListener<M> listener) {
+        try {
+            ConfigEntry configEntry = getListenerConfigEntry(baseDN);
+            if (configEntry != null) {
+                for (ConfigDeleteListener l : configEntry.getDeleteListeners()) {
+                    if (l instanceof ConfigDeleteListenerAdaptor) {
+                        ConfigDeleteListenerAdaptor<?> adaptor = (ConfigDeleteListenerAdaptor<?>) l;
+                        if (adaptor.getServerManagedObjectDeleteListener() == listener) {
+                            configEntry.deregisterDeleteListener(adaptor);
+                        }
+                    }
+                }
+            } else {
+                // The relation entry does not exist so check for and deregister
+                // delayed add listener.
+                deregisterDelayedDeleteListener(baseDN, listener);
+            }
+        } catch (ConfigException e) {
+            // Ignore the exception since this implies deregistration.
+            logger.trace("Unable to deregister delete listener", e);
+        }
+    }
+
+    // Gets a config entry required for a listener and throws a config
+    // exception on failure or returns null if the entry does not exist.
+    private ConfigEntry getListenerConfigEntry(DN dn) throws ConfigException {
+        // Attempt to retrieve the listener base entry.
+        ConfigEntry configEntry;
+        try {
+            configEntry = DirectoryServer.getConfigEntry(dn);
+        } catch (ConfigException e) {
+            logger.trace("Unable to get listener base entry", e);
+            LocalizableMessage message = ERR_ADMIN_CANNOT_GET_LISTENER_BASE.get(String.valueOf(dn),
+                    stackTraceToSingleLineString(e, DynamicConstants.DEBUG_BUILD));
+            throw new ConfigException(message, e);
+        }
+
+        return configEntry;
+    }
+
+    // Register an instantiable or optional relation add listener.
+    private void registerAddListener(DN baseDN, ConfigAddListener adaptor) throws IllegalArgumentException,
+            ConfigException {
+        ConfigEntry relationEntry = getListenerConfigEntry(baseDN);
+
+        if (relationEntry != null) {
+            relationEntry.registerAddListener(adaptor);
+        } else {
+            // The relation entry does not exist yet so register a delayed
+            // add listener.
+            ConfigAddListener delayedListener = new DelayedConfigAddListener(baseDN, adaptor);
+            registerDelayedListener(baseDN, delayedListener);
+        }
+    }
+
+    // Register a delayed listener with the nearest existing parent
+    // entry to the provided base DN.
+    private void registerDelayedListener(DN baseDN, ConfigAddListener delayedListener) throws ConfigException {
+        DN parentDN = baseDN.parent();
+        while (parentDN != null) {
+            ConfigEntry relationEntry = getListenerConfigEntry(parentDN);
+            if (relationEntry == null) {
+                delayedListener = new DelayedConfigAddListener(parentDN, delayedListener);
+                parentDN = parentDN.parent();
+            } else {
+                relationEntry.registerAddListener(delayedListener);
+                return;
+            }
+        }
+
+        // No parent entry could be found.
+        LocalizableMessage message = ERR_ADMIN_UNABLE_TO_REGISTER_LISTENER.get(String.valueOf(baseDN));
+        throw new ConfigException(message);
+    }
+
+    // Deregister a delayed listener with the nearest existing parent
+    // entry to the provided base DN.
+    private <M extends Configuration> void deregisterDelayedAddListener(DN baseDN,
+            ConfigurationAddListener<M> listener)
+            throws ConfigException {
+        DN parentDN = baseDN.parent();
+        int delayWrappers = 0;
+        while (parentDN != null) {
+            ConfigEntry relationEntry = getListenerConfigEntry(parentDN);
+            if (relationEntry == null) {
+                parentDN = parentDN.parent();
+                delayWrappers++;
+            } else {
+                for (ConfigAddListener l : relationEntry.getAddListeners()) {
+                    if (l instanceof DelayedConfigAddListener) {
+                        DelayedConfigAddListener delayListener = (DelayedConfigAddListener) l;
+                        ConfigAddListener wrappedListener;
+
+                        int i = delayWrappers;
+                        for (; i > 0; i--) {
+                            wrappedListener = delayListener.getDelayedAddListener();
+                            if (wrappedListener != null && wrappedListener instanceof DelayedConfigAddListener) {
+                                delayListener = (DelayedConfigAddListener) l;
+                            } else {
+                                break;
+                            }
+                        }
+
+                        if (i > 0) {
+                            // There are not enough level of wrapping so this
+                            // can't be
+                            // the listener we are looking for.
+                            continue;
+                        }
+
+                        ConfigAddListener delayedListener = delayListener.getDelayedAddListener();
+
+                        if (delayedListener != null && delayedListener instanceof ConfigAddListenerAdaptor) {
+                            ConfigAddListenerAdaptor<?> adaptor = (ConfigAddListenerAdaptor<?>) delayedListener;
+                            ServerManagedObjectAddListener<?> l2 = adaptor.getServerManagedObjectAddListener();
+                            if (l2 instanceof ServerManagedObjectAddListenerAdaptor<?>) {
+                                ServerManagedObjectAddListenerAdaptor<?> adaptor2 =
+                                        (ServerManagedObjectAddListenerAdaptor<?>) l2;
+                                if (adaptor2.getConfigurationAddListener() == listener) {
+                                    relationEntry.deregisterAddListener(l);
+                                }
+                            }
+                        }
+                    }
+                }
+                return;
+            }
+        }
+    }
+
+    // Deregister a delayed listener with the nearest existing parent
+    // entry to the provided base DN.
+    private <M extends Configuration> void deregisterDelayedDeleteListener(DN baseDN,
+            ConfigurationDeleteListener<M> listener) throws ConfigException {
+        DN parentDN = baseDN.parent();
+        int delayWrappers = 0;
+        while (parentDN != null) {
+            ConfigEntry relationEntry = getListenerConfigEntry(parentDN);
+            if (relationEntry == null) {
+                parentDN = parentDN.parent();
+                delayWrappers++;
+            } else {
+                for (ConfigAddListener l : relationEntry.getAddListeners()) {
+                    if (l instanceof DelayedConfigAddListener) {
+                        DelayedConfigAddListener delayListener = (DelayedConfigAddListener) l;
+                        ConfigAddListener wrappedListener;
+
+                        int i = delayWrappers;
+                        for (; i > 0; i--) {
+                            wrappedListener = delayListener.getDelayedAddListener();
+                            if (wrappedListener != null && wrappedListener instanceof DelayedConfigAddListener) {
+                                delayListener = (DelayedConfigAddListener) l;
+                            } else {
+                                break;
+                            }
+                        }
+
+                        if (i > 0) {
+                            // There are not enough level of wrapping so this
+                            // can't be
+                            // the listener we are looking for.
+                            continue;
+                        }
+
+                        ConfigDeleteListener delayedListener = delayListener.getDelayedDeleteListener();
+
+                        if (delayedListener != null && delayedListener instanceof ConfigDeleteListenerAdaptor) {
+                            ConfigDeleteListenerAdaptor<?> adaptor = (ConfigDeleteListenerAdaptor<?>) delayedListener;
+                            ServerManagedObjectDeleteListener<?> l2 = adaptor.getServerManagedObjectDeleteListener();
+                            if (l2 instanceof ServerManagedObjectDeleteListenerAdaptor<?>) {
+                                ServerManagedObjectDeleteListenerAdaptor<?> adaptor2 =
+                                        (ServerManagedObjectDeleteListenerAdaptor<?>) l2;
+                                if (adaptor2.getConfigurationDeleteListener() == listener) {
+                                    relationEntry.deregisterAddListener(l);
+                                }
+                            }
+                        }
+                    }
+                }
+                return;
+            }
+        }
+    }
+
+    // Deregister a delayed listener with the nearest existing parent
+    // entry to the provided base DN.
+    private <M extends Configuration> void deregisterDelayedAddListener(DN baseDN,
+            ServerManagedObjectAddListener<M> listener) throws ConfigException {
+        DN parentDN = baseDN.parent();
+        int delayWrappers = 0;
+        while (parentDN != null) {
+            ConfigEntry relationEntry = getListenerConfigEntry(parentDN);
+            if (relationEntry == null) {
+                parentDN = parentDN.parent();
+                delayWrappers++;
+            } else {
+                for (ConfigAddListener l : relationEntry.getAddListeners()) {
+                    if (l instanceof DelayedConfigAddListener) {
+                        DelayedConfigAddListener delayListener = (DelayedConfigAddListener) l;
+                        ConfigAddListener wrappedListener;
+
+                        int i = delayWrappers;
+                        for (; i > 0; i--) {
+                            wrappedListener = delayListener.getDelayedAddListener();
+                            if (wrappedListener != null && wrappedListener instanceof DelayedConfigAddListener) {
+                                delayListener = (DelayedConfigAddListener) l;
+                            } else {
+                                break;
+                            }
+                        }
+
+                        if (i > 0) {
+                            // There are not enough level of wrapping so this
+                            // can't be
+                            // the listener we are looking for.
+                            continue;
+                        }
+
+                        ConfigAddListener delayedListener = delayListener.getDelayedAddListener();
+
+                        if (delayedListener != null && delayedListener instanceof ConfigAddListenerAdaptor) {
+                            ConfigAddListenerAdaptor<?> adaptor = (ConfigAddListenerAdaptor<?>) delayedListener;
+                            if (adaptor.getServerManagedObjectAddListener() == listener) {
+                                relationEntry.deregisterAddListener(l);
+                            }
+                        }
+                    }
+                }
+                return;
+            }
+        }
+    }
+
+    // Deregister a delayed listener with the nearest existing parent
+    // entry to the provided base DN.
+    private <M extends Configuration> void deregisterDelayedDeleteListener(DN baseDN,
+            ServerManagedObjectDeleteListener<M> listener) throws ConfigException {
+        DN parentDN = baseDN.parent();
+        int delayWrappers = 0;
+        while (parentDN != null) {
+            ConfigEntry relationEntry = getListenerConfigEntry(parentDN);
+            if (relationEntry == null) {
+                parentDN = parentDN.parent();
+                delayWrappers++;
+            } else {
+                for (ConfigAddListener l : relationEntry.getAddListeners()) {
+                    if (l instanceof DelayedConfigAddListener) {
+                        DelayedConfigAddListener delayListener = (DelayedConfigAddListener) l;
+                        ConfigAddListener wrappedListener;
+
+                        int i = delayWrappers;
+                        for (; i > 0; i--) {
+                            wrappedListener = delayListener.getDelayedAddListener();
+                            if (wrappedListener != null && wrappedListener instanceof DelayedConfigAddListener) {
+                                delayListener = (DelayedConfigAddListener) l;
+                            } else {
+                                break;
+                            }
+                        }
+
+                        if (i > 0) {
+                            // There are not enough level of wrapping so this
+                            // can't be
+                            // the listener we are looking for.
+                            continue;
+                        }
+
+                        ConfigDeleteListener delayedListener = delayListener.getDelayedDeleteListener();
+
+                        if (delayedListener != null && delayedListener instanceof ConfigDeleteListenerAdaptor) {
+                            ConfigDeleteListenerAdaptor<?> adaptor = (ConfigDeleteListenerAdaptor<?>) delayedListener;
+                            if (adaptor.getServerManagedObjectDeleteListener() == listener) {
+                                relationEntry.deregisterAddListener(l);
+                            }
+                        }
+                    }
+                }
+                return;
+            }
+        }
+    }
+
+    // Register an instantiable or optional relation delete listener.
+    private void registerDeleteListener(DN baseDN, ConfigDeleteListener adaptor) throws ConfigException {
+        ConfigEntry relationEntry = getListenerConfigEntry(baseDN);
+
+        if (relationEntry != null) {
+            relationEntry.registerDeleteListener(adaptor);
+        } else {
+            // The relation entry does not exist yet so register a delayed
+            // add listener.
+            ConfigAddListener delayedListener = new DelayedConfigAddListener(baseDN, adaptor);
+            registerDelayedListener(baseDN, delayedListener);
+        }
+    }
+
+    // Validate that a relation definition belongs to this managed
+    // object.
+    private void validateRelationDefinition(RelationDefinition<?, ?> rd) throws IllegalArgumentException {
+        RelationDefinition<?, ?> tmp = definition.getRelationDefinition(rd.getName());
+        if (tmp != rd) {
+            throw new IllegalArgumentException("The relation " + rd.getName() + " is not associated with a "
+                    + definition.getName());
+        }
+    }
 }
diff --git a/opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagedObjectDecodingException.java b/opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagedObjectDecodingException.java
index a2cc3cb..f8d7fba 100644
--- a/opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagedObjectDecodingException.java
+++ b/opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagedObjectDecodingException.java
@@ -27,8 +27,6 @@
 
 package org.opends.server.admin.server;
 
-
-
 import static com.forgerock.opendj.ldap.AdminMessages.*;
 
 import java.util.Collection;
@@ -42,107 +40,90 @@
 import org.opends.server.admin.PropertyException;
 import static com.forgerock.opendj.util.Validator.*;
 
-
-
 /**
- * The requested server managed object was found but one or more of
- * its properties could not be decoded successfully.
+ * The requested server managed object was found but one or more of its
+ * properties could not be decoded successfully.
  */
 public class ServerManagedObjectDecodingException extends DecodingException {
 
-  /**
-   * Version ID required by serializable classes.
-   */
-  private static final long serialVersionUID = 1598401431084729853L;
+    /**
+     * Version ID required by serializable classes.
+     */
+    private static final long serialVersionUID = 1598401431084729853L;
 
+    // Create the message.
+    private static LocalizableMessage createMessage(ServerManagedObject<?> partialManagedObject,
+            Collection<PropertyException> causes) {
+        ensureNotNull(causes);
+        ensureTrue(!causes.isEmpty(), "causes should nnot be empty");
 
+        ManagedObjectDefinition<?, ?> d = partialManagedObject.getManagedObjectDefinition();
+        if (causes.size() == 1) {
+            return ERR_MANAGED_OBJECT_DECODING_EXCEPTION_SINGLE.get(d.getUserFriendlyName(), causes.iterator().next()
+                    .getLocalizableMessageObject());
+        } else {
+            LocalizableMessageBuilder builder = new LocalizableMessageBuilder();
 
-  // Create the message.
-  private static LocalizableMessage createMessage(
-      ServerManagedObject<?> partialManagedObject,
-      Collection<PropertyException> causes) {
-    ensureNotNull(causes);
-    ensureTrue(!causes.isEmpty(), "causes should nnot be empty");
+            boolean isFirst = true;
+            for (PropertyException cause : causes) {
+                if (!isFirst) {
+                    builder.append("; ");
+                }
+                builder.append(cause.getLocalizableMessageObject());
+                isFirst = false;
+            }
 
-    ManagedObjectDefinition<?, ?> d = partialManagedObject
-        .getManagedObjectDefinition();
-    if (causes.size() == 1) {
-      return ERR_MANAGED_OBJECT_DECODING_EXCEPTION_SINGLE.get(d
-          .getUserFriendlyName(), causes.iterator().next().getMessageObject());
-    } else {
-      LocalizableMessageBuilder builder = new MessageBuilder();
-
-      boolean isFirst = true;
-      for (PropertyException cause : causes) {
-        if (!isFirst) {
-          builder.append("; ");
+            return ERR_MANAGED_OBJECT_DECODING_EXCEPTION_PLURAL.get(d.getUserFriendlyName(), builder.toMessage());
         }
-        builder.append(cause.getMessageObject());
-        isFirst = false;
-      }
-
-      return ERR_MANAGED_OBJECT_DECODING_EXCEPTION_PLURAL.get(d
-          .getUserFriendlyName(), builder.toMessage());
     }
-  }
 
-  // The exception(s) that caused this decoding exception.
-  private final Collection<PropertyException> causes;
+    // The exception(s) that caused this decoding exception.
+    private final Collection<PropertyException> causes;
 
-  // The partially created server managed object.
-  private final ServerManagedObject<?> partialManagedObject;
+    // The partially created server managed object.
+    private final ServerManagedObject<?> partialManagedObject;
 
+    /**
+     * Create a new property decoding exception.
+     *
+     * @param partialManagedObject
+     *            The partially created server managed object containing
+     *            properties which were successfully decoded and empty
+     *            properties for those which were not (this may include empty
+     *            mandatory properties).
+     * @param causes
+     *            The exception(s) that caused this decoding exception.
+     */
+    public ServerManagedObjectDecodingException(ServerManagedObject<?> partialManagedObject,
+            Collection<PropertyException> causes) {
+        super(createMessage(partialManagedObject, causes));
 
+        this.partialManagedObject = partialManagedObject;
+        this.causes = Collections.unmodifiableList(new LinkedList<PropertyException>(causes));
+    }
 
-  /**
-   * Create a new property decoding exception.
-   *
-   * @param partialManagedObject
-   *          The partially created server managed object containing
-   *          properties which were successfully decoded and empty
-   *          properties for those which were not (this may include
-   *          empty mandatory properties).
-   * @param causes
-   *          The exception(s) that caused this decoding exception.
-   */
-  public ServerManagedObjectDecodingException(
-      ServerManagedObject<?> partialManagedObject,
-      Collection<PropertyException> causes) {
-    super(createMessage(partialManagedObject, causes));
+    /**
+     * Get an unmodifiable collection view of the causes of this exception.
+     *
+     * @return Returns an unmodifiable collection view of the causes of this
+     *         exception.
+     */
+    public Collection<PropertyException> getCauses() {
+        return causes;
+    }
 
-    this.partialManagedObject = partialManagedObject;
-    this.causes = Collections
-        .unmodifiableList(new LinkedList<PropertyException>(causes));
-  }
-
-
-
-  /**
-   * Get an unmodifiable collection view of the causes of this
-   * exception.
-   *
-   * @return Returns an unmodifiable collection view of the causes of
-   *         this exception.
-   */
-  public Collection<PropertyException> getCauses() {
-    return causes;
-  }
-
-
-
-  /**
-   * Get the partially created server managed object containing
-   * properties which were successfully decoded and empty properties
-   * for those which were not (this may include empty mandatory
-   * properties).
-   *
-   * @return Returns the partially created server managed object
-   *         containing properties which were successfully decoded and
-   *         empty properties for those which were not (this may
-   *         include empty mandatory properties).
-   */
-  public ServerManagedObject<?> getPartialManagedObject() {
-    return partialManagedObject;
-  }
+    /**
+     * Get the partially created server managed object containing properties
+     * which were successfully decoded and empty properties for those which were
+     * not (this may include empty mandatory properties).
+     *
+     * @return Returns the partially created server managed object containing
+     *         properties which were successfully decoded and empty properties
+     *         for those which were not (this may include empty mandatory
+     *         properties).
+     */
+    public ServerManagedObject<?> getPartialManagedObject() {
+        return partialManagedObject;
+    }
 
 }
diff --git a/opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagementContext.java b/opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagementContext.java
index e982e4d..90f94ec 100644
--- a/opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagementContext.java
+++ b/opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagementContext.java
@@ -27,11 +27,7 @@
 
 package org.opends.server.admin.server;
 
-
-
 import static com.forgerock.opendj.ldap.AdminMessages.*;
-import static org.opends.server.loggers.debug.DebugLogger.*;
-import static org.opends.server.util.StaticUtils.*;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -76,911 +72,783 @@
 import org.opends.server.admin.UndefinedDefaultBehaviorProvider;
 import org.opends.server.admin.UnknownPropertyDefinitionException;
 import org.opends.server.admin.DefinitionDecodingException.Reason;
-import org.opends.server.admin.std.meta.RootCfgDefn;
-import org.opends.server.admin.std.server.RootCfg;
-import org.opends.server.api.AttributeValueDecoder;
-import org.opends.server.config.ConfigEntry;
 import org.opends.server.config.ConfigException;
 import org.opends.server.core.DirectoryServer;
-import org.opends.server.loggers.debug.DebugTracer;
-import org.opends.server.types.AttributeType;
-import org.opends.server.types.AttributeValue;
+import org.forgerock.opendj.admin.meta.RootCfgDefn;
+import org.forgerock.opendj.admin.server.RootCfg;
 import org.forgerock.opendj.ldap.DN;
-import org.opends.server.types.DebugLogLevel;
 import org.opends.server.types.DirectoryException;
 
-
-
 /**
  * Server management connection context.
  */
 public final class ServerManagementContext {
 
-  /**
-   * A default behavior visitor used for retrieving the default values
-   * of a property.
-   *
-   * @param <T>
-   *          The type of the property.
-   */
-  private class DefaultValueFinder<T> implements
-      DefaultBehaviorProviderVisitor<T, Collection<T>, Void> {
+    /**
+     * A default behavior visitor used for retrieving the default values of a
+     * property.
+     *
+     * @param <T>
+     *            The type of the property.
+     */
+    private class DefaultValueFinder<T> implements DefaultBehaviorProviderVisitor<T, Collection<T>, Void> {
 
-    // Any exception that occurred whilst retrieving inherited default
-    // values.
-    private DefaultBehaviorException exception = null;
+        // Any exception that occurred whilst retrieving inherited default
+        // values.
+        private DefaultBehaviorException exception = null;
 
-    // Optional new configuration entry which does not yet exist in
-    // the configuration back-end.
-    private final ConfigEntry newConfigEntry;
+        // Optional new configuration entry which does not yet exist in
+        // the configuration back-end.
+        private final ConfigEntry newConfigEntry;
 
-    // The path of the managed object containing the next property.
-    private ManagedObjectPath<?, ?> nextPath = null;
+        // The path of the managed object containing the next property.
+        private ManagedObjectPath<?, ?> nextPath = null;
 
-    // The next property whose default values were required.
-    private PropertyDefinition<T> nextProperty = null;
+        // The next property whose default values were required.
+        private PropertyDefinition<T> nextProperty = null;
 
+        // Private constructor.
+        private DefaultValueFinder(ConfigEntry newConfigEntry) {
+            this.newConfigEntry = newConfigEntry;
+        }
 
+        /**
+         * {@inheritDoc}
+         */
+        public Collection<T> visitAbsoluteInherited(AbsoluteInheritedDefaultBehaviorProvider<T> d, Void p) {
+            try {
+                return getInheritedProperty(d.getManagedObjectPath(), d.getManagedObjectDefinition(),
+                        d.getPropertyName());
+            } catch (DefaultBehaviorException e) {
+                exception = e;
+                return Collections.emptySet();
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public Collection<T> visitAlias(AliasDefaultBehaviorProvider<T> d, Void p) {
+            return Collections.emptySet();
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public Collection<T> visitDefined(DefinedDefaultBehaviorProvider<T> d, Void p) {
+            Collection<String> stringValues = d.getDefaultValues();
+            List<T> values = new ArrayList<T>(stringValues.size());
+
+            for (String stringValue : stringValues) {
+                try {
+                    values.add(nextProperty.decodeValue(stringValue));
+                } catch (IllegalPropertyValueStringException e) {
+                    exception = new DefaultBehaviorException(nextProperty, e);
+                    break;
+                }
+            }
+
+            return values;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public Collection<T> visitRelativeInherited(RelativeInheritedDefaultBehaviorProvider<T> d, Void p) {
+            try {
+                return getInheritedProperty(d.getManagedObjectPath(nextPath), d.getManagedObjectDefinition(),
+                        d.getPropertyName());
+            } catch (DefaultBehaviorException e) {
+                exception = e;
+                return Collections.emptySet();
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public Collection<T> visitUndefined(UndefinedDefaultBehaviorProvider<T> d, Void p) {
+            return Collections.emptySet();
+        }
+
+        // Find the default values for the next path/property.
+        private Collection<T> find(ManagedObjectPath<?, ?> p, PropertyDefinition<T> pd) throws DefaultBehaviorException {
+            nextPath = p;
+            nextProperty = pd;
+
+            Collection<T> values = nextProperty.getDefaultBehaviorProvider().accept(this, null);
+
+            if (exception != null) {
+                throw exception;
+            }
+
+            if (values.size() > 1 && !pd.hasOption(PropertyOption.MULTI_VALUED)) {
+                throw new DefaultBehaviorException(pd, new PropertyIsSingleValuedException(pd));
+            }
+
+            return values;
+        }
+
+        // Get an inherited property value.
+        @SuppressWarnings("unchecked")
+        private Collection<T> getInheritedProperty(ManagedObjectPath target, AbstractManagedObjectDefinition<?, ?> d,
+                String propertyName) throws DefaultBehaviorException {
+            // First check that the requested type of managed object
+            // corresponds to the path.
+            AbstractManagedObjectDefinition<?, ?> supr = target.getManagedObjectDefinition();
+            if (!supr.isParentOf(d)) {
+                throw new DefaultBehaviorException(nextProperty, new DefinitionDecodingException(supr,
+                        Reason.WRONG_TYPE_INFORMATION));
+            }
+
+            // Save the current property in case of recursion.
+            PropertyDefinition<T> pd1 = nextProperty;
+
+            try {
+                // Get the actual managed object definition.
+                DN dn = DNBuilder.create(target);
+                ConfigEntry configEntry;
+                if (newConfigEntry != null && newConfigEntry.getDN().equals(dn)) {
+                    configEntry = newConfigEntry;
+                } else {
+                    configEntry = getManagedObjectConfigEntry(dn);
+                }
+
+                DefinitionResolver resolver = new MyDefinitionResolver(configEntry);
+                ManagedObjectDefinition<?, ?> mod = d.resolveManagedObjectDefinition(resolver);
+
+                PropertyDefinition<T> pd2;
+                try {
+                    PropertyDefinition<?> pdTmp = mod.getPropertyDefinition(propertyName);
+                    pd2 = pd1.getClass().cast(pdTmp);
+                } catch (IllegalArgumentException e) {
+                    throw new PropertyNotFoundException(propertyName);
+                } catch (ClassCastException e) {
+                    // FIXME: would be nice to throw a better exception here.
+                    throw new PropertyNotFoundException(propertyName);
+                }
+
+                List<AttributeValue> values = getAttribute(mod, pd2, configEntry);
+                if (values.isEmpty()) {
+                    // Recursively retrieve this property's default values.
+                    Collection<T> tmp = find(target, pd2);
+                    Collection<T> pvalues = new ArrayList<T>(tmp.size());
+                    for (T value : tmp) {
+                        pd1.validateValue(value);
+                        pvalues.add(value);
+                    }
+                    return pvalues;
+                } else {
+                    Collection<T> pvalues = new ArrayList<T>(values.size());
+                    for (AttributeValue value : values) {
+                        pvalues.add(ValueDecoder.decode(pd1, value));
+                    }
+                    return pvalues;
+                }
+            } catch (DefinitionDecodingException e) {
+                throw new DefaultBehaviorException(pd1, e);
+            } catch (PropertyNotFoundException e) {
+                throw new DefaultBehaviorException(pd1, e);
+            } catch (IllegalPropertyValueException e) {
+                throw new DefaultBehaviorException(pd1, e);
+            } catch (IllegalPropertyValueStringException e) {
+                throw new DefaultBehaviorException(pd1, e);
+            } catch (ConfigException e) {
+                throw new DefaultBehaviorException(pd1, e);
+            }
+        }
+    }
+
+    /**
+     * A definition resolver that determines the managed object definition from
+     * the object classes of a ConfigEntry.
+     */
+    private class MyDefinitionResolver implements DefinitionResolver {
+
+        // The config entry.
+        private final ConfigEntry entry;
+
+        // Private constructor.
+        private MyDefinitionResolver(ConfigEntry entry) {
+            this.entry = entry;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public boolean matches(AbstractManagedObjectDefinition<?, ?> d) {
+            String oc = LDAPProfile.getInstance().getObjectClass(d);
+            return entry.hasObjectClass(oc);
+        }
+    }
+
+    /**
+     * A visitor which is used to decode property LDAP values.
+     */
+    private static final class ValueDecoder extends PropertyDefinitionVisitor<Object, String> {
+
+        /**
+         * Decodes the provided property LDAP value.
+         *
+         * @param <PD>
+         *            The type of the property.
+         * @param pd
+         *            The property definition.
+         * @param value
+         *            The LDAP string representation.
+         * @return Returns the decoded LDAP value.
+         * @throws IllegalPropertyValueStringException
+         *             If the property value could not be decoded because it was
+         *             invalid.
+         */
+        public static <PD> PD decode(PropertyDefinition<PD> pd, AttributeValue value)
+                throws IllegalPropertyValueStringException {
+            String s = value.getValue().toString();
+            return pd.castValue(pd.accept(new ValueDecoder(), s));
+        }
+
+        // Prevent instantiation.
+        private ValueDecoder() {
+            // No implementation required.
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public <C extends ConfigurationClient, S extends Configuration> Object visitAggregation(
+                AggregationPropertyDefinition<C, S> d, String p) {
+            // Aggregations values are stored as full DNs in LDAP, but
+            // just their common name is exposed in the admin framework.
+            try {
+                Reference<C, S> reference = Reference.parseDN(d.getParentPath(), d.getRelationDefinition(), p);
+                return reference.getName();
+            } catch (IllegalArgumentException e) {
+                throw new IllegalPropertyValueStringException(d, p);
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public <T> Object visitUnknown(PropertyDefinition<T> d, String p) throws UnknownPropertyDefinitionException {
+            // By default the property definition's decoder will do.
+            return d.decodeValue(p);
+        }
+    }
+
+    // Singleton instance.
+    private final static ServerManagementContext INSTANCE = new ServerManagementContext();
+
+    /**
+     * The root server managed object.
+     */
+    private static final ServerManagedObject<RootCfg> ROOT = new ServerManagedObject<RootCfg>(
+            ManagedObjectPath.emptyPath(), RootCfgDefn.getInstance(),
+            Collections.<PropertyDefinition<?>, SortedSet<?>> emptyMap(), null);
+
+    /**
+     * Get the single server-side management context.
+     *
+     * @return Returns the single server-side management context.
+     */
+    public static ServerManagementContext getInstance() {
+        return INSTANCE;
+    }
 
     // Private constructor.
-    private DefaultValueFinder(ConfigEntry newConfigEntry) {
-      this.newConfigEntry = newConfigEntry;
+    private ServerManagementContext() {
+        // No implementation required.
     }
 
-
-
     /**
-     * {@inheritDoc}
+     * Gets the named managed object.
+     *
+     * @param <C>
+     *            The type of client managed object configuration that the path
+     *            definition refers to.
+     * @param <S>
+     *            The type of server managed object configuration that the path
+     *            definition refers to.
+     * @param path
+     *            The path of the managed object.
+     * @return Returns the named managed object.
+     * @throws ConfigException
+     *             If the named managed object could not be found or if it could
+     *             not be decoded.
      */
-    public Collection<T> visitAbsoluteInherited(
-        AbsoluteInheritedDefaultBehaviorProvider<T> d, Void p) {
-      try {
-        return getInheritedProperty(d.getManagedObjectPath(), d
-            .getManagedObjectDefinition(), d.getPropertyName());
-      } catch (DefaultBehaviorException e) {
-        exception = e;
-        return Collections.emptySet();
-      }
-    }
-
-
-
-    /**
-     * {@inheritDoc}
-     */
-    public Collection<T> visitAlias(AliasDefaultBehaviorProvider<T> d, Void p) {
-      return Collections.emptySet();
-    }
-
-
-
-    /**
-     * {@inheritDoc}
-     */
-    public Collection<T> visitDefined(DefinedDefaultBehaviorProvider<T> d,
-        Void p) {
-      Collection<String> stringValues = d.getDefaultValues();
-      List<T> values = new ArrayList<T>(stringValues.size());
-
-      for (String stringValue : stringValues) {
-        try {
-          values.add(nextProperty.decodeValue(stringValue));
-        } catch (IllegalPropertyValueStringException e) {
-          exception = new DefaultBehaviorException(nextProperty, e);
-          break;
-        }
-      }
-
-      return values;
-    }
-
-
-
-    /**
-     * {@inheritDoc}
-     */
-    public Collection<T> visitRelativeInherited(
-        RelativeInheritedDefaultBehaviorProvider<T> d, Void p) {
-      try {
-        return getInheritedProperty(d.getManagedObjectPath(nextPath), d
-            .getManagedObjectDefinition(), d.getPropertyName());
-      } catch (DefaultBehaviorException e) {
-        exception = e;
-        return Collections.emptySet();
-      }
-    }
-
-
-
-    /**
-     * {@inheritDoc}
-     */
-    public Collection<T> visitUndefined(UndefinedDefaultBehaviorProvider<T> d,
-        Void p) {
-      return Collections.emptySet();
-    }
-
-
-
-    // Find the default values for the next path/property.
-    private Collection<T> find(ManagedObjectPath<?, ?> p,
-        PropertyDefinition<T> pd) throws DefaultBehaviorException {
-      nextPath = p;
-      nextProperty = pd;
-
-      Collection<T> values = nextProperty.getDefaultBehaviorProvider().accept(
-          this, null);
-
-      if (exception != null) {
-        throw exception;
-      }
-
-      if (values.size() > 1 && !pd.hasOption(PropertyOption.MULTI_VALUED)) {
-        throw new DefaultBehaviorException(pd,
-            new PropertyIsSingleValuedException(pd));
-      }
-
-      return values;
-    }
-
-
-
-    // Get an inherited property value.
     @SuppressWarnings("unchecked")
-    private Collection<T> getInheritedProperty(ManagedObjectPath target,
-        AbstractManagedObjectDefinition<?, ?> d, String propertyName)
-        throws DefaultBehaviorException {
-      // First check that the requested type of managed object
-      // corresponds to the path.
-      AbstractManagedObjectDefinition<?, ?> supr = target
-          .getManagedObjectDefinition();
-      if (!supr.isParentOf(d)) {
-        throw new DefaultBehaviorException(
-            nextProperty, new DefinitionDecodingException(supr,
-                Reason.WRONG_TYPE_INFORMATION));
-      }
-
-      // Save the current property in case of recursion.
-      PropertyDefinition<T> pd1 = nextProperty;
-
-      try {
-        // Get the actual managed object definition.
-        DN dn = DNBuilder.create(target);
-        ConfigEntry configEntry;
-        if (newConfigEntry != null && newConfigEntry.getDN().equals(dn)) {
-          configEntry = newConfigEntry;
-        } else {
-          configEntry = getManagedObjectConfigEntry(dn);
+    public <C extends ConfigurationClient, S extends Configuration> ServerManagedObject<? extends S> getManagedObject(
+            ManagedObjectPath<C, S> path) throws ConfigException {
+        // Be careful to handle the root configuration.
+        if (path.isEmpty()) {
+            return (ServerManagedObject<S>) getRootConfigurationManagedObject();
         }
 
+        // Get the configuration entry.
+        DN targetDN = DNBuilder.create(path);
+        ConfigEntry configEntry = getManagedObjectConfigEntry(targetDN);
+        try {
+            ServerManagedObject<? extends S> managedObject;
+            managedObject = decode(path, configEntry);
+
+            // Enforce any constraints.
+            managedObject.ensureIsUsable();
+
+            return managedObject;
+        } catch (DefinitionDecodingException e) {
+            throw ConfigExceptionFactory.getInstance().createDecodingExceptionAdaptor(targetDN, e);
+        } catch (ServerManagedObjectDecodingException e) {
+            throw ConfigExceptionFactory.getInstance().createDecodingExceptionAdaptor(e);
+        } catch (ConstraintViolationException e) {
+            throw ConfigExceptionFactory.getInstance().createDecodingExceptionAdaptor(e);
+        }
+    }
+
+    /**
+     * Gets the effective value of a property in the named managed object.
+     *
+     * @param <C>
+     *            The type of client managed object configuration that the path
+     *            definition refers to.
+     * @param <S>
+     *            The type of server managed object configuration that the path
+     *            definition refers to.
+     * @param <PD>
+     *            The type of the property to be retrieved.
+     * @param path
+     *            The path of the managed object containing the property.
+     * @param pd
+     *            The property to be retrieved.
+     * @return Returns the property's effective value, or <code>null</code> if
+     *         there are no values defined.
+     * @throws IllegalArgumentException
+     *             If the property definition is not associated with the
+     *             referenced managed object's definition.
+     * @throws PropertyException
+     *             If the managed object was found but the requested property
+     *             could not be decoded.
+     * @throws ConfigException
+     *             If the named managed object could not be found or if it could
+     *             not be decoded.
+     */
+    public <C extends ConfigurationClient, S extends Configuration, PD> PD getPropertyValue(
+            ManagedObjectPath<C, S> path, PropertyDefinition<PD> pd) throws IllegalArgumentException, ConfigException,
+            PropertyException {
+        SortedSet<PD> values = getPropertyValues(path, pd);
+        if (values.isEmpty()) {
+            return null;
+        } else {
+            return values.first();
+        }
+    }
+
+    /**
+     * Gets the effective values of a property in the named managed object.
+     *
+     * @param <C>
+     *            The type of client managed object configuration that the path
+     *            definition refers to.
+     * @param <S>
+     *            The type of server managed object configuration that the path
+     *            definition refers to.
+     * @param <PD>
+     *            The type of the property to be retrieved.
+     * @param path
+     *            The path of the managed object containing the property.
+     * @param pd
+     *            The property to be retrieved.
+     * @return Returns the property's effective values, or an empty set if there
+     *         are no values defined.
+     * @throws IllegalArgumentException
+     *             If the property definition is not associated with the
+     *             referenced managed object's definition.
+     * @throws PropertyException
+     *             If the managed object was found but the requested property
+     *             could not be decoded.
+     * @throws ConfigException
+     *             If the named managed object could not be found or if it could
+     *             not be decoded.
+     */
+    @SuppressWarnings("unchecked")
+    public <C extends ConfigurationClient, S extends Configuration, PD> SortedSet<PD> getPropertyValues(
+            ManagedObjectPath<C, S> path, PropertyDefinition<PD> pd) throws IllegalArgumentException, ConfigException,
+            PropertyException {
+        // Check that the requested property is from the definition
+        // associated with the path.
+        AbstractManagedObjectDefinition<C, S> d = path.getManagedObjectDefinition();
+        PropertyDefinition<?> tmp = d.getPropertyDefinition(pd.getName());
+        if (tmp != pd) {
+            throw new IllegalArgumentException("The property " + pd.getName() + " is not associated with a "
+                    + d.getName());
+        }
+
+        // Determine the exact type of managed object referenced by the
+        // path.
+        DN dn = DNBuilder.create(path);
+        ConfigEntry configEntry = getManagedObjectConfigEntry(dn);
+
         DefinitionResolver resolver = new MyDefinitionResolver(configEntry);
-        ManagedObjectDefinition<?, ?> mod = d
-            .resolveManagedObjectDefinition(resolver);
+        ManagedObjectDefinition<? extends C, ? extends S> mod;
 
-        PropertyDefinition<T> pd2;
         try {
-          PropertyDefinition<?> pdTmp = mod.getPropertyDefinition(propertyName);
-          pd2 = pd1.getClass().cast(pdTmp);
-        } catch (IllegalArgumentException e) {
-          throw new PropertyNotFoundException(propertyName);
-        } catch (ClassCastException e) {
-          // FIXME: would be nice to throw a better exception here.
-          throw new PropertyNotFoundException(propertyName);
+            mod = d.resolveManagedObjectDefinition(resolver);
+        } catch (DefinitionDecodingException e) {
+            throw ConfigExceptionFactory.getInstance().createDecodingExceptionAdaptor(dn, e);
         }
 
-        List<AttributeValue> values = getAttribute(mod, pd2, configEntry);
-        if (values.isEmpty()) {
-          // Recursively retrieve this property's default values.
-          Collection<T> tmp = find(target, pd2);
-          Collection<T> pvalues = new ArrayList<T>(tmp.size());
-          for (T value : tmp) {
-            pd1.validateValue(value);
-            pvalues.add(value);
-          }
-          return pvalues;
-        } else {
-          Collection<T> pvalues = new ArrayList<T>(values.size());
-          for (AttributeValue value : values) {
-            pvalues.add(ValueDecoder.decode(pd1, value));
-          }
-          return pvalues;
-        }
-      } catch (DefinitionDecodingException e) {
-        throw new DefaultBehaviorException(pd1, e);
-      } catch (PropertyNotFoundException e) {
-        throw new DefaultBehaviorException(pd1, e);
-      } catch (IllegalPropertyValueException e) {
-        throw new DefaultBehaviorException(pd1, e);
-      } catch (IllegalPropertyValueStringException e) {
-        throw new DefaultBehaviorException(pd1, e);
-      } catch (ConfigException e) {
-        throw new DefaultBehaviorException(pd1, e);
-      }
+        // Make sure we use the correct property definition, the
+        // provided one might have been overridden in the resolved
+        // definition.
+        pd = (PropertyDefinition<PD>) mod.getPropertyDefinition(pd.getName());
+
+        List<AttributeValue> values = getAttribute(mod, pd, configEntry);
+        return decodeProperty(path.asSubType(mod), pd, values, null);
     }
-  }
-
-
-
-  /**
-   * A definition resolver that determines the managed object
-   * definition from the object classes of a ConfigEntry.
-   */
-  private class MyDefinitionResolver implements DefinitionResolver {
-
-    // The config entry.
-    private final ConfigEntry entry;
-
-
-
-    // Private constructor.
-    private MyDefinitionResolver(ConfigEntry entry) {
-      this.entry = entry;
-    }
-
-
 
     /**
-     * {@inheritDoc}
-     */
-    public boolean matches(AbstractManagedObjectDefinition<?, ?> d) {
-      String oc = LDAPProfile.getInstance().getObjectClass(d);
-      return entry.hasObjectClass(oc);
-    }
-  }
-
-
-
-  /**
-   * A visitor which is used to decode property LDAP values.
-   */
-  private static final class ValueDecoder extends
-      PropertyDefinitionVisitor<Object, String> {
-
-    /**
-     * Decodes the provided property LDAP value.
+     * Get the root configuration manager associated with this management
+     * context.
      *
-     * @param <PD>
-     *          The type of the property.
-     * @param pd
-     *          The property definition.
-     * @param value
-     *          The LDAP string representation.
-     * @return Returns the decoded LDAP value.
-     * @throws IllegalPropertyValueStringException
-     *           If the property value could not be decoded because it
-     *           was invalid.
+     * @return Returns the root configuration manager associated with this
+     *         management context.
      */
-    public static <PD> PD decode(PropertyDefinition<PD> pd,
-        AttributeValue value) throws IllegalPropertyValueStringException {
-      String s = value.getValue().toString();
-      return pd.castValue(pd.accept(new ValueDecoder(), s));
+    public RootCfg getRootConfiguration() {
+        return getRootConfigurationManagedObject().getConfiguration();
     }
 
-
-
-    // Prevent instantiation.
-    private ValueDecoder() {
-      // No implementation required.
-    }
-
-
-
     /**
-     * {@inheritDoc}
+     * Get the root configuration server managed object associated with this
+     * management context.
+     *
+     * @return Returns the root configuration server managed object associated
+     *         with this management context.
      */
-    @Override
-    public <C extends ConfigurationClient, S extends Configuration>
-    Object visitAggregation(AggregationPropertyDefinition<C, S> d, String p) {
-      // Aggregations values are stored as full DNs in LDAP, but
-      // just their common name is exposed in the admin framework.
-      try {
-        Reference<C, S> reference = Reference.parseDN(d.getParentPath(), d
-            .getRelationDefinition(), p);
-        return reference.getName();
-      } catch (IllegalArgumentException e) {
-        throw new IllegalPropertyValueStringException(d, p);
-      }
+    public ServerManagedObject<RootCfg> getRootConfigurationManagedObject() {
+        return ROOT;
     }
 
-
-
     /**
-     * {@inheritDoc}
+     * Lists the child managed objects of the named parent managed object.
+     *
+     * @param <C>
+     *            The type of client managed object configuration that the
+     *            relation definition refers to.
+     * @param <S>
+     *            The type of server managed object configuration that the
+     *            relation definition refers to.
+     * @param parent
+     *            The path of the parent managed object.
+     * @param rd
+     *            The instantiable relation definition.
+     * @return Returns the names of the child managed objects.
+     * @throws IllegalArgumentException
+     *             If the relation definition is not associated with the parent
+     *             managed object's definition.
      */
-    @Override
-    public <T> Object visitUnknown(PropertyDefinition<T> d, String p)
-        throws UnknownPropertyDefinitionException {
-      // By default the property definition's decoder will do.
-      return d.decodeValue(p);
-    }
-  }
+    public <C extends ConfigurationClient, S extends Configuration> String[] listManagedObjects(
+            ManagedObjectPath<?, ?> parent, InstantiableRelationDefinition<C, S> rd) throws IllegalArgumentException {
+        validateRelationDefinition(parent, rd);
 
-
-
-  // Singleton instance.
-  private final static ServerManagementContext INSTANCE =
-    new ServerManagementContext();
-
-  /**
-   * The root server managed object.
-   */
-  private static final ServerManagedObject<RootCfg> ROOT =
-    new ServerManagedObject<RootCfg>(
-      ManagedObjectPath.emptyPath(), RootCfgDefn.getInstance(), Collections
-          .<PropertyDefinition<?>, SortedSet<?>> emptyMap(), null);
-
-  /**
-   * The tracer object for the debug logger.
-   */
-  private static final DebugTracer TRACER = getTracer();
-
-
-
-  /**
-   * Get the single server-side management context.
-   *
-   * @return Returns the single server-side management context.
-   */
-  public static ServerManagementContext getInstance() {
-    return INSTANCE;
-  }
-
-
-
-  // Private constructor.
-  private ServerManagementContext() {
-    // No implementation required.
-  }
-
-
-
-  /**
-   * Gets the named managed object.
-   *
-   * @param <C>
-   *          The type of client managed object configuration that the
-   *          path definition refers to.
-   * @param <S>
-   *          The type of server managed object configuration that the
-   *          path definition refers to.
-   * @param path
-   *          The path of the managed object.
-   * @return Returns the named managed object.
-   * @throws ConfigException
-   *           If the named managed object could not be found or if it
-   *           could not be decoded.
-   */
-  @SuppressWarnings("unchecked")
-  public <C extends ConfigurationClient, S extends Configuration>
-  ServerManagedObject<? extends S> getManagedObject(
-      ManagedObjectPath<C, S> path) throws ConfigException {
-    // Be careful to handle the root configuration.
-    if (path.isEmpty()) {
-      return (ServerManagedObject<S>) getRootConfigurationManagedObject();
-    }
-
-    // Get the configuration entry.
-    DN targetDN = DNBuilder.create(path);
-    ConfigEntry configEntry = getManagedObjectConfigEntry(targetDN);
-    try {
-      ServerManagedObject<? extends S> managedObject;
-      managedObject = decode(path, configEntry);
-
-      // Enforce any constraints.
-      managedObject.ensureIsUsable();
-
-      return managedObject;
-    } catch (DefinitionDecodingException e) {
-      throw ConfigExceptionFactory.getInstance()
-          .createDecodingExceptionAdaptor(targetDN, e);
-    } catch (ServerManagedObjectDecodingException e) {
-      throw ConfigExceptionFactory.getInstance()
-          .createDecodingExceptionAdaptor(e);
-    } catch (ConstraintViolationException e) {
-      throw ConfigExceptionFactory.getInstance()
-          .createDecodingExceptionAdaptor(e);
-    }
-  }
-
-
-
-  /**
-   * Gets the effective value of a property in the named managed
-   * object.
-   *
-   * @param <C>
-   *          The type of client managed object configuration that the
-   *          path definition refers to.
-   * @param <S>
-   *          The type of server managed object configuration that the
-   *          path definition refers to.
-   * @param <PD>
-   *          The type of the property to be retrieved.
-   * @param path
-   *          The path of the managed object containing the property.
-   * @param pd
-   *          The property to be retrieved.
-   * @return Returns the property's effective value, or
-   *         <code>null</code> if there are no values defined.
-   * @throws IllegalArgumentException
-   *           If the property definition is not associated with the
-   *           referenced managed object's definition.
-   * @throws PropertyException
-   *           If the managed object was found but the requested
-   *           property could not be decoded.
-   * @throws ConfigException
-   *           If the named managed object could not be found or if it
-   *           could not be decoded.
-   */
-  public <C extends ConfigurationClient, S extends Configuration, PD>
-  PD getPropertyValue(ManagedObjectPath<C, S> path,
-      PropertyDefinition<PD> pd) throws IllegalArgumentException,
-      ConfigException, PropertyException {
-    SortedSet<PD> values = getPropertyValues(path, pd);
-    if (values.isEmpty()) {
-      return null;
-    } else {
-      return values.first();
-    }
-  }
-
-
-
-  /**
-   * Gets the effective values of a property in the named managed
-   * object.
-   *
-   * @param <C>
-   *          The type of client managed object configuration that the
-   *          path definition refers to.
-   * @param <S>
-   *          The type of server managed object configuration that the
-   *          path definition refers to.
-   * @param <PD>
-   *          The type of the property to be retrieved.
-   * @param path
-   *          The path of the managed object containing the property.
-   * @param pd
-   *          The property to be retrieved.
-   * @return Returns the property's effective values, or an empty set
-   *         if there are no values defined.
-   * @throws IllegalArgumentException
-   *           If the property definition is not associated with the
-   *           referenced managed object's definition.
-   * @throws PropertyException
-   *           If the managed object was found but the requested
-   *           property could not be decoded.
-   * @throws ConfigException
-   *           If the named managed object could not be found or if it
-   *           could not be decoded.
-   */
-  @SuppressWarnings("unchecked")
-  public <C extends ConfigurationClient, S extends Configuration, PD>
-  SortedSet<PD> getPropertyValues(ManagedObjectPath<C, S> path,
-      PropertyDefinition<PD> pd) throws IllegalArgumentException,
-      ConfigException, PropertyException {
-    // Check that the requested property is from the definition
-    // associated with the path.
-    AbstractManagedObjectDefinition<C, S> d = path.getManagedObjectDefinition();
-    PropertyDefinition<?> tmp = d.getPropertyDefinition(pd.getName());
-    if (tmp != pd) {
-      throw new IllegalArgumentException("The property " + pd.getName()
-          + " is not associated with a " + d.getName());
-    }
-
-    // Determine the exact type of managed object referenced by the
-    // path.
-    DN dn = DNBuilder.create(path);
-    ConfigEntry configEntry = getManagedObjectConfigEntry(dn);
-
-    DefinitionResolver resolver = new MyDefinitionResolver(configEntry);
-    ManagedObjectDefinition<? extends C, ? extends S> mod;
-
-    try {
-      mod = d.resolveManagedObjectDefinition(resolver);
-    } catch (DefinitionDecodingException e) {
-      throw ConfigExceptionFactory.getInstance()
-          .createDecodingExceptionAdaptor(dn, e);
-    }
-
-    // Make sure we use the correct property definition, the
-    // provided one might have been overridden in the resolved
-    // definition.
-    pd = (PropertyDefinition<PD>) mod.getPropertyDefinition(pd.getName());
-
-    List<AttributeValue> values = getAttribute(mod, pd, configEntry);
-    return decodeProperty(path.asSubType(mod), pd, values, null);
-  }
-
-
-
-  /**
-   * Get the root configuration manager associated with this
-   * management context.
-   *
-   * @return Returns the root configuration manager associated with
-   *         this management context.
-   */
-  public RootCfg getRootConfiguration() {
-    return getRootConfigurationManagedObject().getConfiguration();
-  }
-
-
-
-  /**
-   * Get the root configuration server managed object associated with
-   * this management context.
-   *
-   * @return Returns the root configuration server managed object
-   *         associated with this management context.
-   */
-  public ServerManagedObject<RootCfg> getRootConfigurationManagedObject() {
-    return ROOT;
-  }
-
-
-
-  /**
-   * Lists the child managed objects of the named parent managed
-   * object.
-   *
-   * @param <C>
-   *          The type of client managed object configuration that the
-   *          relation definition refers to.
-   * @param <S>
-   *          The type of server managed object configuration that the
-   *          relation definition refers to.
-   * @param parent
-   *          The path of the parent managed object.
-   * @param rd
-   *          The instantiable relation definition.
-   * @return Returns the names of the child managed objects.
-   * @throws IllegalArgumentException
-   *           If the relation definition is not associated with the
-   *           parent managed object's definition.
-   */
-  public <C extends ConfigurationClient, S extends Configuration>
-  String[] listManagedObjects(
-      ManagedObjectPath<?, ?> parent, InstantiableRelationDefinition<C, S> rd)
-      throws IllegalArgumentException {
-    validateRelationDefinition(parent, rd);
-
-    // Get the target entry.
-    DN targetDN = DNBuilder.create(parent, rd);
-    ConfigEntry configEntry;
-    try {
-      configEntry = DirectoryServer.getConfigEntry(targetDN);
-    } catch (ConfigException e) {
-      return new String[0];
-    }
-
-    if (configEntry == null) {
-      return new String[0];
-    }
-
-    // Retrieve the children.
-    Set<DN> children = configEntry.getChildren().keySet();
-    ArrayList<String> names = new ArrayList<String>(children.size());
-    for (DN child : children) {
-      // Assume that RDNs are single-valued and can be trimmed.
-      AttributeValue av = child.getRDN().getAttributeValue(0);
-      names.add(av.getValue().toString().trim());
-    }
-
-    return names.toArray(new String[names.size()]);
-  }
-
-
-
-  /**
-   * Lists the child managed objects of the named parent managed
-   * object.
-   *
-   * @param <C>
-   *          The type of client managed object configuration that the
-   *          relation definition refers to.
-   * @param <S>
-   *          The type of server managed object configuration that the
-   *          relation definition refers to.
-   * @param parent
-   *          The path of the parent managed object.
-   * @param rd
-   *          The set relation definition.
-   * @return Returns the names of the child managed objects.
-   * @throws IllegalArgumentException
-   *           If the relation definition is not associated with the
-   *           parent managed object's definition.
-   */
-  public <C extends ConfigurationClient, S extends Configuration>
-  String[] listManagedObjects(
-      ManagedObjectPath<?, ?> parent, SetRelationDefinition<C, S> rd)
-      throws IllegalArgumentException {
-    validateRelationDefinition(parent, rd);
-
-    // Get the target entry.
-    DN targetDN = DNBuilder.create(parent, rd);
-    ConfigEntry configEntry;
-    try {
-      configEntry = DirectoryServer.getConfigEntry(targetDN);
-    } catch (ConfigException e) {
-      return new String[0];
-    }
-
-    if (configEntry == null) {
-      return new String[0];
-    }
-
-    // Retrieve the children.
-    Set<DN> children = configEntry.getChildren().keySet();
-    ArrayList<String> names = new ArrayList<String>(children.size());
-    for (DN child : children) {
-      // Assume that RDNs are single-valued and can be trimmed.
-      AttributeValue av = child.getRDN().getAttributeValue(0);
-      names.add(av.toString().trim());
-    }
-
-    return names.toArray(new String[names.size()]);
-  }
-
-
-
-  /**
-   * Determines whether or not the named managed object exists.
-   *
-   * @param path
-   *          The path of the named managed object.
-   * @return Returns <code>true</code> if the named managed object
-   *         exists, <code>false</code> otherwise.
-   */
-  public boolean managedObjectExists(ManagedObjectPath<?, ?> path) {
-    // Get the configuration entry.
-    DN targetDN = DNBuilder.create(path);
-    try {
-      return (getManagedObjectConfigEntry(targetDN) != null);
-    } catch (ConfigException e) {
-      // Assume it doesn't exist.
-      return false;
-    }
-  }
-
-
-
-  /**
-   * Decodes a configuration entry into the required type of server
-   * managed object.
-   *
-   * @param <C>
-   *          The type of client managed object configuration that the
-   *          path definition refers to.
-   * @param <S>
-   *          The type of server managed object configuration that the
-   *          path definition refers to.
-   * @param path
-   *          The location of the server managed object.
-   * @param configEntry
-   *          The configuration entry that should be decoded.
-   * @return Returns the new server-side managed object from the
-   *         provided definition and configuration entry.
-   * @throws DefinitionDecodingException
-   *           If the managed object's type could not be determined.
-   * @throws ServerManagedObjectDecodingException
-   *           If one or more of the managed object's properties could
-   *           not be decoded.
-   */
-  <C extends ConfigurationClient, S extends Configuration>
-  ServerManagedObject<? extends S> decode(
-      ManagedObjectPath<C, S> path, ConfigEntry configEntry)
-      throws DefinitionDecodingException, ServerManagedObjectDecodingException {
-    return decode(path, configEntry, null);
-  }
-
-
-
-  /**
-   * Decodes a configuration entry into the required type of server
-   * managed object.
-   *
-   * @param <C>
-   *          The type of client managed object configuration that the
-   *          path definition refers to.
-   * @param <S>
-   *          The type of server managed object configuration that the
-   *          path definition refers to.
-   * @param path
-   *          The location of the server managed object.
-   * @param configEntry
-   *          The configuration entry that should be decoded.
-   * @param newConfigEntry
-   *          Optional new configuration that does not exist yet in
-   *          the configuration back-end. This will be used for
-   *          resolving inherited default values.
-   * @return Returns the new server-side managed object from the
-   *         provided definition and configuration entry.
-   * @throws DefinitionDecodingException
-   *           If the managed object's type could not be determined.
-   * @throws ServerManagedObjectDecodingException
-   *           If one or more of the managed object's properties could
-   *           not be decoded.
-   */
-  <C extends ConfigurationClient, S extends Configuration>
-  ServerManagedObject<? extends S> decode(
-      ManagedObjectPath<C, S> path, ConfigEntry configEntry,
-      ConfigEntry newConfigEntry) throws DefinitionDecodingException,
-      ServerManagedObjectDecodingException {
-    // First determine the correct definition to use for the entry.
-    // This could either be the provided definition, or one of its
-    // sub-definitions.
-    DefinitionResolver resolver = new MyDefinitionResolver(configEntry);
-    AbstractManagedObjectDefinition<C, S> d = path.getManagedObjectDefinition();
-    ManagedObjectDefinition<? extends C, ? extends S> mod = d
-        .resolveManagedObjectDefinition(resolver);
-
-    // Build the managed object's properties.
-    List<PropertyException> exceptions = new LinkedList<PropertyException>();
-    Map<PropertyDefinition<?>, SortedSet<?>> properties =
-      new HashMap<PropertyDefinition<?>, SortedSet<?>>();
-    for (PropertyDefinition<?> pd : mod.getAllPropertyDefinitions()) {
-      List<AttributeValue> values = getAttribute(mod, pd, configEntry);
-      try {
-        SortedSet<?> pvalues = decodeProperty(path, pd, values, newConfigEntry);
-        properties.put(pd, pvalues);
-      } catch (PropertyException e) {
-        exceptions.add(e);
-      }
-    }
-
-    // If there were no decoding problems then return the managed
-    // object, otherwise throw an operations exception.
-    ServerManagedObject<? extends S> mo = decodeAux(path, mod, properties,
-        configEntry);
-    if (exceptions.isEmpty()) {
-      return mo;
-    } else {
-      throw new ServerManagedObjectDecodingException(mo, exceptions);
-    }
-  }
-
-
-
-  // Decode helper method required to avoid generics warning.
-  private <C extends ConfigurationClient, S extends Configuration>
-  ServerManagedObject<S> decodeAux(
-      ManagedObjectPath<? super C, ? super S> path,
-      ManagedObjectDefinition<C, S> d,
-      Map<PropertyDefinition<?>, SortedSet<?>> properties,
-      ConfigEntry configEntry) {
-    ManagedObjectPath<C, S> newPath = path.asSubType(d);
-    return new ServerManagedObject<S>(newPath, d, properties, configEntry);
-  }
-
-
-
-  // Create a property using the provided string values.
-  private <T> SortedSet<T> decodeProperty(ManagedObjectPath<?, ?> path,
-      PropertyDefinition<T> pd, List<AttributeValue> values,
-      ConfigEntry newConfigEntry) throws PropertyException {
-    PropertyException exception = null;
-    SortedSet<T> pvalues = new TreeSet<T>(pd);
-
-    if (!values.isEmpty()) {
-      // The property has values defined for it.
-      for (AttributeValue value : values) {
+        // Get the target entry.
+        DN targetDN = DNBuilder.create(parent, rd);
+        ConfigEntry configEntry;
         try {
-          pvalues.add(ValueDecoder.decode(pd, value));
-        } catch (IllegalPropertyValueStringException e) {
-          exception = e;
+            configEntry = DirectoryServer.getConfigEntry(targetDN);
+        } catch (ConfigException e) {
+            return new String[0];
         }
-      }
-    } else {
-      // No values defined so get the defaults.
-      try {
-        pvalues.addAll(getDefaultValues(path, pd, newConfigEntry));
-      } catch (DefaultBehaviorException e) {
-        exception = e;
-      }
+
+        if (configEntry == null) {
+            return new String[0];
+        }
+
+        // Retrieve the children.
+        Set<DN> children = configEntry.getChildren().keySet();
+        ArrayList<String> names = new ArrayList<String>(children.size());
+        for (DN child : children) {
+            // Assume that RDNs are single-valued and can be trimmed.
+            AttributeValue av = child.rdn().getAttributeValue(0);
+            names.add(av.getValue().toString().trim());
+        }
+
+        return names.toArray(new String[names.size()]);
     }
 
-    if (pvalues.size() > 1 && !pd.hasOption(PropertyOption.MULTI_VALUED)) {
-      // This exception takes precedence over previous exceptions.
-      exception = new PropertyIsSingleValuedException(pd);
-      T value = pvalues.first();
-      pvalues.clear();
-      pvalues.add(value);
+    /**
+     * Lists the child managed objects of the named parent managed object.
+     *
+     * @param <C>
+     *            The type of client managed object configuration that the
+     *            relation definition refers to.
+     * @param <S>
+     *            The type of server managed object configuration that the
+     *            relation definition refers to.
+     * @param parent
+     *            The path of the parent managed object.
+     * @param rd
+     *            The set relation definition.
+     * @return Returns the names of the child managed objects.
+     * @throws IllegalArgumentException
+     *             If the relation definition is not associated with the parent
+     *             managed object's definition.
+     */
+    public <C extends ConfigurationClient, S extends Configuration> String[] listManagedObjects(
+            ManagedObjectPath<?, ?> parent, SetRelationDefinition<C, S> rd) throws IllegalArgumentException {
+        validateRelationDefinition(parent, rd);
+
+        // Get the target entry.
+        DN targetDN = DNBuilder.create(parent, rd);
+        ConfigEntry configEntry;
+        try {
+            configEntry = DirectoryServer.getConfigEntry(targetDN);
+        } catch (ConfigException e) {
+            return new String[0];
+        }
+
+        if (configEntry == null) {
+            return new String[0];
+        }
+
+        // Retrieve the children.
+        Set<DN> children = configEntry.getChildren().keySet();
+        ArrayList<String> names = new ArrayList<String>(children.size());
+        for (DN child : children) {
+            // Assume that RDNs are single-valued and can be trimmed.
+            AttributeValue av = child.rdn().getAttributeValue(0);
+            names.add(av.toString().trim());
+        }
+
+        return names.toArray(new String[names.size()]);
     }
 
-    if (pvalues.isEmpty() && pd.hasOption(PropertyOption.MANDATORY)) {
-      // The values maybe empty because of a previous exception.
-      if (exception == null) {
-        exception = new PropertyIsMandatoryException(pd);
-      }
+    /**
+     * Determines whether or not the named managed object exists.
+     *
+     * @param path
+     *            The path of the named managed object.
+     * @return Returns <code>true</code> if the named managed object exists,
+     *         <code>false</code> otherwise.
+     */
+    public boolean managedObjectExists(ManagedObjectPath<?, ?> path) {
+        // Get the configuration entry.
+        DN targetDN = DNBuilder.create(path);
+        try {
+            return (getManagedObjectConfigEntry(targetDN) != null);
+        } catch (ConfigException e) {
+            // Assume it doesn't exist.
+            return false;
+        }
     }
 
-    if (exception != null) {
-      throw exception;
-    } else {
-      return pvalues;
-    }
-  }
-
-
-
-  // Gets the attribute associated with a property from a ConfigEntry.
-  private List<AttributeValue> getAttribute(ManagedObjectDefinition<?, ?> d,
-      PropertyDefinition<?> pd, ConfigEntry configEntry) {
-    // TODO: we create a default attribute type if it is
-    // undefined. We should log a warning here if this is the case
-    // since the attribute should have been defined.
-    String attrID = LDAPProfile.getInstance().getAttributeName(d, pd);
-    AttributeType type = DirectoryServer.getAttributeType(attrID, true);
-    AttributeValueDecoder<AttributeValue> decoder =
-      new AttributeValueDecoder<AttributeValue>() {
-
-      public AttributeValue decode(AttributeValue value)
-          throws DirectoryException {
-        return value;
-      }
-    };
-
-    List<AttributeValue> values = new LinkedList<AttributeValue>();
-    try {
-      configEntry.getEntry().getAttributeValues(type, decoder, values);
-    } catch (DirectoryException e) {
-      // Should not happen.
-      throw new RuntimeException(e);
-    }
-    return values;
-  }
-
-
-
-  // Get the default values for the specified property.
-  private <T> Collection<T> getDefaultValues(ManagedObjectPath<?, ?> p,
-      PropertyDefinition<T> pd, ConfigEntry newConfigEntry)
-      throws DefaultBehaviorException {
-    DefaultValueFinder<T> v = new DefaultValueFinder<T>(newConfigEntry);
-    return v.find(p, pd);
-  }
-
-
-
-  // Gets a config entry required for a managed object and throws a
-  // config exception on failure.
-  private ConfigEntry getManagedObjectConfigEntry(
-      DN dn) throws ConfigException {
-    ConfigEntry configEntry;
-    try {
-      configEntry = DirectoryServer.getConfigEntry(dn);
-    } catch (ConfigException e) {
-      if (debugEnabled()) {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-
-      LocalizableMessage message = ERR_ADMIN_CANNOT_GET_MANAGED_OBJECT.get(
-          String.valueOf(dn), stackTraceToSingleLineString(e));
-      throw new ConfigException(message, e);
+    /**
+     * Decodes a configuration entry into the required type of server managed
+     * object.
+     *
+     * @param <C>
+     *            The type of client managed object configuration that the path
+     *            definition refers to.
+     * @param <S>
+     *            The type of server managed object configuration that the path
+     *            definition refers to.
+     * @param path
+     *            The location of the server managed object.
+     * @param configEntry
+     *            The configuration entry that should be decoded.
+     * @return Returns the new server-side managed object from the provided
+     *         definition and configuration entry.
+     * @throws DefinitionDecodingException
+     *             If the managed object's type could not be determined.
+     * @throws ServerManagedObjectDecodingException
+     *             If one or more of the managed object's properties could not
+     *             be decoded.
+     */
+    <C extends ConfigurationClient, S extends Configuration> ServerManagedObject<? extends S> decode(
+            ManagedObjectPath<C, S> path, ConfigEntry configEntry) throws DefinitionDecodingException,
+            ServerManagedObjectDecodingException {
+        return decode(path, configEntry, null);
     }
 
-    // The configuration handler is free to return null indicating
-    // that the entry does not exist.
-    if (configEntry == null) {
-      LocalizableMessage message = ERR_ADMIN_MANAGED_OBJECT_DOES_NOT_EXIST
-          .get(String.valueOf(dn));
-      throw new ConfigException(message);
+    /**
+     * Decodes a configuration entry into the required type of server managed
+     * object.
+     *
+     * @param <C>
+     *            The type of client managed object configuration that the path
+     *            definition refers to.
+     * @param <S>
+     *            The type of server managed object configuration that the path
+     *            definition refers to.
+     * @param path
+     *            The location of the server managed object.
+     * @param configEntry
+     *            The configuration entry that should be decoded.
+     * @param newConfigEntry
+     *            Optional new configuration that does not exist yet in the
+     *            configuration back-end. This will be used for resolving
+     *            inherited default values.
+     * @return Returns the new server-side managed object from the provided
+     *         definition and configuration entry.
+     * @throws DefinitionDecodingException
+     *             If the managed object's type could not be determined.
+     * @throws ServerManagedObjectDecodingException
+     *             If one or more of the managed object's properties could not
+     *             be decoded.
+     */
+    <C extends ConfigurationClient, S extends Configuration> ServerManagedObject<? extends S> decode(
+            ManagedObjectPath<C, S> path, ConfigEntry configEntry, ConfigEntry newConfigEntry)
+            throws DefinitionDecodingException, ServerManagedObjectDecodingException {
+        // First determine the correct definition to use for the entry.
+        // This could either be the provided definition, or one of its
+        // sub-definitions.
+        DefinitionResolver resolver = new MyDefinitionResolver(configEntry);
+        AbstractManagedObjectDefinition<C, S> d = path.getManagedObjectDefinition();
+        ManagedObjectDefinition<? extends C, ? extends S> mod = d.resolveManagedObjectDefinition(resolver);
+
+        // Build the managed object's properties.
+        List<PropertyException> exceptions = new LinkedList<PropertyException>();
+        Map<PropertyDefinition<?>, SortedSet<?>> properties = new HashMap<PropertyDefinition<?>, SortedSet<?>>();
+        for (PropertyDefinition<?> pd : mod.getAllPropertyDefinitions()) {
+            List<AttributeValue> values = getAttribute(mod, pd, configEntry);
+            try {
+                SortedSet<?> pvalues = decodeProperty(path, pd, values, newConfigEntry);
+                properties.put(pd, pvalues);
+            } catch (PropertyException e) {
+                exceptions.add(e);
+            }
+        }
+
+        // If there were no decoding problems then return the managed
+        // object, otherwise throw an operations exception.
+        ServerManagedObject<? extends S> mo = decodeAux(path, mod, properties, configEntry);
+        if (exceptions.isEmpty()) {
+            return mo;
+        } else {
+            throw new ServerManagedObjectDecodingException(mo, exceptions);
+        }
     }
 
-    return configEntry;
-  }
-
-
-
-  // Validate that a relation definition belongs to the path.
-  private void validateRelationDefinition(ManagedObjectPath<?, ?> path,
-      RelationDefinition<?, ?> rd) throws IllegalArgumentException {
-    AbstractManagedObjectDefinition<?, ?> d = path.getManagedObjectDefinition();
-    RelationDefinition<?, ?> tmp = d.getRelationDefinition(rd.getName());
-    if (tmp != rd) {
-      throw new IllegalArgumentException("The relation " + rd.getName()
-          + " is not associated with a " + d.getName());
+    // Decode helper method required to avoid generics warning.
+    private <C extends ConfigurationClient, S extends Configuration> ServerManagedObject<S> decodeAux(
+            ManagedObjectPath<? super C, ? super S> path, ManagedObjectDefinition<C, S> d,
+            Map<PropertyDefinition<?>, SortedSet<?>> properties, ConfigEntry configEntry) {
+        ManagedObjectPath<C, S> newPath = path.asSubType(d);
+        return new ServerManagedObject<S>(newPath, d, properties, configEntry);
     }
-  }
+
+    // Create a property using the provided string values.
+    private <T> SortedSet<T> decodeProperty(ManagedObjectPath<?, ?> path, PropertyDefinition<T> pd,
+            List<AttributeValue> values, ConfigEntry newConfigEntry) throws PropertyException {
+        PropertyException exception = null;
+        SortedSet<T> pvalues = new TreeSet<T>(pd);
+
+        if (!values.isEmpty()) {
+            // The property has values defined for it.
+            for (AttributeValue value : values) {
+                try {
+                    pvalues.add(ValueDecoder.decode(pd, value));
+                } catch (IllegalPropertyValueStringException e) {
+                    exception = e;
+                }
+            }
+        } else {
+            // No values defined so get the defaults.
+            try {
+                pvalues.addAll(getDefaultValues(path, pd, newConfigEntry));
+            } catch (DefaultBehaviorException e) {
+                exception = e;
+            }
+        }
+
+        if (pvalues.size() > 1 && !pd.hasOption(PropertyOption.MULTI_VALUED)) {
+            // This exception takes precedence over previous exceptions.
+            exception = new PropertyIsSingleValuedException(pd);
+            T value = pvalues.first();
+            pvalues.clear();
+            pvalues.add(value);
+        }
+
+        if (pvalues.isEmpty() && pd.hasOption(PropertyOption.MANDATORY)) {
+            // The values maybe empty because of a previous exception.
+            if (exception == null) {
+                exception = new PropertyIsMandatoryException(pd);
+            }
+        }
+
+        if (exception != null) {
+            throw exception;
+        } else {
+            return pvalues;
+        }
+    }
+
+    // Gets the attribute associated with a property from a ConfigEntry.
+    private List<AttributeValue> getAttribute(ManagedObjectDefinition<?, ?> d, PropertyDefinition<?> pd,
+            ConfigEntry configEntry) {
+        // TODO: we create a default attribute type if it is
+        // undefined. We should log a warning here if this is the case
+        // since the attribute should have been defined.
+        String attrID = LDAPProfile.getInstance().getAttributeName(d, pd);
+        AttributeType type = DirectoryServer.getAttributeType(attrID, true);
+        AttributeValueDecoder<AttributeValue> decoder = new AttributeValueDecoder<AttributeValue>() {
+
+            public AttributeValue decode(AttributeValue value) throws DirectoryException {
+                return value;
+            }
+        };
+
+        List<AttributeValue> values = new LinkedList<AttributeValue>();
+        try {
+            configEntry.getEntry().getAttributeValues(type, decoder, values);
+        } catch (DirectoryException e) {
+            // Should not happen.
+            throw new RuntimeException(e);
+        }
+        return values;
+    }
+
+    // Get the default values for the specified property.
+    private <T> Collection<T> getDefaultValues(ManagedObjectPath<?, ?> p, PropertyDefinition<T> pd,
+            ConfigEntry newConfigEntry) throws DefaultBehaviorException {
+        DefaultValueFinder<T> v = new DefaultValueFinder<T>(newConfigEntry);
+        return v.find(p, pd);
+    }
+
+    // Gets a config entry required for a managed object and throws a
+    // config exception on failure.
+    private ConfigEntry getManagedObjectConfigEntry(DN dn) throws ConfigException {
+        ConfigEntry configEntry;
+        try {
+            configEntry = DirectoryServer.getConfigEntry(dn);
+        } catch (ConfigException e) {
+            if (debugEnabled()) {
+                TRACER.debugCaught(DebugLogLevel.ERROR, e);
+            }
+
+            LocalizableMessage message = ERR_ADMIN_CANNOT_GET_MANAGED_OBJECT.get(String.valueOf(dn),
+                    stackTraceToSingleLineString(e));
+            throw new ConfigException(message, e);
+        }
+
+        // The configuration handler is free to return null indicating
+        // that the entry does not exist.
+        if (configEntry == null) {
+            LocalizableMessage message = ERR_ADMIN_MANAGED_OBJECT_DOES_NOT_EXIST.get(String.valueOf(dn));
+            throw new ConfigException(message);
+        }
+
+        return configEntry;
+    }
+
+    // Validate that a relation definition belongs to the path.
+    private void validateRelationDefinition(ManagedObjectPath<?, ?> path, RelationDefinition<?, ?> rd)
+            throws IllegalArgumentException {
+        AbstractManagedObjectDefinition<?, ?> d = path.getManagedObjectDefinition();
+        RelationDefinition<?, ?> tmp = d.getRelationDefinition(rd.getName());
+        if (tmp != rd) {
+            throw new IllegalArgumentException("The relation " + rd.getName() + " is not associated with a "
+                    + d.getName());
+        }
+    }
 }

--
Gitblit v1.10.0