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

Mark Craig
11.59.2015 314e6e2709c4b0ebfe509e262ca366874f9069da
CR-6316 OPENDJ-1786 Automate integration of generated content

This first patch makes it possible to get a full refentry when running
OPENDJ_JAVA_ARGS="-Dorg.forgerock.opendj.gendoc=true" <command> -?
with any command.

This is a subtask of the following issue:
OPENDJ-386 Move to single reference document
4 files added
9 files modified
1143 ■■■■ changed files
opendj-cli/src/main/java/com/forgerock/opendj/cli/Argument.java 22 ●●●● patch | view | raw | blame | history
opendj-cli/src/main/java/com/forgerock/opendj/cli/ArgumentParser.java 311 ●●●● patch | view | raw | blame | history
opendj-cli/src/main/java/com/forgerock/opendj/cli/DocDescriptionSupplement.java 50 ●●●●● patch | view | raw | blame | history
opendj-cli/src/main/java/com/forgerock/opendj/cli/DocGenerationHelper.java 23 ●●●●● patch | view | raw | blame | history
opendj-cli/src/main/java/com/forgerock/opendj/cli/SubCommand.java 19 ●●●● patch | view | raw | blame | history
opendj-cli/src/main/java/com/forgerock/opendj/cli/SubCommandArgumentParser.java 116 ●●●● patch | view | raw | blame | history
opendj-cli/src/main/java/com/forgerock/opendj/cli/ToolRefDocContainer.java 162 ●●●●● patch | view | raw | blame | history
opendj-cli/src/main/resources/templates/optionsRefSect1.ftl 62 ●●●●● patch | view | raw | blame | history
opendj-cli/src/main/resources/templates/refEntry.ftl 51 ●●●● patch | view | raw | blame | history
opendj-cli/src/main/resources/templates/refSect1.ftl 41 ●●●●● patch | view | raw | blame | history
opendj-cli/src/main/resources/templates/refSect2.ftl 42 ●●●● patch | view | raw | blame | history
opendj-config/src/main/java/org/forgerock/opendj/config/dsconfig/DSConfig.java 4 ●●● patch | view | raw | blame | history
opendj-config/src/main/resources/com/forgerock/opendj/dsconfig/dsconfig.properties 240 ●●●●● patch | view | raw | blame | history
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;
    }
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
opendj-cli/src/main/java/com/forgerock/opendj/cli/DocDescriptionSupplement.java
New file
@@ -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);
}
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;
    }
}
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;
    }
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();
    }
}
opendj-cli/src/main/java/com/forgerock/opendj/cli/ToolRefDocContainer.java
New file
@@ -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);
}
opendj-cli/src/main/resources/templates/optionsRefSect1.ftl
New file
@@ -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>
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>
opendj-cli/src/main/resources/templates/refSect1.ftl
New file
@@ -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>
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>
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() {
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>