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>