From 0a2e22293f5c36807d89441f9bd8c56ae0b59097 Mon Sep 17 00:00:00 2001
From: matthew_swift <matthew_swift@localhost>
Date: Fri, 16 Nov 2007 16:40:35 +0000
Subject: [PATCH] Update admin framework and dsconfig to support tagging of component definitions as advanced and customizable:

---
 opends/resource/admin/preprocessor.xsl                                          |    4 
 opends/src/server/org/opends/server/admin/AbstractManagedObjectDefinition.java  |   49 ++++
 opends/src/server/org/opends/server/tools/dsconfig/CLIProfile.java              |   18 ++
 opends/resource/admin/admin.xsd                                                 |   35 +++
 opends/src/messages/messages/dsconfig.properties                                |    5 
 opends/src/server/org/opends/server/admin/ManagedObjectOption.java              |   49 +++++
 opends/resource/admin/cliMOProfile.xsl                                          |   12 +
 opends/resource/admin/metaMO.xsl                                                |   81 ++++++--
 opends/src/server/org/opends/server/tools/dsconfig/HelpSubCommandHandler.java   |   32 ++
 opends/src/server/org/opends/server/tools/dsconfig/ListSubCommandHandler.java   |   41 ++++
 opends/resource/admin/admin-cli.xsd                                             |   24 ++
 opends/src/server/org/opends/server/admin/RelationOption.java                   |   10 
 opends/src/server/org/opends/server/tools/dsconfig/SubCommandHandler.java       |   46 ++++
 opends/src/server/org/opends/server/tools/dsconfig/CreateSubCommandHandler.java |  103 +++++++++--
 opends/src/server/org/opends/server/tools/dsconfig/DSConfig.java                |   14 +
 15 files changed, 457 insertions(+), 66 deletions(-)

diff --git a/opends/resource/admin/admin-cli.xsd b/opends/resource/admin/admin-cli.xsd
index 0c7b788..ddf5363 100644
--- a/opends/resource/admin/admin-cli.xsd
+++ b/opends/resource/admin/admin-cli.xsd
@@ -14,6 +14,30 @@
       experience.
     </xsd:documentation>
   </xsd:annotation>
+  <xsd:element name="managed-object">
+    <xsd:annotation>
+      <xsd:documentation>
+        Defines CLI annotations for use with managed object definitions.
+      </xsd:documentation>
+    </xsd:annotation>
+    <xsd:complexType>
+      <xsd:attribute name="custom" default="false" type="xsd:boolean">
+        <xsd:annotation>
+          <xsd:documentation>
+            Indicates whether the CLI should refer to this managed
+            object type as "custom" as opposed to "generic". Custom
+            managed object types generally are the top-level type of
+            component (e.g. connection-handler but not
+            ldap-connection-handler) having a non-advanced java-class
+            property. Users create this type of component with a custom
+            implementation class. It is better to refer to these as
+            "custom" since the term "generic" can mislead users (e.g.
+            many users confuse a generic backend as being a JE backend).
+          </xsd:documentation>
+        </xsd:annotation>
+      </xsd:attribute>
+    </xsd:complexType>
+  </xsd:element>
   <xsd:element name="relation">
     <xsd:annotation>
       <xsd:documentation>
diff --git a/opends/resource/admin/admin.xsd b/opends/resource/admin/admin.xsd
index 4c544a1..8a8625c 100644
--- a/opends/resource/admin/admin.xsd
+++ b/opends/resource/admin/admin.xsd
@@ -754,6 +754,16 @@
         </xsd:documentation>
       </xsd:annotation>
     </xsd:attribute>
+    <xsd:attribute name="advanced" type="xsd:boolean" use="optional"
+      default="false">
+      <xsd:annotation>
+        <xsd:documentation>
+          Indicates whether or not managed objects referenced by this
+          relation should be treated as advanced and be hidden by
+          default in client applications.
+        </xsd:documentation>
+      </xsd:annotation>
+    </xsd:attribute>
     <xsd:attribute name="hidden" type="xsd:boolean" use="optional"
       default="false">
       <xsd:annotation>
@@ -1836,11 +1846,34 @@
               </xsd:documentation>
             </xsd:annotation>
           </xsd:attribute>
+          <xsd:attribute name="advanced" type="xsd:boolean"
+            use="optional" default="false">
+            <xsd:annotation>
+              <xsd:documentation>
+                Indicates whether or not this managed object should be
+                treated as advanced and therefore should be hidden by
+                default in client applications. This feature is not
+                inherited by child managed objects.
+              </xsd:documentation>
+            </xsd:annotation>
+          </xsd:attribute>
+          <xsd:attribute name="hidden" type="xsd:boolean" use="optional"
+            default="false">
+            <xsd:annotation>
+              <xsd:documentation>
+                Indicates whether or not this managed object should be
+                hidden from client applications. Hidden managed objects
+                should rarely be used but are sometimes required in
+                order to provide functionality that needs to be exposed
+                in management APIs but not in front-ends such as CLIs.
+              </xsd:documentation>
+            </xsd:annotation>
+          </xsd:attribute>
           <xsd:attribute name="extends" type="tns:name-type"
             use="optional">
             <xsd:annotation>
               <xsd:documentation>
-                Indicates whether or not this managed object is inherits
+                Indicates whether or not this managed object inherits
                 from a parent managed object and, if so, the name of the
                 parent. If specified, this managed object will inherit
                 all of the properties and relations defined in the
diff --git a/opends/resource/admin/cliMOProfile.xsl b/opends/resource/admin/cliMOProfile.xsl
index c4f93b4..d6a5310 100644
--- a/opends/resource/admin/cliMOProfile.xsl
+++ b/opends/resource/admin/cliMOProfile.xsl
@@ -35,6 +35,18 @@
   -->
   <xsl:template match="/">
     <!--
+      Determine if the managed object is for customization.
+    -->
+    <xsl:choose>
+      <xsl:when
+        test="$this/adm:profile[@name='cli']/cli:managed-object/@custom='true'">
+        <xsl:value-of select="'is-for-customization=true&#xa;'" />
+      </xsl:when>
+      <xsl:otherwise>
+        <xsl:value-of select="'is-for-customization=false&#xa;'" />
+      </xsl:otherwise>
+    </xsl:choose>
+    <!--
       Process each relation definition.
     -->
     <xsl:for-each select="$this-all-relations">
diff --git a/opends/resource/admin/metaMO.xsl b/opends/resource/admin/metaMO.xsl
index 105a87a..31341fd 100644
--- a/opends/resource/admin/metaMO.xsl
+++ b/opends/resource/admin/metaMO.xsl
@@ -153,6 +153,26 @@
       <xsl:call-template name="generate-relation-constructor" />
     </xsl:for-each>
     <!--
+      Register any optins associated with this managed object definition.
+    -->
+    <xsl:if test="$this-is-advanced or $this-is-hidden">
+      <xsl:text>&#xa;</xsl:text>
+      <xsl:text>&#xa;</xsl:text>
+      <xsl:text>&#xa;</xsl:text>
+      <xsl:value-of
+        select="'  // Register the options associated with this managed object definition.&#xa;'" />
+      <xsl:value-of select="'  static {&#xa;'" />
+      <xsl:if test="$this-is-advanced">
+        <xsl:value-of
+          select="concat('    INSTANCE.registerOption(ManagedObjectOption.ADVANCED);&#xa;')" />
+      </xsl:if>
+      <xsl:if test="$this-is-hidden">
+        <xsl:value-of
+          select="concat('    INSTANCE.registerOption(ManagedObjectOption.HIDDEN);&#xa;')" />
+      </xsl:if>
+      <xsl:value-of select="'  }&#xa;'" />
+    </xsl:if>
+    <!--
       Register any tags associated with this managed object definition.
     -->
     <xsl:if test="$this/adm:tag">
@@ -923,6 +943,10 @@
                            'CfgDefn.getInstance().get',
                            $java-property-name, 'PropertyDefinition());&#xa;')" />
     </xsl:if>
+    <xsl:if test="@advanced='true'">
+      <xsl:value-of
+        select="'    builder.setOption(RelationOption.ADVANCED);&#xa;'" />
+    </xsl:if>
     <xsl:if test="@hidden='true'">
       <xsl:value-of
         select="'    builder.setOption(RelationOption.HIDDEN);&#xa;'" />
@@ -1615,26 +1639,39 @@
         </xsl:message>
       </xsl:if>
       <!--
-        Check that all advanced properties are non-mandatory or have a default.
+        Check that all advanced properties conform to one of
+        the following rules:
+        
+        * is mandatory and has a defined default value(s)
+        * is mandatory and is part of an advanced managed object
+        * is mandatory and is part of an abstract managed object
+        * is not mandatory
       -->
-      <xsl:if
-        test="not($this-is-abstract) and @advanced='true' and @mandatory='true'">
-        <xsl:choose>
-          <xsl:when test="adm:default-behavior/adm:defined">
-            <!--  OK  -->
-          </xsl:when>
-          <xsl:when test="adm:default-behavior/adm:inherited">
-            <!--  OK  -->
-          </xsl:when>
-          <xsl:otherwise>
-            <xsl:message terminate="yes">
-              <xsl:value-of
-                select="concat('Property &quot;', @name,
-                         '&quot; is advanced and mandatory but has no default values.')" />
-            </xsl:message>
-          </xsl:otherwise>
-        </xsl:choose>
-      </xsl:if>
+      <xsl:choose>
+        <xsl:when test="$this-is-advanced">
+          <!--  OK  -->
+        </xsl:when>
+        <xsl:when test="$this-is-abstract">
+          <!--  OK  -->
+        </xsl:when>
+        <xsl:when test="@advanced='true' and @mandatory='true'">
+          <xsl:choose>
+            <xsl:when test="adm:default-behavior/adm:defined">
+              <!--  OK  -->
+            </xsl:when>
+            <xsl:when test="adm:default-behavior/adm:inherited">
+              <!--  OK  -->
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:message terminate="yes">
+                <xsl:value-of
+                  select="concat('Advanced property &quot;', @name,
+                         '&quot; must have defined or inherited default values.')" />
+              </xsl:message>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:when>
+      </xsl:choose>
     </xsl:for-each>
     <!-- 
       Now generate the definition.
@@ -1750,9 +1787,13 @@
               select="concat(@managed-object-package, '.server.', $java-class-name, 'Cfg')" />
           </xsl:element>
         </xsl:for-each>
-        <xsl:if test="$this-local-relations[@hidden='true']">
+        <xsl:if
+          test="$this-local-relations[@advanced='true' or @hidden='true']">
           <import>org.opends.server.admin.RelationOption</import>
         </xsl:if>
+        <xsl:if test="$this-is-hidden or $this-is-advanced">
+          <import>org.opends.server.admin.ManagedObjectOption</import>
+        </xsl:if>
         <xsl:if test="$this-all-relations/adm:one-to-many">
           <import>
             org.opends.server.admin.InstantiableRelationDefinition
diff --git a/opends/resource/admin/preprocessor.xsl b/opends/resource/admin/preprocessor.xsl
index f409363..cb2f35c 100644
--- a/opends/resource/admin/preprocessor.xsl
+++ b/opends/resource/admin/preprocessor.xsl
@@ -1123,6 +1123,10 @@
     select="$_this_tmp/adm:managed-object | $_this_tmp/adm:root-managed-object" />
   <xsl:variable name="this-is-abstract"
     select="boolean(string($this/@abstract) = 'true')" />
+  <xsl:variable name="this-is-advanced"
+    select="boolean(string($this/@advanced) = 'true')" />
+  <xsl:variable name="this-is-hidden"
+    select="boolean(string($this/@hidden) = 'true')" />
   <xsl:variable name="this-is-root"
     select="not(local-name($this) = 'managed-object')" />
   <xsl:variable name="this-package">
diff --git a/opends/src/messages/messages/dsconfig.properties b/opends/src/messages/messages/dsconfig.properties
index 2bf2d9d..53aed11 100644
--- a/opends/src/messages/messages/dsconfig.properties
+++ b/opends/src/messages/messages/dsconfig.properties
@@ -442,3 +442,8 @@
 INFO_DSCFG_PROMPT_EDIT_TO_ENABLE_146=The referenced %s \
  called "%s" must be enabled so that it can be used with this %s. Do \
  you want to edit its properties in order to enable it?
+INFO_DSCFG_CUSTOM_TYPE_OPTION_147=Custom %s
+INFO_DSCFG_CUSTOM_TYPE_SYNOPSIS_148=A Custom %s with a user-defined \
+ implementation class
+INFO_DSCFG_GENERIC_TYPE_SYNOPSIS_149=A Generic %s
+INFO_DSCFG_CREATE_TYPE_HELP_HEADING_150=Help: %s
diff --git a/opends/src/server/org/opends/server/admin/AbstractManagedObjectDefinition.java b/opends/src/server/org/opends/server/admin/AbstractManagedObjectDefinition.java
index 7903cc6..10fbd64 100644
--- a/opends/src/server/org/opends/server/admin/AbstractManagedObjectDefinition.java
+++ b/opends/src/server/org/opends/server/admin/AbstractManagedObjectDefinition.java
@@ -32,6 +32,7 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedList;
@@ -92,6 +93,9 @@
   // The set of tags associated with this managed object.
   private final Set<Tag> allTags;
 
+  // Options applicable to this definition.
+  private final Set<ManagedObjectOption> options;
+
   // The set of managed object definitions which inherit from this definition.
   private final Map<String,
     AbstractManagedObjectDefinition<? extends C, ? extends S>> children;
@@ -120,6 +124,8 @@
     this.allRelationDefinitions =
       new HashMap<String, RelationDefinition<?, ?>>();
     this.allTags = new HashSet<Tag>();
+    this.options = EnumSet.noneOf(ManagedObjectOption.class);
+
     this.children = new HashMap<String,
         AbstractManagedObjectDefinition<? extends C, ? extends S>>();
 
@@ -592,6 +598,21 @@
 
   /**
    * Determines whether or not this managed object definition has the
+   * specified option.
+   *
+   * @param option
+   *          The option to test.
+   * @return Returns <code>true</code> if the option is set, or
+   *         <code>false</code> otherwise.
+   */
+  public final boolean hasOption(ManagedObjectOption option) {
+    return options.contains(option);
+  }
+
+
+
+  /**
+   * Determines whether or not this managed object definition has the
    * specified tag.
    *
    * @param t
@@ -749,7 +770,7 @@
 
 
   /**
-   * Register a constraint with the managed object definition.
+   * Register a constraint with this managed object definition.
    * <p>
    * This method <b>must not</b> be called by applications.
    *
@@ -763,7 +784,7 @@
 
 
   /**
-   * Register a property definition with the managed object definition,
+   * Register a property definition with this managed object definition,
    * overriding any existing property definition with the same name.
    * <p>
    * This method <b>must not</b> be called by applications.
@@ -781,7 +802,7 @@
 
 
   /**
-   * Register a relation definition with the managed object definition,
+   * Register a relation definition with this managed object definition,
    * overriding any existing relation definition with the same name.
    * <p>
    * This method <b>must not</b> be called by applications.
@@ -799,15 +820,29 @@
 
 
   /**
-   * Register a tag with the managed object definition.
+   * Register an option with this managed object definition.
    * <p>
    * This method <b>must not</b> be called by applications.
    *
-   * @param t
+   * @param option
+   *          The option to be registered.
+   */
+  protected final void registerOption(ManagedObjectOption option) {
+    options.add(option);
+  }
+
+
+
+  /**
+   * Register a tag with this managed object definition.
+   * <p>
+   * This method <b>must not</b> be called by applications.
+   *
+   * @param tag
    *          The tag to be registered.
    */
-  protected final void registerTag(Tag t) {
-    allTags.add(t);
+  protected final void registerTag(Tag tag) {
+    allTags.add(tag);
   }
 
 
diff --git a/opends/src/server/org/opends/server/admin/ManagedObjectOption.java b/opends/src/server/org/opends/server/admin/ManagedObjectOption.java
new file mode 100644
index 0000000..cdf7d75
--- /dev/null
+++ b/opends/src/server/org/opends/server/admin/ManagedObjectOption.java
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+package org.opends.server.admin;
+
+
+
+/**
+ * This enumeration contains various options that can be associated
+ * with managed object definitions.
+ */
+public enum ManagedObjectOption {
+  /**
+   * Use this option to identify managed object types which should be
+   * considered as advanced and should not be exposed by default in
+   * client applications.
+   */
+  ADVANCED,
+
+  /**
+   * Use this option to identify managed object types which must not
+   * be directly exposed in client applications.
+   */
+  HIDDEN;
+}
diff --git a/opends/src/server/org/opends/server/admin/RelationOption.java b/opends/src/server/org/opends/server/admin/RelationOption.java
index 1624f2b..04c6342 100644
--- a/opends/src/server/org/opends/server/admin/RelationOption.java
+++ b/opends/src/server/org/opends/server/admin/RelationOption.java
@@ -32,12 +32,16 @@
 /**
  * This enumeration contains various options that can be associated
  * with relation definitions.
- * <p>
- * Only one option is supported at the moment, but others may be added
- * in future.
  */
 public enum RelationOption {
   /**
+   * Use this option to identify relations which should be considered
+   * as advanced and should not be exposed by default in client
+   * applications.
+   */
+  ADVANCED,
+
+  /**
    * Use this option to identify relations which must not be directly
    * exposed in client applications.
    */
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/CLIProfile.java b/opends/src/server/org/opends/server/tools/dsconfig/CLIProfile.java
index 1b260c6..86a9fe0 100644
--- a/opends/src/server/org/opends/server/tools/dsconfig/CLIProfile.java
+++ b/opends/src/server/org/opends/server/tools/dsconfig/CLIProfile.java
@@ -33,6 +33,7 @@
 import java.util.LinkedHashSet;
 import java.util.Set;
 
+import org.opends.server.admin.AbstractManagedObjectDefinition;
 import org.opends.server.admin.ManagedObjectDefinitionResource;
 import org.opends.server.admin.RelationDefinition;
 
@@ -83,4 +84,21 @@
         + r.getName() + ".list-properties");
     return new LinkedHashSet<String>(Arrays.asList(s.split(",")));
   }
+
+
+
+  /**
+   * Determines if instances of the specified managed object
+   * definition are to be used for customization.
+   *
+   * @param d
+   *          The managed object definition.
+   * @return Returns <code>true</code> if instances of the specified
+   *         managed object definition are to be used for
+   *         customization.
+   */
+  public boolean isForCustomization(AbstractManagedObjectDefinition<?, ?> d) {
+    String s = resource.getString(d, "is-for-customization");
+    return Boolean.parseBoolean(s);
+  }
 }
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/CreateSubCommandHandler.java b/opends/src/server/org/opends/server/tools/dsconfig/CreateSubCommandHandler.java
index 5d85d12..6b4ce5e 100644
--- a/opends/src/server/org/opends/server/tools/dsconfig/CreateSubCommandHandler.java
+++ b/opends/src/server/org/opends/server/tools/dsconfig/CreateSubCommandHandler.java
@@ -55,6 +55,7 @@
 import org.opends.server.admin.ManagedObjectAlreadyExistsException;
 import org.opends.server.admin.ManagedObjectDefinition;
 import org.opends.server.admin.ManagedObjectNotFoundException;
+import org.opends.server.admin.ManagedObjectOption;
 import org.opends.server.admin.ManagedObjectPath;
 import org.opends.server.admin.OptionalRelationDefinition;
 import org.opends.server.admin.PropertyDefinition;
@@ -254,6 +255,20 @@
      * {@inheritDoc}
      */
     public void display(ConsoleApplication app) {
+      app.println(INFO_DSCFG_CREATE_TYPE_HELP_HEADING.get(d
+          .getUserFriendlyPluralName()));
+
+      app.println();
+      app.println(d.getSynopsis());
+
+      if (d.getDescription() != null) {
+        app.println();
+        app.println(d.getDescription());
+      }
+
+      app.println();
+      app.println();
+
       // Create a table containing a description of each component
       // type.
       TableBuilder builder = new TableBuilder();
@@ -266,6 +281,30 @@
 
       boolean isFirst = true;
       for (ManagedObjectDefinition<?, ?> mod : getSubTypes(d).values()) {
+        // Only display advanced types and custom types in advanced mode.
+        if (!app.isAdvancedMode()) {
+          if (mod.hasOption(ManagedObjectOption.ADVANCED)) {
+            continue;
+          }
+
+          if (CLIProfile.getInstance().isForCustomization(mod)) {
+            continue;
+          }
+        }
+
+        Message ufn = mod.getUserFriendlyName();
+        Message synopsis = mod.getSynopsis();
+        Message description = mod.getDescription();
+        if (CLIProfile.getInstance().isForCustomization(mod)) {
+          ufn = INFO_DSCFG_CUSTOM_TYPE_OPTION.get(ufn);
+          synopsis = INFO_DSCFG_CUSTOM_TYPE_SYNOPSIS.get(ufn);
+          description = null;
+        } else if (mod == d) {
+          ufn = INFO_DSCFG_GENERIC_TYPE_OPTION.get(ufn);
+          synopsis = INFO_DSCFG_GENERIC_TYPE_SYNOPSIS.get(ufn);
+          description = null;
+        }
+
         if (!isFirst) {
           builder.startRow();
           builder.startRow();
@@ -274,13 +313,13 @@
         }
 
         builder.startRow();
-        builder.appendCell(mod.getUserFriendlyName());
-        builder.appendCell(mod.getSynopsis());
-        if (mod.getDescription() != null) {
+        builder.appendCell(ufn);
+        builder.appendCell(synopsis);
+        if (description != null) {
           builder.startRow();
           builder.startRow();
           builder.appendCell();
-          builder.appendCell(mod.getDescription());
+          builder.appendCell(description);
         }
       }
 
@@ -296,12 +335,6 @@
 
 
   /**
-   * The value for the -t argument which will be used for the most
-   * generic managed object when it is instantiable.
-   */
-  private static final String GENERIC_TYPE = "generic";
-
-  /**
    * The value for the long option set.
    */
   private static final String OPTION_DSCFG_LONG_SET = "set";
@@ -815,17 +848,27 @@
       new TreeMap<String, ManagedObjectDefinition<? extends C, ? extends S>>();
 
     // If the top-level definition is instantiable, we use the value
-    // "generic".
-    if (d instanceof ManagedObjectDefinition) {
-      ManagedObjectDefinition<? extends C, ? extends S> mod =
-        (ManagedObjectDefinition<? extends C, ? extends S>) d;
-      map.put(GENERIC_TYPE, mod);
+    // "generic" or "custom".
+    if (!d.hasOption(ManagedObjectOption.HIDDEN)) {
+      if (d instanceof ManagedObjectDefinition) {
+        ManagedObjectDefinition<? extends C, ? extends S> mod =
+          (ManagedObjectDefinition<? extends C, ? extends S>) d;
+        if (CLIProfile.getInstance().isForCustomization(mod)) {
+          map.put(DSConfig.CUSTOM_TYPE, mod);
+        } else {
+          map.put(DSConfig.GENERIC_TYPE, mod);
+        }
+      }
     }
 
     // Process its sub-definitions.
     String suffix = "-" + d.getName();
     for (AbstractManagedObjectDefinition<? extends C, ? extends S> c : d
         .getAllChildren()) {
+      if (d.hasOption(ManagedObjectOption.HIDDEN)) {
+        continue;
+      }
+
       if (c instanceof ManagedObjectDefinition) {
         ManagedObjectDefinition<? extends C, ? extends S> mod =
           (ManagedObjectDefinition<? extends C, ? extends S>) c;
@@ -838,6 +881,12 @@
           name = name.substring(0, name.length() - suffix.length());
         }
 
+        // If this type is intended for customization, prefix it with
+        // "custom".
+        if (CLIProfile.getInstance().isForCustomization(mod)) {
+          name = String.format("%s-%s", DSConfig.CUSTOM_TYPE, name);
+        }
+
         map.put(name, mod);
       }
     }
@@ -869,8 +918,21 @@
       builder.setPrompt(msg);
 
       for (ManagedObjectDefinition<? extends C, ? extends S> mod : types) {
+        // Only display advanced types and custom types in advanced mode.
+        if (!app.isAdvancedMode()) {
+          if (mod.hasOption(ManagedObjectOption.ADVANCED)) {
+            continue;
+          }
+
+          if (CLIProfile.getInstance().isForCustomization(mod)) {
+            continue;
+          }
+        }
+
         Message option = mod.getUserFriendlyName();
-        if ((mod == d) && (mod instanceof ManagedObjectDefinition)) {
+        if (CLIProfile.getInstance().isForCustomization(mod)) {
+          option = INFO_DSCFG_CUSTOM_TYPE_OPTION.get(option);
+        } else if (mod == d) {
           option = INFO_DSCFG_GENERIC_TYPE_OPTION.get(option);
         }
         builder.addNumberedOption(option,
@@ -963,7 +1025,7 @@
     }
     this.typeUsage = builder.toString();
 
-    if (!types.containsKey(GENERIC_TYPE)) {
+    if (!types.containsKey(DSConfig.GENERIC_TYPE)) {
       // The option is mandatory when non-interactive.
       this.typeArgument = new StringArgument("type", OPTION_DSCFG_SHORT_TYPE,
           OPTION_DSCFG_LONG_TYPE, false, false, true, "{TYPE}", null, null,
@@ -972,9 +1034,10 @@
     } else {
       // The option has a sensible default "generic".
       this.typeArgument = new StringArgument("type", OPTION_DSCFG_SHORT_TYPE,
-          OPTION_DSCFG_LONG_TYPE, false, false, true, "{TYPE}", GENERIC_TYPE,
-          null, INFO_DSCFG_DESCRIPTION_TYPE_DEFAULT.get(r.getChildDefinition()
-              .getUserFriendlyName(), GENERIC_TYPE, typeUsage));
+          OPTION_DSCFG_LONG_TYPE, false, false, true, "{TYPE}",
+          DSConfig.GENERIC_TYPE, null, INFO_DSCFG_DESCRIPTION_TYPE_DEFAULT.get(
+              r.getChildDefinition().getUserFriendlyName(),
+              DSConfig.GENERIC_TYPE, typeUsage));
 
       // Hide the option if it defaults to generic and generic is the
       // only possible value.
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/DSConfig.java b/opends/src/server/org/opends/server/tools/dsconfig/DSConfig.java
index c41d49c..60caf23 100644
--- a/opends/src/server/org/opends/server/tools/dsconfig/DSConfig.java
+++ b/opends/src/server/org/opends/server/tools/dsconfig/DSConfig.java
@@ -250,6 +250,20 @@
   }
 
   /**
+   * The type name which will be used for the most generic managed
+   * object types when they are instantiable and intended for
+   * customization only.
+   */
+  public static final String CUSTOM_TYPE = "custom";
+
+  /**
+   * The type name which will be used for the most generic managed
+   * object types when they are instantiable and not intended for
+   * customization.
+   */
+  public static final String GENERIC_TYPE = "generic";
+
+  /**
    * The value for the long option advanced.
    */
   private static final String OPTION_DSCFG_LONG_ADVANCED = "advanced";
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/HelpSubCommandHandler.java b/opends/src/server/org/opends/server/tools/dsconfig/HelpSubCommandHandler.java
index 5c46e91..c265be2 100644
--- a/opends/src/server/org/opends/server/tools/dsconfig/HelpSubCommandHandler.java
+++ b/opends/src/server/org/opends/server/tools/dsconfig/HelpSubCommandHandler.java
@@ -52,6 +52,7 @@
 import org.opends.server.admin.DefaultBehaviorProviderVisitor;
 import org.opends.server.admin.DefinedDefaultBehaviorProvider;
 import org.opends.server.admin.EnumPropertyDefinition;
+import org.opends.server.admin.ManagedObjectOption;
 import org.opends.server.admin.PropertyDefinition;
 import org.opends.server.admin.PropertyDefinitionUsageBuilder;
 import org.opends.server.admin.PropertyDefinitionVisitor;
@@ -358,11 +359,6 @@
     }
   }
 
-  /**
-   * The type component name to be used for top-level definitions.
-   */
-  private static final String GENERIC_TYPE = "generic";
-
   // Strings used in property help.
   private final static String HEADING_SEPARATOR = " : ";
 
@@ -765,7 +761,7 @@
     String typeName = null;
     if (parent == d) {
       // This was a top-level definition.
-      typeName = GENERIC_TYPE;
+      typeName = DSConfig.GENERIC_TYPE;
     } else {
       // For the type name we shorten it, if possible, by stripping
       // off the trailing part of the name which matches the
@@ -836,7 +832,7 @@
         }
       } else {
         // Cache the generic definition for improved errors later on.
-        tmp = subTypes.get(GENERIC_TYPE);
+        tmp = subTypes.get(DSConfig.GENERIC_TYPE);
       }
 
       if (typeName != null) {
@@ -959,6 +955,17 @@
         // Display help for each property.
         AbstractManagedObjectDefinition<?, ?> mod = subTypes.get(type);
 
+        // Skip hidden types.
+        if (mod.hasOption(ManagedObjectOption.HIDDEN)) {
+          continue;
+        }
+
+        // Skip advanced types if required.
+        if (!app.isAdvancedMode()
+            && mod.hasOption(ManagedObjectOption.ADVANCED)) {
+          continue;
+        }
+
         // Skip if this does not have the required tag.
         if (tag != null && !mod.hasTag(tag)) {
           continue;
@@ -1062,6 +1069,17 @@
         // Display help for each property.
         AbstractManagedObjectDefinition<?, ?> mod = subTypes.get(type);
 
+        // Skip hidden types.
+        if (mod.hasOption(ManagedObjectOption.HIDDEN)) {
+          continue;
+        }
+
+        // Skip advanced types if required.
+        if (!app.isAdvancedMode()
+            && mod.hasOption(ManagedObjectOption.ADVANCED)) {
+          continue;
+        }
+
         // Skip if this does not have the required tag.
         if (tag != null && !mod.hasTag(tag)) {
           continue;
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/ListSubCommandHandler.java b/opends/src/server/org/opends/server/tools/dsconfig/ListSubCommandHandler.java
index b533045..193a2ba 100644
--- a/opends/src/server/org/opends/server/tools/dsconfig/ListSubCommandHandler.java
+++ b/opends/src/server/org/opends/server/tools/dsconfig/ListSubCommandHandler.java
@@ -42,6 +42,7 @@
 import org.opends.server.admin.InstantiableRelationDefinition;
 import org.opends.server.admin.ManagedObjectDefinition;
 import org.opends.server.admin.ManagedObjectNotFoundException;
+import org.opends.server.admin.ManagedObjectOption;
 import org.opends.server.admin.ManagedObjectPath;
 import org.opends.server.admin.OptionalRelationDefinition;
 import org.opends.server.admin.PropertyDefinition;
@@ -322,6 +323,20 @@
     if (app.isScriptFriendly()) {
       // Output just the names of the children.
       for (String name : children.keySet()) {
+        // Skip advanced and hidden components in non-advanced mode.
+        if (!app.isAdvancedMode()) {
+          ManagedObject<?> child = children.get(name);
+          ManagedObjectDefinition<?, ?> d = child.getManagedObjectDefinition();
+
+          if (d.hasOption(ManagedObjectOption.HIDDEN)) {
+            continue;
+          }
+
+          if (d.hasOption(ManagedObjectOption.ADVANCED)) {
+            continue;
+          }
+        }
+
         app.println(Message.raw(name));
       }
     } else {
@@ -341,6 +356,17 @@
         ManagedObject<?> child = children.get(name);
         ManagedObjectDefinition<?, ?> d = child.getManagedObjectDefinition();
 
+        // Skip advanced and hidden components in non-advanced mode.
+        if (!app.isAdvancedMode()) {
+          if (d.hasOption(ManagedObjectOption.HIDDEN)) {
+            continue;
+          }
+
+          if (d.hasOption(ManagedObjectOption.ADVANCED)) {
+            continue;
+          }
+        }
+
         // First output the name.
         builder.startRow();
         builder.appendCell(name);
@@ -348,11 +374,20 @@
         // Output the managed object type in the form used in
         // create-xxx commands.
         String childType = d.getName();
+        boolean isCustom = CLIProfile.getInstance().isForCustomization(d);
         if (baseType.equals(childType)) {
-          builder.appendCell("generic");
+          if (isCustom) {
+            builder.appendCell(DSConfig.CUSTOM_TYPE);
+          } else {
+            builder.appendCell(DSConfig.GENERIC_TYPE);
+          }
         } else if (childType.endsWith(typeSuffix)) {
-          builder.appendCell(childType.substring(0, childType.length()
-              - typeSuffix.length()));
+          String ctname = childType.substring(0, childType.length()
+              - typeSuffix.length());
+          if (isCustom) {
+            ctname = String.format("%s-%s", DSConfig.CUSTOM_TYPE, ctname);
+          }
+          builder.appendCell(ctname);
         } else {
           builder.appendCell(childType);
         }
diff --git a/opends/src/server/org/opends/server/tools/dsconfig/SubCommandHandler.java b/opends/src/server/org/opends/server/tools/dsconfig/SubCommandHandler.java
index 3292bc7..6a4d8e3 100644
--- a/opends/src/server/org/opends/server/tools/dsconfig/SubCommandHandler.java
+++ b/opends/src/server/org/opends/server/tools/dsconfig/SubCommandHandler.java
@@ -40,6 +40,8 @@
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
 
 import org.opends.messages.Message;
 import org.opends.server.admin.AbstractManagedObjectDefinition;
@@ -48,7 +50,9 @@
 import org.opends.server.admin.DefinitionDecodingException;
 import org.opends.server.admin.DurationUnit;
 import org.opends.server.admin.InstantiableRelationDefinition;
+import org.opends.server.admin.ManagedObjectDefinition;
 import org.opends.server.admin.ManagedObjectNotFoundException;
+import org.opends.server.admin.ManagedObjectOption;
 import org.opends.server.admin.ManagedObjectPath;
 import org.opends.server.admin.ManagedObjectPathSerializer;
 import org.opends.server.admin.OptionalRelationDefinition;
@@ -987,8 +991,41 @@
 
     app.println();
     app.println();
-    String[] children = parent.listChildren(r, d);
-    switch (children.length) {
+
+    // Filter out advanced and hidden types if required.
+    String[] childNames = parent.listChildren(r, d);
+    SortedSet<String> children = new TreeSet<String>(
+        String.CASE_INSENSITIVE_ORDER);
+
+    for (String childName : childNames) {
+      ManagedObject<?> child;
+      try {
+        child = parent.getChild(r, childName);
+
+        ManagedObjectDefinition<?, ?> cd = child.getManagedObjectDefinition();
+
+        if (cd.hasOption(ManagedObjectOption.HIDDEN)) {
+          continue;
+        }
+
+        if (!app.isAdvancedMode()
+            && cd.hasOption(ManagedObjectOption.ADVANCED)) {
+          continue;
+        }
+
+        children.add(childName);
+      } catch (DefinitionDecodingException e) {
+        // Add it anyway: maybe the user is trying to fix the problem.
+        children.add(childName);
+      } catch (ManagedObjectDecodingException e) {
+        // Add it anyway: maybe the user is trying to fix the problem.
+        children.add(childName);
+      } catch (ManagedObjectNotFoundException e) {
+        // Skip it - the managed object has been concurrently removed.
+      }
+    }
+
+    switch (children.size()) {
     case 0: {
       // No options available - abort.
       Message msg =
@@ -999,9 +1036,9 @@
       // Only one option available so confirm that the user wishes to
       // access it.
       Message msg = INFO_DSCFG_FINDER_PROMPT_SINGLE.get(
-              d.getUserFriendlyName(), children[0]);
+              d.getUserFriendlyName(), children.first());
       if (app.confirmAction(msg, true)) {
-        return MenuResult.success(children[0]);
+        return MenuResult.success(children.first());
       } else {
         return MenuResult.cancel();
       }
@@ -1013,7 +1050,6 @@
       builder.setPrompt(INFO_DSCFG_FINDER_PROMPT_MANY.get(d
           .getUserFriendlyName()));
 
-      Arrays.sort(children, String.CASE_INSENSITIVE_ORDER);
       for (String child : children) {
         Message option = Message.raw("%s", child);
         builder.addNumberedOption(option, MenuResult.success(child));

--
Gitblit v1.10.0