From 314e6e2709c4b0ebfe509e262ca366874f9069da Mon Sep 17 00:00:00 2001
From: Mark Craig <mark.craig@forgerock.com>
Date: Wed, 11 Mar 2015 11:59:20 +0000
Subject: [PATCH] CR-6316 OPENDJ-1786 Automate integration of generated content

---
 opendj-cli/src/main/resources/templates/refEntry.ftl                               |   51 -
 opendj-cli/src/main/resources/templates/refSect1.ftl                               |   41 ++
 opendj-config/src/main/java/org/forgerock/opendj/config/dsconfig/DSConfig.java     |    4 
 opendj-cli/src/main/java/com/forgerock/opendj/cli/DocDescriptionSupplement.java    |   50 ++
 opendj-cli/src/main/java/com/forgerock/opendj/cli/Argument.java                    |   22 
 opendj-cli/src/main/java/com/forgerock/opendj/cli/DocGenerationHelper.java         |   23 +
 opendj-cli/src/main/java/com/forgerock/opendj/cli/ToolRefDocContainer.java         |  162 ++++++++
 opendj-cli/src/main/java/com/forgerock/opendj/cli/SubCommand.java                  |   19 
 opendj-cli/src/main/resources/templates/optionsRefSect1.ftl                        |   62 +++
 opendj-cli/src/main/resources/templates/refSect2.ftl                               |   42 +-
 opendj-cli/src/main/java/com/forgerock/opendj/cli/SubCommandArgumentParser.java    |  116 ++++-
 opendj-config/src/main/resources/com/forgerock/opendj/dsconfig/dsconfig.properties |  240 ++++++++++++
 opendj-cli/src/main/java/com/forgerock/opendj/cli/ArgumentParser.java              |  311 +++++++++++----
 13 files changed, 929 insertions(+), 214 deletions(-)

diff --git a/opendj-cli/src/main/java/com/forgerock/opendj/cli/Argument.java b/opendj-cli/src/main/java/com/forgerock/opendj/cli/Argument.java
index 0b11e7b..3c57458 100644
--- a/opendj-cli/src/main/java/com/forgerock/opendj/cli/Argument.java
+++ b/opendj-cli/src/main/java/com/forgerock/opendj/cli/Argument.java
@@ -40,7 +40,7 @@
  * for an application. This is an abstract class that must be subclassed in
  * order to provide specific functionality.
  */
-public abstract class Argument {
+public abstract class Argument implements DocDescriptionSupplement {
     /**
      * Indicates whether this argument should be hidden in the usage
      * information.
@@ -239,30 +239,16 @@
     }
 
     /**
-     * A supplement to the description for this argument
-     * intended for use in generated reference documentation.
+     * A supplement to the description intended for use in generated reference documentation.
      */
     private LocalizableMessage docDescriptionSupplement;
 
-    /**
-     * Retrieves a supplement to the description for this argument
-     * intended for use in generated reference documentation.
-     *
-     * @return The supplement to the description for this argument
-     *         for use in generated reference documentation,
-     *         or LocalizableMessage.EMPTY if there is no supplement.
-     */
+    /** {@inheritDoc} */
     public LocalizableMessage getDocDescriptionSupplement() {
         return docDescriptionSupplement != null ? docDescriptionSupplement : LocalizableMessage.EMPTY;
     }
 
-    /**
-     * Sets a supplement to the description for this argument
-     * intended for use in generated reference documentation.
-     *
-     * @param docDescriptionSupplement  The supplement to the description for this argument
-     *                                  for use in generated reference documentation.
-     */
+    /** {@inheritDoc} */
     public void setDocDescriptionSupplement(final LocalizableMessage docDescriptionSupplement) {
         this.docDescriptionSupplement = docDescriptionSupplement;
     }
diff --git a/opendj-cli/src/main/java/com/forgerock/opendj/cli/ArgumentParser.java b/opendj-cli/src/main/java/com/forgerock/opendj/cli/ArgumentParser.java
index a55aa2e..2dee2ad 100644
--- a/opendj-cli/src/main/java/com/forgerock/opendj/cli/ArgumentParser.java
+++ b/opendj-cli/src/main/java/com/forgerock/opendj/cli/ArgumentParser.java
@@ -65,7 +65,7 @@
  * file to obtain default values for arguments there if they are not specified
  * on the command-line.
  */
-public class ArgumentParser {
+public class ArgumentParser implements ToolRefDocContainer {
 
     private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
     /**
@@ -617,23 +617,14 @@
      */
     private LocalizableMessage shortToolDescription;
 
-    /**
-     * Gets a short description for this tool, suitable in a man page summary line.
-     *
-     * @return  A short description for this tool,
-     *          suitable in a man page summary line,
-     *          or LocalizableMessage.EMPTY if there is no short description.
-     */
-    LocalizableMessage getShortToolDescription() {
+    /** {@inheritDoc} */
+    @Override
+    public LocalizableMessage getShortToolDescription() {
         return shortToolDescription != null ? shortToolDescription : LocalizableMessage.EMPTY;
     }
 
-    /**
-     * Sets a short description for this tool, suitable in a man page summary line.
-     *
-     * @param   shortDescription    The short description for this tool,
-     *                              suitable in a man page summary line.
-     */
+    /** {@inheritDoc} */
+    @Override
     public void setShortToolDescription(final LocalizableMessage shortDescription) {
         this.shortToolDescription = shortDescription;
     }
@@ -642,29 +633,86 @@
      * A supplement to the description for this tool
      * intended for use in generated reference documentation.
      */
-    private LocalizableMessage docToolDescriptionSupplement;
+    private DocDescriptionSupplement docToolDescriptionSupplement;
 
-    /**
-     * Retrieves a supplement to the description for this tool,
-     * intended for use in generated reference documentation.
-     *
-     * @return A supplement to the description for this tool
-     *         intended for use in generated reference documentation,
-     *         or LocalizableMessage.EMPTY if there is no supplement.
-     */
-    LocalizableMessage getDocToolDescriptionSupplement() {
-        return docToolDescriptionSupplement != null ? docToolDescriptionSupplement : LocalizableMessage.EMPTY;
+    /** {@inheritDoc} */
+    @Override
+    public LocalizableMessage getDocToolDescriptionSupplement() {
+        this.docToolDescriptionSupplement =
+                constructIfNull(this.docToolDescriptionSupplement);
+        return this.docToolDescriptionSupplement.getDocDescriptionSupplement();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void setDocToolDescriptionSupplement(final LocalizableMessage supplement) {
+        this.docToolDescriptionSupplement =
+                constructIfNull(this.docToolDescriptionSupplement);
+        this.docToolDescriptionSupplement.setDocDescriptionSupplement(supplement);
     }
 
     /**
-     * Sets a supplement to the description for this tool,
+     * A supplement to the description for all subcommands of this tool,
      * intended for use in generated reference documentation.
-     *
-     * @param docToolDescriptionSupplement  The supplement to the description for this tool
-     *                                      intended for use in generated reference documentation.
      */
-    public void setDocToolDescriptionSupplement(final LocalizableMessage docToolDescriptionSupplement) {
-        this.docToolDescriptionSupplement = docToolDescriptionSupplement;
+    private class DocSubcommandsDescriptionSupplement implements DocDescriptionSupplement {
+        /**
+         * A supplement to the description intended for use in generated reference documentation.
+         */
+        private LocalizableMessage docDescriptionSupplement;
+
+        /** {@inheritDoc} */
+        public LocalizableMessage getDocDescriptionSupplement() {
+            return docDescriptionSupplement != null ? docDescriptionSupplement : LocalizableMessage.EMPTY;
+        }
+
+        /** {@inheritDoc} */
+        public void setDocDescriptionSupplement(final LocalizableMessage docDescriptionSupplement) {
+            this.docDescriptionSupplement = docDescriptionSupplement;
+        }
+    }
+
+    private DocDescriptionSupplement docSubcommandsDescriptionSupplement;
+
+    /** {@inheritDoc} */
+    @Override
+    public LocalizableMessage getDocSubcommandsDescriptionSupplement() {
+        this.docSubcommandsDescriptionSupplement =
+                constructIfNull(this.docSubcommandsDescriptionSupplement);
+        return this.docSubcommandsDescriptionSupplement.getDocDescriptionSupplement();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void setDocSubcommandsDescriptionSupplement(final LocalizableMessage supplement) {
+        this.docSubcommandsDescriptionSupplement =
+                constructIfNull(this.docSubcommandsDescriptionSupplement);
+        this.docSubcommandsDescriptionSupplement.setDocDescriptionSupplement(supplement);
+    }
+
+    private DocDescriptionSupplement constructIfNull(DocDescriptionSupplement supplement) {
+        if (supplement != null) {
+            return supplement;
+        }
+        return new DocSubcommandsDescriptionSupplement();
+    }
+
+    /**
+     * Additional paths to DocBook XML {@code RefSect1} documents
+     * to be appended after generated content in reference documentation.
+     */
+    private String[] pathsToTrailingRefSect1s;
+
+    /** {@inheritDoc} */
+    @Override
+    public String[] getPathsToTrailingRefSect1s() {
+        return pathsToTrailingRefSect1s != null ? pathsToTrailingRefSect1s : new String[0];
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void setPathsToTrailingRefSect1s(final String... paths) {
+        this.pathsToTrailingRefSect1s = paths;
     }
 
     /**
@@ -689,7 +737,7 @@
         final StringBuilder buffer = new StringBuilder();
         usageOrVersionDisplayed = true;
         if (System.getProperty("org.forgerock.opendj.gendoc") != null) {
-            toRefEntry(buffer);
+            toRefEntry(buffer, getSynopsisArgs(), argumentList);
         } else {
             getUsage(buffer);
         }
@@ -697,56 +745,128 @@
     }
 
     /**
+     * Return the list of arguments for the generated reference documentation.
+     *
+     * @return  The list of arguments for the generated reference documentation.
+     */
+    String getSynopsisArgs() {
+        if (allowsTrailingArguments()) {
+            if (trailingArgsDisplayName != null) {
+                return trailingArgsDisplayName;
+            } else {
+                return INFO_ARGPARSER_USAGE_TRAILINGARGS.get().toString();
+            }
+        }
+        return null;
+    }
+
+    /**
      * Appends a generated DocBook XML RefEntry (man page) to the StringBuilder.
      *
-     * @param sb    Append the RefEntry element to this.
+     * @param builder       Append the RefEntry element to this.
+     * @param synopsisArgs  List of arguments for the command synopsis.
+     * @param argList       List of (global) arguments for this tool.
      */
-    private void toRefEntry(StringBuilder sb) {
+    void toRefEntry(StringBuilder builder, String synopsisArgs, List<Argument> argList) {
         final String scriptName = getScriptName();
         if (scriptName == null) {
             throw new RuntimeException("The script name should have been set via the environment property '"
                     + PROPERTY_SCRIPT_NAME + "'.");
         }
 
-        // Model for a FreeMarker template.
         Map<String, Object> map = new HashMap<String, Object>();
         map.put("locale", Locale.getDefault().getLanguage());
         map.put("year", new SimpleDateFormat("yyyy").format(new Date()));
         map.put("name", scriptName);
         map.put("shortDesc", getShortToolDescription());
         map.put("descTitle", REF_TITLE_DESCRIPTION.get());
-        map.put("optsTitle", REF_TITLE_OPTIONS.get());
-        map.put("optsIntro", REF_INTRO_OPTIONS.get(scriptName));
-        String args = null;
-        if (allowsTrailingArguments) {
-            if (trailingArgsDisplayName != null) {
-                args = trailingArgsDisplayName;
-            } else {
-                args = INFO_ARGPARSER_USAGE_TRAILINGARGS.get().toString();
-            }
-        }
-        map.put("args", args);
+        map.put("args", synopsisArgs);
         map.put("description", getToolDescription());
-
-        // If there is a supplement to the description for this utility,
-        // then it is already DocBook XML, so use it as is.
         map.put("info", getDocToolDescriptionSupplement());
-        if (!argumentList.isEmpty()) {
-            List<Map<String, Object>> options = new LinkedList<Map<String, Object>>();
-            for (Argument a : argumentList) {
-                Map<String, Object> option = new HashMap<String, Object>();
-                option.put("synopsis", getOptionSynopsis(a));
-                option.put("description", a.getDescription());
-                option.put("default", REF_DEFAULT.get(a.getDefaultValue()));
-
-                // If there is a supplement to the description for this argument,
-                // then it is already DocBook XML, so use it as is.
-                option.put("info", a.getDocDescriptionSupplement());
-                options.add(option);
-            }
-            map.put("options", options);
+        if (!argList.isEmpty()) {
+            map.put("optionSection", getOptionsRefSect1(scriptName));
         }
-        applyTemplate(sb, "refEntry.ftl", map);
+        map.put("subcommands", null);
+        map.put("trailingSections", pathsToXIncludes(getPathsToTrailingRefSect1s()));
+        applyTemplate(builder, "refEntry.ftl", map);
+    }
+
+
+    /**
+     * Returns a generated DocBook XML RefSect1 element for all command options.
+     * @param scriptName    The name of this script.
+     * @return              The RefSect1 element as a String.
+     */
+    protected String getOptionsRefSect1(String scriptName) {
+        Map<String, Object> map = new HashMap<String, Object>();
+        map.put("name", scriptName);
+        map.put("title", REF_TITLE_OPTIONS.get());
+        map.put("intro", REF_INTRO_OPTIONS.get(scriptName));
+
+        Argument helpArgument = null;
+        final boolean printHeaders = printUsageGroupHeaders();
+        List<Map<String, Object>> groups = new LinkedList<Map<String, Object>>();
+        for (final ArgumentGroup argGroup : argumentGroups) {
+            Map<String, Object> group = new HashMap<String, Object>();
+
+            // Add the group's description if any
+            if (argGroup.containsArguments() && printHeaders) {
+                LocalizableMessage description = argGroup.getDescription();
+                if (description != LocalizableMessage.EMPTY) {
+                    group.put("description", argGroup.getDescription());
+                } else {
+                    group.put("description", INFO_SUBCMDPARSER_WHERE_OPTIONS_INCLUDE.get());
+                }
+            }
+
+            List<Map<String, Object>> options = new LinkedList<Map<String, Object>>();
+            final SortedSet<Argument> args = sortArguments(argGroup.getArguments());
+            for (final Argument a : args) {
+                if (a.isHidden()) {
+                    continue;
+                }
+
+                // The help argument should be added at the end.
+                if (isUsageArgument(a)) {
+                    helpArgument = a;
+                    continue;
+                }
+
+                options.add(getArgumentMap(a));
+            }
+            group.put("options", options);
+            if (!options.isEmpty()) {
+                groups.add(group);
+            }
+        }
+        if (helpArgument != null) {
+            Map<String, Object> helpGroup = new HashMap<String, Object>();
+            helpGroup.put("description", null);
+            List<Map<String, Object>> options = new LinkedList<Map<String, Object>>();
+            options.add(getArgumentMap(helpArgument));
+            helpGroup.put("options", options);
+            groups.add(helpGroup);
+        }
+        map.put("groups", groups);
+
+        StringBuilder sb = new StringBuilder();
+        applyTemplate(sb, "optionsRefSect1.ftl", map);
+        return sb.toString();
+    }
+
+    /**
+     * Returns a map containing information about an argument option.
+     * @param   a   The argument
+     * @return      A map containing information about an argument option
+     */
+    private Map<String, Object> getArgumentMap(final Argument a) {
+        Map<String, Object> option = new HashMap<String, Object>();
+        option.put("synopsis", getOptionSynopsis(a));
+        option.put("description", a.getDescription());
+        String dv = a.getDefaultValue();
+        option.put("default", dv != null ? REF_DEFAULT.get(dv) : null);
+        option.put("info", a.getDocDescriptionSupplement());
+        return option;
     }
 
     /**
@@ -805,33 +925,8 @@
                 }
             }
 
-            final SortedSet<Argument> args = new TreeSet<Argument>(new Comparator<Argument>() {
-
-                /** {@inheritDoc} */
-                @Override
-                public int compare(final Argument o1, final Argument o2) {
-                    final String s1 = getIdentifier(o1);
-                    final String s2 = getIdentifier(o2);
-                    final int res = s1.compareToIgnoreCase(s2);
-                    if (res != 0) {
-                        return res;
-                    }
-                    // Lowercase options first then uppercase.
-                    return -s1.compareTo(s2);
-                }
-
-                private String getIdentifier(final Argument o1) {
-                    if (o1.getShortIdentifier() != null) {
-                        return o1.getShortIdentifier().toString();
-                    }
-                    return o1.getLongIdentifier();
-                }
-
-            });
-            args.addAll(argGroup.getArguments());
-
+            final SortedSet<Argument> args = sortArguments(argGroup.getArguments());
             for (final Argument a : args) {
-                // If this argument is hidden, then skip it.
                 if (a.isHidden()) {
                     continue;
                 }
@@ -854,6 +949,40 @@
     }
 
     /**
+     * Sorts arguments by identifier, lowercase options first then uppercase.
+     *
+     * @param arguments     The arguments to sort.
+     * @return              The set of arguments in sorted order.
+     */
+    SortedSet<Argument> sortArguments(final List<Argument> arguments) {
+        final SortedSet<Argument> result = new TreeSet<Argument>(new Comparator<Argument>() {
+
+            /** {@inheritDoc} */
+            @Override
+            public int compare(final Argument o1, final Argument o2) {
+                final String s1 = getIdentifier(o1);
+                final String s2 = getIdentifier(o2);
+                final int res = s1.compareToIgnoreCase(s2);
+                if (res != 0) {
+                    return res;
+                }
+                // Lowercase options first then uppercase.
+                return -s1.compareTo(s2);
+            }
+
+            private String getIdentifier(final Argument o1) {
+                if (o1.getShortIdentifier() != null) {
+                    return o1.getShortIdentifier().toString();
+                }
+                return o1.getLongIdentifier();
+            }
+
+        });
+        result.addAll(arguments);
+        return result;
+    }
+
+    /**
      * Returns the script name or a Java equivalent command-line string.
      *
      * @return the script name or a Java equivalent command-line string
diff --git a/opendj-cli/src/main/java/com/forgerock/opendj/cli/DocDescriptionSupplement.java b/opendj-cli/src/main/java/com/forgerock/opendj/cli/DocDescriptionSupplement.java
new file mode 100644
index 0000000..09562e6
--- /dev/null
+++ b/opendj-cli/src/main/java/com/forgerock/opendj/cli/DocDescriptionSupplement.java
@@ -0,0 +1,50 @@
+/*
+ * 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 legal-notices/CDDLv1_0.txt
+ * or http://forgerock.org/license/CDDLv1.0.html.
+ * 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 legal-notices/CDDLv1_0.txt.
+ * 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
+ *
+ *
+ *      Copyright 2015 ForgeRock AS.
+ */
+package com.forgerock.opendj.cli;
+
+import org.forgerock.i18n.LocalizableMessage;
+
+/**
+ * Documentation that supplements generated descriptions.
+ */
+public interface DocDescriptionSupplement {
+
+    /**
+     * Retrieves a supplement to the description intended for use in generated reference documentation.
+     *
+     * @return The supplement to the description for use in generated reference documentation,
+     *         or LocalizableMessage.EMPTY if there is no supplement.
+     */
+    public LocalizableMessage getDocDescriptionSupplement();
+
+    /**
+     * Sets a supplement to the description intended for use in generated reference documentation.
+     *
+     * @param docDescriptionSupplement  The supplement to the description
+     *                                  for use in generated reference documentation.
+     */
+    public void setDocDescriptionSupplement(final LocalizableMessage docDescriptionSupplement);
+}
diff --git a/opendj-cli/src/main/java/com/forgerock/opendj/cli/DocGenerationHelper.java b/opendj-cli/src/main/java/com/forgerock/opendj/cli/DocGenerationHelper.java
index a60d99a..828029f 100644
--- a/opendj-cli/src/main/java/com/forgerock/opendj/cli/DocGenerationHelper.java
+++ b/opendj-cli/src/main/java/com/forgerock/opendj/cli/DocGenerationHelper.java
@@ -32,6 +32,8 @@
 import java.io.ByteArrayOutputStream;
 import java.io.OutputStreamWriter;
 import java.io.Writer;
+import java.util.LinkedList;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -134,4 +136,25 @@
         final String id = argument.getLongIdentifier();
         return ("add".equals(id) || "remove".equals(id) || "reset".equals(id) || "set".equals(id));
     }
+
+    /**
+     * Translate paths to XML files to XInclude elements.
+     *
+     * @return  XInclude elements corresponding to the paths.
+     */
+    static List<String> pathsToXIncludes(final String[] paths) {
+        if (paths == null) {
+            return new LinkedList<String>();
+        }
+
+        // Assume xmlns:xinclude="http://www.w3.org/2001/XInclude",
+        // as in the declaration of resources/templates/refEntry.ftl.
+        final String nameSpace = "xinclude";
+        List<String> xIncludes = new LinkedList<String>();
+        for (int i = 0; i < paths.length; ++i) {
+            xIncludes.add("<" + nameSpace + ":include href=\"" + paths[i] + "\" />");
+        }
+
+        return xIncludes;
+    }
 }
diff --git a/opendj-cli/src/main/java/com/forgerock/opendj/cli/SubCommand.java b/opendj-cli/src/main/java/com/forgerock/opendj/cli/SubCommand.java
index 9fec2a5..42f4580 100644
--- a/opendj-cli/src/main/java/com/forgerock/opendj/cli/SubCommand.java
+++ b/opendj-cli/src/main/java/com/forgerock/opendj/cli/SubCommand.java
@@ -39,7 +39,7 @@
  * This class defines a data structure for holding information about a subcommand that may be used with the subcommand
  * argument parser. The subcommand has a name, a description, and a set of arguments.
  */
-public class SubCommand {
+public class SubCommand implements DocDescriptionSupplement {
     /** Indicates whether this subCommand should be hidden in the usage information. */
     private boolean isHidden;
 
@@ -169,25 +169,12 @@
      */
     private LocalizableMessage docDescriptionSupplement;
 
-    /**
-     * Retrieves a supplement to the description for this subcommand
-     * intended for use in generated reference documentation.
-     *
-     * @return The supplement to the description for this subcommand
-     *         for use in generated reference documentation,
-     *         or LocalizableMessage.EMPTY if there is no supplement.
-     */
+    /** {@inheritDoc} */
     public LocalizableMessage getDocDescriptionSupplement() {
         return docDescriptionSupplement != null ? docDescriptionSupplement : LocalizableMessage.EMPTY;
     }
 
-    /**
-     * Sets a supplement to the description for this subcommand
-     * intended for use in generated reference documentation.
-     *
-     * @param docDescriptionSupplement  The supplement to the description for this subcommand
-     *                                  for use in generated reference documentation.
-     */
+    /** {@inheritDoc} */
     public void setDocDescriptionSupplement(final LocalizableMessage docDescriptionSupplement) {
         this.docDescriptionSupplement = docDescriptionSupplement;
     }
diff --git a/opendj-cli/src/main/java/com/forgerock/opendj/cli/SubCommandArgumentParser.java b/opendj-cli/src/main/java/com/forgerock/opendj/cli/SubCommandArgumentParser.java
index 6777007..262c3b0 100644
--- a/opendj-cli/src/main/java/com/forgerock/opendj/cli/SubCommandArgumentParser.java
+++ b/opendj-cli/src/main/java/com/forgerock/opendj/cli/SubCommandArgumentParser.java
@@ -33,12 +33,15 @@
 import static com.forgerock.opendj.util.StaticUtils.*;
 
 import java.io.OutputStream;
+import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Properties;
 import java.util.SortedMap;
@@ -1104,31 +1107,32 @@
     }
 
     /**
-     * Appends a list generated DocBook XML RefSect2 elements to the StringBuilder, one per subcommand.
+     * Appends a generated DocBook XML RefEntry element for this command to the StringBuilder.
      *
-     * <br>
-     *
-     * Note: The result is not a complete XML document.
-     * Instead you must wrap the resulting list of RefSect2 elements in a RefSect1.
-     *
-     * @param builder   Append the list of RefSect2 elements to this.
-     * @param values    The SubCommands containing the reference information.
+     * @param builder       Append the RefEntry element to this.
+     * @param subCommands   SubCommands containing reference information.
      */
-    private void generateReferenceDoc(final StringBuilder builder, Collection<SubCommand> values) {
-        for (SubCommand s : values) {
-            toRefSect2(s, builder);
+    private void generateReferenceDoc(final StringBuilder builder, Collection<SubCommand> subCommands) {
+        toRefEntry(builder, subCommands);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    String getSynopsisArgs() {
+        if (subCommands.isEmpty()) {
+            return INFO_SUBCMDPARSER_OPTIONS.get().toString();
+        } else {
+            return INFO_SUBCMDPARSER_SUBCMD_AND_OPTIONS.get().toString();
         }
     }
 
     /**
-     * Appends a generated DocBook XML RefSect2 element for a single subcommand to the StringBuilder.
+     * Appends a generated DocBook XML RefEntry (man page) to the StringBuilder.
      *
-     * @param sc
-     *            The SubCommand containing reference information.
-     * @param sb
-     *            Append the RefSect2 element to this.
+     * @param builder       Append the RefEntry element to this.
+     * @param subCommands   Collection of subcommands for this tool.
      */
-    private void toRefSect2(SubCommand sc, StringBuilder sb) {
+    void toRefEntry(StringBuilder builder, Collection<SubCommand> subCommands) {
         final String scriptName = getScriptName();
         if (scriptName == null) {
             throw new RuntimeException("The script name should have been set via the environment property '"
@@ -1137,20 +1141,72 @@
 
         // Model for a FreeMarker template.
         Map<String, Object> map = new HashMap<String, Object>();
-        map.put("id", scriptName + "-" + sc.getName());
-        final String name = scriptName + " " + sc.getName();
+        map.put("locale", Locale.getDefault().getLanguage());
+        map.put("year", new SimpleDateFormat("yyyy").format(new Date()));
+        map.put("name", scriptName);
+        map.put("shortDesc", getShortToolDescription());
+        map.put("descTitle", REF_TITLE_DESCRIPTION.get());
+        map.put("args", getSynopsisArgs());
+        map.put("description", getToolDescription());
+        map.put("info", getDocToolDescriptionSupplement());
+        if (!globalArgumentList.isEmpty()) {
+            map.put("optionSection", getOptionsRefSect1(scriptName));
+        }
+        map.put("subcommands", toRefSect1(scriptName, subCommands));
+        map.put("trailingSections", pathsToXIncludes(getPathsToTrailingRefSect1s()));
+        applyTemplate(builder, "refEntry.ftl", map);
+    }
+
+    /**
+     * Returns a generated DocBook XML RefSect1 element for all subcommands.
+     * @param scriptName    The name of this script.
+     * @param subCommands   The SubCommands containing the reference information.
+     * @return              The RefSect1 element as a String.
+     */
+    private String toRefSect1(String scriptName, Collection<SubCommand> subCommands) {
+        if (subCommands.isEmpty()) {
+            return "";
+        }
+
+        Map<String, Object> map = new HashMap<String, Object>();
+        map.put("name", scriptName);
+        map.put("info", getDocSubcommandsDescriptionSupplement());
+
+        List<String> scUsageList = new ArrayList<String>();
+        for (SubCommand subCommand : subCommands) {
+            scUsageList.add(toRefSect2(scriptName, subCommand));
+        }
+        map.put("subcommands", scUsageList);
+
+        StringBuilder sb = new StringBuilder();
+        applyTemplate(sb, "refSect1.ftl", map);
+        return sb.toString();
+    }
+
+    /**
+     * Returns a generated DocBook XML RefSect2 element for a single subcommand to the StringBuilder.
+     *
+     * @param scriptName    The name of this script.
+     * @param subCommand    The SubCommand containing reference information.
+     * @return    The RefSect2 element as a String.
+     */
+    private String toRefSect2(String scriptName, SubCommand subCommand) {
+        // Model for a FreeMarker template.
+        Map<String, Object> map = new HashMap<String, Object>();
+        map.put("id", scriptName + "-" + subCommand.getName());
+        final String name = scriptName + " " + subCommand.getName();
         map.put("name", name);
-        map.put("description", sc.getDescription());
-        map.put("optsTitle", REF_TITLE_OPTIONS.get());
-        map.put("optsIntro", REF_INTRO_OPTIONS.get(name));
+        map.put("description", subCommand.getDescription());
+        map.put("optionsTitle", REF_TITLE_OPTIONS.get());
+        map.put("optionsIntro", REF_INTRO_OPTIONS.get(name));
 
         // If there is a supplement to the description for this subcommand,
         // then it is already DocBook XML, so use it as is.
-        map.put("info", sc.getDocDescriptionSupplement());
-        if (!sc.getArguments().isEmpty()) {
+        map.put("info", subCommand.getDocDescriptionSupplement());
+        if (!subCommand.getArguments().isEmpty()) {
             List<Map<String, Object>> options = new LinkedList<Map<String, Object>>();
             String nameOption = null;
-            for (Argument a : sc.getArguments()) {
+            for (Argument a : subCommand.getArguments()) {
                 Map<String, Object> option = new HashMap<String, Object>();
                 String optionSynopsis = getOptionSynopsis(a);
                 option.put("synopsis", optionSynopsis);
@@ -1162,9 +1218,10 @@
                     }
 
                     // Let this build its own arbitrarily formatted additional info.
-                    info.put("usage", subCommandUsageHandler.getArgumentAdditionalInfo(sc, a, nameOption));
+                    info.put("usage", subCommandUsageHandler.getArgumentAdditionalInfo(subCommand, a, nameOption));
                 } else {
-                    info.put("default", REF_DEFAULT.get(a.getDefaultValue()));
+                    String defaultValue = a.getDefaultValue();
+                    info.put("default", defaultValue != null ? REF_DEFAULT.get(defaultValue) : null);
 
                     // If there is a supplement to the description for this argument,
                     // then it is already DocBook XML, so use it as is.
@@ -1177,8 +1234,11 @@
         }
 
         if (subCommandUsageHandler != null) {
-            map.put("properties", subCommandUsageHandler.getProperties(sc));
+            map.put("propertiesInfo", subCommandUsageHandler.getProperties(subCommand));
         }
+
+        StringBuilder sb = new StringBuilder();
         applyTemplate(sb, "refSect2.ftl", map);
+        return sb.toString();
     }
 }
diff --git a/opendj-cli/src/main/java/com/forgerock/opendj/cli/ToolRefDocContainer.java b/opendj-cli/src/main/java/com/forgerock/opendj/cli/ToolRefDocContainer.java
new file mode 100644
index 0000000..36aa9d2
--- /dev/null
+++ b/opendj-cli/src/main/java/com/forgerock/opendj/cli/ToolRefDocContainer.java
@@ -0,0 +1,162 @@
+/*
+ * 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 legal-notices/CDDLv1_0.txt
+ * or http://forgerock.org/license/CDDLv1.0.html.
+ * 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 legal-notices/CDDLv1_0.txt.
+ * 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
+ *
+ *
+ *      Copyright 2015 ForgeRock AS.
+ */
+package com.forgerock.opendj.cli;
+
+import org.forgerock.i18n.LocalizableMessage;
+
+/**
+ * An interface for an object that holds reference documentation for a command-line tool.
+ */
+public interface ToolRefDocContainer {
+
+    /**
+     * Gets a short description for this tool, suitable in a man page summary line.
+     *
+     * @return  A short description for this tool,
+     *          suitable in a man page summary line,
+     *          or LocalizableMessage.EMPTY if there is no short description.
+     */
+    LocalizableMessage getShortToolDescription();
+
+    /**
+     * Sets a short description for this tool, suitable in a man page summary line.
+     *
+     * @param   shortDescription    The short description for this tool,
+     *                              suitable in a man page summary line.
+     */
+    void setShortToolDescription(final LocalizableMessage shortDescription);
+
+    /**
+     * Retrieves a supplement to the description for this tool,
+     * intended for use in generated reference documentation.
+     *
+     * @return A supplement to the description for this tool
+     *         intended for use in generated reference documentation,
+     *         or LocalizableMessage.EMPTY if there is no supplement.
+     */
+    LocalizableMessage getDocToolDescriptionSupplement();
+
+    /**
+     * Sets a supplement to the description for this tool,
+     * intended for use in generated reference documentation.
+     *
+     * @param docToolDescriptionSupplement  The supplement to the description for this tool
+     *                                      intended for use in generated reference documentation.
+     */
+    void setDocToolDescriptionSupplement(final LocalizableMessage docToolDescriptionSupplement);
+
+    /**
+     * Retrieves a supplement to the description for all subcommands of this tool,
+     * intended for use in generated reference documentation.
+     *
+     * @return A supplement to the description for all subcommands of this tool
+     *         intended for use in generated reference documentation,
+     *         or LocalizableMessage.EMPTY if there is no supplement.
+     */
+    LocalizableMessage getDocSubcommandsDescriptionSupplement();
+
+    /**
+     * Sets a supplement to the description for all subcommands of this tool,
+     * intended for use in generated reference documentation.
+     *
+     * @param docSubcommandsDescriptionSupplement
+     *          The supplement to the description for all subcommands of this tool
+     *          intended for use in generated reference documentation.
+     */
+    void setDocSubcommandsDescriptionSupplement(final LocalizableMessage docSubcommandsDescriptionSupplement);
+
+    /**
+     * Get additional paths to DocBook XML {@code RefSect1} documents
+     * to be appended after generated content in reference documentation.
+     *
+     * <br>
+     *
+     * DocBook represents a reference manual page with the {@code RefEntry}.
+     * See <a href="http://www.docbook.org/tdg51/en/html/refentry.html">refentry</a>.
+     *
+     * <br>
+     *
+     * A {@code RefEntry} describing an OpenDJ tool contains
+     * block elements in the following order:
+     *
+     * <pre>
+     *     RefMeta
+     *     RefNameDiv
+     *     RefSynopsisDiv
+     *     RefSect1 - Description (generated, potentially with a hand-written supplement)
+     *     RefSect1 - Options (generated)
+     *     RefSect1 - Subcommands (optional, hand-written intro + generated RefSect2s)
+     *     RefSect1 - Filter (optional, hand-written)
+     *     RefSect1 - Attribute (optional, hand-written)
+     *     RefSect1 - Exit Codes (hand-written)
+     *     RefSect1 - Files (optional, hand-written)
+     *     RefSect1 - Examples (hand-written)
+     *     RefSect1 - See Also (hand-written)
+     * </pre>
+     *
+     * As the trailing RefSect1s following Subcommands are hand-written,
+     * they are included in the generated content as XIncludes elements.
+     *
+     * @return  The paths to trailing {@code RefSect1} documents.
+     */
+    String[] getPathsToTrailingRefSect1s();
+
+    /**
+     * Set additional paths to DocBook XML {@code RefSect1} documents
+     * to be appended after generated content in reference documentation.
+     *
+     * <br>
+     *
+     * DocBook represents a reference manual page with the {@code RefEntry}.
+     * See <a href="http://www.docbook.org/tdg51/en/html/refentry.html">refentry</a>.
+     *
+     * <br>
+     *
+     * A {@code RefEntry} describing an OpenDJ tool contains
+     * block elements in the following order:
+     *
+     * <pre>
+     *     RefMeta
+     *     RefNameDiv
+     *     RefSynopsisDiv
+     *     RefSect1 - Description (generated, potentially with a hand-written supplement)
+     *     RefSect1 - Options (generated)
+     *     RefSect1 - Subcommands (optional, hand-written intro + generated RefSect2s)
+     *     RefSect1 - Filter (optional, hand-written)
+     *     RefSect1 - Attribute (optional, hand-written)
+     *     RefSect1 - Exit Codes (hand-written)
+     *     RefSect1 - Files (optional, hand-written)
+     *     RefSect1 - Examples (hand-written)
+     *     RefSect1 - See Also (hand-written)
+     * </pre>
+     *
+     * As the trailing RefSect1s following Subcommands are hand-written,
+     * they are included in the generated content as XIncludes elements.
+     *
+     * @param paths The paths to trailing {@code RefSect1} documents.
+     */
+    public void setPathsToTrailingRefSect1s(final String... paths);
+}
diff --git a/opendj-cli/src/main/resources/templates/optionsRefSect1.ftl b/opendj-cli/src/main/resources/templates/optionsRefSect1.ftl
new file mode 100644
index 0000000..ee7a085
--- /dev/null
+++ b/opendj-cli/src/main/resources/templates/optionsRefSect1.ftl
@@ -0,0 +1,62 @@
+<#--
+ # 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 legal-notices/CDDLv1_0.txt
+ # or http://forgerock.org/license/CDDLv1.0.html.
+ # 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 legal-notices/CDDLv1_0.txt.
+ # 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
+ #
+ #      Copyright 2015 ForgeRock AS.
+ #
+ #-->
+<refsect1 xml:id="${name}-options">
+  <title>${title}</title>
+
+  <para>
+   ${intro}
+  </para>
+
+  <#list groups as group>
+    <variablelist>
+    <#if group.description??>
+      <para>
+       ${group.description}
+      </para>
+    </#if>
+
+    <#list group.options as option>
+      <varlistentry>
+        <term><option>${option.synopsis?xml}</option></term>
+        <listitem>
+          <para>
+            ${option.description}
+          </para>
+
+          <#if option.default??>
+            <para>
+              ${option.default}
+            </para>
+          </#if>
+
+          <#if option.info??>${option.info}</#if>
+        </listitem>
+      </varlistentry>
+    </#list>
+    </variablelist>
+  </#list>
+</refsect1>
diff --git a/opendj-cli/src/main/resources/templates/refEntry.ftl b/opendj-cli/src/main/resources/templates/refEntry.ftl
index 13b3908..db23699 100644
--- a/opendj-cli/src/main/resources/templates/refEntry.ftl
+++ b/opendj-cli/src/main/resources/templates/refEntry.ftl
@@ -78,7 +78,7 @@
  <refsynopsisdiv>
   <cmdsynopsis>
    <command>${name}</command>
-   <arg choice="plain">${args}</arg>
+   <#if args??><arg choice="plain">${args}</arg></#if>
   </cmdsynopsis>
  </refsynopsisdiv>
 
@@ -92,44 +92,17 @@
    <#if info??>${info}</#if>
  </refsect1>
 
- <#if options??>
-   <refsect1>
-    <title>${optsTitle}</title>
-
-    <variablelist>
-     <para>
-      ${optsIntro}
-     </para>
-
-     <#list options as option>
-       <varlistentry>
-         <term><option>${option.synopsis?xml}</option></term>
-         <listitem>
-           <para>
-             ${option.description}
-           </para>
-
-           <#if option.default??>
-             <para>
-               ${option.default}
-             </para>
-           </#if>
-
-           <#if option.info??>${option.info}</#if>
-         </listitem>
-       </varlistentry>
-
-     </#list>
-
-     </variablelist>
-   </refsect1>
+ <#if optionSection??>
+   ${optionSection}
  </#if>
 
- <!-- TODO: subcommands -->
- <!-- TODO: filter -->
- <!-- TODO: attribute -->
- <!-- TODO: exitCodes -->
- <!-- TODO: files -->
- <!-- TODO: examples -->
- <!-- TODO: seeAlso -->
+ <#if subcommands??>
+   ${subcommands}
+ </#if>
+
+ <#if trailingSections??>
+   <#list trailingSections as section>
+    ${section}
+   </#list>
+ </#if>
 </refentry>
diff --git a/opendj-cli/src/main/resources/templates/refSect1.ftl b/opendj-cli/src/main/resources/templates/refSect1.ftl
new file mode 100644
index 0000000..c4e71fe
--- /dev/null
+++ b/opendj-cli/src/main/resources/templates/refSect1.ftl
@@ -0,0 +1,41 @@
+<#--
+ # 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 legal-notices/CDDLv1_0.txt
+ # or http://forgerock.org/license/CDDLv1.0.html.
+ # 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 legal-notices/CDDLv1_0.txt.
+ # 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
+ #
+ #      Copyright 2015 ForgeRock AS.
+ #
+ #-->
+<refsect1 xml:id="${name}-subcommands">
+  <title>Subcommands</title>
+
+  <#if info??>
+    ${info}
+  </#if>
+
+  <para>
+   The <command>${name}</command> utility supports the following subcommands.
+  </para>
+
+  <#list subcommands as subcommand>
+    ${subcommand}
+  </#list>
+</refsect1>
diff --git a/opendj-cli/src/main/resources/templates/refSect2.ftl b/opendj-cli/src/main/resources/templates/refSect2.ftl
index 2529f3d..059aa49 100644
--- a/opendj-cli/src/main/resources/templates/refSect2.ftl
+++ b/opendj-cli/src/main/resources/templates/refSect2.ftl
@@ -35,42 +35,42 @@
 
   <#if options??>
     <refsect3 xml:id="${id}-options">
-      <title>${optsTitle}</title>
+      <title>${optionsTitle}</title>
 
       <variablelist>
         <para>
-         ${optsIntro}
+         ${optionsIntro}
         </para>
 
         <#list options as option>
 
-        <varlistentry>
-          <term><option>${option.synopsis?xml}</option></term>
-          <listitem>
-           <para>
-             ${option.description}
-           </para>
+          <varlistentry>
+            <term><option>${option.synopsis?xml}</option></term>
+            <listitem>
+             <para>
+               ${option.description}
+             </para>
 
-           <#if option.info??>
-             <#if info.usage??>${option.info.usage}</#if>
+             <#if option.info??>
+               <#if option.info.usage??>${option.info.usage}</#if>
 
-             <#if info.default??>
-                <para>
-                  ${option.info.default}
-                </para>
+               <#if option.info.default??>
+                  <para>
+                    ${option.info.default}
+                  </para>
+               </#if>
+
+               <#if option.info.doc??>${option.info.doc}</#if>
              </#if>
-
-             <#if info.doc??>${option.info.doc}</#if>
-           </#if>
-          </listitem>
-        </varlistentry>
+            </listitem>
+          </varlistentry>
 
         </#list>
       </variablelist>
     </refsect3>
   </#if>
 
-  <#if properties??>
-    ${properties}
+  <#if propertiesInfo??>
+    ${propertiesInfo}
   </#if>
 </refsect2>
diff --git a/opendj-config/src/main/java/org/forgerock/opendj/config/dsconfig/DSConfig.java b/opendj-config/src/main/java/org/forgerock/opendj/config/dsconfig/DSConfig.java
index 9ee400c..925f9fe 100644
--- a/opendj-config/src/main/java/org/forgerock/opendj/config/dsconfig/DSConfig.java
+++ b/opendj-config/src/main/java/org/forgerock/opendj/config/dsconfig/DSConfig.java
@@ -487,7 +487,7 @@
                     final Object[] constants = en.getEnumConstants();
                     for (Object enumConstant : constants) {
                         final LocalizableMessage valueSynopsis = prop.getValueSynopsis((Enum) enumConstant);
-                        appendVarListEntry(b, enumConstant.toString(), valueSynopsis);
+                        appendVarListEntry(b, enumConstant.toString(), op + valueSynopsis + cp);
                     }
                     b.append("</variablelist>").append(EOL);
                     return null;
@@ -864,6 +864,8 @@
 
         this.parser = new SubCommandArgumentParser(getClass().getName(), INFO_DSCFG_TOOL_DESCRIPTION.get(), false);
         this.parser.setShortToolDescription(REF_SHORT_DESC_DSCONFIG.get());
+        this.parser.setDocToolDescriptionSupplement(REF_DSCFG_DOC_TOOL_DESCRIPTION.get());
+        this.parser.setDocSubcommandsDescriptionSupplement(REF_DSCFG_DOC_SUBCOMMANDS_DESCRIPTION.get());
         this.parser.setVersionHandler(new VersionHandler() {
             @Override
             public void printVersion() {
diff --git a/opendj-config/src/main/resources/com/forgerock/opendj/dsconfig/dsconfig.properties b/opendj-config/src/main/resources/com/forgerock/opendj/dsconfig/dsconfig.properties
index 71d729c..290e2ba 100644
--- a/opendj-config/src/main/resources/com/forgerock/opendj/dsconfig/dsconfig.properties
+++ b/opendj-config/src/main/resources/com/forgerock/opendj/dsconfig/dsconfig.properties
@@ -504,3 +504,243 @@
 REF_DSCFG_STRING_1038=A String
 REF_DSCFG_UNKNOWN_1039=Unknown
 REF_SHORT_DESC_DSCONFIG_1040=manage OpenDJ directory server configuration
+REF_DSCFG_DOC_TOOL_DESCRIPTION_1041=<para>                                                 \
+ The <command>dsconfig</command> command is the primary command-line tool                  \
+ for viewing and editing OpenDJ configuration.                                             \
+ When started without arguments,                                                           \
+ <command>dsconfig</command> prompts you for administration connection information,        \
+ including the host name, administration port number,                                      \
+ administrator bind DN and administrator password.                                         \
+ The <command>dsconfig</command> command then connects securely                            \
+ to the directory server over the administration port.                                     \
+ Once connected it presents you with a menu-driven interface to the server configuration.  \
+</para>                                                                                    \
+                                                                                           \
+<para>                                                                                     \
+ When you pass connection information, subcommands, and additional options                 \
+ to <command>dsconfig</command>,                                                           \
+ the command runs in script mode and so is not interactive,                                \
+ though it can prompt you to ask whether to apply changes                                  \
+ and whether to trust certificates                                                         \
+ (unless you use the <option>--no-prompt</option>                                          \
+ and <option>--trustAll</option> options, respectively).                                   \
+</para>                                                                                    \
+                                                                                           \
+<para>                                                                                     \
+ You can prepare <command>dsconfig</command> batch scripts                                 \
+ by running the tool with the <option>--commandFilePath</option> option                    \
+ in interactive mode,                                                                      \
+ then reading from the batch file with the <option>--batchFilePath</option> option         \
+ in script mode.                                                                           \
+ Batch files can be useful when you have many <command>dsconfig</command> commands to run  \
+ and want to avoid starting the JVM and setting up a new connection for each command.      \
+</para>                                                                                    \
+                                                                                           \
+<para>                                                                                     \
+ The <command>dsconfig</command> command categorizes                                       \
+ directory server configuration into <firstterm>components</firstterm>,                    \
+ also called <firstterm>managed objects</firstterm>.                                       \
+ Actual components often inherit from a parent component type.                             \
+ For example, one component is a Connection Handler.                                       \
+ An LDAP Connection Handler is a type of Connection Handler.                               \
+ You configure the LDAP Connection Handler component                                       \
+ to specify how OpenDJ directory server handles LDAP connections                           \
+ coming from client applications.                                                          \
+</para>                                                                                    \
+                                                                                           \
+<para>                                                                                     \
+ Configuration components have <firstterm>properties</firstterm>.                          \
+ For example, the LDAP Connection Handler component has properties                         \
+ such as <literal>listen-port</literal> and <literal>allow-start-tls</literal>.            \
+ You can set the component's <literal>listen-port</literal> property                       \
+ to <literal>389</literal> to use the default LDAP port number.                            \
+ You can set the component's <literal>allow-start-tls</literal> property                   \
+ to <literal>true</literal> to permit LDAP client applications to use StartTLS.            \
+ Much of the configuration you do with <command>dsconfig</command>                         \
+ involves setting component properties.                                                    \
+</para>
+REF_DSCFG_DOC_SUBCOMMANDS_DESCRIPTION_1042=<para>                                       \
+  The <command>dsconfig</command> command provides many subcommands.                    \
+ </para>                                                                                \
+                                                                                        \
+ <para>                                                                                 \
+  Subcommands let you create, list, and delete entire configuration components,         \
+  and also let you get and set component properties.                                    \
+  Subcommands therefore have names that reflect these five actions.                     \
+ </para>                                                                                \
+                                                                                        \
+ <itemizedlist>                                                                         \
+  <listitem><para>create-<replaceable>component</replaceable></para></listitem>         \
+  <listitem><para>list-<replaceable>component</replaceable>s</para></listitem>          \
+  <listitem><para>delete-<replaceable>component</replaceable></para></listitem>         \
+  <listitem><para>get-<replaceable>component</replaceable>-prop</para></listitem>       \
+  <listitem><para>set-<replaceable>component</replaceable>-prop</para></listitem>       \
+ </itemizedlist>                                                                        \
+                                                                                        \
+ <para>                                                                                 \
+  Here, <replaceable>component</replaceable> names are names of managed object types.   \
+  Subcommand <replaceable>component</replaceable> names                                 \
+  are lower-case, hyphenated versions of the friendly names.                            \
+  When you act on an actual configuration component,                                    \
+  you provide the name of the component as an option argument.                          \
+ </para>                                                                                \
+                                                                                        \
+ <itemizedlist>                                                                         \
+  <para>                                                                                \
+   For example, the Log Publisher component has these corresponding subcommands.        \
+  </para>                                                                               \
+                                                                                        \
+  <listitem><para><command>create-log-publisher</command></para></listitem>             \
+  <listitem><para><command>list-log-publishers</command></para></listitem>              \
+  <listitem><para><command>delete-log-publisher</command></para></listitem>             \
+  <listitem><para><command>get-log-publisher-prop</command></para></listitem>           \
+  <listitem><para><command>set-log-publisher-prop</command></para></listitem>           \
+ </itemizedlist>                                                                        \
+                                                                                        \
+ <para>                                                                                 \
+  When you create or delete Log Publisher components                                    \
+  and when you get and set their configuration properties,                              \
+  you provide the name of the actual log publisher,                                     \
+  which you can find by using the <command>list-log-publishers</command> subcommand.    \
+ </para>                                                                                \
+                                                                                        \
+ <screen>                                                                         \n    \
+$ <userinput>dsconfig \\                                                          \n    \
+ list-log-publishers \\                                                           \n    \
+ --hostname opendj.example.com \\                                                 \n    \
+ --port 4444 \\                                                                   \n    \
+ --bindDN "cn=Directory Manager" \\                                               \n    \
+ --bindPassword password \\                                                       \n    \
+ --trustAll</userinput>                                                           \n    \
+<computeroutput>                                                                  \n    \
+Log Publisher                 : Type                   : enabled                  \n    \
+------------------------------:------------------------:--------                  \n    \
+File-Based Access Logger      : file-based-access      : true                     \n    \
+File-Based Audit Logger       : file-based-audit       : false                    \n    \
+File-Based Debug Logger       : file-based-debug       : false                    \n    \
+File-Based Error Logger       : file-based-error       : true                     \n    \
+File-Based HTTP Access Logger : file-based-http-access : false                    \n    \
+Replication Repair Logger     : file-based-error       : true</computeroutput>    \n    \
+                                                                                  \n    \
+$ <userinput>dsconfig \\                                                          \n    \
+ get-log-publisher-prop \\                                                        \n    \
+ --publisher-name "File-Based Access Logger" \\                                   \n    \
+ --property rotation-policy \\                                                    \n    \
+ --hostname opendj.example.com \\                                                 \n    \
+ --port 4444 \\                                                                   \n    \
+ --bindDN "cn=Directory Manager" \\                                               \n    \
+ --bindPassword password \\                                                       \n    \
+ --trustAll</userinput>                                                           \n    \
+<computeroutput>Property        : Value(s)                                        \n    \
+----------------:--------------------------------------------------------------   \n    \
+rotation-policy : 24 Hours Time Limit Rotation Policy, Size Limit Rotation        \n    \
+                : Policy</computeroutput>                                         \n    \
+ </screen>                                                                              \
+                                                                                        \
+ <para>                                                                                 \
+  Many subcommands let you set property values.                                         \
+  Notice in the reference for the subcommands below                                     \
+  that specific options are available for handling multi-valued properties.             \
+  Whereas you can assign a single property value                                        \
+  by using the <option>--set</option> option,                                           \
+  you assign multiple values to a multi-valued property                                 \
+  by using the <option>--add</option> option.                                           \
+  You can reset the values of the multi-valued property                                 \
+  by using the <option>--reset</option> option.                                         \
+ </para>                                                                                \
+                                                                                        \
+ <itemizedlist>                                                                         \
+  <para>                                                                                \
+  Some property values take a time duration.                                            \
+  Durations are expressed as numbers followed by units.                                 \
+  For example <literal>1 s</literal> means one second,                                  \
+  and <literal>2 w</literal> means two weeks.                                           \
+  Some durations have minimum granularity or maximum units,                             \
+  so you cannot necessary specify every duration in milliseconds or weeks for example.  \
+  Some durations allow you to use a special value to mean unlimited.                    \
+  Units are specified as follows:                                                       \
+ </para>                                                                                \
+                                                                                        \
+  <listitem><para><literal>ms</literal>: milliseconds</para></listitem>                 \
+  <listitem><para><literal>s</literal>: seconds</para></listitem>                       \
+  <listitem><para><literal>m</literal>: minutes</para></listitem>                       \
+  <listitem><para><literal>h</literal>: hours</para></listitem>                         \
+  <listitem><para><literal>d</literal>: days</para></listitem>                          \
+  <listitem><para><literal>w</literal>: weeks</para></listitem>                         \
+ </itemizedlist>                                                                        \
+                                                                                        \
+ <para>                                                                                 \
+  Use the following options to view help for subcommands.                               \
+ </para>                                                                                \
+                                                                                        \
+ <variablelist>                                                                         \
+  <varlistentry>                                                                        \
+   <term><command>dsconfig --help-all</command></term>                                  \
+   <listitem>                                                                           \
+    <para>                                                                              \
+     Display all subcommands                                                            \
+    </para>                                                                             \
+   </listitem>                                                                          \
+  </varlistentry>                                                                       \
+  <varlistentry>                                                                        \
+   <term><command>dsconfig --help-core-server</command></term>                          \
+   <listitem>                                                                           \
+    <para>                                                                              \
+     Display subcommands relating to core server                                        \
+    </para>                                                                             \
+   </listitem>                                                                          \
+  </varlistentry>                                                                       \
+  <varlistentry>                                                                        \
+   <term><command>dsconfig --help-database</command></term>                             \
+   <listitem>                                                                           \
+    <para>                                                                              \
+     Display subcommands relating to caching and back-ends                              \
+    </para>                                                                             \
+   </listitem>                                                                          \
+  </varlistentry>                                                                       \
+  <varlistentry>                                                                        \
+   <term><command>dsconfig --help-logging</command></term>                              \
+   <listitem>                                                                           \
+    <para>                                                                              \
+     Display subcommands relating to logging                                            \
+    </para>                                                                             \
+   </listitem>                                                                          \
+  </varlistentry>                                                                       \
+  <varlistentry>                                                                        \
+   <term><command>dsconfig --help-replication</command></term>                          \
+   <listitem>                                                                           \
+    <para>                                                                              \
+     Display subcommands relating to replication                                        \
+    </para>                                                                             \
+   </listitem>                                                                          \
+  </varlistentry>                                                                       \
+  <varlistentry>                                                                        \
+   <term><command>dsconfig --help-security</command></term>                             \
+   <listitem>                                                                           \
+    <para>                                                                              \
+     Display subcommands relating to authentication and authorization                   \
+    </para>                                                                             \
+   </listitem>                                                                          \
+  </varlistentry>                                                                       \
+  <varlistentry>                                                                        \
+   <term><command>dsconfig --help-user-management</command></term>                      \
+   <listitem>                                                                           \
+    <para>                                                                              \
+     Display subcommands relating to user management                                    \
+    </para>                                                                             \
+   </listitem>                                                                          \
+  </varlistentry>                                                                       \
+ </variablelist>                                                                        \
+                                                                                        \
+ <para>                                                                                 \
+  For help with individual subcommands,                                                 \
+  either use <command>dsconfig <replaceable>subcommand</replaceable> --help</command>,  \
+  or start <command>dsconfig</command> in interactive mode,                             \
+  without specifying a subcommand.                                                      \
+ </para>                                                                                \
+                                                                                        \
+ <para>                                                                                 \
+  To view all component properties,                                                     \
+  use the <command>dsconfig list-properties</command> command.                          \
+ </para>
+

--
Gitblit v1.10.0