From 8990a259a41f2f90606233139c4937fc1c8182cc Mon Sep 17 00:00:00 2001
From: Mark Craig <mark.craig@forgerock.com>
Date: Wed, 18 Feb 2015 10:12:37 +0000
Subject: [PATCH] CR-6114 OPENDJ-1822 Separate generated content from formatting
---
opendj-cli/src/main/java/com/forgerock/opendj/cli/SubCommandUsageHandler.java | 16
opendj-cli/src/main/resources/templates/refEntry.ftl | 135 ++++++
opendj-config/src/main/java/org/forgerock/opendj/config/dsconfig/DSConfig.java | 363 +++++++---------
opendj-cli/src/main/resources/templates/dscfgAppendProps.ftl | 35 +
opendj-cli/src/main/resources/templates/dscfgVariableList.ftl | 51 ++
opendj-cli/src/main/java/com/forgerock/opendj/cli/DocGenerationHelper.java | 137 ++++++
opendj-cli/src/main/resources/templates/dscfgListSubtypes.ftl | 56 ++
opendj-cli/src/main/resources/com/forgerock/opendj/cli/cli.properties | 7
opendj-cli/src/main/resources/templates/refSect2.ftl | 76 +++
opendj-cli/src/main/java/com/forgerock/opendj/cli/SubCommandArgumentParser.java | 165 ++-----
opendj-config/src/main/resources/com/forgerock/opendj/dsconfig/dsconfig.properties | 69 +++
opendj-cli/pom.xml | 7
opendj-cli/src/main/java/com/forgerock/opendj/cli/ArgumentParser.java | 90 ++--
opendj-cli/src/main/resources/templates/dscfgVarListEntry.ftl | 32 +
14 files changed, 859 insertions(+), 380 deletions(-)
diff --git a/opendj-cli/pom.xml b/opendj-cli/pom.xml
index 9e766a1..fb39c3a 100644
--- a/opendj-cli/pom.xml
+++ b/opendj-cli/pom.xml
@@ -21,7 +21,7 @@
!
! CDDL HEADER END
!
- ! Copyright 2014 ForgeRock AS
+ ! Copyright 2014-2015 ForgeRock AS.
!
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
@@ -60,6 +60,11 @@
<version>${forgerockBuildToolsVersion}</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.freemarker</groupId>
+ <artifactId>freemarker</artifactId>
+ <version>2.3.21</version>
+ </dependency>
</dependencies>
<properties>
<opendj.osgi.import>
diff --git a/opendj-cli/src/main/java/com/forgerock/opendj/cli/ArgumentParser.java b/opendj-cli/src/main/java/com/forgerock/opendj/cli/ArgumentParser.java
index d5739e1..77b5003 100644
--- a/opendj-cli/src/main/java/com/forgerock/opendj/cli/ArgumentParser.java
+++ b/opendj-cli/src/main/java/com/forgerock/opendj/cli/ArgumentParser.java
@@ -28,18 +28,23 @@
import static com.forgerock.opendj.cli.ArgumentConstants.*;
import static com.forgerock.opendj.cli.CliMessages.*;
+import static com.forgerock.opendj.cli.DocGenerationHelper.*;
import static com.forgerock.opendj.cli.Utils.*;
import static com.forgerock.opendj.util.StaticUtils.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.OutputStream;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Comparator;
+import java.util.Date;
import java.util.Enumeration;
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.Set;
import java.util.SortedSet;
@@ -658,74 +663,63 @@
final StringBuilder buffer = new StringBuilder();
usageOrVersionDisplayed = true;
if (System.getProperty("org.forgerock.opendj.gendoc") != null) {
- toRefSect2(buffer);
+ toRefEntry(buffer);
} else {
getUsage(buffer);
}
return buffer.toString();
}
- private void toRefSect2(StringBuilder sb) {
+ /**
+ * Appends a generated DocBook XML RefEntry (man page) to the StringBuilder.
+ *
+ * @param sb Append the RefEntry element to this.
+ */
+ private void toRefEntry(StringBuilder sb) {
final String scriptName = getScriptName();
if (scriptName == null) {
throw new RuntimeException("The script name should have been set via the environment property '"
+ PROPERTY_SCRIPT_NAME + "'.");
}
- sb.append("<refsect2 xml:id=\"").append(scriptName).append("\">").append(EOL);
- sb.append(" <title>").append(scriptName).append("</title>").append(EOL);
- sb.append(" <para>").append(getToolDescription()).append("</para>").append(EOL);
+ // 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("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("description", getToolDescription());
// If there is a supplement to the description for this utility,
- // then it is formatted for use in generated reference documentation.
- // In other words, it is already DocBook XML, so append it as is.
- final LocalizableMessage toolDocDescriptionSupplement = getDocToolDescriptionSupplement();
- if (!LocalizableMessage.EMPTY.equals(toolDocDescriptionSupplement)) {
- sb.append(toolDocDescriptionSupplement.toString()).append(EOL);
- }
-
+ // then it is already DocBook XML, so use it as is.
+ map.put("info", getDocToolDescriptionSupplement());
if (!argumentList.isEmpty()) {
- sb.append(" <variablelist>").append(EOL);
+ List<Map<String, Object>> options = new LinkedList<Map<String, Object>>();
for (Argument a : argumentList) {
- sb.append(" <varlistentry>").append(EOL);
- sb.append(" <term><option>");
- final Character shortID = a.getShortIdentifier();
- if (shortID != null) {
- sb.append("-").append(shortID.charValue());
- }
- final String longID = a.getLongIdentifier();
- if (shortID != null && longID != null) {
- sb.append(" | ");
- }
- if (longID != null) {
- sb.append("--").append(longID);
- }
- if (a.needsValue()) {
- sb.append(" ").append(a.getValuePlaceholder());
- }
- sb.append("</option></term>").append(EOL);
- sb.append(" <listitem>").append(EOL);
- sb.append(" <para>").append(a.getDescription()).append("</para>").append(EOL);
-
- final String defaultValue = a.getDefaultValue();
- if (defaultValue != null && !defaultValue.isEmpty()) {
- sb.append(" <para>Default: ").append(defaultValue).append("</para>").append(EOL);
- }
+ 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 for now it is already formatted in DocBook XML.
- final LocalizableMessage aDocDescriptionSupplement = a.getDocDescriptionSupplement();
- if (!LocalizableMessage.EMPTY.equals(aDocDescriptionSupplement)) {
- sb.append(aDocDescriptionSupplement.toString()).append(EOL);
- }
-
- sb.append(" </listitem>").append(EOL);
- sb.append(" </varlistentry>").append(EOL);
+ // then it is already DocBook XML, so use it as is.
+ option.put("info", a.getDocDescriptionSupplement());
+ options.add(option);
}
- sb.append(" </variablelist>").append(EOL);
+ map.put("options", options);
}
-
- sb.append("</refsect2>").append(EOL);
+ applyTemplate(sb, "refEntry.ftl", map);
}
/**
diff --git a/opendj-cli/src/main/java/com/forgerock/opendj/cli/DocGenerationHelper.java b/opendj-cli/src/main/java/com/forgerock/opendj/cli/DocGenerationHelper.java
new file mode 100644
index 0000000..a60d99a
--- /dev/null
+++ b/opendj-cli/src/main/java/com/forgerock/opendj/cli/DocGenerationHelper.java
@@ -0,0 +1,137 @@
+/*
+ * 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 freemarker.template.Configuration;
+import freemarker.template.Template;
+import freemarker.template.TemplateExceptionHandler;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.util.Map;
+
+/**
+ * This class provides utility functions to help generate reference documentation.
+ */
+public final class DocGenerationHelper {
+
+ /** Prevent instantiation. */
+ private DocGenerationHelper() {
+ // Do nothing.
+ }
+
+ /** FreeMarker template configuration. */
+ private static Configuration configuration;
+
+ /**
+ * Gets a FreeMarker configuration for applying templates.
+ *
+ * @return A FreeMarker configuration.
+ */
+ private static Configuration getConfiguration() {
+ if (configuration == null) {
+ configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
+ configuration.setClassForTemplateLoading(DocGenerationHelper.class, "/templates");
+ configuration.setDefaultEncoding("UTF-8");
+ configuration.setTemplateExceptionHandler(TemplateExceptionHandler.DEBUG_HANDLER);
+ }
+ return configuration;
+ }
+
+ /**
+ * Appends the String result from applying a FreeMarker template.
+ *
+ * @param builder Append the result to this.
+ * @param template The name of a template file found in {@code resources/templates/}.
+ * @param map The map holding the data to use in the template.
+ */
+ public static void applyTemplate(StringBuilder builder, final String template, final Map<String, Object> map) {
+ // FixMe: This method is public so it can be used by the SubCommandUsageHandler
+ // in org.forgerock.opendj.config.dsconfig.DSConfig.
+
+ // FreeMarker requires a configuration to find the template.
+ configuration = getConfiguration();
+
+ // FreeMarker takes the data and a Writer to process the template.
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ Writer writer = new OutputStreamWriter(outputStream);
+ try {
+ Template configurationTemplate = configuration.getTemplate(template);
+ configurationTemplate.process(map, writer);
+ builder.append(outputStream.toString());
+ } catch (Exception e) {
+ throw new RuntimeException(e.getMessage(), e);
+ } finally {
+ org.forgerock.util.Utils.closeSilently(writer, outputStream);
+ }
+ }
+
+ /**
+ * Returns an option synopsis.
+ *
+ * <br>
+ *
+ * Note: The synopsis might contain characters that must be escaped in XML.
+ *
+ * @param argument The argument option.
+ * @return A synopsis.
+ */
+ static String getOptionSynopsis(final Argument argument) {
+ StringBuilder builder = new StringBuilder();
+
+ final Character shortID = argument.getShortIdentifier();
+ if (shortID != null) {
+ builder.append("-").append(shortID.charValue());
+ }
+ final String longID = argument.getLongIdentifier();
+ if (shortID != null && longID != null) {
+ builder.append(" | ");
+ }
+ if (longID != null) {
+ builder.append("--").append(longID);
+ }
+ if (argument.needsValue()) {
+ builder.append(" ").append(argument.getValuePlaceholder());
+ }
+
+ return builder.toString();
+ }
+
+ /**
+ * Returns true when the argument handles properties.
+ *
+ * @param argument The argument.
+ * @return True if the argument handles properties.
+ */
+ public static boolean doesHandleProperties(final Argument argument) {
+ // FixMe: This method is public so it can be used by the SubCommandUsageHandler
+ // in org.forgerock.opendj.config.dsconfig.DSConfig.
+
+ final String id = argument.getLongIdentifier();
+ return ("add".equals(id) || "remove".equals(id) || "reset".equals(id) || "set".equals(id));
+ }
+}
diff --git a/opendj-cli/src/main/java/com/forgerock/opendj/cli/SubCommandArgumentParser.java b/opendj-cli/src/main/java/com/forgerock/opendj/cli/SubCommandArgumentParser.java
index f6fb9d0..6777007 100644
--- a/opendj-cli/src/main/java/com/forgerock/opendj/cli/SubCommandArgumentParser.java
+++ b/opendj-cli/src/main/java/com/forgerock/opendj/cli/SubCommandArgumentParser.java
@@ -28,6 +28,7 @@
import static com.forgerock.opendj.cli.ArgumentConstants.*;
import static com.forgerock.opendj.cli.CliMessages.*;
+import static com.forgerock.opendj.cli.DocGenerationHelper.*;
import static com.forgerock.opendj.cli.Utils.*;
import static com.forgerock.opendj.util.StaticUtils.*;
@@ -1102,7 +1103,17 @@
}
}
- /** Generate reference documentation for dsconfig subcommands. */
+ /**
+ * Appends a list generated DocBook XML RefSect2 elements to the StringBuilder, one per subcommand.
+ *
+ * <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.
+ */
private void generateReferenceDoc(final StringBuilder builder, Collection<SubCommand> values) {
for (SubCommand s : values) {
toRefSect2(s, builder);
@@ -1110,58 +1121,12 @@
}
/**
- * Generate reference documentation for dsconfig subcommands in DocBook 5 XML format. As the number of categories is
- * large, the subcommand entries are sorted here by name for inclusion in a <refsect1> covering all dsconfig
- * Subcommands as part of the <refentry> for dsconfig (in man-dsconfig.xml).
- * <p>
- * Although it would be possible to categorize subcommands in the same way as they are categorized in dsconfig
- * interactive mode, this generator does not use the categories.
- * <p>
- * It would also be possible to generate the sort of information provided by the configuration reference, such that
- * this reference would not stop at simply listing an option like --set {PROP:VAL}, but instead would also provide
- * the list of PROPs and their possible VALs. A future improvement could no doubt merge the configuration reference
- * with this content, though perhaps the problem calls for hypertext rather than the linear structure of a
- * <refentry>.
- * <p>
- * Each individual subcommand results in a <refsect2> element similar to the following.
- *
- * <pre>
- * <refsect2 xml:id="dsconfig-create-local-db-index">
- * <title>dsconfig create-local-db-index</title>
- * <para>Creates Local DB Indexes</para>
- * <variablelist>
- * <varlistentry>
- * <term><option>--backend-name {name}
- * </option></term>
- * <listitem>
- * <para>The name of the Local DB Backend</para>
- * </listitem>
- * </varlistentry>
- * <varlistentry>
- * <term><option>--index-name {OID}</option></term>
- * <listitem>
- * <para>The name of the new Local DB Index which will also be used
- * as the value of the "attribute" property: Specifies the name
- * of the attribute for which the index is to be maintained.</para>
- * </listitem>
- * </varlistentry>
- * <varlistentry>
- * <term><option>--set {PROP:VALUE}</option></term>
- * <listitem>
- * <para>Assigns a value to a property where PROP is the name of the
- * property and VALUE is the single value to be assigned. Specify the same
- * property multiple times in order to assign more than one value to
- * it</para>
- * </listitem>
- * </varlistentry>
- * </variablelist>
- * </refsect2>
- * </pre>
+ * Appends a generated DocBook XML RefSect2 element for a single subcommand to the StringBuilder.
*
* @param sc
* The SubCommand containing reference information.
* @param sb
- * The string builder where to output the Refsect2 representation of the subcommand
+ * Append the RefSect2 element to this.
*/
private void toRefSect2(SubCommand sc, StringBuilder sb) {
final String scriptName = getScriptName();
@@ -1170,90 +1135,50 @@
+ PROPERTY_SCRIPT_NAME + "'.");
}
- final String idRef = scriptName + "-" + sc.getName();
- final String nameRef = scriptName + " " + sc.getName();
- sb.append("<refsect2 xml:id=\"").append(idRef).append("\">").append(EOL);
- sb.append(" <title>").append(nameRef).append("</title>").append(EOL);
- sb.append(" <para>").append(sc.getDescription()).append("</para>").append(EOL);
+ // 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("name", name);
+ map.put("description", sc.getDescription());
+ map.put("optsTitle", REF_TITLE_OPTIONS.get());
+ map.put("optsIntro", REF_INTRO_OPTIONS.get(name));
// If there is a supplement to the description for this subcommand,
- // then it is formatted for use in generated reference documentation.
- // In other words, it is already DocBook XML, so append it as is.
- final LocalizableMessage scDocDescriptionSupplement = sc.getDocDescriptionSupplement();
- if (!LocalizableMessage.EMPTY.equals(scDocDescriptionSupplement)) {
- sb.append(scDocDescriptionSupplement.toString()).append(EOL);
- }
-
+ // then it is already DocBook XML, so use it as is.
+ map.put("info", sc.getDocDescriptionSupplement());
if (!sc.getArguments().isEmpty()) {
- sb.append(" <refsect3 xml:id=\"").append(idRef).append("-options\">").append(EOL);
- sb.append(" <title>Options</title>").append(EOL);
- sb.append(" <variablelist>").append(EOL);
- sb.append(" <para>").append(EOL);
- sb.append(" The <command>").append(nameRef)
- .append("</command> command supports the following options.").append(EOL);
- sb.append(" </para>").append(EOL);
+ List<Map<String, Object>> options = new LinkedList<Map<String, Object>>();
String nameOption = null;
for (Argument a : sc.getArguments()) {
- sb.append(" <varlistentry>").append(EOL);
- sb.append(" <term>");
- final String option = getOption(a);
- sb.append(option);
- sb.append("</term>").append(EOL);
- sb.append(" <listitem>").append(EOL);
- sb.append(" <para>").append(a.getDescription()).append("</para>").append(EOL);
- final String longID = a.getLongIdentifier();
- if (!"set".equals(longID)
- && !"reset".equals(longID)
- && !"add".equals(longID)
- && !"remove".equals(longID)) {
- nameOption = option;
- }
+ Map<String, Object> option = new HashMap<String, Object>();
+ String optionSynopsis = getOptionSynopsis(a);
+ option.put("synopsis", optionSynopsis);
+ option.put("description", a.getDescription());
+ Map<String, Object> info = new HashMap<String, Object>();
if (subCommandUsageHandler != null) {
- subCommandUsageHandler.appendArgumentAdditionalInfo(sb, sc, a, nameOption);
- } else {
- final String defaultValue = a.getDefaultValue();
- if (defaultValue != null && !defaultValue.isEmpty()) {
- sb.append(" <para>Default: ").append(defaultValue).append("</para>").append(EOL);
+ if (!doesHandleProperties(a)) {
+ nameOption = "<option>" + optionSynopsis + "</option>";
}
+ // Let this build its own arbitrarily formatted additional info.
+ info.put("usage", subCommandUsageHandler.getArgumentAdditionalInfo(sc, a, nameOption));
+ } else {
+ info.put("default", REF_DEFAULT.get(a.getDefaultValue()));
+
// If there is a supplement to the description for this argument,
- // then for now it is already formatted in DocBook XML.
- final LocalizableMessage aDocDescriptionSupplement = a.getDocDescriptionSupplement();
- if (!LocalizableMessage.EMPTY.equals(aDocDescriptionSupplement)) {
- sb.append(aDocDescriptionSupplement.toString()).append(EOL);
- }
+ // then it is already DocBook XML, so use it as is.
+ info.put("doc", a.getDocDescriptionSupplement());
}
- sb.append(" </listitem>").append(EOL);
- sb.append(" </varlistentry>").append(EOL);
+ option.put("info", info);
+ options.add(option);
}
- sb.append(" </variablelist>").append(EOL);
- sb.append(" </refsect3>").append(EOL);
+ map.put("options", options);
}
+
if (subCommandUsageHandler != null) {
- subCommandUsageHandler.appendProperties(sb, sc);
+ map.put("properties", subCommandUsageHandler.getProperties(sc));
}
-
- sb.append("</refsect2>").append(EOL);
- }
-
- private String getOption(Argument a) {
- final StringBuilder sb = new StringBuilder();
- sb.append("<option>");
- final Character shortID = a.getShortIdentifier();
- if (shortID != null) {
- sb.append("-").append(shortID.charValue());
- }
- final String longID = a.getLongIdentifier();
- if (shortID != null && longID != null) {
- sb.append(" | ");
- }
- if (longID != null) {
- sb.append("--").append(longID);
- }
- if (a.needsValue()) {
- sb.append(" ").append(a.getValuePlaceholder());
- }
- sb.append("</option>");
- return sb.toString();
+ applyTemplate(sb, "refSect2.ftl", map);
}
}
diff --git a/opendj-cli/src/main/java/com/forgerock/opendj/cli/SubCommandUsageHandler.java b/opendj-cli/src/main/java/com/forgerock/opendj/cli/SubCommandUsageHandler.java
index 4884b73..8a7bf89 100644
--- a/opendj-cli/src/main/java/com/forgerock/opendj/cli/SubCommandUsageHandler.java
+++ b/opendj-cli/src/main/java/com/forgerock/opendj/cli/SubCommandUsageHandler.java
@@ -21,7 +21,7 @@
* CDDL HEADER END
*
*
- * Copyright 2015 ForgeRock AS
+ * Copyright 2015 ForgeRock AS.
*/
package com.forgerock.opendj.cli;
@@ -32,27 +32,25 @@
public interface SubCommandUsageHandler {
/**
- * Appends properties information for the sub-command.
+ * Returns properties information for the sub-command.
*
- * @param builder
- * the string builder where to append
* @param subCommand
* the sub command for which to print usage information
+ * @return The properties information for the sub-command.
*/
- void appendProperties(StringBuilder builder, SubCommand subCommand);
+ String getProperties(SubCommand subCommand);
/**
- * Appends additional information for the provided sub-command argument.
+ * Returns additional information for the provided sub-command argument.
*
- * @param builder
- * the string builder where to append
* @param subCommand
* the sub command for which to print usage information
* @param arg
* the argument for which to append additional information
* @param nameOption
* the string representing the name option
+ * @return The additional information for the sub-command argument.
*/
- void appendArgumentAdditionalInfo(StringBuilder builder, SubCommand subCommand, Argument arg, String nameOption);
+ String getArgumentAdditionalInfo(SubCommand subCommand, Argument arg, String nameOption);
}
diff --git a/opendj-cli/src/main/resources/com/forgerock/opendj/cli/cli.properties b/opendj-cli/src/main/resources/com/forgerock/opendj/cli/cli.properties
index 1d1c969..b216492 100755
--- a/opendj-cli/src/main/resources/com/forgerock/opendj/cli/cli.properties
+++ b/opendj-cli/src/main/resources/com/forgerock/opendj/cli/cli.properties
@@ -973,6 +973,13 @@
ERR_ERROR_CANNOT_READ_BIND_NAME=Unable to read bind name
ERR_ERROR_CANNOT_READ_HOST_NAME=Cannot read the host name
+# Strings for generated reference documentation.
+REF_TITLE_DESCRIPTION=Description
+REF_TITLE_OPTIONS=Options
+REF_INTRO_OPTIONS=The <command>%s</command> command takes the following options:
+REF_DEFAULT=Default: %s
+REF_TITLE_SUBCOMMANDS=Subcommands
+
# Supplements to descriptions for generated reference documentation.
SUPPLEMENT_DESCRIPTION_CONTROLS=<para> \
For some <replaceable>controloid</replaceable> values, \
diff --git a/opendj-cli/src/main/resources/templates/dscfgAppendProps.ftl b/opendj-cli/src/main/resources/templates/dscfgAppendProps.ftl
new file mode 100644
index 0000000..790d19a
--- /dev/null
+++ b/opendj-cli/src/main/resources/templates/dscfgAppendProps.ftl
@@ -0,0 +1,35 @@
+<#--
+ # 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.
+ #
+ #-->
+<refsect3 xml:id="${id}">
+ <title>${title}</title>
+
+ <para>
+ ${intro}
+ </para>
+
+ ${list}
+</refsect3>
diff --git a/opendj-cli/src/main/resources/templates/dscfgListSubtypes.ftl b/opendj-cli/src/main/resources/templates/dscfgListSubtypes.ftl
new file mode 100644
index 0000000..7aa96b1
--- /dev/null
+++ b/opendj-cli/src/main/resources/templates/dscfgListSubtypes.ftl
@@ -0,0 +1,56 @@
+<#--
+ # 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.
+ #
+ #-->
+<variablelist>
+
+ <para>
+ ${dependencies}
+ </para>
+
+ <para>
+ ${typesIntro}
+ </para>
+
+ <#list children as child>
+ <varlistentry>
+ <term>${child.name}</term>
+ <listitem>
+ <para>
+ ${child.default}
+ </para>
+
+ <para>
+ ${child.enabled}
+ </para>
+
+ <para>
+ ${child.link}
+ </para>
+ </listitem>
+ </varlistentry>
+ </#list>
+
+</variablelist>
diff --git a/opendj-cli/src/main/resources/templates/dscfgVarListEntry.ftl b/opendj-cli/src/main/resources/templates/dscfgVarListEntry.ftl
new file mode 100644
index 0000000..2e07620
--- /dev/null
+++ b/opendj-cli/src/main/resources/templates/dscfgVarListEntry.ftl
@@ -0,0 +1,32 @@
+<#--
+ # 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.
+ #
+ #-->
+<varlistentry>
+ <term>${term}</term>
+ <listitem>
+ ${definition}
+ </listitem>
+</varlistentry>
diff --git a/opendj-cli/src/main/resources/templates/dscfgVariableList.ftl b/opendj-cli/src/main/resources/templates/dscfgVariableList.ftl
new file mode 100644
index 0000000..b3fd18d
--- /dev/null
+++ b/opendj-cli/src/main/resources/templates/dscfgVariableList.ftl
@@ -0,0 +1,51 @@
+<#--
+ # 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.
+ #
+ #-->
+<variablelist>
+
+<#list properties as property>
+
+ <varlistentry xml:id="${property.id}">
+ <term>${property.term}</term>
+ <listitem>
+ <variablelist>
+
+ <varlistentry>
+ <term>${property.descTitle}</term>
+ <listitem>
+ <para>
+ ${property.description}
+ </para>
+ </listitem>
+ </varlistentry>
+
+ ${property.list}
+ </variablelist>
+ </listitem>
+ </varlistentry>
+</#list>
+
+</variablelist>
diff --git a/opendj-cli/src/main/resources/templates/refEntry.ftl b/opendj-cli/src/main/resources/templates/refEntry.ftl
new file mode 100644
index 0000000..31542a0
--- /dev/null
+++ b/opendj-cli/src/main/resources/templates/refEntry.ftl
@@ -0,0 +1,135 @@
+<#--
+ # 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.
+ #
+ #-->
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ! CCPL HEADER START
+ !
+ ! This work is licensed under the Creative Commons
+ ! Attribution-NonCommercial-NoDerivs 3.0 Unported License.
+ ! To view a copy of this license, visit
+ ! http://creativecommons.org/licenses/by-nc-nd/3.0/
+ ! or send a letter to Creative Commons, 444 Castro Street,
+ ! Suite 900, Mountain View, California, 94041, USA.
+ !
+ ! You can also obtain a copy of the license at
+ ! trunk/opendj/legal-notices/CC-BY-NC-ND.txt.
+ ! See the License for the specific language governing permissions
+ ! and limitations under the License.
+ !
+ ! If applicable, add the following below this CCPL HEADER, with the fields
+ ! enclosed by brackets "[]" replaced with your own identifying information:
+ ! Portions Copyright [yyyy] [name of copyright owner]
+ !
+ ! CCPL HEADER END
+ !
+ ! Copyright 2011-${year} ForgeRock AS.
+ !
+-->
+<refentry xml:id="${name}-1"
+ xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="${locale}"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://docbook.org/ns/docbook
+ http://docbook.org/xml/5.0/xsd/docbook.xsd"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:xinclude="http://www.w3.org/2001/XInclude">
+
+ <info>
+ <copyright>
+ <year>2011-${year}</year>
+ <holder>ForgeRock AS.</holder>
+ </copyright>
+ </info>
+
+ <refmeta>
+ <refentrytitle>${name}</refentrytitle><manvolnum>1</manvolnum>
+ <refmiscinfo class="software">OpenDJ</refmiscinfo>
+ <refmiscinfo class="version">${r"${project.version}"}</refmiscinfo>
+ </refmeta>
+
+ <refnamediv>
+ <refname>${name}</refname>
+ <refpurpose>TODO short description</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <cmdsynopsis>
+ <command>${name}</command>
+ <arg choice="plain">${args}</arg>
+ </cmdsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1 xml:id="${name}-description">
+ <title>${descTitle}</title>
+
+ <para>
+ ${description}
+ </para>
+
+ <#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>
+
+ <!-- TODO: subcommands -->
+ <!-- TODO: filter -->
+ <!-- TODO: attribute -->
+ <!-- TODO: exitCodes -->
+ <!-- TODO: files -->
+ <!-- TODO: examples -->
+ <!-- TODO: seeAlso -->
+</refentry>
diff --git a/opendj-cli/src/main/resources/templates/refSect2.ftl b/opendj-cli/src/main/resources/templates/refSect2.ftl
new file mode 100644
index 0000000..2529f3d
--- /dev/null
+++ b/opendj-cli/src/main/resources/templates/refSect2.ftl
@@ -0,0 +1,76 @@
+<#--
+ # 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.
+ #
+ #-->
+<refsect2 xml:id="${id}">
+ <title>${name}</title>
+
+ <para>
+ ${description}
+ </para>
+
+ <#if info??>${info}</#if>
+
+ <#if options??>
+ <refsect3 xml:id="${id}-options">
+ <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.info??>
+ <#if info.usage??>${option.info.usage}</#if>
+
+ <#if info.default??>
+ <para>
+ ${option.info.default}
+ </para>
+ </#if>
+
+ <#if info.doc??>${option.info.doc}</#if>
+ </#if>
+ </listitem>
+ </varlistentry>
+
+ </#list>
+ </variablelist>
+ </refsect3>
+ </#if>
+
+ <#if properties??>
+ ${properties}
+ </#if>
+</refsect2>
diff --git a/opendj-config/src/main/java/org/forgerock/opendj/config/dsconfig/DSConfig.java b/opendj-config/src/main/java/org/forgerock/opendj/config/dsconfig/DSConfig.java
index 261028a..a3288c0 100644
--- a/opendj-config/src/main/java/org/forgerock/opendj/config/dsconfig/DSConfig.java
+++ b/opendj-config/src/main/java/org/forgerock/opendj/config/dsconfig/DSConfig.java
@@ -22,12 +22,13 @@
*
*
* Copyright 2007-2010 Sun Microsystems, Inc.
- * Portions Copyright 2012-2015 ForgeRock AS
+ * Portions Copyright 2012-2015 ForgeRock AS.
*/
package org.forgerock.opendj.config.dsconfig;
import static com.forgerock.opendj.cli.ArgumentConstants.*;
import static com.forgerock.opendj.cli.CliMessages.*;
+import static com.forgerock.opendj.cli.DocGenerationHelper.*;
import static com.forgerock.opendj.cli.Utils.*;
import static com.forgerock.opendj.dsconfig.DsconfigMessages.*;
import static com.forgerock.opendj.util.StaticUtils.*;
@@ -54,6 +55,7 @@
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
@@ -127,93 +129,61 @@
*/
public final class DSConfig extends ConsoleApplication {
- private static final String ALLOW_UNLIMITED = "A value of \"-1\" or \"unlimited\" for no limit.";
- private static final String ACI_SYNTAX_REL_URL =
- "<link" + EOL
- + " xlink:show=\"new\"" + EOL
- + " xlink:href=\"admin-guide#about-acis\"" + EOL
- + " xlink:role=\"http://docbook.org/xlink/role/olink\">" + EOL
- + "<citetitle>About Access Control Instructions</citetitle></link>" + EOL;
- private static final String DURATION_SYNTAX_REL_URL =
- " <itemizedlist>" + EOL
- + " <para>Some property values take a time duration. Durations are expressed" + EOL
- + " as numbers followed by units. For example <literal>1 s</literal> means" + EOL
- + " one second, and <literal>2 w</literal> means two weeks. Some durations" + EOL
- + " have minimum granularity or maximum units, so you cannot necessary specify" + EOL
- + " every duration in milliseconds or weeks for example. Some durations allow" + EOL
- + " you to use a special value to mean unlimited. Units are specified as" + EOL
- + " follows.</para>" + EOL
- + " <listitem><para><literal>ms</literal>: milliseconds</para></listitem>" + EOL
- + " <listitem><para><literal>s</literal>: seconds</para></listitem>" + EOL
- + " <listitem><para><literal>m</literal>: minutes</para></listitem>" + EOL
- + " <listitem><para><literal>h</literal>: hours</para></listitem>" + EOL
- + " <listitem><para><literal>d</literal>: days</para></listitem>" + EOL
- + " <listitem><para><literal>w</literal>: weeks</para></listitem>" + EOL
- + " </itemizedlist>" + EOL;
-
- // FIXME: I18n support. Today all the strings are hardcoded in this file
+ /**
+ * This class provides additional information about subcommands for generated reference documentation.
+ */
private final class DSConfigSubCommandUsageHandler implements SubCommandUsageHandler {
+ /** Marker to open a DocBook XML paragraph. */
+ private String op = "<para>";
+
+ /** Marker to close a DocBook XML paragraph. */
+ private String cp = "</para>";
+
/** {@inheritDoc} */
@Override
- public void appendArgumentAdditionalInfo(StringBuilder sb, SubCommand sc, Argument a, String nameOption) {
+ public String getArgumentAdditionalInfo(SubCommand sc, Argument a, String nameOption) {
+ StringBuilder sb = new StringBuilder();
final AbstractManagedObjectDefinition<?, ?> defn = getManagedObjectDefinition(sc);
if (defn == null) {
- return;
+ return "";
}
- final String longID = a.getLongIdentifier();
- if ("set".equals(longID)
- || "reset".equals(longID)
- || "add".equals(longID)
- || "remove".equals(longID)) {
- sb.append(" <para>").append(EOL);
+ if (doesHandleProperties(a)) {
final LocalizableMessage name = defn.getUserFriendlyName();
- sb.append(" ").append(name).append(" properties depend on the ").append(name)
- .append(" type, which depends on the ").append(nameOption).append(" option.").append(EOL);
- sb.append(" </para>").append(EOL);
+ sb.append(op).append(REF_DSCFG_ARG_ADDITIONAL_INFO.get(name, name, nameOption)).append(cp).append(EOL);
} else {
listSubtypes(sb, a, defn);
}
- return;
+ return sb.toString();
}
private void listSubtypes(StringBuilder sb, Argument a, AbstractManagedObjectDefinition<?, ?> defn) {
final LocalizableMessage placeholder = a.getValuePlaceholder();
- sb.append(" <variablelist>").append(EOL);
- sb.append(" <para>").append(EOL);
- final LocalizableMessage name = defn.getUserFriendlyName();
- sb.append(" ").append(name).append(" properties depend on the ").append(name)
- .append(" type, which depends on the ").append(placeholder).append(" you provide.").append(EOL);
- sb.append(" </para>").append(EOL);
- sb.append(" <para>").append(EOL);
- sb.append(" By default, OpenDJ directory server supports the following ")
- .append(name).append(" types:").append(EOL);
- sb.append(" </para>").append(EOL);
+ Map<String, Object> map = new HashMap<String, Object>();
+
+ final LocalizableMessage name = defn.getUserFriendlyName();
+ map.put("dependencies", REF_DSCFG_SUBTYPE_DEPENDENCIES.get(name, name, placeholder));
+ map.put("typesIntro", REF_DSCFG_SUBTYPE_TYPES_INTRO.get(name));
+
+ List<Map<String, Object>> children = new LinkedList<Map<String, Object>>();
for (AbstractManagedObjectDefinition<?, ?> childDefn : getLeafChildren(defn)) {
- sb.append(" <varlistentry>").append(EOL);
- sb.append(" <term>").append(childDefn.getName()).append("</term>").append(EOL);
- sb.append(" <listitem>").append(EOL);
- sb.append(" <para>").append(EOL);
- sb.append(" Default ").append(placeholder).append(": ")
- .append(childDefn.getUserFriendlyName()).append(EOL);
- sb.append(" </para>").append(EOL);
- sb.append(" <para>").append(EOL);
- final boolean isEnabled = propertyExists(childDefn, "enabled");
- sb.append(" Enabled by default: ").append(isEnabled).append(EOL);
- sb.append(" </para>").append(EOL);
- sb.append(" <para>").append(EOL);
- sb.append(" See <xref linkend=\"")
- .append(getScriptName()).append("-")
- .append(a.getLongIdentifier()).append("-")
- .append(defn.getName()).append("-prop-").append(childDefn.getName())
- .append("\" /> for the properties of this ").append(defn.getUserFriendlyName())
- .append(" type.").append(EOL);
- sb.append(" </para>").append(EOL);
- sb.append(" </listitem>").append(EOL);
- sb.append(" </varlistentry>").append(EOL);
+
+ Map<String, Object> child = new HashMap<String, Object>();
+
+ child.put("name", childDefn.getName());
+ child.put("default", REF_DSCFG_CHILD_DEFAULT.get(placeholder, childDefn.getUserFriendlyName()));
+ child.put("enabled", REF_DSCFG_CHILD_ENABLED_BY_DEFAULT.get(propertyExists(childDefn, "enabled")));
+
+ final String link = getLink(getScriptName() + "-" + a.getLongIdentifier()
+ + "-" + defn.getName() + "-prop-" + childDefn.getName());
+ child.put("link", REF_DSCFG_CHILD_LINK.get(link, defn.getUserFriendlyName()));
+
+ children.add(child);
}
- sb.append(" </variablelist>").append(EOL);
+ map.put("children", children);
+
+ applyTemplate(sb, "dscfgListSubtypes.ftl", map);
}
private boolean propertyExists(AbstractManagedObjectDefinition<?, ?> defn, String name) {
@@ -226,27 +196,26 @@
/** {@inheritDoc} */
@Override
- public void appendProperties(StringBuilder sb, SubCommand sc) {
+ public String getProperties(SubCommand sc) {
+ StringBuilder sb = new StringBuilder();
final AbstractManagedObjectDefinition<?, ?> defn = getManagedObjectDefinition(sc);
if (defn == null) {
- return;
+ return "";
}
for (AbstractManagedObjectDefinition<?, ?> childDefn : getLeafChildren(defn)) {
final List<PropertyDefinition<?>> props =
new ArrayList<PropertyDefinition<?>>(childDefn.getAllPropertyDefinitions());
Collections.sort(props);
-
+ Map<String, Object> map = new HashMap<String, Object>();
final String propPrefix = getScriptName() + "-" + sc.getName() + "-" + childDefn.getName();
- sb.append(" <refsect3 xml:id=\"").append(propPrefix).append("\">").append(EOL);
- sb.append(" <title>").append(childDefn.getUserFriendlyName()).append("</title>").append(EOL);
- sb.append(" <para>").append(EOL);
- sb.append(" ").append(defn.getUserFriendlyPluralName()).append(" of type ")
- .append(childDefn.getName()).append(" have the following properties:").append(EOL);
- sb.append(" </para>").append(EOL);
- toVariableList(props, defn, propPrefix, sb);
- sb.append(" </refsect3>").append(EOL);
+ map.put("id", propPrefix);
+ map.put("title", childDefn.getUserFriendlyName());
+ map.put("intro", REF_DSCFG_PROPS_INTRO.get(defn.getUserFriendlyPluralName(), childDefn.getName()));
+ map.put("list", toVariableList(props, defn, propPrefix));
+ applyTemplate(sb, "dscfgAppendProps.ftl", map);
}
+ return sb.toString();
}
private AbstractManagedObjectDefinition<?, ?> getManagedObjectDefinition(SubCommand sc) {
@@ -298,57 +267,57 @@
return null;
}
- private void toVariableList(List<PropertyDefinition<?>> props, AbstractManagedObjectDefinition<?, ?> defn,
- String propPrefix, StringBuilder b) {
- final String indent = " ";
- b.append(" <variablelist>").append(EOL);
+ private String toVariableList(List<PropertyDefinition<?>> props, AbstractManagedObjectDefinition<?, ?> defn,
+ String propPrefix) {
+ StringBuilder b = new StringBuilder();
+ Map<String, Object> map = new HashMap<String, Object>();
+
+ List<Map<String, Object>> properties = new LinkedList<Map<String, Object>>();
for (PropertyDefinition<?> prop : props) {
- b.append(" <varlistentry xml:id=\"")
- .append(propPrefix).append("-").append(prop.getName()).append("\">").append(EOL);
- b.append(" <term>").append(prop.getName()).append("</term>").append(EOL);
- b.append(" <listitem>").append(EOL);
- b.append(" <variablelist>").append(EOL);
- appendVarlistentry(b, "Description", getDescriptionString(prop), indent);
- appendDefaultBehavior(b, indent, prop);
- appendAllowedValues(b, prop, indent);
- appendVarlistentry(b, "Multi-valued", getYN(prop, MULTI_VALUED), indent);
- appendVarlistentry(b, "Required", getYN(prop, MANDATORY), indent);
- appendVarlistentry(b, "Admin Action Required", getAdminActionRequired(prop, defn), indent);
- appendVarlistentry(b, "Advanced Property", getYNAdvanced(prop, ADVANCED), indent);
- appendVarlistentry(b, "Read-only", getYN(prop, READ_ONLY), indent);
- b.append(" </variablelist>").append(EOL);
- b.append(" </listitem>").append(EOL);
- b.append(" </varlistentry>").append(EOL);
+ Map<String, Object> property = new HashMap<String, Object>();
+ property.put("id", propPrefix + "-" + prop.getName());
+ property.put("term", prop.getName());
+ property.put("descTitle", REF_TITLE_DESCRIPTION.get());
+ property.put("description", getDescriptionString(prop));
+
+ final StringBuilder sb = new StringBuilder();
+ appendDefaultBehavior(sb, prop);
+ appendAllowedValues(sb, prop);
+ appendVarListEntry(sb, REF_DSCFG_PROPS_LABEL_MULTI_VALUED.get().toString(), getYN(prop, MULTI_VALUED));
+ appendVarListEntry(sb, REF_DSCFG_PROPS_LABEL_REQUIRED.get().toString(), getYN(prop, MANDATORY));
+ appendVarListEntry(sb, REF_DSCFG_PROPS_LABEL_ADMIN_ACTION_REQUIRED.get().toString(),
+ getAdminActionRequired(prop, defn));
+ appendVarListEntry(sb, REF_DSCFG_PROPS_LABEL_ADVANCED_PROPERTY.get().toString(),
+ getYNAdvanced(prop, ADVANCED));
+ appendVarListEntry(sb, REF_DSCFG_PROPS_LABEL_READ_ONLY.get().toString(), getYN(prop, READ_ONLY));
+ property.put("list", sb.toString());
+
+ properties.add(property);
}
- b.append(" </variablelist>").append(EOL);
+ map.put("properties", properties);
+
+ applyTemplate(b, "dscfgVariableList.ftl", map);
+ return b.toString();
}
- private StringBuilder appendVarlistentry(StringBuilder b, String term, Object para, String indent) {
- b.append(indent).append("<varlistentry>").append(EOL);
- b.append(indent).append(" <term>").append(term).append("</term>").append(EOL);
- b.append(indent).append(" <listitem>").append(EOL);
- b.append(indent).append(" <para>").append(para).append("</para>").append(EOL);
- b.append(indent).append(" </listitem>").append(EOL);
- b.append(indent).append("</varlistentry>").append(EOL);
+ private StringBuilder appendVarListEntry(StringBuilder b, String term, Object definition) {
+ Map<String, Object> map = new HashMap<String, Object>();
+ map.put("term", term);
+ map.put("definition", definition);
+ applyTemplate(b, "dscfgVarListEntry.ftl", map);
return b;
}
- private void appendDefaultBehavior(StringBuilder b, final String indent, PropertyDefinition<?> prop) {
- b.append(indent).append("<varlistentry>").append(EOL);
- b.append(indent).append(" <term>").append("Default Value").append("</term>").append(EOL);
- b.append(indent).append(" <listitem>").append(EOL);
- appendDefaultBehaviorString(b, indent + " ", prop);
- b.append(indent).append(" </listitem>").append(EOL);
- b.append(indent).append("</varlistentry>").append(EOL);
+ private void appendDefaultBehavior(StringBuilder b, PropertyDefinition<?> prop) {
+ StringBuilder sb = new StringBuilder();
+ appendDefaultBehaviorString(sb, prop);
+ appendVarListEntry(b, REF_DSCFG_PROPS_LABEL_DEFAULT_VALUE.get().toString(), sb.toString());
}
- private void appendAllowedValues(StringBuilder b, PropertyDefinition<?> prop, String indent) {
- b.append(indent).append("<varlistentry>").append(EOL);
- b.append(indent).append(" <term>").append("Allowed Values").append("</term>").append(EOL);
- b.append(indent).append(" <listitem>").append(EOL);
- appendSyntax(b, prop, indent + " ");
- b.append(indent).append(" </listitem>").append(EOL);
- b.append(indent).append("</varlistentry>").append(EOL);
+ private void appendAllowedValues(StringBuilder b, PropertyDefinition<?> prop) {
+ StringBuilder sb = new StringBuilder();
+ appendSyntax(sb, prop);
+ appendVarListEntry(b, REF_DSCFG_PROPS_LABEL_ALLOWED_VALUES.get().toString(), sb.toString());
}
private Object getDescriptionString(PropertyDefinition<?> prop) {
@@ -363,152 +332,146 @@
final Type actionType = adminAction.getType();
final StringBuilder action = new StringBuilder();
if (actionType == Type.COMPONENT_RESTART) {
- action.append("The ").append(defn.getUserFriendlyName())
- .append(" must be disabled and re-enabled for changes to this setting to take effect");
+ action.append(op)
+ .append(REF_DSCFG_ADMIN_ACTION_COMPONENT_RESTART.get(defn.getUserFriendlyName()))
+ .append(cp);
} else if (actionType == Type.SERVER_RESTART) {
- action.append("Restart the server");
+ action.append(op).append(REF_DSCFG_ADMIN_ACTION_SERVER_RESTART.get()).append(cp);
} else if (actionType == Type.NONE) {
- action.append("None");
+ action.append(op).append(REF_DSCFG_ADMIN_ACTION_NONE.get()).append(cp);
}
if (synopsis != null) {
- if (action.length() > 0) {
- action.append(". ");
- }
- action.append(synopsis);
+ action.append(op).append(synopsis).append(cp);
}
return action.toString();
}
- return "None";
+ return op + REF_DSCFG_ADMIN_ACTION_NONE.get() + cp;
}
private String getYN(PropertyDefinition<?> prop, PropertyOption option) {
- return prop.hasOption(option) ? "Yes" : "No";
+ LocalizableMessage msg = prop.hasOption(option) ? REF_DSCFG_PROP_YES.get() : REF_DSCFG_PROP_NO.get();
+ return op + msg + cp;
}
private String getYNAdvanced(PropertyDefinition<?> prop, PropertyOption option) {
- return prop.hasOption(option) ? "Yes (Use --advanced in interactive mode.)" : "No";
+ LocalizableMessage msg = prop.hasOption(option)
+ ? REF_DSCFG_PROP_YES_ADVANCED.get() : REF_DSCFG_PROP_NO.get();
+ return op + msg + cp;
}
- private void appendDefaultBehaviorString(StringBuilder b, String indent, PropertyDefinition<?> prop) {
- b.append(indent);
+ private void appendDefaultBehaviorString(StringBuilder b, PropertyDefinition<?> prop) {
final DefaultBehaviorProvider<?> defaultBehavior = prop.getDefaultBehaviorProvider();
if (defaultBehavior instanceof UndefinedDefaultBehaviorProvider) {
- b.append("<para>None</para>").append(EOL);
- return;
+ b.append(op).append(REF_DSCFG_DEFAULT_BEHAVIOR_NONE.get()).append(cp).append(EOL);
} else if (defaultBehavior instanceof DefinedDefaultBehaviorProvider) {
DefinedDefaultBehaviorProvider<?> behavior = (DefinedDefaultBehaviorProvider<?>) defaultBehavior;
final Collection<String> defaultValues = behavior.getDefaultValues();
if (defaultValues.size() == 0) {
- b.append("<para>None</para>").append(EOL);
+ b.append(op).append(REF_DSCFG_DEFAULT_BEHAVIOR_NONE.get()).append(cp).append(EOL);
} else if (defaultValues.size() == 1) {
- b.append("<para>").append(defaultValues.iterator().next()).append("</para>").append(EOL);
+ b.append(op).append(REF_DSCFG_DEFAULT_BEHAVIOR.get(defaultValues.iterator().next()))
+ .append(cp).append(EOL);
} else {
final Iterator<String> it = defaultValues.iterator();
- b.append("<para>").append(it.next()).append("</para>");
+ b.append(op).append(REF_DSCFG_DEFAULT_BEHAVIOR.get(it.next())).append(cp);
for (; it.hasNext();) {
- final String str = it.next();
- b.append(EOL).append(indent).append("<para>").append(str).append("</para>");
+ b.append(EOL).append(op).append(REF_DSCFG_DEFAULT_BEHAVIOR.get(it.next())).append(cp);
}
b.append(EOL);
}
- return;
} else if (defaultBehavior instanceof AliasDefaultBehaviorProvider) {
AliasDefaultBehaviorProvider<?> behavior = (AliasDefaultBehaviorProvider<?>) defaultBehavior;
- b.append("<para>").append(behavior.getSynopsis()).append("</para>").append(EOL);
- return;
+ b.append(op).append(REF_DSCFG_DEFAULT_BEHAVIOR.get(behavior.getSynopsis())).append(cp).append(EOL);
} else if (defaultBehavior instanceof RelativeInheritedDefaultBehaviorProvider) {
final RelativeInheritedDefaultBehaviorProvider<?> behavior =
(RelativeInheritedDefaultBehaviorProvider<?>) defaultBehavior;
- appendDefaultBehaviorString(b, indent,
+ appendDefaultBehaviorString(b,
behavior.getManagedObjectDefinition().getPropertyDefinition(behavior.getPropertyName()));
- return;
} else if (defaultBehavior instanceof AbsoluteInheritedDefaultBehaviorProvider) {
final AbsoluteInheritedDefaultBehaviorProvider<?> behavior =
(AbsoluteInheritedDefaultBehaviorProvider<?>) defaultBehavior;
- appendDefaultBehaviorString(b, indent,
+ appendDefaultBehaviorString(b,
behavior.getManagedObjectDefinition().getPropertyDefinition(behavior.getPropertyName()));
- return;
}
}
- private void appendSyntax(final StringBuilder b, PropertyDefinition<?> prop, final String indent) {
+ private void appendSyntax(final StringBuilder b, PropertyDefinition<?> prop) {
// Create a visitor for performing syntax specific processing.
PropertyDefinitionVisitor<String, Void> visitor = new PropertyDefinitionVisitor<String, Void>() {
@Override
public String visitACI(ACIPropertyDefinition prop, Void p) {
- b.append(indent).append("<para>").append(ACI_SYNTAX_REL_URL).append("</para>").append(EOL);
+ b.append(op).append(REF_DSCFG_ACI_SYNTAX_REL_URL.get()).append(cp).append(EOL);
return null;
}
@Override
public String visitAggregation(AggregationPropertyDefinition prop, Void p) {
- b.append(indent).append("<para>");
+ b.append(op);
final RelationDefinition<?, ?> rel = prop.getRelationDefinition();
- final String linkStr = getLink(rel.getName() + ".html");
- b.append("The DN of any ").append(linkStr).append(". ");
+ final String linkStr = getLink(rel.getName());
+ b.append(REF_DSCFG_AGGREGATION.get(linkStr)).append(". ");
final LocalizableMessage synopsis = prop.getSourceConstraintSynopsis();
if (synopsis != null) {
b.append(synopsis);
}
- b.append("</para>").append(EOL);
+ b.append(cp).append(EOL);
return null;
}
@Override
public String visitAttributeType(AttributeTypePropertyDefinition prop, Void p) {
- b.append(indent).append("<para>");
- b.append("The name of an attribute type defined in the server schema.");
- b.append("</para>").append(EOL);
+ b.append(op).append(REF_DSCFG_ANY_ATTRIBUTE.get()).append(".").append(cp).append(EOL);
return null;
}
@Override
public String visitBoolean(BooleanPropertyDefinition prop, Void p) {
- b.append(indent).append("<para>true</para>").append(EOL);
- b.append(indent).append("<para>false</para>").append(EOL);
+ b.append(op).append("true").append(cp).append(EOL);
+ b.append(op).append("false").append(cp).append(EOL);
return null;
}
@Override
public String visitClass(ClassPropertyDefinition prop, Void p) {
- b.append(indent).append("<para>");
- b.append("A java class that implements or extends the class(es) :")
- .append(Utils.joinAsString(EOL, prop.getInstanceOfInterface()));
- b.append("</para>").append(EOL);
+ b.append(op).append(REF_DSCFG_JAVA_PLUGIN.get()).append(" ")
+ .append(Utils.joinAsString(EOL, prop.getInstanceOfInterface())).append(cp).append(EOL);
return null;
}
@Override
public String visitDN(DNPropertyDefinition prop, Void p) {
- b.append(indent).append("<para>");
- b.append("A valid DN.");
+ b.append(op).append(REF_DSCFG_VALID_DN.get());
final DN baseDN = prop.getBaseDN();
if (baseDN != null) {
- b.append(" ").append(baseDN);
+ b.append(": ").append(baseDN);
+ } else {
+ b.append(".");
}
- b.append("</para>").append(EOL);
+ b.append(cp).append(EOL);
return null;
}
@Override
public String visitDuration(DurationPropertyDefinition prop, Void p) {
- b.append(indent).append("<para>");
- b.append(DURATION_SYNTAX_REL_URL).append(". ");
+ b.append(REF_DSCFG_DURATION_SYNTAX_REL_URL.get()).append(EOL);
+ b.append(op);
if (prop.isAllowUnlimited()) {
- b.append(ALLOW_UNLIMITED).append(" ");
+ b.append(REF_DSCFG_ALLOW_UNLIMITED.get()).append(" ");
}
if (prop.getMaximumUnit() != null) {
- b.append("Maximum unit is \"").append(prop.getMaximumUnit().getLongName()).append("\". ");
+ final String maxUnitName = prop.getMaximumUnit().getLongName();
+ b.append(REF_DSCFG_DURATION_MAX_UNIT.get(maxUnitName)).append(".");
}
final DurationUnit baseUnit = prop.getBaseUnit();
- b.append("Lower limit is ").append(valueOf(baseUnit, prop.getLowerLimit()))
- .append(" ").append(baseUnit.getLongName()).append(". ");
+ final long lowerLimit = valueOf(baseUnit, prop.getLowerLimit());
+ final String unitName = baseUnit.getLongName();
+ b.append(REF_DSCFG_DURATION_LOWER_LIMIT.get(lowerLimit, unitName)).append(".");
if (prop.getUpperLimit() != null) {
- b.append("Upper limit is ").append(valueOf(baseUnit, prop.getUpperLimit()))
- .append(" ").append(baseUnit.getLongName()).append(". ");
+ final long upperLimit = valueOf(baseUnit, prop.getUpperLimit());
+ b.append(REF_DSCFG_DURATION_UPPER_LIMIT.get(upperLimit, unitName)).append(".");
}
- b.append("</para>").append(EOL);
+ b.append(cp).append(EOL);
return null;
}
@@ -518,79 +481,77 @@
@Override
public String visitEnum(EnumPropertyDefinition prop, Void p) {
- b.append(indent).append("<para>").append(EOL);
- b.append(indent).append(" <variablelist>").append(EOL);
+ b.append("<variablelist>").append(EOL);
final Class<?> en = prop.getEnumClass();
final Object[] constants = en.getEnumConstants();
for (Object enumConstant : constants) {
final LocalizableMessage valueSynopsis = prop.getValueSynopsis((Enum) enumConstant);
- appendVarlistentry(b, enumConstant.toString(), valueSynopsis, indent + " ");
+ appendVarListEntry(b, enumConstant.toString(), valueSynopsis);
}
- b.append(indent).append(" </variablelist>").append(EOL);
- b.append(indent).append("</para>").append(EOL);
+ b.append("</variablelist>").append(EOL);
return null;
}
@Override
public String visitInteger(IntegerPropertyDefinition prop, Void p) {
- b.append(indent).append("<para>");
- b.append("An integer value. Lower value is ").append(prop.getLowerLimit()).append(".");
+ b.append(op).append(REF_DSCFG_INT.get()).append(". ")
+ .append(REF_DSCFG_INT_LOWER_LIMIT.get(prop.getLowerLimit())).append(".");
if (prop.getUpperLimit() != null) {
- b.append(" Upper value is ").append(prop.getUpperLimit()).append(".");
+ b.append(" ").append(REF_DSCFG_INT_UPPER_LIMIT.get(prop.getUpperLimit())).append(".");
}
if (prop.isAllowUnlimited()) {
- b.append(" ").append(ALLOW_UNLIMITED);
+ b.append(" ").append(REF_DSCFG_ALLOW_UNLIMITED.get());
}
if (prop.getUnitSynopsis() != null) {
- b.append(" Unit is ").append(prop.getUnitSynopsis()).append(".");
+ b.append(" ").append(REF_DSCFG_INT_UNIT.get(prop.getUnitSynopsis())).append(".");
}
- b.append("</para>").append(EOL);
+ b.append(cp).append(EOL);
return null;
}
@Override
public String visitIPAddress(IPAddressPropertyDefinition prop, Void p) {
- b.append(indent).append("<para>An IP address</para>").append(EOL);
+ b.append(op).append(REF_DSCFG_IP_ADDRESS.get()).append(cp).append(EOL);
return null;
}
@Override
public String visitIPAddressMask(IPAddressMaskPropertyDefinition prop, Void p) {
- b.append(indent).append("<para>An IP address mask</para>").append(EOL);
+ b.append(op).append(REF_DSCFG_IP_ADDRESS_MASK.get()).append(cp).append(EOL);
return null;
}
@Override
public String visitSize(SizePropertyDefinition prop, Void p) {
- b.append(indent).append("<para>");
+ b.append(op);
if (prop.getLowerLimit() != 0) {
- b.append(" Lower value is ").append(prop.getLowerLimit()).append(".");
+ b.append(REF_DSCFG_INT_LOWER_LIMIT.get(prop.getLowerLimit())).append(".");
}
if (prop.getUpperLimit() != null) {
- b.append(" Upper value is ").append(prop.getUpperLimit()).append(" .");
+ b.append(REF_DSCFG_INT_UPPER_LIMIT.get(prop.getUpperLimit())).append(".");
}
if (prop.isAllowUnlimited()) {
- b.append(" ").append(ALLOW_UNLIMITED);
+ b.append(REF_DSCFG_ALLOW_UNLIMITED.get());
}
- b.append("</para>").append(EOL);
+ b.append(cp).append(EOL);
return null;
}
@Override
public String visitString(StringPropertyDefinition prop, Void p) {
- b.append(indent).append("<para>");
+ b.append(op);
if (prop.getPatternSynopsis() != null) {
b.append(prop.getPatternSynopsis());
} else {
- b.append("A String");
+ b.append(REF_DSCFG_STRING.get());
}
- b.append("</para>").append(EOL);
+ b.append(cp).append(EOL);
return null;
}
@Override
public String visitUnknown(PropertyDefinition prop, Void p) {
- b.append(indent).append("<para>Unknown</para>").append(EOL);
+ b.append(op).append(REF_DSCFG_UNKNOWN.get()).append(cp).append(EOL);
return null;
}
};
@@ -600,7 +561,7 @@
}
private String getLink(String target) {
- return " <xref linkend=" + target + " />";
+ return " <xref linkend=\"" + target + "\" />";
}
}
diff --git a/opendj-config/src/main/resources/com/forgerock/opendj/dsconfig/dsconfig.properties b/opendj-config/src/main/resources/com/forgerock/opendj/dsconfig/dsconfig.properties
index 385717c..8b167a3 100644
--- a/opendj-config/src/main/resources/com/forgerock/opendj/dsconfig/dsconfig.properties
+++ b/opendj-config/src/main/resources/com/forgerock/opendj/dsconfig/dsconfig.properties
@@ -20,7 +20,7 @@
# CDDL HEADER END
#
# Copyright 2006-2010 Sun Microsystems, Inc.
-# Portions Copyright 2011-2014 ForgeRock AS
+# Portions Copyright 2011-2015 ForgeRock AS.
#
# Format string definitions
#
@@ -436,3 +436,70 @@
INFO_DSCFG_BATCH_FILE_PATH_256=Path to a batch file containing \
a set of dsconfig commands to be executed
+# Strings for generated reference documentation.
+REF_DSCFG_ALLOW_UNLIMITED_1000=A value of "-1" or "unlimited" for no limit.
+REF_DSCFG_ACI_SYNTAX_REL_URL_1001=<link xlink:show="new" \
+ xlink:href="admin-guide#about-acis" \
+ xlink:role="http://docbook.org/xlink/role/olink" \
+ ><citetitle>About Access Control Instructions</citetitle></link>
+REF_DSCFG_DURATION_SYNTAX_REL_URL_1002=<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>
+REF_DSCFG_ARG_ADDITIONAL_INFO_1003=%s properties depend on the %s type, \
+ which depends on the %s option.
+REF_DSCFG_SUBTYPE_DEPENDENCIES_1004=%s properties depend on the %s type, \
+ which depends on the %s you provide.
+REF_DSCFG_SUBTYPE_TYPES_INTRO_1005=By default, OpenDJ directory server \
+ supports the following %s types:
+REF_DSCFG_CHILD_DEFAULT_1006=Default %s: %s
+REF_DSCFG_CHILD_ENABLED_BY_DEFAULT_1007=Enabled by default: %b
+REF_DSCFG_CHILD_LINK_1008=See %s for the properties of this %s type.
+REF_DSCFG_PROPS_INTRO_1009=%s of type %s have the following properties:
+REF_DSCFG_PROPS_LABEL_DEFAULT_VALUE_1010=Default Value
+REF_DSCFG_PROPS_LABEL_ALLOWED_VALUES_1011=Allowed Values
+REF_DSCFG_PROPS_LABEL_MULTI_VALUED_1012=Multi-valued
+REF_DSCFG_PROPS_LABEL_REQUIRED_1013=Required
+REF_DSCFG_PROPS_LABEL_ADMIN_ACTION_REQUIRED_1014=Admin Action Required
+REF_DSCFG_PROPS_LABEL_ADVANCED_PROPERTY_1015=Advanced Property
+REF_DSCFG_PROPS_LABEL_READ_ONLY_1016=Read-only
+REF_DSCFG_ADMIN_ACTION_COMPONENT_RESTART_1017=The %s must be disabled \
+ and re-enabled for changes to this setting to take effect
+REF_DSCFG_ADMIN_ACTION_SERVER_RESTART_1018=Restart the server
+REF_DSCFG_ADMIN_ACTION_NONE_1019=None
+REF_DSCFG_PROP_YES_1020=Yes
+REF_DSCFG_PROP_YES_ADVANCED_1021=Yes (Use --advanced in interactive mode.)
+REF_DSCFG_PROP_NO_1022=No
+REF_DSCFG_DEFAULT_BEHAVIOR_NONE_1023=None
+REF_DSCFG_DEFAULT_BEHAVIOR_1024=%s
+REF_DSCFG_AGGREGATION_1025=The DN of any %s
+REF_DSCFG_ANY_ATTRIBUTE_1026=The name of an attribute type defined in the server schema
+REF_DSCFG_JAVA_PLUGIN_1027=A Java class that implements or extends the class(es):
+REF_DSCFG_VALID_DN_1028=A valid DN
+REF_DSCFG_DURATION_MAX_UNIT_1029=Maximum unit is "%s"
+REF_DSCFG_DURATION_LOWER_LIMIT_1030=Lower limit is %d %s
+REF_DSCFG_DURATION_UPPER_LIMIT_1031=Upper limit is %d %s
+REF_DSCFG_INT_1032=An integer value
+REF_DSCFG_INT_LOWER_LIMIT_1033=Lower value is %d
+REF_DSCFG_INT_UPPER_LIMIT_1034=Upper value is %d
+REF_DSCFG_INT_UNIT_1035=Unit is %s
+REF_DSCFG_IP_ADDRESS_1036=An IP address
+REF_DSCFG_IP_ADDRESS_MASK_1037=An IP address mask
+REF_DSCFG_STRING_1038=A String
+REF_DSCFG_UNKNOWN_1039=Unknown
--
Gitblit v1.10.0