From e263f56c0c62b6941249f3541fd2c89e9ebb0306 Mon Sep 17 00:00:00 2001
From: matthew_swift <matthew_swift@localhost>
Date: Tue, 29 May 2007 11:59:21 +0000
Subject: [PATCH] Fix issue 1580: support overriding of property default values.

---
 opendj-sdk/opends/resource/admin/metaMO.xsl                                                                           |  144 ++++++------
 opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/LDAPConnectionHandlerConfiguration.xml                   |   60 +++--
 opendj-sdk/opends/src/server/org/opends/server/admin/AbstractManagedObjectDefinition.java                             |   87 ++-----
 opendj-sdk/opends/resource/admin/admin.xsd                                                                            |   67 ++++++
 opendj-sdk/opends/resource/admin/preprocessor.xsl                                                                     |  115 ++++++++++
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/AbstractManagedObjectDefinitionTest.java |   86 +++++++
 opendj-sdk/opends/src/server/org/opends/server/admin/client/ldap/LDAPManagedObject.java                               |   16 +
 opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/JMXConnectionHandlerConfiguration.xml                    |   60 +++--
 8 files changed, 447 insertions(+), 188 deletions(-)

diff --git a/opendj-sdk/opends/resource/admin/admin.xsd b/opendj-sdk/opends/resource/admin/admin.xsd
index 281d00a..c011f3b 100644
--- a/opendj-sdk/opends/resource/admin/admin.xsd
+++ b/opendj-sdk/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>
diff --git a/opendj-sdk/opends/resource/admin/metaMO.xsl b/opendj-sdk/opends/resource/admin/metaMO.xsl
index 9ba6a10..904b0b9 100644
--- a/opendj-sdk/opends/resource/admin/metaMO.xsl
+++ b/opendj-sdk/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>
diff --git a/opendj-sdk/opends/resource/admin/preprocessor.xsl b/opendj-sdk/opends/resource/admin/preprocessor.xsl
index 246a4e2..2931923 100644
--- a/opendj-sdk/opends/resource/admin/preprocessor.xsl
+++ b/opendj-sdk/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.
diff --git a/opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/JMXConnectionHandlerConfiguration.xml b/opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/JMXConnectionHandlerConfiguration.xml
index 974adcb..0491e22 100644
--- a/opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/JMXConnectionHandlerConfiguration.xml
+++ b/opendj-sdk/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" />
diff --git a/opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/LDAPConnectionHandlerConfiguration.xml b/opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/LDAPConnectionHandlerConfiguration.xml
index 7ca121f..cfd93ba 100644
--- a/opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/LDAPConnectionHandlerConfiguration.xml
+++ b/opendj-sdk/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" />
diff --git a/opendj-sdk/opends/src/server/org/opends/server/admin/AbstractManagedObjectDefinition.java b/opendj-sdk/opends/src/server/org/opends/server/admin/AbstractManagedObjectDefinition.java
index bdb6108..f2d1548 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/admin/AbstractManagedObjectDefinition.java
+++ b/opendj-sdk/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);
   }
 
 
diff --git a/opendj-sdk/opends/src/server/org/opends/server/admin/client/ldap/LDAPManagedObject.java b/opendj-sdk/opends/src/server/org/opends/server/admin/client/ldap/LDAPManagedObject.java
index a0a5bfc..5931ba3 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/admin/client/ldap/LDAPManagedObject.java
+++ b/opendj-sdk/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));
+      }
     }
   }
 
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/AbstractManagedObjectDefinitionTest.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/AbstractManagedObjectDefinitionTest.java
index 616f1b8..40f23b1 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/AbstractManagedObjectDefinitionTest.java
+++ b/opendj-sdk/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"));
+  }
 }

--
Gitblit v1.10.0