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

matthew_swift
14.22.2007 5d6e9428fedead57a9c9438cebe58b485ff476d2
Avoid managed object definition initialization dependency problems. Using features like inherited default values and aggregation properties it is quite straightforward to encounter initialization dependency problems. For example: the global configuration will contain an aggregation property which references the default password policy. This aggregation definition is defined using a managed object path which, when decoded, contains a reference to the root configuration and its "password-policy" relation. This is what happens during initialization of the root configuration:

1) load the root configuration definition class and start constructing and registering its relation definitions

2) initialize the global configuration relation definition. This forces the JVM to load the global configuration definition

3) the global configuration contains an aggregation property definition which references a default password policy. Password policies are contained in the "password-policy" relation of the root configuration. Since the aggregation property definition references the password policy via a managed object path, decoding the path forces the root configuration definition to be loaded and its "password-policy" relation definition to be retrieved

4) the lookup of the "password-policy" relation definition fails because the root configuration has not finished initializing and the relation has not been constructed yet.

The fix is to "delay" decoding of inter-component references such as these until all the associated classes are loaded and initialized. To that end, property definitions and their default behaviors now have a new method called "initialize()". In addition, each property definition and default behavior has been modified so that any managed object paths and property definitions that they depend upon are not decoded during construction. This is now performed by the initialize() method.

The admin framework class loader provider has been modified so that it now performs this two-phase initialization:

1) load and instantiate each managed object definition class, forcing all property definitions and relation definitions to be constructed and registered

2) initialize each managed object definition instance: the instance invokes initialize() on each of its property definitions and default behaviors. This will force all inter-component references to be decoded and validated.

A positive side-effect of this change is that any inter-component references which have not been specified properly in their XML definition will be flagged during server start-up, rather than on-demand.
16 files modified
541 ■■■■■ changed files
opends/resource/admin/metaMO.xsl 2 ●●● patch | view | raw | blame | history
opends/resource/admin/property-types/aggregation.xsl 13 ●●●● patch | view | raw | blame | history
opends/src/messages/messages/admin.properties 21 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/AbsoluteInheritedDefaultBehaviorProvider.java 43 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/AbstractManagedObjectDefinition.java 17 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/AggregationPropertyDefinition.java 200 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/AliasDefaultBehaviorProvider.java 2 ●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/ClassLoaderProvider.java 116 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/DefaultBehaviorProvider.java 67 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/DefinedDefaultBehaviorProvider.java 2 ●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/PropertyDefinition.java 17 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/RelativeInheritedDefaultBehaviorProvider.java 6 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/UndefinedDefaultBehaviorProvider.java 2 ●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestCfg.java 18 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildCfgDefn.java 5 ●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/AggregationTest.java 10 ●●●●● patch | view | raw | blame | history
opends/resource/admin/metaMO.xsl
@@ -699,7 +699,7 @@
        <xsl:variable name="path"
          select="adm:default-behavior/adm:inherited/adm:absolute/@path" />
        <xsl:value-of
          select="concat('ManagedObjectPath.valueOf(&quot;', $path, '&quot;), &quot;', $property-name, '&quot;);&#xa;')" />
          select="concat('&quot;', $path, '&quot;, &quot;', $property-name, '&quot;);&#xa;')" />
        <xsl:value-of
          select="'      builder.setDefaultBehaviorProvider(provider);&#xa;'" />
      </xsl:when>
opends/resource/admin/property-types/aggregation.xsl
@@ -41,15 +41,9 @@
      <xsl:value-of select="'.server.'" />
      <xsl:call-template name="get-server-type" />
    </xsl:element>
    <xsl:element name="import">
      <xsl:call-template name="get-definition-package" />
      <xsl:value-of select="'.meta.'" />
      <xsl:call-template name="get-definition-type" />
    </xsl:element>
    <xsl:if test="../../@multi-valued = 'true'">
      <import>java.util.TreeSet</import>
    </xsl:if>
    <import>org.opends.server.admin.ManagedObjectPath</import>
    <import>org.opends.server.admin.AggregationPropertyDefinition</import>
  </xsl:template>
  <xsl:template match="adm:aggregation" mode="java-value-type">
@@ -91,14 +85,11 @@
      </xsl:message>
    </xsl:if>
    <xsl:value-of
      select="concat('      builder.setParentPath(ManagedObjectPath.valueOf(&quot;',
                     normalize-space(@parent-path), '&quot;));&#xa;')" />
      select="concat('      builder.setParentPath(&quot;',
                     normalize-space(@parent-path), '&quot;);&#xa;')" />
    <xsl:value-of
      select="concat('      builder.setRelationDefinition(&quot;',
                     normalize-space(@relation-name), '&quot;);&#xa;')" />
    <xsl:value-of select="'      builder.setManagedObjectDefinition('" />
    <xsl:call-template name="get-definition-type" />
    <xsl:value-of select="'.getInstance());&#xa;'" />
    <xsl:if test="@source-enabled-property-name">
      <xsl:value-of
        select="concat('      builder.setSourceEnabledPropertyName(&quot;',
opends/src/messages/messages/admin.properties
@@ -274,4 +274,23 @@
SEVERE_ERR_SERVER_REFINT_CANNOT_DISABLE_118=The %s in entry "%s" \
 cannot be disabled because it is referenced by the "%s" property \
 of the %s in entry "%s"
FATAL_ERR_CANNOT_INITIALIZE_ADMIN_FRAMEWORK_119=The administration \
 framework could not be initialized due to the following exception: %s
SEVERE_ERR_CLASS_LOADER_CANNOT_READ_MANIFEST_FILE_120=An unexpected \
 error occurred while reading the manifest file: %s
SEVERE_ERR_CLASS_LOADER_CANNOT_LOAD_CLASS_121=An error occurred while \
 attempting to load class "%s": %s
SEVERE_ERR_CLASS_LOADER_CANNOT_FIND_GET_INSTANCE_METHOD_122=Unable to \
 to find the getInstance() method in the managed object definition \
 class "%s": %s
SEVERE_ERR_CLASS_LOADER_CANNOT_INVOKE_GET_INSTANCE_METHOD_123=Unable to \
 to invoke the getInstance() method in the managed object definition \
 class "%s": %s
SEVERE_ERR_CLASS_LOADER_CANNOT_INITIALIZE_DEFN_124=Unable initialize the \
 "%s" managed object definition in class "%s": %s
SEVERE_ERR_CLASS_LOADER_CANNOT_LOAD_EXTENSION_125=The extension "%s" \
 with manifest file %s cannot be loaded because an unexpected error \
 occurred while trying to initialize it: %s
FATAL_ERR_CLASS_LOADER_CANNOT_LOAD_CORE_126=The core administration \
 classes could not be loaded from manifest file %s because an unexpected \
 error occurred: %s
opends/src/server/org/opends/server/admin/AbsoluteInheritedDefaultBehaviorProvider.java
@@ -30,18 +30,22 @@
/**
 * A default behavior provider which retrieves default values from a
 * managed object in an abolute location. It should be used by
 * managed object in an absolute location. It should be used by
 * properties which inherit their default value(s) from properties
 * held in an other managed object.
 *
 * @param <T>
 *          The type of values represented by this provider.
 */
public final class AbsoluteInheritedDefaultBehaviorProvider<T> implements
public final class AbsoluteInheritedDefaultBehaviorProvider<T> extends
    DefaultBehaviorProvider<T> {
  // The absolute path to the managed object containing the property.
  private final ManagedObjectPath<?, ?> path;
  private ManagedObjectPath<?, ?> path = null;
  // The string representation of the managed object path specifying
  // the absolute location of the managed object.
  private final String pathString;
  // The name of the property containing the inherited default values.
  private final String propertyName;
@@ -52,24 +56,16 @@
   * Create an absolute inherited default behavior provider associated
   * with the managed object at the specified absolute location.
   *
   * @param path
   *          The absolute location of the managed object.
   * @param pathString
   *          The string representation of the managed object path
   *          specifying the absolute location of the managed object.
   * @param propertyName
   *          The name of the property containing the inherited
   *          default values.
   * @throws IllegalArgumentException
   *           If the named property is associated with the managed
   *           object definition identified by the path.
   * @throws ClassCastException
   *           If the named property does not have the same type of
   *           property values as this default behavior provider.
   */
  @SuppressWarnings("unchecked")
  public AbsoluteInheritedDefaultBehaviorProvider(ManagedObjectPath path,
      String propertyName) throws IllegalArgumentException, ClassCastException {
    // We do not decode the property name now because the property
    // might not have been constructed at this point.
    this.path = path;
  public AbsoluteInheritedDefaultBehaviorProvider(String pathString,
      String propertyName) {
    this.pathString = pathString;
    this.propertyName = propertyName;
  }
@@ -111,7 +107,7 @@
  /**
   * Get the name of the property containing the inherited default
   * Gets the name of the property containing the inherited default
   * values.
   *
   * @return Returns the name of the property containing the inherited
@@ -121,4 +117,15 @@
    return propertyName;
  }
  /**
   * {@inheritDoc}
   */
  @Override
  protected void initialize() throws Exception {
    // Decode the path.
    path = ManagedObjectPath.valueOf(pathString);
  }
}
opends/src/server/org/opends/server/admin/AbstractManagedObjectDefinition.java
@@ -713,6 +713,23 @@
  /**
   * Initializes all of the property definitions associated with this
   * managed object definition.
   *
   * @throws Exception
   *           If this managed object definition could not be
   *           initialized.
   */
  protected final void initialize() throws Exception {
    for (PropertyDefinition<?> pd : getAllPropertyDefinitions()) {
      pd.initialize();
      pd.getDefaultBehaviorProvider().initialize();
    }
  }
  /**
   * Register a constraint with the managed object definition.
   * <p>
   * This method <b>must not</b> be called by applications.
opends/src/server/org/opends/server/admin/AggregationPropertyDefinition.java
@@ -113,12 +113,9 @@
      <C extends ConfigurationClient, S extends Configuration>
      extends AbstractBuilder<String, AggregationPropertyDefinition<C, S>> {
    // The type of referenced managed objects.
    private AbstractManagedObjectDefinition<?, ?> cd = null;
    // The name of the managed object which is the parent of the
    // aggregated managed objects.
    private ManagedObjectPath<?, ?> p = null;
    // The string representation of the managed object path specifying
    // the parent of the aggregated managed objects.
    private String parentPathString = null;
    // The name of a relation in the parent managed object which
    // contains the aggregated managed objects.
@@ -145,35 +142,19 @@
    /**
     * Sets the definition of the type of referenced managed objects.
     * <p>
     * This must be defined before the property definition can be
     * built.
     *
     * @param d
     *          The definition of the type of referenced managed
     *          objects.
     */
    public final void setManagedObjectDefinition(
        AbstractManagedObjectDefinition<C, S> d) {
      this.cd = d;
    }
    /**
     * Sets the name of the managed object which is the parent of the
     * aggregated managed objects.
     * <p>
     * This must be defined before the property definition can be
     * built.
     *
     * @param p
     *          The name of the managed object which is the parent of
     *          the aggregated managed objects.
     * @param pathString
     *          The string representation of the managed object path
     *          specifying the parent of the aggregated managed
     *          objects.
     */
    public final void setParentPath(ManagedObjectPath<?, ?> p) {
      this.p = p;
    public final void setParentPath(String pathString) {
      this.parentPathString = pathString;
    }
@@ -236,14 +217,13 @@
    /**
     * {@inheritDoc}
     */
    @SuppressWarnings("unchecked")
    @Override
    protected AggregationPropertyDefinition<C, S> buildInstance(
        AbstractManagedObjectDefinition<?, ?> d, String propertyName,
        EnumSet<PropertyOption> options, AdministratorAction adminAction,
        DefaultBehaviorProvider<String> defaultBehavior) {
      // Make sure that the parent path has been defined.
      if (p == null) {
      if (parentPathString == null) {
        throw new IllegalStateException("Parent path undefined");
      }
@@ -252,29 +232,6 @@
        throw new IllegalStateException("Relation definition undefined");
      }
      // Make sure that the managed object definition has been
      // defined.
      if (cd == null) {
        throw new IllegalStateException("Managed object definition undefined");
      }
      // Make sure that the relation definition is a member of the
      // parent path's definition.
      AbstractManagedObjectDefinition<?, ?> parent = p
          .getManagedObjectDefinition();
      RelationDefinition<?, ?> rd = parent.getRelationDefinition(rdName);
      // Make sure the relation refers to the child type.
      AbstractManagedObjectDefinition<?, ?> dTmp = rd.getChildDefinition();
      if (dTmp != cd) {
        throw new IllegalStateException("Relation definition \"" + rd.getName()
            + "\" does not refer to definition " + d.getName());
      }
      // Force the relation to the correct type.
      InstantiableRelationDefinition<C, S> relation =
        (InstantiableRelationDefinition<C, S>) rd;
      // Make sure that if a source property is specified then a
      // target property is also specified.
      if (sourceEnabledPropertyName != null
@@ -284,8 +241,8 @@
      }
      return new AggregationPropertyDefinition<C, S>(d, propertyName, options,
          adminAction, defaultBehavior, p, relation, sourceEnabledPropertyName,
          targetEnabledPropertyName);
          adminAction, defaultBehavior, parentPathString, rdName,
          sourceEnabledPropertyName, targetEnabledPropertyName);
    }
  }
@@ -397,6 +354,9 @@
      // isConfigurationDeleteAcceptable() call-back should have
      // trapped this.
      if (configuration.dn().equals(dn)) {
        // This should not happen - the
        // isConfigurationDeleteAcceptable() call-back should have
        // trapped this.
        throw new IllegalStateException("Attempting to delete a referenced "
            + configuration.definition().getUserFriendlyName());
      } else {
@@ -661,20 +621,34 @@
  // The name of the managed object which is the parent of the
  // aggregated managed objects.
  private final ManagedObjectPath<?, ?> parentPath;
  private ManagedObjectPath<?, ?> parentPath;
  // The string representation of the managed object path specifying
  // the parent of the aggregated managed objects.
  private final String parentPathString;
  // The name of a relation in the parent managed object which
  // contains the aggregated managed objects.
  private final String rdName;
  // The relation in the parent managed object which contains the
  // aggregated managed objects.
  private final InstantiableRelationDefinition<C, S> relationDefinition;
  private InstantiableRelationDefinition<C, S> relationDefinition;
  // The optional name of a boolean "enabled" property in this managed
  // object. When this property is true, the enabled property in the
  // aggregated managed object must also be true.
  // The decoded source property definition.
  private BooleanPropertyDefinition sourceEnabledProperty;
  // The optional name of a boolean "enabled" property in this
  // managed object. When this property is true, the enabled
  // property in the aggregated managed object must also be true.
  private final String sourceEnabledPropertyName;
  // The decoded target property definition.
  private BooleanPropertyDefinition targetEnabledProperty;
  // The optional name of a boolean "enabled" property in the
  // aggregated managed object. This property must not be false while
  // the aggregated managed object is referenced.
  // aggregated managed object. This property must not be false
  // while the aggregated managed object is referenced.
  private final String targetEnabledPropertyName;
@@ -683,14 +657,13 @@
  private AggregationPropertyDefinition(
      AbstractManagedObjectDefinition<?, ?> d, String propertyName,
      EnumSet<PropertyOption> options, AdministratorAction adminAction,
      DefaultBehaviorProvider<String> defaultBehavior,
      ManagedObjectPath<?, ?> parentPath,
      InstantiableRelationDefinition<C, S> relationDefinition,
      String sourceEnabledPropertyName, String targetEnabledPropertyName) {
      DefaultBehaviorProvider<String> defaultBehavior, String parentPathString,
      String rdName, String sourceEnabledPropertyName,
      String targetEnabledPropertyName) {
    super(d, String.class, propertyName, options, adminAction, defaultBehavior);
    this.parentPath = parentPath;
    this.relationDefinition = relationDefinition;
    this.parentPathString = parentPathString;
    this.rdName = rdName;
    this.sourceEnabledPropertyName = sourceEnabledPropertyName;
    this.targetEnabledPropertyName = targetEnabledPropertyName;
  }
@@ -821,27 +794,9 @@
   * @return Returns the optional boolean "enabled" property in this
   *         managed object, or <code>null</code> if none is
   *         defined.
   * @throws IllegalArgumentException
   *           If the named property does not exist in this property's
   *           associated managed object definition.
   * @throws ClassCastException
   *           If the named property does exist but is not a
   *           {@link BooleanPropertyDefinition}.
   */
  public final BooleanPropertyDefinition getSourceEnabledPropertyDefinition()
      throws IllegalArgumentException, ClassCastException {
    if (sourceEnabledPropertyName == null) {
      return null;
    }
    AbstractManagedObjectDefinition<?, ?> d = getManagedObjectDefinition();
    PropertyDefinition<?> pd;
    pd = d.getPropertyDefinition(sourceEnabledPropertyName);
    // Runtime cast is required to workaround a
    // bug in JDK versions prior to 1.5.0_08.
    return BooleanPropertyDefinition.class.cast(pd);
  public final BooleanPropertyDefinition getSourceEnabledPropertyDefinition() {
    return sourceEnabledProperty;
  }
@@ -854,28 +809,9 @@
   * @return Returns the optional boolean "enabled" property in the
   *         aggregated managed object, or <code>null</code> if none
   *         is defined.
   * @throws IllegalArgumentException
   *           If the named property does not exist in the aggregated
   *           managed object's definition.
   * @throws ClassCastException
   *           If the named property does exist but is not a
   *           {@link BooleanPropertyDefinition}.
   */
  public final BooleanPropertyDefinition getTargetEnabledPropertyDefinition()
      throws IllegalArgumentException, ClassCastException {
    if (targetEnabledPropertyName == null) {
      return null;
    }
    AbstractManagedObjectDefinition<?, ?> d;
    PropertyDefinition<?> pd;
    d = relationDefinition.getChildDefinition();
    pd = d.getPropertyDefinition(targetEnabledPropertyName);
    // Runtime cast is required to workaround a
    // bug in JDK versions prior to 1.5.0_08.
    return BooleanPropertyDefinition.class.cast(pd);
  public final BooleanPropertyDefinition getTargetEnabledPropertyDefinition() {
    return targetEnabledProperty;
  }
@@ -935,4 +871,50 @@
    }
  }
  /**
   * {@inheritDoc}
   */
  @SuppressWarnings("unchecked")
  @Override
  protected void initialize() throws Exception {
    // Decode the path.
    parentPath = ManagedObjectPath.valueOf(parentPathString);
    // Decode the relation definition.
    AbstractManagedObjectDefinition<?, ?> parent = parentPath
        .getManagedObjectDefinition();
    RelationDefinition<?, ?> rd = parent.getRelationDefinition(rdName);
    relationDefinition = (InstantiableRelationDefinition<C, S>) rd;
    // Now decode the property definitions.
    if (sourceEnabledPropertyName == null) {
      sourceEnabledProperty = null;
    } else {
      AbstractManagedObjectDefinition<?, ?> d = getManagedObjectDefinition();
      PropertyDefinition<?> pd;
      pd = d.getPropertyDefinition(sourceEnabledPropertyName);
      // Runtime cast is required to workaround a
      // bug in JDK versions prior to 1.5.0_08.
      sourceEnabledProperty = BooleanPropertyDefinition.class.cast(pd);
    }
    if (targetEnabledPropertyName == null) {
      targetEnabledProperty = null;
    } else {
      AbstractManagedObjectDefinition<?, ?> d;
      PropertyDefinition<?> pd;
      d = relationDefinition.getChildDefinition();
      pd = d.getPropertyDefinition(targetEnabledPropertyName);
      // Runtime cast is required to workaround a
      // bug in JDK versions prior to 1.5.0_08.
      targetEnabledProperty = BooleanPropertyDefinition.class.cast(pd);
    }
  }
}
opends/src/server/org/opends/server/admin/AliasDefaultBehaviorProvider.java
@@ -42,7 +42,7 @@
 * @param <T>
 *          The type of values represented by this provider.
 */
public final class AliasDefaultBehaviorProvider<T> implements
public final class AliasDefaultBehaviorProvider<T> extends
    DefaultBehaviorProvider<T> {
  // The managed object definition associated with this default
opends/src/server/org/opends/server/admin/ClassLoaderProvider.java
@@ -25,15 +25,13 @@
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import org.opends.messages.Message;
import static org.opends.server.loggers.ErrorLogger.logError;
import static org.opends.server.loggers.debug.DebugLogger.*;
import org.opends.server.loggers.debug.DebugTracer;
import static org.opends.messages.AdminMessages.*;
import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString;
import static org.opends.server.loggers.ErrorLogger.*;
import static org.opends.server.loggers.debug.DebugLogger.*;
import static org.opends.server.util.StaticUtils.*;
import java.io.BufferedReader;
import java.io.File;
@@ -41,6 +39,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
@@ -52,8 +51,10 @@
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import org.opends.messages.Message;
import org.opends.server.admin.std.meta.RootCfgDefn;
import org.opends.server.core.DirectoryServer;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.types.DebugLogLevel;
import org.opends.server.types.InitializationException;
import org.opends.server.util.Validator;
@@ -474,21 +475,13 @@
    try {
      loadDefinitionClasses(is);
    } catch (IOException e) {
    } catch (InitializationException e) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      Message message = ERR_ADMIN_CANNOT_READ_CORE_MANIFEST.get(
          CORE_MANIFEST, stackTraceToSingleLineString(e));
      throw new InitializationException(message);
    } catch (Exception e) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      Message message = ERR_ADMIN_CANNOT_LOAD_CLASS_FROM_CORE_MANIFEST.get(
          CORE_MANIFEST, stackTraceToSingleLineString(e));
      Message message = ERR_CLASS_LOADER_CANNOT_LOAD_CORE.get(CORE_MANIFEST,
          stackTraceToSingleLineString(e));
      throw new InitializationException(message);
    }
  }
@@ -519,31 +512,21 @@
          TRACER.debugCaught(DebugLogLevel.ERROR, e);
        }
        Message message = ERR_ADMIN_CANNOT_READ_EXTENSION_MANIFEST.
            get(EXTENSION_MANIFEST, jarFile.getName(),
        Message message = ERR_ADMIN_CANNOT_READ_EXTENSION_MANIFEST.get(
            EXTENSION_MANIFEST, jarFile.getName(),
                stackTraceToSingleLineString(e));
        throw new InitializationException(message);
      }
      try {
        loadDefinitionClasses(is);
      } catch (IOException e) {
      } catch (InitializationException e) {
        if (debugEnabled()) {
          TRACER.debugCaught(DebugLogLevel.ERROR, e);
        }
        Message message = ERR_ADMIN_CANNOT_READ_EXTENSION_MANIFEST.
            get(EXTENSION_MANIFEST, jarFile.getName(),
                stackTraceToSingleLineString(e));
        throw new InitializationException(message);
      } catch (Exception e) {
        if (debugEnabled()) {
          TRACER.debugCaught(DebugLogLevel.ERROR, e);
        }
        Message message = ERR_ADMIN_CANNOT_LOAD_CLASS_FROM_EXTENSION_MANIFEST.
            get(EXTENSION_MANIFEST, jarFile.getName(),
                stackTraceToSingleLineString(e));
        Message message = ERR_CLASS_LOADER_CANNOT_LOAD_EXTENSION.get(jarFile
            .getName(), EXTENSION_MANIFEST, stackTraceToSingleLineString(e));
        throw new InitializationException(message);
      }
    }
@@ -557,24 +540,25 @@
   *
   * @param is
   *          The manifest file input stream.
   * @throws IOException
   *           If an IO error occurred whilst reading the manifest
   *           file.
   * @throws ClassNotFoundException
   *           If an IO error occurred whilst reading the manifest
   *           file.
   * @throws LinkageError
   *           If the linkage fails.
   * @throws ExceptionInInitializerError
   *           If the initialization provoked by this method fails.
   * @throws InitializationException
   *           If the definition classes could not be loaded and
   *           initialized.
   */
  private void loadDefinitionClasses(InputStream is)
      throws IOException, ClassNotFoundException, LinkageError,
      ExceptionInInitializerError {
      throws InitializationException {
    BufferedReader reader = new BufferedReader(new InputStreamReader(
        is));
    List<AbstractManagedObjectDefinition<?, ?>> definitions =
      new LinkedList<AbstractManagedObjectDefinition<?,?>>();
    while (true) {
      String className = reader.readLine();
      String className;
      try {
        className = reader.readLine();
      } catch (IOException e) {
        Message msg = ERR_CLASS_LOADER_CANNOT_READ_MANIFEST_FILE.get(String
            .valueOf(e.getMessage()));
        throw new InitializationException(msg, e);
      }
      // Break out when the end of the manifest is reached.
      if (className == null) {
@@ -594,8 +578,48 @@
      TRACER.debugMessage(DebugLogLevel.INFO, "Loading class " + className);
      // Use the underlying loader.
      Class.forName(className, true, loader);
      // Load the class and get an instance of it if it is a definition.
      Class<?> theClass;
      try {
        theClass = Class.forName(className, true, loader);
      } catch (Exception e) {
        Message msg = ERR_CLASS_LOADER_CANNOT_LOAD_CLASS.get(className, String
            .valueOf(e.getMessage()));
        throw new InitializationException(msg, e);
      }
      if (AbstractManagedObjectDefinition.class.isAssignableFrom(theClass)) {
        // We need to instantiate it using its getInstance() static method.
        Method method;
        try {
          method = theClass.getMethod("getInstance");
        } catch (Exception e) {
          Message msg = ERR_CLASS_LOADER_CANNOT_FIND_GET_INSTANCE_METHOD.get(
              className, String.valueOf(e.getMessage()));
          throw new InitializationException(msg, e);
        }
        // Get the definition instance.
        AbstractManagedObjectDefinition<?, ?> d;
        try {
          d = (AbstractManagedObjectDefinition<?, ?>) method.invoke(null);
        } catch (Exception e) {
          Message msg = ERR_CLASS_LOADER_CANNOT_INVOKE_GET_INSTANCE_METHOD.get(
              className, String.valueOf(e.getMessage()));
          throw new InitializationException(msg, e);
        }
        definitions.add(d);
      }
    }
    // Initialize any definitions that were loaded.
    for (AbstractManagedObjectDefinition<?, ?> d : definitions) {
      try {
        d.initialize();
      } catch (Exception e) {
        Message msg = ERR_CLASS_LOADER_CANNOT_INITIALIZE_DEFN.get(d.getName(),
            d.getClass().getName(), String.valueOf(e.getMessage()));
        throw new InitializationException(msg, e);
      }
    }
  }
opends/src/server/org/opends/server/admin/DefaultBehaviorProvider.java
@@ -29,31 +29,43 @@
/**
 * An interface for determining the default behavior of a property. A property
 * exhibits default behavior when it has no values defined. There are four
 * different types of default behavior:
 * An interface for determining the default behavior of a property. A
 * property exhibits default behavior when it has no values defined.
 * There are four different types of default behavior:
 * <ol>
 * <li>there is no default behavior - e.g. leaving a "description" unset has
 * no side-effects. This default behavior is represented using the
 * {@link UndefinedDefaultBehaviorProvider} implementation
 * <li>the property defaults to one or more real values of the property. This
 * default behavior is represented using the
 * <li>there is no default behavior - e.g. leaving a "description"
 * unset has no side-effects. This default behavior is represented
 * using the {@link UndefinedDefaultBehaviorProvider} implementation
 * <li>the property defaults to one or more real values of the
 * property. This default behavior is represented using the
 * {@link DefinedDefaultBehaviorProvider} implementation
 * <li>the property defaults to some special behavior that cannot be
 * represented using real property values. This default behavior is represented
 * using the {@link AliasDefaultBehaviorProvider} implementation
 * <li>the property inherits its values from property held in another managed
 * object (e.g. the parent managed object). This default behavior is
 * represented using the {@link AbsoluteInheritedDefaultBehaviorProvider} and
 * represented using real property values. This default behavior is
 * represented using the {@link AliasDefaultBehaviorProvider}
 * implementation
 * <li>the property inherits its values from property held in another
 * managed object (e.g. the parent managed object). This default
 * behavior is represented using the
 * {@link AbsoluteInheritedDefaultBehaviorProvider} and
 * {@link RelativeInheritedDefaultBehaviorProvider} implementations.
 * </ol>
 * An application can perform actions based on the type of the default behavior
 * by implementing the {@link DefaultBehaviorProviderVisitor} interface.
 * An application can perform actions based on the type of the default
 * behavior by implementing the {@link DefaultBehaviorProviderVisitor}
 * interface.
 *
 * @param <T>
 *          The type of values represented by this provider.
 */
public interface DefaultBehaviorProvider<T> {
public abstract class DefaultBehaviorProvider<T> {
  /**
   * Creates a new default behavior provider.
   */
  protected DefaultBehaviorProvider() {
    // No implementation required.
  }
  /**
   * Apply a visitor to this default behavior provider.
@@ -61,13 +73,32 @@
   * @param <R>
   *          The return type of the visitor's methods.
   * @param <P>
   *          The type of the additional parameters to the visitor's methods.
   *          The type of the additional parameters to the visitor's
   *          methods.
   * @param v
   *          The default behavior visitor.
   * @param p
   *          Optional additional visitor parameter.
   * @return Returns a result as specified by the visitor.
   */
  <R, P> R accept(DefaultBehaviorProviderVisitor<T, R, P> v, P p);
  public abstract <R, P>
  R accept(DefaultBehaviorProviderVisitor<T, R, P> v, P p);
  /**
   * Performs any run-time initialization required by this default
   * behavior provider. This may include resolving managed object
   * paths and property names.
   * <p>
   * The default implementation is to do nothing.
   *
   * @throws Exception
   *           If this default behavior provider could not be
   *           initialized.
   */
  protected void initialize() throws Exception {
    // Default implementation is to do nothing.
  }
}
opends/src/server/org/opends/server/admin/DefinedDefaultBehaviorProvider.java
@@ -42,7 +42,7 @@
 * @param <T>
 *          The type of values represented by this provider.
 */
public final class DefinedDefaultBehaviorProvider<T> implements
public final class DefinedDefaultBehaviorProvider<T> extends
    DefaultBehaviorProvider<T> {
  // The collection of default values.
opends/src/server/org/opends/server/admin/PropertyDefinition.java
@@ -26,7 +26,6 @@
 */
package org.opends.server.admin;
import org.opends.messages.Message;
@@ -38,6 +37,8 @@
import java.util.MissingResourceException;
import java.util.Set;
import org.opends.messages.Message;
/**
@@ -661,4 +662,18 @@
   */
  public abstract void validateValue(T value)
      throws IllegalPropertyValueException;
  /**
   * Performs any run-time initialization required by this property
   * definition. This may include resolving managed object paths and
   * property names.
   *
   * @throws Exception
   *           If this property definition could not be initialized.
   */
  protected void initialize() throws Exception {
    // No implementation required.
  }
}
opends/src/server/org/opends/server/admin/RelativeInheritedDefaultBehaviorProvider.java
@@ -37,7 +37,7 @@
 * @param <T>
 *          The type of values represented by this provider.
 */
public final class RelativeInheritedDefaultBehaviorProvider<T> implements
public final class RelativeInheritedDefaultBehaviorProvider<T> extends
    DefaultBehaviorProvider<T> {
  // The type of managed object expected at the relative offset.
@@ -69,7 +69,6 @@
   * @throws IllegalArgumentException
   *           If the offset is less than 0.
   */
  @SuppressWarnings("unchecked")
  public RelativeInheritedDefaultBehaviorProvider(
      AbstractManagedObjectDefinition<?, ?> d, String propertyName, int offset)
      throws IllegalArgumentException {
@@ -126,7 +125,7 @@
  /**
   * Get the name of the property containing the inherited default
   * Gets the name of the property containing the inherited default
   * values.
   *
   * @return Returns the name of the property containing the inherited
@@ -148,5 +147,4 @@
  public int getRelativeOffset() {
    return offset;
  }
}
opends/src/server/org/opends/server/admin/UndefinedDefaultBehaviorProvider.java
@@ -37,7 +37,7 @@
 * @param <T>
 *          The type of values represented by this provider.
 */
public final class UndefinedDefaultBehaviorProvider<T> implements
public final class UndefinedDefaultBehaviorProvider<T> extends
    DefaultBehaviorProvider<T> {
  /**
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestCfg.java
@@ -127,6 +127,7 @@
      // Register the test parent resource bundle.
      TestParentCfgDefn d = TestParentCfgDefn.getInstance();
      d.initialize();
      String baseName = d.getClass().getName();
      ResourceBundle resourceBundle = ResourceBundle.getBundle(baseName);
      ManagedObjectDefinitionI18NResource.getInstance().setResourceBundle(d,
@@ -139,6 +140,7 @@
      // Register the test child resource bundle.
      TestChildCfgDefn d = TestChildCfgDefn.getInstance();
      d.initialize();
      String baseName = d.getClass().getName();
      ResourceBundle resourceBundle = ResourceBundle.getBundle(baseName);
      ManagedObjectDefinitionI18NResource.getInstance().setResourceBundle(d,
@@ -216,6 +218,22 @@
  /**
   * Initializes a property definition and its default behavior.
   *
   * @param pd
   *          The property definition to be initialized.
   * @throws Exception
   *           If the property definition could not be initialized.
   */
  public static void initializePropertyDefinition(PropertyDefinition<?> pd)
      throws Exception {
    pd.initialize();
    pd.getDefaultBehaviorProvider().initialize();
  }
  /**
   * Adds a constraint temporarily with test child definition.
   *
   * @param constraint
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/TestChildCfgDefn.java
@@ -39,7 +39,6 @@
import org.opends.server.admin.DefinedDefaultBehaviorProvider;
import org.opends.server.admin.ManagedObjectAlreadyExistsException;
import org.opends.server.admin.ManagedObjectDefinition;
import org.opends.server.admin.ManagedObjectPath;
import org.opends.server.admin.PropertyIsReadOnlyException;
import org.opends.server.admin.PropertyOption;
import org.opends.server.admin.PropertyProvider;
@@ -53,7 +52,6 @@
import org.opends.server.admin.client.MissingMandatoryPropertiesException;
import org.opends.server.admin.client.OperationRejectedException;
import org.opends.server.admin.TestChildCfgClient;
import org.opends.server.admin.std.meta.ConnectionHandlerCfgDefn;
import org.opends.server.admin.server.ConfigurationChangeListener;
import org.opends.server.admin.std.server.ConnectionHandlerCfg;
import org.opends.server.admin.server.ServerManagedObject;
@@ -114,9 +112,8 @@
      builder.setOption(PropertyOption.MULTI_VALUED);
      builder.setAdministratorAction(new AdministratorAction(AdministratorAction.Type.NONE, INSTANCE, "aggregation-property"));
      builder.setDefaultBehaviorProvider(new UndefinedDefaultBehaviorProvider<String>());
      builder.setParentPath(ManagedObjectPath.valueOf("/"));
      builder.setParentPath("/");
      builder.setRelationDefinition("connection-handler");
      builder.setManagedObjectDefinition(ConnectionHandlerCfgDefn.getInstance());
      PD_AGGREGATION_PROPERTY = builder.getInstance();
      INSTANCE.registerPropertyDefinition(PD_AGGREGATION_PROPERTY);
      INSTANCE.registerConstraint(PD_AGGREGATION_PROPERTY);
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/server/AggregationTest.java
@@ -43,7 +43,6 @@
import org.opends.server.admin.AggregationPropertyDefinition;
import org.opends.server.admin.IllegalPropertyValueStringException;
import org.opends.server.admin.ManagedObjectNotFoundException;
import org.opends.server.admin.ManagedObjectPath;
import org.opends.server.admin.PropertyException;
import org.opends.server.admin.PropertyOption;
import org.opends.server.admin.TestCfg;
@@ -56,7 +55,6 @@
import org.opends.server.admin.std.client.ConnectionHandlerCfgClient;
import org.opends.server.admin.std.client.LDAPConnectionHandlerCfgClient;
import org.opends.server.admin.std.client.RootCfgClient;
import org.opends.server.admin.std.meta.ConnectionHandlerCfgDefn;
import org.opends.server.admin.std.meta.LDAPConnectionHandlerCfgDefn;
import org.opends.server.admin.std.server.ConnectionHandlerCfg;
import org.opends.server.admin.std.server.RootCfg;
@@ -306,11 +304,11 @@
        AdministratorAction.Type.NONE, d, "aggregation-property"));
    builder
        .setDefaultBehaviorProvider(new UndefinedDefaultBehaviorProvider<String>());
    builder.setParentPath(ManagedObjectPath.valueOf("/"));
    builder.setParentPath("/");
    builder.setRelationDefinition("connection-handler");
    builder.setManagedObjectDefinition(ConnectionHandlerCfgDefn.getInstance());
    builder.setTargetEnabledPropertyName("enabled");
    aggregationPropertyDefinitionTargetMustBeEnabled = builder.getInstance();
    TestCfg.initializePropertyDefinition(aggregationPropertyDefinitionTargetMustBeEnabled);
    builder = AggregationPropertyDefinition.createBuilder(d,
        "aggregation-property");
@@ -319,13 +317,13 @@
        AdministratorAction.Type.NONE, d, "aggregation-property"));
    builder
        .setDefaultBehaviorProvider(new UndefinedDefaultBehaviorProvider<String>());
    builder.setParentPath(ManagedObjectPath.valueOf("/"));
    builder.setParentPath("/");
    builder.setRelationDefinition("connection-handler");
    builder.setManagedObjectDefinition(ConnectionHandlerCfgDefn.getInstance());
    builder.setTargetEnabledPropertyName("enabled");
    builder.setSourceEnabledPropertyName("mandatory-boolean-property");
    aggregationPropertyDefinitionTargetAndSourceMustBeEnabled = builder
        .getInstance();
    TestCfg.initializePropertyDefinition(aggregationPropertyDefinitionTargetAndSourceMustBeEnabled);
  }