From 025e4068faf844653d6cf1401c16955f70df37ed Mon Sep 17 00:00:00 2001
From: matthew_swift <matthew_swift@localhost>
Date: Tue, 31 Jul 2007 12:48:50 +0000
Subject: [PATCH] Fix issue 1991: dsconfig: split "component" field in list-properties

---
 opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/ArgumentExceptionFactory.java |   53 +++++
 opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/ListSubCommandHandler.java    |    2 
 opendj-sdk/opends/src/server/org/opends/server/messages/ToolMessages.java                   |   81 +++++++
 opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/HelpSubCommandHandler.java    |  423 ++++++++++++++++++++++++++++++++---------
 4 files changed, 450 insertions(+), 109 deletions(-)

diff --git a/opendj-sdk/opends/src/server/org/opends/server/messages/ToolMessages.java b/opendj-sdk/opends/src/server/org/opends/server/messages/ToolMessages.java
index c0ddc83..b8847dc 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/messages/ToolMessages.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/messages/ToolMessages.java
@@ -7299,9 +7299,9 @@
 
   /**
    * The message ID for the message that will be used as the
-   * heading of the managed object type column in tables.
+   * heading of the component category column in tables.
    */
-  public static final int MSGID_DSCFG_HEADING_MANAGED_OBJECT_NAME =
+  public static final int MSGID_DSCFG_HEADING_COMPONENT_NAME =
        CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1018;
 
 
@@ -7912,7 +7912,7 @@
    * The message ID for the message that will be used as the
    * heading of the managed object type column in list tables.
    */
-  public static final int MSGID_DSCFG_HEADING_MANAGED_OBJECT_TYPE =
+  public static final int MSGID_DSCFG_HEADING_COMPONENT_TYPE =
        CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1082;
 
 
@@ -9553,7 +9553,7 @@
 
   /**
    * The message ID for the message which will be used in dsconfig
-   * help for the component heading.
+   * help for the component name heading.
    */
   public static final int MSGID_DSCFG_HELP_HEADING_COMPONENT =
     CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1264;
@@ -9705,6 +9705,49 @@
   public static final int MSGID_DSCFG_CONFIRM_MODIFY_FAIL =
     CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1285;
 
+  /**
+   * The message ID for the message that will be used as the
+   * description of the list-properties category argument. This does
+   * not take any arguments.
+   */
+  public static final int MSGID_DSCFG_DESCRIPTION_HELP_CATEGORY =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1286;
+
+  /**
+   * The message ID for the message that will be used if the user
+   * requests help for a component category but specifies an unknown
+   * category name. This takes a single argument which is the invalid
+   * argument.
+   */
+  public static final int MSGID_DSCFG_ERROR_CATEGORY_UNRECOGNIZED =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1287;
+
+  /**
+   * The message ID for the message that will be used if the user
+   * requests help for a component category and sub-type but specifies
+   * an unknown sub-type name. This takes two arguments which are the
+   * invalid type argument and the category.
+   */
+  public static final int MSGID_DSCFG_ERROR_CATEGORY_TYPE_UNRECOGNIZED =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1288;
+
+  /**
+   * The message ID for the message that will be used if the user
+   * attempts to access a property which is not part of any managed
+   * object. This takes a single argument which is the name of the
+   * invalid property.
+   */
+  public static final int MSGID_DSCFG_ERROR_PROPERTY_UNRECOGNIZED_NO_DEFN =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_SEVERE_ERROR | 1289;
+
+  /**
+   * The message ID for the message that will be used as the
+   * description of the list-properties category argument. This does
+   * not take any arguments.
+   */
+  public static final int MSGID_DSCFG_DESCRIPTION_HELP_INHERITED =
+       CATEGORY_MASK_TOOLS | SEVERITY_MASK_INFORMATIONAL | 1290;
+
 
 
   /**
@@ -12035,9 +12078,19 @@
                     "value of the \"%s\" property: %s");
 
     registerMessage(MSGID_DSCFG_DESCRIPTION_HELP_TYPE,
-                    "The type(s) of components whose properties should be " +
+                    "The type of components whose properties should be " +
+                    "described. The value for TYPE must be one of the " +
+                    "component types associated with the CATEGORY specified " +
+                    "using the \"--category\" option");
+
+    registerMessage(MSGID_DSCFG_DESCRIPTION_HELP_CATEGORY,
+                    "The category of components whose properties should be " +
                     "described");
 
+    registerMessage(MSGID_DSCFG_DESCRIPTION_HELP_INHERITED,
+                    "Modifies the display output to show the inherited " +
+                    "properties of components");
+
     registerMessage(MSGID_DSCFG_DESCRIPTION_TYPE,
                     "The type of %s which should be created. The value " +
                     "for TYPE can be one of: %s");
@@ -12119,6 +12172,9 @@
     registerMessage(MSGID_DSCFG_ERROR_PROPERTY_UNRECOGNIZED,
                     "The property \"%s\" is not a recognized property of %s");
 
+    registerMessage(MSGID_DSCFG_ERROR_PROPERTY_UNRECOGNIZED_NO_DEFN,
+                    "The property \"%s\" is not a recognized property");
+
     registerMessage(MSGID_DSCFG_ERROR_PROPERTY_INVALID_VALUE,
                     "The value \"%s\" is not a valid value for the %s " +
                     "property \"%s\" which has the following syntax: %s");
@@ -12168,10 +12224,10 @@
     registerMessage(MSGID_DSCFG_ERROR_ILLEGAL_NAME_UNKNOWN,
                     "The name \"%s\" is not a valid name for the %s");
 
-    registerMessage(MSGID_DSCFG_HEADING_MANAGED_OBJECT_NAME,
+    registerMessage(MSGID_DSCFG_HEADING_COMPONENT_NAME,
                     "Component");
 
-    registerMessage(MSGID_DSCFG_HEADING_MANAGED_OBJECT_TYPE,
+    registerMessage(MSGID_DSCFG_HEADING_COMPONENT_TYPE,
                     "Type");
 
     registerMessage(MSGID_DSCFG_HEADING_PROPERTY_NAME,
@@ -12386,7 +12442,14 @@
                     "It should be one of: %s");
 
     registerMessage(MSGID_DSCFG_ERROR_TYPE_UNRECOGNIZED,
-                    "\"%s\" is not a recognized type of managed object");
+                    "\"%s\" is not a recognized component type");
+
+    registerMessage(MSGID_DSCFG_ERROR_CATEGORY_UNRECOGNIZED,
+                    "\"%s\" is not a recognized component category");
+
+    registerMessage(MSGID_DSCFG_ERROR_CATEGORY_TYPE_UNRECOGNIZED,
+                    "\"%s\" is not a recognized component type in " +
+                    "category \"%s\"");
 
     registerMessage(MSGID_DSCFG_ERROR_WRONG_MANAGED_OBJECT_TYPE,
                     "The %s could not be retrieved because it was the " +
@@ -12789,7 +12852,7 @@
     registerMessage(MSGID_DSCFG_HELP_HEADING_PROPERTY,
         "Property: %s");
     registerMessage(MSGID_DSCFG_HELP_HEADING_COMPONENT,
-        "Component: %s");
+        "Component name: %s");
     registerMessage(MSGID_DSCFG_HELP_HEADING_DEFAULT,
         "Default behavior");
     registerMessage(MSGID_DSCFG_HELP_HEADING_MANDATORY,
diff --git a/opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/ArgumentExceptionFactory.java b/opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/ArgumentExceptionFactory.java
index b9d6399..2bfd17a 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/ArgumentExceptionFactory.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/ArgumentExceptionFactory.java
@@ -421,6 +421,22 @@
 
   /**
    * Creates an argument exception which should be used when a
+   * component category argument is not recognized.
+   *
+   * @param categoryName
+   *          The unrecognized component category.
+   * @return Returns an argument exception.
+   */
+  public static ArgumentException unknownCategory(String categoryName) {
+    int msgID = MSGID_DSCFG_ERROR_CATEGORY_UNRECOGNIZED;
+    String msg = getMessage(msgID, categoryName);
+    return new ArgumentException(msgID, msg);
+  }
+
+
+
+  /**
+   * Creates an argument exception which should be used when a
    * property name is not recognized.
    *
    * @param d
@@ -440,6 +456,22 @@
 
   /**
    * Creates an argument exception which should be used when a
+   * property name is not recognized.
+   *
+   * @param name
+   *          The unrecognized property name.
+   * @return Returns an argument exception.
+   */
+  public static ArgumentException unknownProperty(String name) {
+    int msgID = MSGID_DSCFG_ERROR_PROPERTY_UNRECOGNIZED_NO_DEFN;
+    String message = getMessage(msgID, name);
+    return new ArgumentException(msgID, message);
+  }
+
+
+
+  /**
+   * Creates an argument exception which should be used when a
    * sub-type argument in a create-xxx sub-command is not recognized.
    *
    * @param r
@@ -465,7 +497,7 @@
    * object type argument is not recognized.
    *
    * @param typeName
-   *          The unrecognized property sub-type.
+   *          The unrecognized component type.
    * @return Returns an argument exception.
    */
   public static ArgumentException unknownType(String typeName) {
@@ -478,6 +510,25 @@
 
   /**
    * Creates an argument exception which should be used when a managed
+   * object type argument is not associated with a category.
+   *
+   * @param categoryName
+   *          The component category.
+   * @param typeName
+   *          The unrecognized component type.
+   * @return Returns an argument exception.
+   */
+  public static ArgumentException unknownTypeInCategory(String categoryName,
+      String typeName) {
+    int msgID = MSGID_DSCFG_ERROR_CATEGORY_TYPE_UNRECOGNIZED;
+    String msg = getMessage(msgID, typeName, categoryName);
+    return new ArgumentException(msgID, msg);
+  }
+
+
+
+  /**
+   * Creates an argument exception which should be used when a managed
    * object is retrieved but does not have the correct type
    * appropriate for the associated sub-command.
    *
diff --git a/opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/HelpSubCommandHandler.java b/opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/HelpSubCommandHandler.java
index 663839d..337c4bc 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/HelpSubCommandHandler.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/HelpSubCommandHandler.java
@@ -35,9 +35,10 @@
 
 import java.io.PrintStream;
 import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
 import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeMap;
@@ -56,10 +57,12 @@
 import org.opends.server.admin.PropertyOption;
 import org.opends.server.admin.RelativeInheritedDefaultBehaviorProvider;
 import org.opends.server.admin.StringPropertyDefinition;
+import org.opends.server.admin.Tag;
 import org.opends.server.admin.UndefinedDefaultBehaviorProvider;
 import org.opends.server.admin.UnknownPropertyDefinitionException;
 import org.opends.server.tools.ClientException;
 import org.opends.server.util.args.ArgumentException;
+import org.opends.server.util.args.BooleanArgument;
 import org.opends.server.util.args.StringArgument;
 import org.opends.server.util.args.SubCommand;
 import org.opends.server.util.args.SubCommandArgumentParser;
@@ -351,6 +354,11 @@
     }
   }
 
+  /**
+   * 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 = " : ";
 
@@ -358,17 +366,35 @@
   private final static int HEADING_WIDTH;
 
   /**
+   * The value for the long option inherited.
+   */
+  private static final String OPTION_DSCFG_LONG_INHERITED = "inherited";
+
+  /**
+   * The value for the short option inherited.
+   */
+  private static final Character OPTION_DSCFG_SHORT_INHERITED = null;
+
+  /**
    * The value for the long option type.
    */
   private static final String OPTION_DSCFG_LONG_TYPE = "type";
 
-
-
   /**
    * The value for the short option type.
    */
   private static final Character OPTION_DSCFG_SHORT_TYPE = 't';
 
+  /**
+   * The value for the long option category.
+   */
+  private static final String OPTION_DSCFG_LONG_CATEGORY = "category";
+
+  /**
+   * The value for the short option category.
+   */
+  private static final Character OPTION_DSCFG_SHORT_CATEGORY = 'c';
+
   static {
     int tmp = getMessage(MSGID_DSCFG_HELP_HEADING_SYNTAX).length();
     tmp = Math.max(tmp, getMessage(MSGID_DSCFG_HELP_HEADING_DEFAULT).length());
@@ -381,6 +407,8 @@
     HEADING_WIDTH = tmp;
   }
 
+
+
   /**
    * Creates a new help-properties sub-command.
    *
@@ -513,17 +541,31 @@
     }
   }
 
-
-
   // The sub-command associated with this handler.
   private final SubCommand subCommand;
 
-  // The argument which should be used to specify the type of managed
-  // object to be retrieved.
+  // The argument which should be used to specify the category of
+  // managed object to be retrieved.
+  private final StringArgument categoryArgument;
+
+  //The argument which should be used to display inherited properties.
+  private BooleanArgument inheritedModeArgument;
+
+  // The argument which should be used to specify the sub-type of
+  // managed object to be retrieved.
   private final StringArgument typeArgument;
 
-  // A table listing all the available types of managed object.
-  private final Map<String, AbstractManagedObjectDefinition<?, ?>> types;
+  // A table listing all the available types of managed object indexed
+  // on their parent type.
+  private final Map<String,
+    Map<String, AbstractManagedObjectDefinition<?, ?>>> categoryMap;
+
+  // A table listing all the available types of managed object indexed
+  // on their tag(s).
+  private final Map<Tag,
+    Map<String, AbstractManagedObjectDefinition<?, ?>>> tagMap;
+
+
 
   // Private constructor.
   private HelpSubCommandHandler(ConsoleApplication app,
@@ -536,17 +578,30 @@
     this.subCommand = new SubCommand(parser, name, false, 0, 0, null,
         descriptionID);
 
+    this.categoryArgument = new StringArgument(OPTION_DSCFG_LONG_CATEGORY,
+        OPTION_DSCFG_SHORT_CATEGORY, OPTION_DSCFG_LONG_CATEGORY, false, false,
+        true, "{CATEGORY}", null, null, MSGID_DSCFG_DESCRIPTION_HELP_CATEGORY);
+    this.subCommand.addArgument(this.categoryArgument);
+
     this.typeArgument = new StringArgument(OPTION_DSCFG_LONG_TYPE,
         OPTION_DSCFG_SHORT_TYPE, OPTION_DSCFG_LONG_TYPE, false, false, true,
         "{TYPE}", null, null, MSGID_DSCFG_DESCRIPTION_HELP_TYPE);
     this.subCommand.addArgument(this.typeArgument);
 
+    this.inheritedModeArgument = new BooleanArgument(
+        OPTION_DSCFG_LONG_INHERITED, OPTION_DSCFG_SHORT_INHERITED,
+        OPTION_DSCFG_LONG_INHERITED, MSGID_DSCFG_DESCRIPTION_HELP_INHERITED);
+    subCommand.addArgument(inheritedModeArgument);
+
     // Register common arguments.
     registerAdvancedModeArgument(this.subCommand,
         MSGID_DSCFG_DESCRIPTION_ADVANCED_HELP);
     registerPropertyNameArgument(this.subCommand);
 
-    this.types = new TreeMap<String, AbstractManagedObjectDefinition<?, ?>>();
+    this.categoryMap = new TreeMap<String,
+      Map<String, AbstractManagedObjectDefinition<?, ?>>>();
+    this.tagMap = new HashMap<Tag,
+      Map<String, AbstractManagedObjectDefinition<?, ?>>>();
   }
 
 
@@ -570,7 +625,47 @@
    */
   public void registerManagedObjectDefinition(
       AbstractManagedObjectDefinition<?, ?> d) {
-    types.put(d.getName(), d);
+    // Determine the definition's base name.
+    AbstractManagedObjectDefinition<?, ?> parent = d;
+    while (parent.getParent() != null) {
+      parent = parent.getParent();
+    }
+
+    String baseName = parent.getName();
+    String typeName = null;
+    if (parent == d) {
+      // This was a top-level definition.
+      typeName = GENERIC_TYPE;
+    } else {
+      // For the type name we shorten it, if possible, by stripping
+      // off the trailing part of the name which matches the
+      // base-type.
+      String suffix = "-" + baseName;
+      typeName = d.getName();
+      if (typeName.endsWith(suffix)) {
+        typeName = typeName.substring(0, typeName.length() - suffix.length());
+      }
+    }
+
+    // Get the sub-type mapping, creating it if necessary.
+    Map<String, AbstractManagedObjectDefinition<?, ?>> subTypes = categoryMap
+        .get(baseName);
+    if (subTypes == null) {
+      subTypes = new TreeMap<String, AbstractManagedObjectDefinition<?, ?>>();
+      categoryMap.put(baseName, subTypes);
+    }
+
+    subTypes.put(typeName, d);
+
+    // Get the tag mapping, creating it if necessary.
+    for (Tag tag : d.getAllTags()) {
+      subTypes = tagMap.get(baseName);
+      if (subTypes == null) {
+        subTypes = new TreeMap<String, AbstractManagedObjectDefinition<?, ?>>();
+        tagMap.put(tag, subTypes);
+      }
+      subTypes.put(typeName, d);
+    }
   }
 
 
@@ -579,53 +674,118 @@
    * {@inheritDoc}
    */
   @Override
-  public int run()
-      throws ArgumentException, ClientException {
+  public int run() throws ArgumentException, ClientException {
+    String categoryName = categoryArgument.getValue();
     String typeName = typeArgument.getValue();
+    Tag tag = null;
     Set<String> propertyNames = getPropertyNames();
 
-    AbstractManagedObjectDefinition<?, ?> d = null;
-    if (typeName != null) {
-      // Requested help regarding a single managed object type.
-      d = types.get(typeName);
-      if (d == null) {
+    List<AbstractManagedObjectDefinition<?, ?>> dlist =
+      new LinkedList<AbstractManagedObjectDefinition<?, ?>>();
+    AbstractManagedObjectDefinition<?, ?> tmp = null;
+
+    if (categoryName != null) {
+      // User requested a category of components.
+      Map<String, AbstractManagedObjectDefinition<?, ?>> subTypes = categoryMap
+          .get(categoryName);
+
+      if (subTypes == null) {
+        // Try a tag-base look-up.
+        try {
+          tag = Tag.valueOf(categoryName);
+        } catch (IllegalArgumentException e) {
+          throw ArgumentExceptionFactory.unknownCategory(categoryName);
+        }
+
+        categoryName = null;
+        subTypes = tagMap.get(tag);
+        if (subTypes == null) {
+          throw ArgumentExceptionFactory.unknownCategory(categoryName);
+        }
+      } else {
+        // Cache the generic definition for improved errors later on.
+        tmp = subTypes.get(GENERIC_TYPE);
+      }
+
+      if (typeName != null) {
+        AbstractManagedObjectDefinition<?, ?> d = subTypes.get(typeName);
+        if (d == null) {
+          throw ArgumentExceptionFactory.unknownTypeInCategory(categoryName,
+              typeName);
+        }
+        dlist.add(d);
+
+        // Cache the generic definition for improved errors later on.
+        tmp = d;
+      } else {
+        dlist.addAll(subTypes.values());
+      }
+    } else if (typeName != null) {
+      // User requested just the sub-type which could appear in
+      // multiple categories.
+      boolean isFound = false;
+
+      for (Map<String, AbstractManagedObjectDefinition<?, ?>> subTypes :
+        categoryMap.values()) {
+        AbstractManagedObjectDefinition<?, ?> d = subTypes.get(typeName);
+        if (d != null) {
+          dlist.add(d);
+          isFound = true;
+        }
+      }
+
+      if (!isFound) {
         throw ArgumentExceptionFactory.unknownType(typeName);
       }
+    } else {
+      // User did not specify a category nor a sub-type.
+      for (Map<String, AbstractManagedObjectDefinition<?, ?>> subTypes :
+        categoryMap.values()) {
+        dlist.addAll(subTypes.values());
+      }
     }
 
-    // Validate property names if the type was specified.
-    if (d != null) {
-      for (String propertyName : propertyNames) {
+    // Validate property names.
+    if (dlist.size() == 1) {
+      // Cache the generic definition for improved errors later on.
+      tmp = dlist.get(0);
+    }
+
+    for (String propertyName : propertyNames) {
+      boolean isFound = false;
+
+      for (AbstractManagedObjectDefinition<?, ?> d : dlist) {
         try {
           d.getPropertyDefinition(propertyName);
+          isFound = true;
         } catch (IllegalArgumentException e) {
-          throw ArgumentExceptionFactory.unknownProperty(d, propertyName);
+          // Ignore for now.
+        }
+      }
+
+      if (!isFound) {
+        if (tmp != null) {
+          throw ArgumentExceptionFactory.unknownProperty(tmp, propertyName);
+        } else {
+          throw ArgumentExceptionFactory.unknownProperty(propertyName);
         }
       }
     }
 
-    // Determine the set of managed objects to be displayed.
-    Collection<AbstractManagedObjectDefinition<?, ?>> defns;
-    if (d == null) {
-      defns = types.values();
+    if (!getConsoleApplication().isVerbose()) {
+      displayNonVerbose(categoryName, typeName, tag, propertyNames);
     } else {
-      defns = Collections.<AbstractManagedObjectDefinition<?, ?>> singleton(d);
+      displayVerbose(categoryName, typeName, tag, propertyNames);
     }
 
-    if (!getConsoleApplication().isVerbose()) {
-      displayNonVerbose(defns, propertyNames);
-    } else {
-      displayVerbose(defns, propertyNames);
-    }
     return 0;
   }
 
 
 
   // Output property summary table.
-  private void displayNonVerbose(
-      Collection<AbstractManagedObjectDefinition<?, ?>> defns,
-      Set<String> propertyNames) {
+  private void displayNonVerbose(String categoryName, String typeName,
+      Tag tag, Set<String> propertyNames) {
     PrintStream out = getConsoleApplication().getOutputStream();
     if (!getConsoleApplication().isScriptFriendly()) {
       out.println(getMessage(MSGID_DSCFG_HELP_DESCRIPTION_OPTION));
@@ -647,7 +807,8 @@
     // Headings.
     TableBuilder builder = new TableBuilder();
 
-    builder.appendHeading(getMessage(MSGID_DSCFG_HEADING_MANAGED_OBJECT_NAME));
+    builder.appendHeading(getMessage(MSGID_DSCFG_HEADING_COMPONENT_NAME));
+    builder.appendHeading(getMessage(MSGID_DSCFG_HEADING_COMPONENT_TYPE));
     builder.appendHeading(getMessage(MSGID_DSCFG_HEADING_PROPERTY_NAME));
     builder.appendHeading(getMessage(MSGID_DSCFG_HEADING_PROPERTY_OPTIONS));
     builder.appendHeading(getMessage(MSGID_DSCFG_HEADING_PROPERTY_SYNTAX));
@@ -655,45 +816,78 @@
     // Sort keys.
     builder.addSortKey(0);
     builder.addSortKey(1);
+    builder.addSortKey(2);
 
     // Generate the table content.
-    for (AbstractManagedObjectDefinition<?, ?> mod : defns) {
-      Collection<PropertyDefinition<?>> pds;
-      if (getConsoleApplication().isScriptFriendly()) {
-        pds = mod.getAllPropertyDefinitions();
-      } else {
-        pds = mod.getPropertyDefinitions();
+    for (String category : categoryMap.keySet()) {
+      // Skip if this is the wrong category.
+      if (categoryName != null && !categoryName.equals(category)) {
+        continue;
       }
 
-      for (PropertyDefinition<?> pd : pds) {
-        if (pd.hasOption(PropertyOption.HIDDEN)) {
+      // Process the sub-types.
+      Map<String, AbstractManagedObjectDefinition<?, ?>> subTypes = categoryMap
+          .get(category);
+      for (String type : subTypes.keySet()) {
+        // Skip if this is the wrong sub-type.
+        if (typeName != null && !typeName.equals(type)) {
           continue;
         }
 
-        if (!isAdvancedMode() && pd.hasOption(PropertyOption.ADVANCED)) {
+        // Display help for each property.
+        AbstractManagedObjectDefinition<?, ?> mod = subTypes.get(type);
+
+        // Skip if this does not have the required tag.
+        if (tag != null && !mod.hasTag(tag)) {
           continue;
         }
 
-        if (!propertyNames.isEmpty() && !propertyNames.contains(pd.getName())) {
-          continue;
+        Set<PropertyDefinition<?>> pds = new TreeSet<PropertyDefinition<?>>();
+        if (inheritedModeArgument.isPresent()) {
+          pds.addAll(mod.getAllPropertyDefinitions());
+        } else {
+          pds.addAll(mod.getPropertyDefinitions());
+
+          // The list will still contain overridden properties.
+          if (mod.getParent() != null) {
+            pds.removeAll(mod.getParent().getAllPropertyDefinitions());
+          }
         }
 
-        // Display the property.
-        builder.startRow();
+        for (PropertyDefinition<?> pd : pds) {
+          if (pd.hasOption(PropertyOption.HIDDEN)) {
+            continue;
+          }
 
-        // Display the managed object type if necessary.
-        builder.appendCell(mod.getName());
+          if (!isAdvancedMode() && pd.hasOption(PropertyOption.ADVANCED)) {
+            continue;
+          }
 
-        // Display the property name.
-        builder.appendCell(pd.getName());
+          if (!propertyNames.isEmpty() &&
+              !propertyNames.contains(pd.getName())) {
+            continue;
+          }
 
-        // Display the options.
-        builder.appendCell(getPropertyOptionSummary(pd));
+          // Display the property.
+          builder.startRow();
 
-        // Display the syntax.
-        PropertyDefinitionUsageBuilder v =
-          new PropertyDefinitionUsageBuilder(false);
-        builder.appendCell(v.getUsage(pd));
+          // Display the component category.
+          builder.appendCell(category);
+
+          // Display the component type.
+          builder.appendCell(type);
+
+          // Display the property name.
+          builder.appendCell(pd.getName());
+
+          // Display the options.
+          builder.appendCell(getPropertyOptionSummary(pd));
+
+          // Display the syntax.
+          PropertyDefinitionUsageBuilder v = new PropertyDefinitionUsageBuilder(
+              false);
+          builder.appendCell(v.getUsage(pd));
+        }
       }
     }
 
@@ -709,9 +903,8 @@
 
 
   // Display detailed help on managed objects and their properties.
-  private void displayVerbose(
-      Collection<AbstractManagedObjectDefinition<?, ?>> defns,
-      Set<String> propertyNames) {
+  private void displayVerbose(String categoryName, String typeName,
+      Tag tag, Set<String> propertyNames) {
     PrintStream out = getConsoleApplication().getOutputStream();
 
     // Construct line used to separate consecutive sections.
@@ -722,54 +915,88 @@
 
     // Display help for each managed object.
     boolean isFirstManagedObject = true;
-    for (AbstractManagedObjectDefinition<?, ?> mod : defns) {
-      // Display help for each property.
-      Set<PropertyDefinition<?>> pds =
-        new TreeSet<PropertyDefinition<?>>(mod.getAllPropertyDefinitions());
-      boolean isFirstProperty = true;
-      for (PropertyDefinition<?> pd : pds) {
-        if (pd.hasOption(PropertyOption.HIDDEN)) {
+    for (String category : categoryMap.keySet()) {
+      // Skip if this is the wrong category.
+      if (categoryName != null && !categoryName.equals(category)) {
+        continue;
+      }
+
+      // Process the sub-types.
+      Map<String, AbstractManagedObjectDefinition<?, ?>> subTypes = categoryMap
+          .get(category);
+      for (String type : subTypes.keySet()) {
+        // Skip if this is the wrong sub-type.
+        if (typeName != null && !typeName.equals(type)) {
           continue;
         }
 
-        if (!isAdvancedMode() && pd.hasOption(PropertyOption.ADVANCED)) {
+        // Display help for each property.
+        AbstractManagedObjectDefinition<?, ?> mod = subTypes.get(type);
+
+        // Skip if this does not have the required tag.
+        if (tag != null && !mod.hasTag(tag)) {
           continue;
         }
 
-        if (!propertyNames.isEmpty() && !propertyNames.contains(pd.getName())) {
-          continue;
+        Set<PropertyDefinition<?>> pds = new TreeSet<PropertyDefinition<?>>();
+        if (inheritedModeArgument.isPresent()) {
+          pds.addAll(mod.getAllPropertyDefinitions());
+        } else {
+          pds.addAll(mod.getPropertyDefinitions());
+
+          // The list will still contain overridden properties.
+          if (mod.getParent() != null) {
+            pds.removeAll(mod.getParent().getAllPropertyDefinitions());
+          }
         }
 
-        if (isFirstProperty) {
-          // User has requested properties relating to this managed
-          // object definition, so display the summary of the managed
-          // object.
-          if (!isFirstManagedObject) {
-            out.println();
-            out.println(c1);
-            out.println();
-          } else {
-            isFirstManagedObject = false;
+        boolean isFirstProperty = true;
+        for (PropertyDefinition<?> pd : pds) {
+          if (pd.hasOption(PropertyOption.HIDDEN)) {
+            continue;
           }
 
-          // Display the title.
-          out.println(wrapText(getMessage(MSGID_DSCFG_HELP_HEADING_COMPONENT,
-              mod.getUserFriendlyName()), MAX_LINE_WIDTH));
+          if (!isAdvancedMode() && pd.hasOption(PropertyOption.ADVANCED)) {
+            continue;
+          }
+
+          if (!propertyNames.isEmpty() &&
+              !propertyNames.contains(pd.getName())) {
+            continue;
+          }
+
+          if (isFirstProperty) {
+            // User has requested properties relating to this managed
+            // object definition, so display the summary of the
+            // managed
+            // object.
+            if (!isFirstManagedObject) {
+              out.println();
+              out.println(c1);
+              out.println();
+            } else {
+              isFirstManagedObject = false;
+            }
+
+            // Display the title.
+            out.println(wrapText(getMessage(MSGID_DSCFG_HELP_HEADING_COMPONENT,
+                mod.getUserFriendlyName()), MAX_LINE_WIDTH));
+
+            out.println();
+            out.println(wrapText(mod.getSynopsis(), MAX_LINE_WIDTH));
+            if (mod.getDescription() != null) {
+              out.println();
+              out.println(wrapText(mod.getDescription(), MAX_LINE_WIDTH));
+            }
+          }
 
           out.println();
-          out.println(wrapText(mod.getSynopsis(), MAX_LINE_WIDTH));
-          if (mod.getDescription() != null) {
-            out.println();
-            out.println(wrapText(mod.getDescription(), MAX_LINE_WIDTH));
-          }
+          out.println(c2);
+          out.println();
+
+          displayVerboseSingleProperty(mod, pd.getName(), out);
+          isFirstProperty = false;
         }
-
-        out.println();
-        out.println(c2);
-        out.println();
-
-        displayVerboseSingleProperty(mod, pd.getName(), out);
-        isFirstProperty = false;
       }
     }
   }
diff --git a/opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/ListSubCommandHandler.java b/opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/ListSubCommandHandler.java
index 68cc6dc..bad549f 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/ListSubCommandHandler.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/tools/dsconfig/ListSubCommandHandler.java
@@ -331,7 +331,7 @@
       TableBuilder builder = new TableBuilder();
       builder.appendHeading(relation.getUserFriendlyName());
       builder
-          .appendHeading(getMessage(MSGID_DSCFG_HEADING_MANAGED_OBJECT_TYPE));
+          .appendHeading(getMessage(MSGID_DSCFG_HEADING_COMPONENT_TYPE));
       if (!propertyNames.isEmpty()) {
       }
       for (String propertyName : propertyNames) {

--
Gitblit v1.10.0