From 1c8d96d71d1bae9188f2aa3d1237082afd47c649 Mon Sep 17 00:00:00 2001
From: Jean-Noel Rouvignac <jean-noel.rouvignac@forgerock.com>
Date: Fri, 06 Feb 2015 09:13:16 +0000
Subject: [PATCH] OPENDJ-1242 (CR-5982) Enable dsconfig to generate doc for properties changed through subcommand options

---
 opendj-config/src/main/java/org/forgerock/opendj/config/dsconfig/DSConfig.java |  201 +++++++++++++++++++++++++++++++++++++-------------
 1 files changed, 148 insertions(+), 53 deletions(-)

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 4d04547..b9594ed 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
@@ -47,6 +47,7 @@
 import java.io.PrintStream;
 import java.net.URL;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Date;
@@ -126,51 +127,158 @@
  */
 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
     private final class DSConfigSubCommandUsageHandler implements SubCommandUsageHandler {
 
-        private static final String ALLOW_UNLIMITED = "A value of \"-1\" or \"unlimited\" for no limit.";
-        private static final String ACI_SYNTAX_REL_URL =
-            "<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>";
-        private static final String DURATION_SYNTAX_REL_URL =
-            "  <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>";
+        /** {@inheritDoc} */
+        @Override
+        public void appendArgumentAdditionalInfo(StringBuilder sb, SubCommand sc, Argument a, String nameOption) {
+            final AbstractManagedObjectDefinition<?, ?> defn = getManagedObjectDefinition(sc);
+            if (defn == null) {
+                return;
+            }
+            final String longID = a.getLongIdentifier();
+            if ("set".equals(longID)
+                    || "reset".equals(longID)
+                    || "add".equals(longID)
+                    || "remove".equals(longID)) {
+                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(nameOption).append(" option.").append(EOL);
+                sb.append("         </para>").append(EOL);
+            } else {
+                listSubtypes(sb, a.getValuePlaceholder(), defn);
+            }
+            return;
+        }
+
+        private void listSubtypes(StringBuilder sb, LocalizableMessage placeholder,
+                AbstractManagedObjectDefinition<?, ?> defn) {
+            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(defn.getUserFriendlyName()).append(" types:").append(EOL);
+            sb.append("           </para>").append(EOL);
+
+            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);
+                final String string = "dsconfig-set-log-publisher-prop-file-based-access";
+                sb.append("                 See <xref linkend=\"").append(string)
+                    .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);
+            }
+            sb.append("         </variablelist>").append(EOL);
+        }
+
+        private boolean propertyExists(AbstractManagedObjectDefinition<?, ?> defn, String name) {
+            try {
+                return defn.getPropertyDefinition(name) != null;
+            } catch (IllegalArgumentException e) {
+                return false;
+            }
+        }
 
         /** {@inheritDoc} */
         @Override
-        public void appendUsage(StringBuilder sb, SubCommand sc, String argLongID) {
-            final SubCommandHandler sch = handlers.get(sc);
-            if (sch instanceof HelpSubCommandHandler) {
+        public void appendProperties(StringBuilder sb, SubCommand sc) {
+            final AbstractManagedObjectDefinition<?, ?> defn = getManagedObjectDefinition(sc);
+            if (defn == null) {
                 return;
             }
-            final RelationDefinition<?, ?> rd = getRelationDefinition(sch);
-            final AbstractManagedObjectDefinition<?, ?> defn = rd.getChildDefinition();
-            final List<PropertyDefinition<?>> props =
-                    new ArrayList<PropertyDefinition<?>>(defn.getAllPropertyDefinitions());
-            Collections.sort(props);
 
-            final String propPrefix = getScriptName() + "-" + sc.getName() + "-" + argLongID + "-";
-            sb.append(EOL);
-            toSimpleList(props, propPrefix, sb);
-            sb.append(EOL);
-            toVariableList(props, defn, propPrefix, sb);
+            for (AbstractManagedObjectDefinition<?, ?> childDefn : getLeafChildren(defn)) {
+                final List<PropertyDefinition<?>> props =
+                    new ArrayList<PropertyDefinition<?>>(childDefn.getAllPropertyDefinitions());
+                Collections.sort(props);
+
+                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);
+            }
+        }
+
+        private AbstractManagedObjectDefinition<?, ?> getManagedObjectDefinition(SubCommand sc) {
+            final SubCommandHandler sch = handlers.get(sc);
+            if (sch instanceof HelpSubCommandHandler) {
+                return null;
+            }
+            final RelationDefinition<?, ?> rd = getRelationDefinition(sch);
+            return rd.getChildDefinition();
+        }
+
+        private List<AbstractManagedObjectDefinition<?, ?>> getLeafChildren(
+                AbstractManagedObjectDefinition<?, ?> defn) {
+            final ArrayList<AbstractManagedObjectDefinition<?, ?>> results =
+                    new ArrayList<AbstractManagedObjectDefinition<?, ?>>();
+            addLeafChildren(results, defn);
+            Collections.sort(results, new Comparator<AbstractManagedObjectDefinition<?, ?>>() {
+                @Override
+                public int compare(AbstractManagedObjectDefinition<?, ?> o1, AbstractManagedObjectDefinition<?, ?> o2) {
+                    return o1.getName().compareTo(o2.getName());
+                }
+            });
+            return results;
+        }
+
+        private void addLeafChildren(final Collection<AbstractManagedObjectDefinition<?, ?>> results,
+                final AbstractManagedObjectDefinition<?, ?> defn) {
+            for (AbstractManagedObjectDefinition<?, ?> child : defn.getChildren()) {
+                if (child.getChildren().isEmpty()) {
+                    results.add(child);
+                } else {
+                    addLeafChildren(results, child);
+                }
+            }
         }
 
         private RelationDefinition<?, ?> getRelationDefinition(final SubCommandHandler sch) {
@@ -188,22 +296,13 @@
             return null;
         }
 
-        private void toSimpleList(List<PropertyDefinition<?>> props, String propPrefix, StringBuilder b) {
-            b.append("    <simplelist>").append(EOL);
-            for (PropertyDefinition<?> prop : props) {
-                b.append("      <member><xref linkend=\"")
-                    .append(propPrefix).append(prop.getName()).append("\" /></member>").append(EOL);
-            }
-            b.append("    </simplelist>").append(EOL);
-        }
-
         private void toVariableList(List<PropertyDefinition<?>> props, AbstractManagedObjectDefinition<?, ?> defn,
                 String propPrefix, StringBuilder b) {
             final String indent = "            ";
             b.append("    <variablelist>").append(EOL);
             for (PropertyDefinition<?> prop : props) {
                 b.append("      <varlistentry xml:id=\"")
-                    .append(propPrefix).append(prop.getName()).append("\">").append(EOL);
+                    .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);
@@ -235,24 +334,20 @@
         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);
             if (prop instanceof EnumPropertyDefinition) {
-                b.append(indent).append("  <listitem>").append(EOL);
                 b.append(indent).append("    <variablelist>").append(EOL);
                 appendSyntax(b, prop, indent + "      ");
                 b.append(indent).append("    </variablelist>").append(EOL);
-                b.append(indent).append("  </listitem>").append(EOL);
             } else if (prop instanceof BooleanPropertyDefinition) {
-                b.append(indent).append("  <listitem>").append(EOL);
                 b.append(indent).append("    <para>true</para>").append(EOL);
                 b.append(indent).append("    <para>false</para>").append(EOL);
-                b.append(indent).append("  </listitem>").append(EOL);
             } else {
-                b.append(indent).append("  <listitem>").append(EOL);
                 b.append(indent).append("    <para>");
                 appendSyntax(b, prop, indent);
                 b.append("</para>").append(EOL);
-                b.append(indent).append("  </listitem>").append(EOL);
             }
+            b.append(indent).append("  </listitem>").append(EOL);
             b.append(indent).append("</varlistentry>").append(EOL);
         }
 
@@ -303,7 +398,7 @@
                 final StringBuilder res = new StringBuilder();
                 for (Iterator<String> it = behavior.getDefaultValues().iterator(); it.hasNext();) {
                     String str = it.next();
-                    res.append(str).append(it.hasNext() ? "\n" : "");
+                    res.append(str).append(it.hasNext() ? "\n" : ""); // TODO JNR refactor
                 }
                 return res.toString();
             } else if (defaultBehavior instanceof AliasDefaultBehaviorProvider) {

--
Gitblit v1.10.0