From e3323d107f6d3b2585615b01f19b44421405cba5 Mon Sep 17 00:00:00 2001
From: Mark Craig <mark.craig@forgerock.com>
Date: Mon, 17 Sep 2012 16:03:51 +0000
Subject: [PATCH] CR-658 Fix for OPENDJ-566: Add log reference to OpenDJ docs

---
 opends/src/build-tools/org/opends/build/tools/GenerateMessageFile.java |  315 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 300 insertions(+), 15 deletions(-)

diff --git a/opends/src/build-tools/org/opends/build/tools/GenerateMessageFile.java b/opends/src/build-tools/org/opends/build/tools/GenerateMessageFile.java
index a596a9e..992ce1e 100644
--- a/opends/src/build-tools/org/opends/build/tools/GenerateMessageFile.java
+++ b/opends/src/build-tools/org/opends/build/tools/GenerateMessageFile.java
@@ -46,9 +46,14 @@
 import java.io.PrintWriter;
 import java.io.DataOutputStream;
 import java.io.IOException;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
 import java.util.Properties;
 import java.util.List;
 import java.util.ArrayList;
+import java.util.TreeSet;
 import java.util.UnknownFormatConversionException;
 import java.util.Calendar;
 import java.util.Arrays;
@@ -70,6 +75,7 @@
   private File source;
   private File dest;
   private boolean overwrite;
+  private boolean writeLogRef;
 
   static private final String MESSAGES_FILE_STUB =
           "resource/Messages.java.stub";
@@ -517,6 +523,239 @@
   }
 
   /**
+   * Indicates when true that an XML log message reference should be generated
+   * instead of a Java messages file.
+   *
+   * @param xml
+   *          true means write an XML log message reference
+   */
+  public void setWriteLogRef(boolean xml) {
+    this.writeLogRef = xml;
+  }
+
+  /**
+   * Represents a log reference entry for an individual message.
+   */
+  private class MessageRefEntry implements Comparable<MessageRefEntry>
+  {
+
+    private Severity severity;
+    private Integer id;
+    private String formatString;
+
+    /**
+     * Build log reference entry for an log message.
+     *
+     * @param category
+     * @param severity
+     * @param ordinal
+     * @param formatString
+     */
+    public MessageRefEntry(final Category category, final Severity severity,
+        final Integer ordinal, final String formatString)
+    {
+      this.severity = severity;
+      this.formatString = formatString;
+      id = calculateId(category, severity, ordinal);
+    }
+
+    private Integer calculateId(final Category category,
+        final Severity severity, final Integer ordinal)
+    {
+      return new Integer(ordinal | category.getMask() | severity.getMask());
+    }
+
+    /**
+     * Return a DocBook XML &lt;varlistentry&gt; of this log reference entry.
+     * This implementation copies the message string verbatim, and does not
+     * interpret format specifiers.
+     *
+     * @return DocBook XML &lt;varlistentry&gt;.
+     */
+    public String toString()
+    {
+      return
+          "  <varlistentry xml:id=\"log-ref-" + id.intValue() + "\">" + EOL
+          + "   <term>ID: " + id.intValue() + "</term>" + EOL
+          + "   <listitem>" + EOL
+          + "    <para>Severity: " + severity.name() + "</para>" + EOL
+          + "    <para>Message: " + formatString + "</para>" + EOL
+          + "   </listitem>" + EOL + "  </varlistentry>" + EOL;
+    }
+
+    /**
+     * Calls {@link #toString()}.
+     */
+    public String toXML()
+    {
+      return toString();
+    }
+
+    /**
+     * The unique message identifier is calculated using the category, severity,
+     * and message ordinal.
+     *
+     * @return unique message identifier
+     */
+    public Integer getId()
+    {
+      return this.id;
+    }
+
+    /**
+     * Compare message entries by unique identifier.
+     *
+     * @return See {@link java.lang.Comparable#compareTo(Object)}.
+     */
+    public int compareTo(MessageRefEntry mre)
+    {
+      return this.id.compareTo(mre.getId());
+    }
+  }
+
+  /**
+   * One-line descriptions for log reference categories
+   */
+  static private HashMap<String,String> CATEGORY_DESCRIPTIONS;
+  static {
+    CATEGORY_DESCRIPTIONS = new HashMap<String,String>();
+    CATEGORY_DESCRIPTIONS.put("ACCESS_CONTROL", "Access Control.");
+    CATEGORY_DESCRIPTIONS.put("ADMIN", "the administration framework.");
+    CATEGORY_DESCRIPTIONS.put("ADMIN_TOOL", "the tool like the offline"
+            + " installer and uninstaller.");
+    CATEGORY_DESCRIPTIONS.put("BACKEND", "generic backends.");
+    CATEGORY_DESCRIPTIONS.put("CONFIG", "configuration handling.");
+    CATEGORY_DESCRIPTIONS.put("CORE", "the core server.");
+    CATEGORY_DESCRIPTIONS.put("DSCONFIG", "the dsconfig administration tool.");
+    CATEGORY_DESCRIPTIONS.put("EXTENSIONS", "server extensions for example,"
+            + " extended operations, SASL mechanisms, password storage"
+            + " schemes, password validators, and so on).");
+    CATEGORY_DESCRIPTIONS.put("JEB", "the JE backend.");
+    CATEGORY_DESCRIPTIONS.put("LOG", "the server loggers.");
+    CATEGORY_DESCRIPTIONS.put("PLUGIN", "plugin processing.");
+    CATEGORY_DESCRIPTIONS.put("PROTOCOL", "connection and protocol handling"
+            +  " (for example, ASN.1 and LDAP).");
+    CATEGORY_DESCRIPTIONS.put("QUICKSETUP", "quicksetup tools.");
+    CATEGORY_DESCRIPTIONS.put("RUNTIME_INFORMATION", "the runtime"
+            + " information.");
+    CATEGORY_DESCRIPTIONS.put("SCHEMA", "the server schema elements.");
+    CATEGORY_DESCRIPTIONS.put("SYNC", "the Synchronization.");
+    CATEGORY_DESCRIPTIONS.put("TASK", "tasks.");
+    CATEGORY_DESCRIPTIONS.put("THIRD_PARTY", "third-party (including"
+            + " user-defined) modules.");
+    CATEGORY_DESCRIPTIONS.put("TOOLS", "tools.");
+    CATEGORY_DESCRIPTIONS.put("USER_DEFINED", "user-defined modules.");
+    CATEGORY_DESCRIPTIONS.put("UTIL", "the general server utilities.");
+    CATEGORY_DESCRIPTIONS.put("VERSION", "version information.");
+  }
+
+  /**
+   * Represents a log reference list of messages for a category.
+   */
+  private class MessageRefCategory
+  {
+    private Category category;
+    private TreeSet<MessageRefEntry> messages;
+    private String description;
+
+    MessageRefCategory(final Category category,
+        final TreeSet<MessageRefEntry> messages)
+    {
+      this.category = category;
+      this.messages = messages;
+      this.description = getDescription(category);
+    }
+
+    private String getDescription(final Category category)
+    {
+      return "<para>This category concerns messages associated with "
+          + CATEGORY_DESCRIPTIONS.get(category.name()) + "</para>" + EOL;
+    }
+
+    /**
+     * Return a DocBook XML &lt;variablelist&gt; of this log reference category.
+     *
+     * @return DocBook XML &lt;variablelist&gt;
+     */
+    public String toString()
+    {
+      StringBuilder entries = new StringBuilder();
+      for (MessageRefEntry entry : messages)
+      {
+        entries.append(entry.toXML());
+      }
+
+      return getVariablelistHead() + entries.toString() + getVariablelistTail();
+    }
+
+    /**
+     * Calls {@link #toString()}.
+     */
+    public String toXML()
+    {
+      return toString();
+    }
+
+    private String getXMLPreamble()
+    {
+      DateFormat df = new SimpleDateFormat("yyyy");
+      Date now = new Date();
+      String year = df.format(now);
+
+      return new StringBuilder()
+        .append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>").append(EOL)
+        .append("<!--").append(EOL)
+        .append("  ! CCPL HEADER START").append(EOL)
+        .append("  !").append(EOL)
+        .append("  ! This work is licensed under the Creative Commons").append(EOL)
+        .append("  ! Attribution-NonCommercial-NoDerivs 3.0 Unported License.").append(EOL)
+        .append("  ! To view a copy of this license, visit").append(EOL)
+        .append("  ! http://creativecommons.org/licenses/by-nc-nd/3.0/").append(EOL)
+        .append("  ! or send a letter to Creative Commons, 444 Castro Street,").append(EOL)
+        .append("  ! Suite 900, Mountain View, California, 94041, USA.").append(EOL)
+        .append("  !").append(EOL)
+        .append("  ! See the License for the specific language governing permissions").append(EOL)
+        .append("  ! and limitations under the License.").append(EOL)
+        .append("  !").append(EOL)
+        .append("  ! If applicable, add the following below this CCPL HEADER, with the fields").append(EOL)
+        .append("  ! enclosed by brackets \"[]\" replaced with your own identifying information:").append(EOL)
+        .append("  !      Portions Copyright [yyyy] [name of copyright owner]").append(EOL)
+        .append("  !").append(EOL)
+        .append("  ! CCPL HEADER END").append(EOL)
+        .append("  !").append(EOL)
+        .append("  !      Copyright " + year + " ForgeRock AS").append(EOL)
+        .append("  !").append(EOL)
+        .append("-->").append(EOL)
+        .toString();
+    }
+
+    private String getBaseElementAttrs()
+    {
+      return "xmlns='http://docbook.org/ns/docbook'"
+          + " version='5.0' xml:lang='en'"
+          + " 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'";
+    }
+
+    private String getVariablelistHead()
+    {
+      return getXMLPreamble() + " <variablelist xml:id=\"log-ref-"
+          + this.category.name() + "\" " + getBaseElementAttrs() + ">" + EOL
+          + "  <title>Log Message Category: " + category.name() + "</title>"
+          + EOL + "  " + this.description;
+    }
+
+    private String getVariablelistTail()
+    {
+      return " </variablelist>" + EOL;
+    }
+
+  }
+
+  /**
    * {@inheritDoc}
    */
   @Override
@@ -555,8 +794,13 @@
       // filename without ".properties"
       filename = filename.substring(0, filename.length()-11);
       // change to src-generated directory keeping package name
-      pathname = pathname.replace(getProject().getProperty("msg.dir"),
-                                  getProject().getProperty("msg.javagen.dir"));
+      if (writeLogRef) {
+        pathname = pathname.replace(getProject().getProperty("msg.dir"),
+                                    getProject().getProperty("msg.logref.dir"));
+      } else {
+        pathname = pathname.replace(getProject().getProperty("msg.dir"),
+                                    getProject().getProperty("msg.javagen.dir"));
+      }
 
 
       // append characters from filename to pathname starting with an uppercase
@@ -575,7 +819,11 @@
           sb.append(c);
         }
       }
-      sb.append("Messages.java");
+      if (writeLogRef) {
+        sb.append("Messages.xml");
+      } else {
+        sb.append("Messages.java");
+      }
 
       setDestJava(new File(sb.toString()));
     }
@@ -612,6 +860,8 @@
       String stubLine;
       Properties properties = new Properties();
       properties.load(new FileInputStream(source));
+      TreeSet<MessageRefEntry> messageRefEntries =
+          new TreeSet<MessageRefEntry>();
       while (null != (stubLine = stubReader.readLine())) {
         if (stubLine.contains("${MESSAGES}")) {
           Integer globalOrdinal = null;
@@ -722,17 +972,33 @@
               }
             }
 
-            message.setConstructorArguments(
-                    "BASE",
-                    quote(key.toString()),
-                    globalMask != null ? globalMask.toString() : c.name(),
-                    s.name(),
-                    globalOrdinal != null ?
-                            globalOrdinal.toString() :
-                            key.getOrdinal().toString()
-            );
-            destWriter.println(message.toString());
-            destWriter.println();
+            if (writeLogRef) {
+              // Document only FATAL_ERROR and SEVERE_ERROR messages.
+              if (s.name().equalsIgnoreCase("FATAL_ERROR")
+                  || s.name().equalsIgnoreCase("SEVERE_ERROR")) {
+                MessageRefEntry entry =
+                        new MessageRefEntry(
+                                c,
+                                s,
+                                globalOrdinal != null ?
+                                        globalOrdinal :
+                                        key.getOrdinal(),
+                                formatString.replaceAll("<", "&lt;"));
+                messageRefEntries.add(entry);
+                }
+            } else {
+              message.setConstructorArguments(
+                "BASE",
+                quote(key.toString()),
+                globalMask != null ? globalMask.toString() : c.name(),
+                s.name(),
+                globalOrdinal != null ?
+                        globalOrdinal.toString() :
+                        key.getOrdinal().toString()
+              );
+              destWriter.println(message.toString());
+              destWriter.println();
+            }
 
             // Keep track of when we use the generic descriptor
             // so that we can report it later
@@ -741,11 +1007,21 @@
             }
           }
 
+          if (writeLogRef) {
+            if (messageRefEntries.isEmpty()) {
+              destWriter.println("<!-- No message for this category -->");
+            } else {
+              MessageRefCategory mrc =
+                      new MessageRefCategory(globalCategory, messageRefEntries);
+              destWriter.println(mrc.toXML());
+            }
+          }
+
           log("  Message Generated:" + keyMap.size(), Project.MSG_VERBOSE);
           log("  MessageDescriptor.ArgN:" + usesOfGenericDescriptor,
                   Project.MSG_VERBOSE);
 
-        } else {
+        } else if (!writeLogRef) {
           stubLine = stubLine.replace("${PACKAGE}", getPackage());
           stubLine = stubLine.replace("${CLASS_NAME}",
                   dest.getName().substring(0, dest.getName().length() -
@@ -820,6 +1096,8 @@
   }
 
   private String getPackage() {
+    if (writeLogRef) { return "dummy.package.name"; }
+
     String destPath = unixifyPath(dest.getAbsolutePath());
     String msgJavaGenDir = unixifyPath(
                                    getProject().getProperty("msg.javagen.dir"));
@@ -951,6 +1229,13 @@
     File source = new File("src/messages/messages/tools.properties");
     File dest = new File("/tmp/org/opends/XXX.java");
     GenerateMessageFile gmf = new GenerateMessageFile();
+
+    if (args.length > 0 && args[0].equalsIgnoreCase("generateMessageReference"))
+    {
+      dest = new File("/tmp/tools-ref.xml");
+      gmf.setWriteLogRef(true);
+    }
+
     gmf.setOverwrite(true);
     gmf.setDestJava(dest);
     gmf.setSourceProps(source);

--
Gitblit v1.10.0