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

matthew_swift
29.59.2007 9ba239d1a7f3caf0be1a02f01b00762ec3f01397
Fix issue 1580: support overriding of property default values.

It is now possible to override the default behavior and required admin action of an inherited property definition using a "property-override" element. This makes it possible to specify default values for inherited properties like java-implementation-class and will, ultimately, make a client tools much more user-friendly.

A subsequent change will add default values for java-implementation-class properties in all managed object definitions.
8 files modified
635 ■■■■ changed files
opends/resource/admin/admin.xsd 67 ●●●●● patch | view | raw | blame | history
opends/resource/admin/metaMO.xsl 144 ●●●● patch | view | raw | blame | history
opends/resource/admin/preprocessor.xsl 115 ●●●●● patch | view | raw | blame | history
opends/src/admin/defn/org/opends/server/admin/std/JMXConnectionHandlerConfiguration.xml 60 ●●●●● patch | view | raw | blame | history
opends/src/admin/defn/org/opends/server/admin/std/LDAPConnectionHandlerConfiguration.xml 60 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/AbstractManagedObjectDefinition.java 87 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/admin/client/ldap/LDAPManagedObject.java 16 ●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/AbstractManagedObjectDefinitionTest.java 86 ●●●●● patch | view | raw | blame | history
opends/resource/admin/admin.xsd
@@ -115,6 +115,21 @@
            </xsd:documentation>
          </xsd:annotation>
        </xsd:element>
        <xsd:element name="property-override"
          type="tns:property-override-type">
          <xsd:annotation>
            <xsd:documentation>
              Overrides a property definition inherited from a parent
              managed object definition. Using a property override it is
              possible to modify the behavior of an inherited property
              definition in a non-critical way. For example, a managed
              object definition might override the default behavior of
              an inherited Java implementation class property so that
              new instances are created with the correct default
              implementation class.
            </xsd:documentation>
          </xsd:annotation>
        </xsd:element>
        <xsd:element name="property-reference"
          type="tns:property-reference-type">
          <xsd:annotation>
@@ -407,6 +422,58 @@
      </xsd:annotation>
    </xsd:attribute>
  </xsd:complexType>
  <xsd:complexType name="property-override-type">
    <xsd:annotation>
      <xsd:documentation>
        Overrides a property definition inherited from a parent managed
        object definition. Using a property override it is possible to
        modify the behavior of an inherited property definition in a
        non-critical way. For example, a managed object definition might
        override the default behavior of an inherited Java
        implementation class property so that new instances are created
        with the correct default implementation class.
      </xsd:documentation>
    </xsd:annotation>
    <xsd:sequence>
      <xsd:element name="requires-admin-action"
        type="tns:admin-action-type" minOccurs="0">
        <xsd:annotation>
          <xsd:documentation>
            Optionally override the administrative action defined in the
            overridden property definition. An administrative action
            defines an optional action which administators must perform
            after they have modified this property. By default
            modifications to properties are assumed to take effect
            immediately and require no additional administrative action.
            Developers should be aware that, where feasible, they should
            implement components such that property modifications
            require no additional administrative action. This is
            required in order to minimize server downtime during
            administration and provide a more user-friendly experience.
          </xsd:documentation>
        </xsd:annotation>
      </xsd:element>
      <xsd:element name="default-behavior" type="tns:default-type"
        minOccurs="0">
        <xsd:annotation>
          <xsd:documentation>
            Optionally override the default behavior defined in the
            overridden property definition. The default behavior is
            applicable when the property has no values specified. All
            properties must have a default behavior defined unless they
            are mandatory.
          </xsd:documentation>
        </xsd:annotation>
      </xsd:element>
    </xsd:sequence>
    <xsd:attribute name="name" type="tns:name-type" use="required">
      <xsd:annotation>
        <xsd:documentation>
          The name of the overridden property.
        </xsd:documentation>
      </xsd:annotation>
    </xsd:attribute>
  </xsd:complexType>
  <xsd:complexType name="relation-type">
    <xsd:annotation>
      <xsd:documentation>
opends/resource/admin/metaMO.xsl
@@ -594,86 +594,79 @@
      <xsl:value-of
        select="'      builder.setOption(PropertyOption.HIDDEN);&#xa;'" />
    </xsl:if>
    <xsl:if
      test="not(@mandatory='true') and not(adm:default-behavior)">
      <xsl:message terminate="yes">
        <xsl:value-of
          select="concat('No default behavior defined for non-mandatory property &quot;', @name,
                         '&quot;.')" />
      </xsl:message>
    </xsl:if>
    <xsl:choose>
      <xsl:when test="@mandatory='true'">
      <xsl:when test="not(adm:default-behavior) or adm:default-behavior/adm:undefined">
        <xsl:value-of
          select="concat('      builder.setDefaultBehaviorProvider(new UndefinedDefaultBehaviorProvider&lt;', $value-type,'&gt;());&#xa;')" />
      </xsl:when>
      <xsl:otherwise>
        <xsl:if test="not(adm:default-behavior)">
          <xsl:message terminate="yes">
            <xsl:value-of
              select="concat('No default behavior defined for non-mandatory property &quot;', @name,
                         '&quot;.')" />
          </xsl:message>
        </xsl:if>
        <xsl:choose>
          <xsl:when test="adm:default-behavior/adm:undefined">
            <xsl:value-of
              select="concat('      builder.setDefaultBehaviorProvider(new UndefinedDefaultBehaviorProvider&lt;', $value-type,'&gt;());&#xa;')" />
          </xsl:when>
          <xsl:when test="adm:default-behavior/adm:alias">
            <xsl:value-of
              select="concat('      builder.setDefaultBehaviorProvider(new AliasDefaultBehaviorProvider&lt;', $value-type,'&gt;(INSTANCE, &quot;', @name, '&quot;));&#xa;')" />
          </xsl:when>
          <xsl:when test="adm:default-behavior/adm:defined">
            <xsl:value-of
              select="concat('      DefaultBehaviorProvider&lt;', $value-type,'&gt; provider = ',
      <xsl:when test="adm:default-behavior/adm:alias">
        <xsl:value-of
          select="concat('      builder.setDefaultBehaviorProvider(new AliasDefaultBehaviorProvider&lt;', $value-type,'&gt;(INSTANCE, &quot;', @name, '&quot;));&#xa;')" />
      </xsl:when>
      <xsl:when test="adm:default-behavior/adm:defined">
        <xsl:value-of
          select="concat('      DefaultBehaviorProvider&lt;', $value-type,'&gt; provider = ',
                             'new DefinedDefaultBehaviorProvider&lt;', $value-type,'&gt;(')" />
            <xsl:for-each
              select="adm:default-behavior/adm:defined/adm:value">
              <xsl:value-of
                select="concat('&quot;', normalize-space(), '&quot;')" />
              <xsl:if test="position() != last()">
                <xsl:value-of select="', '" />
              </xsl:if>
            </xsl:for-each>
            <xsl:value-of select="');&#xa;'" />
            <xsl:value-of
              select="'      builder.setDefaultBehaviorProvider(provider);&#xa;'" />
          </xsl:when>
          <xsl:when
            test="adm:default-behavior/adm:inherited/adm:relative">
            <xsl:value-of
              select="concat('      DefaultBehaviorProvider&lt;', $value-type,'&gt; provider = ',
        <xsl:for-each
          select="adm:default-behavior/adm:defined/adm:value">
          <xsl:value-of
            select="concat('&quot;', normalize-space(), '&quot;')" />
          <xsl:if test="position() != last()">
            <xsl:value-of select="', '" />
          </xsl:if>
        </xsl:for-each>
        <xsl:value-of select="');&#xa;'" />
        <xsl:value-of
          select="'      builder.setDefaultBehaviorProvider(provider);&#xa;'" />
      </xsl:when>
      <xsl:when
        test="adm:default-behavior/adm:inherited/adm:relative">
        <xsl:value-of
          select="concat('      DefaultBehaviorProvider&lt;', $value-type,'&gt; provider = ',
                             'new RelativeInheritedDefaultBehaviorProvider&lt;', $value-type,'&gt;(')" />
            <xsl:variable name="managed-object-name">
              <xsl:call-template name="name-to-java">
                <xsl:with-param name="value"
                  select="adm:default-behavior/adm:inherited/adm:relative/@managed-object-name" />
              </xsl:call-template>
            </xsl:variable>
            <xsl:variable name="property-name"
              select="adm:default-behavior/adm:inherited/adm:relative/@property-name" />
            <xsl:variable name="offset"
              select="adm:default-behavior/adm:inherited/adm:relative/@offset" />
            <xsl:value-of
              select="concat($managed-object-name, 'CfgDefn.getInstance(), &quot;', $property-name, '&quot;, ', $offset, ');&#xa;')" />
            <xsl:value-of
              select="'      builder.setDefaultBehaviorProvider(provider);&#xa;'" />
          </xsl:when>
          <xsl:when
            test="adm:default-behavior/adm:inherited/adm:absolute">
            <xsl:value-of
              select="concat('      DefaultBehaviorProvider&lt;', $value-type,'&gt; provider = ',
        <xsl:variable name="managed-object-name">
          <xsl:call-template name="name-to-java">
            <xsl:with-param name="value"
              select="adm:default-behavior/adm:inherited/adm:relative/@managed-object-name" />
          </xsl:call-template>
        </xsl:variable>
        <xsl:variable name="property-name"
          select="adm:default-behavior/adm:inherited/adm:relative/@property-name" />
        <xsl:variable name="offset"
          select="adm:default-behavior/adm:inherited/adm:relative/@offset" />
        <xsl:value-of
          select="concat($managed-object-name, 'CfgDefn.getInstance(), &quot;', $property-name, '&quot;, ', $offset, ');&#xa;')" />
        <xsl:value-of
          select="'      builder.setDefaultBehaviorProvider(provider);&#xa;'" />
      </xsl:when>
      <xsl:when
        test="adm:default-behavior/adm:inherited/adm:absolute">
        <xsl:value-of
          select="concat('      DefaultBehaviorProvider&lt;', $value-type,'&gt; provider = ',
                             'new AbsoluteInheritedDefaultBehaviorProvider&lt;', $value-type,'&gt;(')" />
            <xsl:variable name="property-name"
              select="adm:default-behavior/adm:inherited/adm:absolute/@property-name" />
            <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;')" />
            <xsl:value-of
              select="'      builder.setDefaultBehaviorProvider(provider);&#xa;'" />
          </xsl:when>
          <xsl:otherwise>
            <xsl:message terminate="yes">
              <xsl:value-of
                select="concat('Unrecognized default behavior type for property &quot;', @name,
        <xsl:variable name="property-name"
          select="adm:default-behavior/adm:inherited/adm:absolute/@property-name" />
        <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;')" />
        <xsl:value-of
          select="'      builder.setDefaultBehaviorProvider(provider);&#xa;'" />
      </xsl:when>
      <xsl:otherwise>
        <xsl:message terminate="yes">
          <xsl:value-of
            select="concat('Unrecognized default behavior type for property &quot;', @name,
                         '&quot;.')" />
            </xsl:message>
          </xsl:otherwise>
        </xsl:choose>
        </xsl:message>
      </xsl:otherwise>
    </xsl:choose>
    <xsl:call-template name="get-property-definition-ctor" />
@@ -1066,7 +1059,8 @@
          </xsl:choose>
          <xsl:value-of select="' value)'" />
          <xsl:if test="@read-only='true'">
            <xsl:value-of select="' throws PropertyIsReadOnlyException'" />
            <xsl:value-of
              select="' throws PropertyIsReadOnlyException'" />
          </xsl:if>
          <xsl:value-of
            select="concat(' {&#xa;' ,
@@ -1781,7 +1775,9 @@
              <import>java.util.Collection</import>
            </xsl:if>
            <xsl:if test="$this-all-properties[@read-only='true']">
              <import>org.opends.server.admin.PropertyIsReadOnlyException</import>
              <import>
                org.opends.server.admin.PropertyIsReadOnlyException
              </import>
            </xsl:if>
          </xsl:otherwise>
        </xsl:choose>
opends/resource/admin/preprocessor.xsl
@@ -208,11 +208,15 @@
      <!--
        Copy all inherited properties.
      -->
      <xsl:copy-of select="$hierarchy/adm:managed-object/adm:property" />
      <xsl:variable name="property-overrides"
        select="adm:property-override" />
      <xsl:copy-of
        select="$hierarchy/adm:managed-object/adm:property[not(@name=$property-overrides/@name)]" />
      <!--
        Copy all local properties.
      -->
      <xsl:apply-templates select="adm:property|adm:property-reference"
      <xsl:apply-templates
        select="adm:property|adm:property-reference|adm:property-override"
        mode="pre-process">
        <xsl:with-param name="moname" select="@name" />
        <xsl:with-param name="mopackage" select="@package" />
@@ -463,6 +467,113 @@
    </xsl:element>
  </xsl:template>
  <!--
    Pre-process a property override pulling in the inherited property
    definition and by adding a "preprocessor" profile which contains
    information about where the property was redefined.
  -->
  <xsl:template match="adm:property-override" mode="pre-process">
    <xsl:param name="mopackage" select="/.." />
    <xsl:param name="moname" select="/.." />
    <xsl:param name="hierarchy" />
    <!--
      Make sure that this property override does not have the same name as another
      property override in this managed object.
    -->
    <xsl:variable name="name" select="@name" />
    <xsl:if test="../adm:property-override[@name=$name][2]">
      <xsl:message terminate="yes">
        <xsl:value-of
          select="concat('Property override ', @name, ' is already overridden in this managed object')" />
      </xsl:message>
    </xsl:if>
    <!--
      Make sure that this property overrides an existing property.
    -->
    <xsl:if
      test="not($hierarchy/adm:managed-object/adm:property[@name=$name])">
      <xsl:message terminate="yes">
        <xsl:value-of
          select="concat('Cannot find inherited property ', @name, ' for property override')" />
      </xsl:message>
    </xsl:if>
    <!--
      Copy the inherited property definition taking care to override
      the default behavior and admin action if required.
    -->
    <xsl:variable name="property"
      select="$hierarchy/adm:managed-object/adm:property[@name=$name]" />
    <xsl:element name="adm:property">
      <xsl:copy-of select="$property/@*" />
      <xsl:apply-templates
        select="$property/adm:TODO | $property/adm:synopsis | $property/adm:description"
        mode="pre-process">
        <xsl:with-param name="mopackage" select="$mopackage" />
        <xsl:with-param name="moname" select="$moname" />
        <xsl:with-param name="hierarchy" select="$hierarchy" />
      </xsl:apply-templates>
      <xsl:choose>
        <xsl:when test="adm:requires-admin-action">
          <xsl:apply-templates select="adm:requires-admin-action"
            mode="pre-process">
            <xsl:with-param name="mopackage" select="$mopackage" />
            <xsl:with-param name="moname" select="$moname" />
            <xsl:with-param name="hierarchy" select="$hierarchy" />
          </xsl:apply-templates>
        </xsl:when>
        <xsl:otherwise>
          <xsl:apply-templates
            select="$property/adm:requires-admin-action"
            mode="pre-process">
            <xsl:with-param name="mopackage" select="$mopackage" />
            <xsl:with-param name="moname" select="$moname" />
            <xsl:with-param name="hierarchy" select="$hierarchy" />
          </xsl:apply-templates>
        </xsl:otherwise>
      </xsl:choose>
      <xsl:choose>
        <xsl:when test="adm:default-behavior">
          <xsl:apply-templates select="adm:default-behavior"
            mode="pre-process">
            <xsl:with-param name="mopackage" select="$mopackage" />
            <xsl:with-param name="moname" select="$moname" />
            <xsl:with-param name="hierarchy" select="$hierarchy" />
          </xsl:apply-templates>
        </xsl:when>
        <xsl:otherwise>
          <xsl:apply-templates select="$property/adm:default-behavior"
            mode="pre-process">
            <xsl:with-param name="mopackage" select="$mopackage" />
            <xsl:with-param name="moname" select="$moname" />
            <xsl:with-param name="hierarchy" select="$hierarchy" />
          </xsl:apply-templates>
        </xsl:otherwise>
      </xsl:choose>
      <xsl:apply-templates
        select="$property/adm:syntax | $property/adm:profile[@name!='preprocessor']"
        mode="pre-process">
        <xsl:with-param name="mopackage" select="$mopackage" />
        <xsl:with-param name="moname" select="$moname" />
        <xsl:with-param name="hierarchy" select="$hierarchy" />
      </xsl:apply-templates>
      <!--
        Now append the preprocessor profile.
      -->
      <xsl:element name="adm:profile">
        <xsl:attribute name="name">
          <xsl:value-of select="'preprocessor'" />
        </xsl:attribute>
        <xsl:element name="admpp:managed-object">
          <xsl:attribute name="name">
            <xsl:value-of select="$moname" />
          </xsl:attribute>
          <xsl:attribute name="package">
            <xsl:value-of select="$mopackage" />
          </xsl:attribute>
        </xsl:element>
      </xsl:element>
    </xsl:element>
  </xsl:template>
  <!--
    Pre-process a relation, merging information from the referenced
    managed object where required, and by adding a "preprocessor" profile
    which contains information about where the relation was defined.
opends/src/admin/defn/org/opends/server/admin/std/JMXConnectionHandlerConfiguration.xml
@@ -1,31 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
 ! CDDL HEADER START
 !
 ! The contents of this file are subject to the terms of the
 ! Common Development and Distribution License, Version 1.0 only
 ! (the "License").  You may not use this file except in compliance
 ! with the License.
 !
 ! You can obtain a copy of the license at
 ! trunk/opends/resource/legal-notices/OpenDS.LICENSE
 ! or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 ! See the License for the specific language governing permissions
 ! and limitations under the License.
 !
 ! When distributing Covered Code, include this CDDL HEADER in each
 ! file and include the License file at
 ! trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 ! add the following below this CDDL HEADER, with the fields enclosed
 ! by brackets "[]" replaced with your own identifying information:
 !      Portions Copyright [yyyy] [name of copyright owner]
 !
 ! CDDL HEADER END
 !
 !
 !      Portions Copyright 2007 Sun Microsystems, Inc.
 ! -->
  ! CDDL HEADER START
  !
  ! The contents of this file are subject to the terms of the
  ! Common Development and Distribution License, Version 1.0 only
  ! (the "License").  You may not use this file except in compliance
  ! with the License.
  !
  ! You can obtain a copy of the license at
  ! trunk/opends/resource/legal-notices/OpenDS.LICENSE
  ! or https://OpenDS.dev.java.net/OpenDS.LICENSE.
  ! See the License for the specific language governing permissions
  ! and limitations under the License.
  !
  ! When distributing Covered Code, include this CDDL HEADER in each
  ! file and include the License file at
  ! trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
  ! add the following below this CDDL HEADER, with the fields enclosed
  ! by brackets "[]" replaced with your own identifying information:
  !      Portions Copyright [yyyy] [name of copyright owner]
  !
  ! CDDL HEADER END
  !
  !
  !      Portions Copyright 2007 Sun Microsystems, Inc.
  ! -->
<adm:managed-object name="jmx-connection-handler"
  plural-name="jmx-connection-handlers"
  package="org.opends.server.admin.std" extends="connection-handler"
@@ -44,6 +43,15 @@
      <ldap:superior>ds-cfg-connection-handler</ldap:superior>
    </ldap:object-class>
  </adm:profile>
  <adm:property-override name="java-implementation-class">
    <adm:default-behavior>
      <adm:defined>
        <adm:value>
          org.opends.server.protocols.jmx.JmxConnectionHandler
        </adm:value>
      </adm:defined>
    </adm:default-behavior>
  </adm:property-override>
  <adm:property-reference name="listen-port" />
  <adm:property-reference name="use-ssl" />
  <adm:property-reference name="ssl-cert-nickname" />
opends/src/admin/defn/org/opends/server/admin/std/LDAPConnectionHandlerConfiguration.xml
@@ -1,31 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
 ! CDDL HEADER START
 !
 ! The contents of this file are subject to the terms of the
 ! Common Development and Distribution License, Version 1.0 only
 ! (the "License").  You may not use this file except in compliance
 ! with the License.
 !
 ! You can obtain a copy of the license at
 ! trunk/opends/resource/legal-notices/OpenDS.LICENSE
 ! or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 ! See the License for the specific language governing permissions
 ! and limitations under the License.
 !
 ! When distributing Covered Code, include this CDDL HEADER in each
 ! file and include the License file at
 ! trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 ! add the following below this CDDL HEADER, with the fields enclosed
 ! by brackets "[]" replaced with your own identifying information:
 !      Portions Copyright [yyyy] [name of copyright owner]
 !
 ! CDDL HEADER END
 !
 !
 !      Portions Copyright 2007 Sun Microsystems, Inc.
 ! -->
  ! CDDL HEADER START
  !
  ! The contents of this file are subject to the terms of the
  ! Common Development and Distribution License, Version 1.0 only
  ! (the "License").  You may not use this file except in compliance
  ! with the License.
  !
  ! You can obtain a copy of the license at
  ! trunk/opends/resource/legal-notices/OpenDS.LICENSE
  ! or https://OpenDS.dev.java.net/OpenDS.LICENSE.
  ! See the License for the specific language governing permissions
  ! and limitations under the License.
  !
  ! When distributing Covered Code, include this CDDL HEADER in each
  ! file and include the License file at
  ! trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
  ! add the following below this CDDL HEADER, with the fields enclosed
  ! by brackets "[]" replaced with your own identifying information:
  !      Portions Copyright [yyyy] [name of copyright owner]
  !
  ! CDDL HEADER END
  !
  !
  !      Portions Copyright 2007 Sun Microsystems, Inc.
  ! -->
<adm:managed-object name="ldap-connection-handler"
  plural-name="ldap-connection-handlers"
  package="org.opends.server.admin.std" extends="connection-handler"
@@ -44,6 +43,15 @@
      <ldap:superior>ds-cfg-connection-handler</ldap:superior>
    </ldap:object-class>
  </adm:profile>
  <adm:property-override name="java-implementation-class">
    <adm:default-behavior>
      <adm:defined>
        <adm:value>
          org.opends.server.protocols.ldap.LDAPConnectionHandler
        </adm:value>
      </adm:defined>
    </adm:default-behavior>
  </adm:property-override>
  <adm:property-reference name="listen-port" />
  <adm:property-reference name="use-ssl" />
  <adm:property-reference name="ssl-cert-nickname" />
opends/src/server/org/opends/server/admin/AbstractManagedObjectDefinition.java
@@ -73,6 +73,14 @@
  // definition.
  private final Map<String, RelationDefinition<?, ?>> relationDefinitions;
  // The set of all property definitions associated with this managed
  // object definition including inherited property definitions.
  private final Map<String, PropertyDefinition<?>> allPropertyDefinitions;
  // The set of all relation definitions associated with this managed
  // object definition including inherited relation definitions.
  private final Map<String, RelationDefinition<?, ?>> allRelationDefinitions;
  // The set of managed object definitions which inherit from this definition.
  private final Map<String,
    AbstractManagedObjectDefinition<? extends C, ? extends S>> children;
@@ -94,12 +102,23 @@
    this.parent = parent;
    this.propertyDefinitions = new HashMap<String, PropertyDefinition<?>>();
    this.relationDefinitions = new HashMap<String, RelationDefinition<?,?>>();
    this.allPropertyDefinitions = new HashMap<String, PropertyDefinition<?>>();
    this.allRelationDefinitions =
      new HashMap<String, RelationDefinition<?, ?>>();
    this.children = new HashMap<String,
      AbstractManagedObjectDefinition<? extends C, ? extends S>>();
        AbstractManagedObjectDefinition<? extends C, ? extends S>>();
    // If we have a parent definition then inherit its features.
    if (parent != null) {
      parent.children.put(name, this);
      for (PropertyDefinition<?> pd : parent.getAllPropertyDefinitions()) {
        allPropertyDefinitions.put(pd.getName(), pd);
      }
      for (RelationDefinition<?, ?> rd : parent.getAllRelationDefinitions()) {
        allRelationDefinitions.put(rd.getName(), rd);
      }
    }
  }
@@ -139,14 +158,7 @@
   *         object.
   */
  public final Collection<PropertyDefinition<?>> getAllPropertyDefinitions() {
    if (parent == null) {
      return getPropertyDefinitions();
    } else {
      List<PropertyDefinition<?>> list = new ArrayList<PropertyDefinition<?>>(
          propertyDefinitions.values());
      list.addAll(parent.getAllPropertyDefinitions());
      return Collections.unmodifiableCollection(list);
    }
    return Collections.unmodifiableCollection(allPropertyDefinitions.values());
  }
@@ -162,14 +174,7 @@
   */
  public final Collection<RelationDefinition<?, ?>>
      getAllRelationDefinitions() {
    if (parent == null) {
      return getRelationDefinitions();
    } else {
      List<RelationDefinition<?, ?>> list =
        new ArrayList<RelationDefinition<?, ?>>(relationDefinitions.values());
      list.addAll(parent.getAllRelationDefinitions());
      return Collections.unmodifiableCollection(list);
    }
    return Collections.unmodifiableCollection(allRelationDefinitions.values());
  }
@@ -314,15 +319,10 @@
      throw new IllegalArgumentException("null or empty property name");
    }
    PropertyDefinition d = propertyDefinitions.get(name);
    PropertyDefinition d = allPropertyDefinitions.get(name);
    if (d == null) {
      if (parent != null) {
        return parent.getPropertyDefinition(name);
      } else {
        throw new IllegalArgumentException("property definition \"" + name
            + "\" not found");
      }
      throw new IllegalArgumentException("property definition \"" + name
          + "\" not found");
    }
    return d;
@@ -365,15 +365,10 @@
      throw new IllegalArgumentException("null or empty relation name");
    }
    RelationDefinition d = relationDefinitions.get(name);
    RelationDefinition d = allRelationDefinitions.get(name);
    if (d == null) {
      if (parent != null) {
        return parent.getRelationDefinition(name);
      } else {
        throw new IllegalArgumentException("relation definition \"" + name
            + "\" not found");
      }
      throw new IllegalArgumentException("relation definition \"" + name
          + "\" not found");
    }
    return d;
@@ -497,30 +492,6 @@
  /**
   * Determine whether this type of managed object has any property definitions.
   *
   * @return Returns <code>true</code> if this type of managed object has any
   *         property definitions, <code>false</code> otherwise.
   */
  public final boolean hasPropertyDefinitions() {
    return !propertyDefinitions.isEmpty();
  }
  /**
   * Determine whether this type of managed object has any relation definitions.
   *
   * @return Returns <code>true</code> if this type of managed object has any
   *         relation definitions, <code>false</code> otherwise.
   */
  public final boolean hasRelationDefinitions() {
    return !relationDefinitions.isEmpty();
  }
  /**
   * Determines whether or not this managed object definition is a
   * sub-type of the provided managed object definition. This managed
   * object definition is a sub-type of the provided managed object
@@ -579,6 +550,7 @@
    String name = d.getName();
    propertyDefinitions.put(name, d);
    allPropertyDefinitions.put(name, d);
  }
@@ -596,6 +568,7 @@
    String name = d.getName();
    relationDefinitions.put(name, d);
    allRelationDefinitions.put(name, d);
  }
opends/src/server/org/opends/server/admin/client/ldap/LDAPManagedObject.java
@@ -424,7 +424,8 @@
    for (PropertyDefinition<?> pd : definition.getAllPropertyDefinitions()) {
      Property<?> p = properties.getProperty(pd);
      if (pd.hasOption(PropertyOption.MANDATORY) && p.isEmpty()) {
      if (pd.hasOption(PropertyOption.MANDATORY)
          && p.getEffectiveValues().isEmpty()) {
        exceptions.add(new PropertyIsMandatoryException(pd));
      }
    }
@@ -941,8 +942,17 @@
  private <T> void encodeProperty(Attribute attribute,
      PropertyDefinition<T> pd, PropertySet properties) {
    Property<T> p = properties.getProperty(pd);
    for (T value : p.getPendingValues()) {
      attribute.add(pd.encodeValue(value));
    if (pd.hasOption(PropertyOption.MANDATORY)) {
      // For mandatory properties we fall-back to the default values
      // if defined which can sometimes be the case e.g when a
      // mandatory property is overridden.
      for (T value : p.getEffectiveValues()) {
        attribute.add(pd.encodeValue(value));
      }
    } else {
      for (T value : p.getPendingValues()) {
        attribute.add(pd.encodeValue(value));
      }
    }
  }
opends/tests/unit-tests-testng/src/server/org/opends/server/admin/AbstractManagedObjectDefinitionTest.java
@@ -32,7 +32,13 @@
import static org.testng.Assert.*;
import java.util.Collection;
import java.util.Collections;
import org.opends.server.TestCaseUtils;
import org.opends.server.admin.std.meta.ConnectionHandlerCfgDefn;
import org.opends.server.admin.std.meta.JMXConnectionHandlerCfgDefn;
import org.opends.server.admin.std.meta.LDAPConnectionHandlerCfgDefn;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
@@ -78,6 +84,21 @@
  /**
   * Sets up tests
   *
   * @throws Exception
   *           If the server could not be initialized.
   */
  @BeforeClass
  public void setUp() throws Exception {
    // This test suite depends on having the schema available, so
    // we'll start the server.
    TestCaseUtils.startServer();
  }
  /**
   * @return data for testIsChildOf.
   */
  @DataProvider(name = "testIsChildOf")
@@ -212,4 +233,69 @@
    assertEquals(children.size(), 0);
  }
  /**
   * Tests that overridden properties work properly. FIXME: should not
   * use Connection Handlers - should define our own definitions.
   * <p>
   * Check that the generic connection handler definition does not
   * have a default behavior defined for the
   * java-implementation-class.
   */
  @Test
  public void testPropertyOverride1() {
    AbstractManagedObjectDefinition<?, ?> d = ConnectionHandlerCfgDefn
        .getInstance();
    PropertyDefinition<?> pd = d
        .getPropertyDefinition("java-implementation-class");
    DefaultBehaviorProvider<?> dbp = pd.getDefaultBehaviorProvider();
    assertEquals(dbp.getClass(), UndefinedDefaultBehaviorProvider.class);
  }
  /**
   * Tests that overridden properties work properly. FIXME: should not
   * use Connection Handlers - should define our own definitions.
   * <p>
   * Check that the LDAP connection handler definition does have a
   * default behavior defined for the java-implementation-class.
   */
  @Test
  public void testPropertyOverride2() {
    AbstractManagedObjectDefinition<?, ?> d = LDAPConnectionHandlerCfgDefn
        .getInstance();
    PropertyDefinition<?> pd = d
        .getPropertyDefinition("java-implementation-class");
    DefaultBehaviorProvider<?> dbp = pd.getDefaultBehaviorProvider();
    assertEquals(dbp.getClass(), DefinedDefaultBehaviorProvider.class);
    DefinedDefaultBehaviorProvider<?> ddbp = (DefinedDefaultBehaviorProvider<?>) dbp;
    assertEquals(ddbp.getDefaultValues(), Collections
        .singleton("org.opends.server.protocols.ldap.LDAPConnectionHandler"));
  }
  /**
   * Tests that overridden properties work properly. FIXME: should not
   * use Connection Handlers - should define our own definitions.
   * <p>
   * Check that the JMX connection handler definition does have a
   * default behavior defined for the java-implementation-class.
   */
  @Test
  public void testPropertyOverride3() {
    AbstractManagedObjectDefinition<?, ?> d = JMXConnectionHandlerCfgDefn
        .getInstance();
    PropertyDefinition<?> pd = d
        .getPropertyDefinition("java-implementation-class");
    DefaultBehaviorProvider<?> dbp = pd.getDefaultBehaviorProvider();
    assertEquals(dbp.getClass(), DefinedDefaultBehaviorProvider.class);
    DefinedDefaultBehaviorProvider<?> ddbp = (DefinedDefaultBehaviorProvider<?>) dbp;
    assertEquals(ddbp.getDefaultValues(), Collections
        .singleton("org.opends.server.protocols.jmx.JmxConnectionHandler"));
  }
}