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

Mark Craig
28.15.2015 1b975d40610cec2085f4be6cd6caf82c8b76770b
CR-7072 OPENDJ-2060 Build config reference again

This patch adds a Maven plugin to build the configuration reference
alongside the other server docs.

This patch also makes some minor changes to comment out
links in the configuration reference that might break
and that are not strictly necessary.

Finally this patch refactors the OpenDJ doc plugin
where some methods are used across Mojos.
2 files added
6 files renamed
4 files modified
510 ■■■■ changed files
opendj-doc-maven-plugin/src/main/java/org/forgerock/opendj/maven/doc/GenerateConfigurationReferenceMojo.java 164 ●●●●● patch | view | raw | blame | history
opendj-doc-maven-plugin/src/main/java/org/forgerock/opendj/maven/doc/GenerateRefEntriesMojo.java 126 ●●●● patch | view | raw | blame | history
opendj-doc-maven-plugin/src/main/java/org/forgerock/opendj/maven/doc/Utils.java 177 ●●●●● patch | view | raw | blame | history
opendj-doc-maven-plugin/src/main/resources/config-ref/duration-syntax.html patch | view | raw | blame | history
opendj-doc-maven-plugin/src/main/resources/config-ref/opendj-config.css patch | view | raw | blame | history
opendj-doc-maven-plugin/src/main/resources/config-ref/opendj_logo_sm.png patch | view | raw | blame | history
opendj-doc-maven-plugin/src/main/resources/config-ref/pageaction.gif patch | view | raw | blame | history
opendj-doc-maven-plugin/src/main/resources/config-ref/tab_deselected.jpg patch | view | raw | blame | history
opendj-doc-maven-plugin/src/main/resources/config-ref/tab_selected.gif patch | view | raw | blame | history
opendj-server-legacy/build.xml 5 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/pom.xml 20 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/admin/doc/ConfigGuideGeneration.java 18 ●●●● patch | view | raw | blame | history
opendj-doc-maven-plugin/src/main/java/org/forgerock/opendj/maven/doc/GenerateConfigurationReferenceMojo.java
New file
@@ -0,0 +1,164 @@
/*
 * 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 org.forgerock.opendj.maven.doc;
import static org.forgerock.opendj.maven.doc.Utils.*;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedList;
import java.util.List;
/**
 * Generates the configuration reference, a set of HTML documents describing the server configuration.
 */
@Mojo(name = "generate-config-ref", defaultPhase = LifecyclePhase.PRE_SITE)
public class GenerateConfigurationReferenceMojo extends AbstractMojo {
    /**
     * The Maven Project.
     */
    @Parameter(property = "project", readonly = true, required = true)
    private MavenProject project;
    /**
     * The path to the directory where the configuration reference should be written.
     * This path must be under {@code ${project.build.directory} }.
     */
    @Parameter(defaultValue = "${project.build.directory}/site/configref")
    private String outputDirectory;
    /**
     * Generates the configuration reference under the output directory.
     * @throws MojoExecutionException   Generation failed
     * @throws MojoFailureException     Not used
     */
    @Override
    public void execute() throws MojoExecutionException, MojoFailureException {
        createOutputDirectory();
        generateConfigRef();
        try {
            copyResources();
        } catch (IOException e) {
            throw new MojoExecutionException("Failed to copy resource files.", e);
        }
    }
    /**
     * Creates the output directory where the configuration reference is written.
     * @throws MojoExecutionException   The output directory is not under {@code ${project.build.directory} }
     *                                  or could not be created.
     */
    private void createOutputDirectory() throws MojoExecutionException {
        String projectBuildDir = project.getBuild().getDirectory();
        if (!outputDirectory.contains(projectBuildDir)) {
            String errorMsg = String.format(
                    "The outputDirectory (%s) must be under the ${project.build.directory} (%s).",
                    outputDirectory,
                    projectBuildDir);
            getLog().error(errorMsg);
            throw new MojoExecutionException(errorMsg);
        }
        try {
            createDirectory(outputDirectory);
        } catch (IOException e) {
            getLog().error(e.getMessage());
            throw new MojoExecutionException(e.getMessage(), e);
        }
    }
    /**
     * Runs the configuration reference generator class.
     * @throws MojoExecutionException   Failed to run the generator
     */
    private void generateConfigRef() throws MojoExecutionException {
        String generatorClass = "org.opends.server.admin.doc.ConfigGuideGeneration";
        List<String> commands = new LinkedList<>();
        try {
            commands.add(getJavaCommand());
            commands.add("-classpath");
            commands.add(getClassPath(getRuntimeClassLoader(project, getLog())));
            commands.add("-DGenerationDir=" + outputDirectory);
            commands.add(generatorClass);
        } catch (Exception e) {
            throw new MojoExecutionException("Failed to set the classpath.", e);
        }
        try {
            ProcessBuilder builder = new ProcessBuilder(commands);
            Process process = builder.start();
            process.waitFor();
            final int result = process.exitValue();
            if (result != 0) {
                final StringBuilder message = new StringBuilder();
                message.append("Failed to generate the config ref. Exit code: ").append(result).append(EOL)
                        .append("To debug the problem, run the following command and connect your IDE:").append(EOL);
                commands.add(1, "-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=8000");
                for (String arg: commands) {
                    message.append(arg).append(' ');
                }
                message.append(EOL);
                throw new MojoExecutionException(message.toString());
            }
        }  catch (InterruptedException e) {
            throw new MojoExecutionException(generatorClass + " interrupted", e);
        } catch (IOException e) {
            throw new MojoExecutionException(generatorClass + " not found", e);
        }
    }
    /** List of static file resources needed by the configuration reference. */
    private static String[] resourceFiles = {
        "duration-syntax.html",
        "opendj-config.css",
        "opendj_logo_sm.png",
        "pageaction.gif",
        "tab_deselected.jpg",
        "tab_selected.gif"
    };
    /**
     * Copies static files needed by the configuration reference.
     * @throws IOException  Failed to read a resource or to write a file
     */
    private void copyResources() throws IOException {
        for (String file : resourceFiles) {
            InputStream original = this.getClass().getResourceAsStream("/config-ref/" + file);
            File copy = new File(outputDirectory, file);
            copyInputStreamToFile(original, copy);
        }
    }
}
opendj-doc-maven-plugin/src/main/java/org/forgerock/opendj/maven/doc/GenerateRefEntriesMojo.java
@@ -25,7 +25,9 @@
 */
package org.forgerock.opendj.maven.doc;
import org.apache.maven.artifact.DependencyResolutionRequiredException;
import static org.forgerock.opendj.maven.doc.Utils.*;
import static org.forgerock.util.Utils.*;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
@@ -34,28 +36,20 @@
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.project.MavenProject;
import org.forgerock.util.Utils;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -96,7 +90,12 @@
        // A Maven plugin classpath does not include project files.
        // Prepare a ClassLoader capable of loading the command-line tools.
        final URLClassLoader toolsClassLoader = getBootToolsClassLoader();
        final URLClassLoader toolsClassLoader;
        try {
            toolsClassLoader = getRuntimeClassLoader(project, getLog());
        } catch (Exception e) {
            throw new MojoExecutionException("Failed to get class loader.", e);
        }
        for (CommandLineTool tool : tools) {
            if (tool.isEnabled()) {
                generateManPageForTool(toolsClassLoader, tool);
@@ -105,31 +104,6 @@
    }
    /**
     * Returns a ClassLoader capable of loading the command-line tools.
     * @return A ClassLoader capable of loading the command-line tools.
     * @throws MojoFailureException     Failed to build classpath.
     */
    private URLClassLoader getBootToolsClassLoader() throws MojoFailureException {
        try {
            List<String> runtimeClasspathElements = project.getRuntimeClasspathElements();
            Set<URL> runtimeUrls = new LinkedHashSet<>();
            for (String element : runtimeClasspathElements) {
                runtimeUrls.add(new File(element).toURI().toURL());
            }
            final URLClassLoader toolsClassLoader = new URLClassLoader(
                    runtimeUrls.toArray(new URL[runtimeClasspathElements.size()]),
                    Thread.currentThread().getContextClassLoader());
            debugClassPathElements(toolsClassLoader);
            return toolsClassLoader;
        } catch (DependencyResolutionRequiredException e) {
            throw new MojoFailureException("Failed to access the runtime classpath.", e);
        } catch (MalformedURLException e) {
            throw new MojoFailureException("Failed to add element to classpath.", e);
        }
    }
    /**
     * Generate a RefEntry file to the output directory for a tool.
     * The files name corresponds to the tool name: {@code man-&lt;name>.xml}.
     * @param toolsClassLoader          The ClassLoader to run the tool.
@@ -147,7 +121,11 @@
        commands.add(getJavaCommand());
        commands.addAll(getJavaArgs(toolScript, toolSects));
        commands.add("-classpath");
        try {
        commands.add(getClassPath(toolsClassLoader));
        } catch (URISyntaxException e) {
            throw new MojoExecutionException("Failed to set the classpath.", e);
        }
        commands.add(toolClass);
        commands.add(getUsageArgument(toolScript));
@@ -161,8 +139,8 @@
            final int result = process.exitValue();
            if (result != 0) {
                final StringBuilder message = new StringBuilder();
                message.append("Failed to write page. Tool exit code: ").append(result).append(EOL);
                message.append("To debug the problem, run the following command and connect your IDE:").append(EOL);
                message.append("Failed to write page. Tool exit code: ").append(result).append(EOL)
                        .append("To debug the problem, run the following command and connect your IDE:").append(EOL);
                commands.add(1, "-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=8000");
                for (String arg: commands) {
                    // Surround with quotes to handle trailing sections.
@@ -196,14 +174,6 @@
    }
    /**
     * Returns the path to the current Java executable.
     * @return The path to the current Java executable.
     */
    private String getJavaCommand() {
        return System.getProperty("java.home") + File.separator + "bin" + File.separator + "java";
    }
    /**
     * Returns the Java args for running a tool.
     * @param scriptName        The name of the tool.
     * @param trailingSections  The man page sections to Xinclude.
@@ -219,47 +189,6 @@
    }
    /**
     * Returns the classpath for the class loader.
     * @param classLoader   Contains the URLs of the class path to return.
     * @return The classpath for the class loader.
     */
    private String getClassPath(final URLClassLoader classLoader) {
        final StringBuilder stringBuilder = new StringBuilder();
        final URL[] urls = classLoader.getURLs();
        for (int i = 0; i < urls.length; i++) {
            if (i > 0) {
                stringBuilder.append(File.pathSeparator);
            }
            try {
                stringBuilder.append(new File(urls[i].toURI()).getPath());
            } catch (URISyntaxException e) {
                getLog().info("Failed to add classpath element", e);
            }
        }
        return stringBuilder.toString();
    }
    /**
     * Logs what is on the classpath for debugging.
     * @param classLoader   The ClassLoader with the classpath.
     */
    private void debugClassPathElements(ClassLoader classLoader) {
        if (null == classLoader) {
            return;
        }
        getLog().debug("--------------------");
        getLog().debug(classLoader.toString());
        if (classLoader instanceof URLClassLoader) {
            final URLClassLoader ucl = (URLClassLoader) classLoader;
            int i = 0;
            for (URL url : ucl.getURLs()) {
                getLog().debug("url[" + (i++) + "]=" + url);
            }
        }
        debugClassPathElements(classLoader.getParent());
    }
    /**
     * Translates relative paths to XML files into XInclude elements.
     *
     * @param paths Paths to XInclude'd files, relative to the RefEntry.
@@ -306,7 +235,7 @@
                writer.write(EOL);
            }
        } finally {
            Utils.closeSilently(writer);
            closeSilently(writer);
        }
    }
@@ -347,7 +276,7 @@
                throw new IOException("Failed to delete " +  pageCopy.getName());
            }
        } finally {
            Utils.closeSilently(reader);
            closeSilently(reader);
        }
    }
@@ -361,25 +290,4 @@
        InputStream is = new ByteArrayInputStream(input.getBytes(Charset.forName("UTF-8")));
        writeToFile(is, output);
    }
    /**
     * Copies the content of the original file to the copy.
     * @param original      The original file.
     * @param copy          The copy.
     * @throws IOException  Failed to make the copy.
     */
    private void copyFile(File original, File copy) throws IOException {
        if (!copy.exists() && !copy.createNewFile()) {
            throw new IOException("Failed to create " + copy);
        }
        FileChannel in  = null;
        FileChannel out = null;
        try {
            in  = new FileInputStream(original).getChannel();
            out = new FileOutputStream(copy).getChannel();
            out.transferFrom(in, 0, in.size());
        } finally {
            Utils.closeSilently(in, out);
        }
    }
}
opendj-doc-maven-plugin/src/main/java/org/forgerock/opendj/maven/doc/Utils.java
New file
@@ -0,0 +1,177 @@
/*
 * 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 org.forgerock.opendj.maven.doc;
import static org.forgerock.util.Utils.*;
import org.apache.maven.artifact.DependencyResolutionRequiredException;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.project.MavenProject;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
/**
 * Provides utility methods for generating documentation.
 */
public final class Utils {
    /** Line separator. */
    static final String EOL = System.getProperty("line.separator");
    /**
     * Creates a directory unless it already exists.
     * @param directory     The directory to create.
     * @throws IOException  Failed to create directory.
     */
    static void createDirectory(final String directory) throws IOException {
        File dir = new File(directory);
        if (!dir.exists()) {
            if (!dir.mkdirs()) {
                throw new IOException("Failed to create directory: " + directory);
            }
        }
    }
    /**
     * Returns the path to the current Java executable.
     * @return The path to the current Java executable.
     */
    static String getJavaCommand() {
        return System.getProperty("java.home") + File.separator + "bin" + File.separator + "java";
    }
    /**
     * Copies the content of the original file to the copy.
     * @param original      The original file.
     * @param copy          The copy.
     * @throws IOException  Failed to make the copy.
     */
    static void copyFile(File original, File copy) throws IOException {
        copyInputStreamToFile(new FileInputStream(original), copy);
    }
    /**
     * Copies the content of the original input stream to the copy.
     * @param original      The original input stream.
     * @param copy          The copy.
     * @throws IOException  Failed to make the copy.
     */
    static void copyInputStreamToFile(InputStream original, File copy) throws IOException {
        if (original == null) {
            throw new IOException("Could not read input to copy.");
        }
        if (!copy.exists() && !copy.createNewFile()) {
            throw new IOException("Failed to create " + copy);
        }
        OutputStream outputStream = new FileOutputStream(copy);
        int bytesRead;
        byte[] buffer = new byte[4096];
        while ((bytesRead = original.read(buffer)) > 0) {
            outputStream.write(buffer, 0, bytesRead);
        }
        closeSilently(original, outputStream);
    }
    /**
     * Returns the classpath for the class loader and its parent.
     * @param classLoader   Contains the URLs of the class path to return.
     * @return The classpath for the class loader and its parent.
     */
    static String getClassPath(URLClassLoader classLoader) throws URISyntaxException {
        Set<URL> urls = new LinkedHashSet<>();
        Collections.addAll(urls, classLoader.getURLs());
        Collections.addAll(urls, ((URLClassLoader) classLoader.getParent()).getURLs());
        Set<String> paths = new LinkedHashSet<>();
        for (URL url: urls) {
            paths.add(new File(url.toURI()).getPath());
        }
        return joinAsString(File.pathSeparator, paths);
    }
    /**
     * Returns a ClassLoader including the project's runtime classpath elements.
     * This is useful when running a Java command from inside a Maven plugin.
     *
     * @param project   The Maven project holding runtime classpath elements.
     * @param log       A plugin log to use for debugging.
     * @return A ClassLoader including the project's runtime classpath elements.
     * @throws DependencyResolutionRequiredException    Failed to access the runtime classpath
     * @throws MalformedURLException                    Failed to add an element to the classpath
     */
    static URLClassLoader getRuntimeClassLoader(MavenProject project, Log log)
            throws DependencyResolutionRequiredException, MalformedURLException {
        List<String> runtimeClasspathElements = project.getRuntimeClasspathElements();
        Set<URL> runtimeUrls = new LinkedHashSet<>();
        for (String element : runtimeClasspathElements) {
            runtimeUrls.add(new File(element).toURI().toURL());
        }
        final URLClassLoader urlClassLoader = new URLClassLoader(
                runtimeUrls.toArray(new URL[runtimeClasspathElements.size()]),
                Thread.currentThread().getContextClassLoader());
        debugClassPathElements(urlClassLoader, log);
        return urlClassLoader;
    }
    /**
     * Logs what is on the classpath for debugging.
     * @param classLoader   The ClassLoader with the classpath.
     * @param log           The Maven plugin log in which to write debug messages.
     */
    static void debugClassPathElements(ClassLoader classLoader, Log log) {
        if (null == classLoader) {
            return;
        }
        log.debug("--------------------");
        log.debug(classLoader.toString());
        if (classLoader instanceof URLClassLoader) {
            final URLClassLoader ucl = (URLClassLoader) classLoader;
            int i = 0;
            for (URL url : ucl.getURLs()) {
                log.debug("url[" + (i++) + "]=" + url);
            }
        }
        debugClassPathElements(classLoader.getParent(), log);
    }
    private Utils() {
        // Not used.
    }
}
opendj-doc-maven-plugin/src/main/resources/config-ref/duration-syntax.html
opendj-doc-maven-plugin/src/main/resources/config-ref/opendj-config.css
opendj-doc-maven-plugin/src/main/resources/config-ref/opendj_logo_sm.png

opendj-doc-maven-plugin/src/main/resources/config-ref/pageaction.gif

opendj-doc-maven-plugin/src/main/resources/config-ref/tab_deselected.jpg

opendj-doc-maven-plugin/src/main/resources/config-ref/tab_selected.gif

opendj-server-legacy/build.xml
@@ -22,7 +22,7 @@
 !
 !
 !      Copyright 2006-2010 Sun Microsystems, Inc.
 !      Portions Copyright 2011-2015 ForgeRock AS
 !      Portions Copyright 2011-2015 ForgeRock AS.
 !      Portions Copyright 2012 Delta Victor Consultants
 ! -->
@@ -155,7 +155,8 @@
  <property name="admin.defn.dir"  location="${build.dir}/config/admin/defn" />
  <property name="admin.src.dir"   location="src/admin/generated" />
  <property name="admin.rules.dir" location="resource/admin" />
  <property name="configguide.resource.dir" location="resource/admin/config-guide" />
  <property name="configguide.resource.dir"
            location="../opendj-doc-maven-plugin/src/main/resources/config-ref" />
  <!-- Properties for generating messages. -->
  <property name="msg.dir"         location="src/messages" />
opendj-server-legacy/pom.xml
@@ -1886,8 +1886,28 @@
            <groupId>org.forgerock.opendj</groupId>
            <artifactId>opendj-doc-maven-plugin</artifactId>
            <version>${project.version}</version>
            <!--
              Configuration reference generation requires
              that opendj-config be on the runtime classpath for the plugin.
              It is not enough to declare it as a dependency of this module.
            -->
            <dependencies>
              <dependency>
                <groupId>org.forgerock.opendj</groupId>
                <artifactId>opendj-config</artifactId>
                <version>${project.version}</version>
              </dependency>
            </dependencies>
            <executions>
              <execution>
                <id>generate-configuration-reference-doc</id>
                <phase>compile</phase>
                <goals>
                  <goal>generate-config-ref</goal>
                </goals>
              </execution>
              <execution>
                <id>generate-schema-reference-doc</id>
                <phase>prepare-package</phase>
                <goals>
opendj-server-legacy/src/main/java/org/opends/server/admin/doc/ConfigGuideGeneration.java
@@ -22,7 +22,7 @@
 *
 *
 *      Copyright 2007-2010 Sun Microsystems, Inc.
 *      Portions Copyright 2011-2015 ForgeRock AS
 *      Portions Copyright 2011-2015 ForgeRock AS.
 */
package org.opends.server.admin.doc;
@@ -988,21 +988,31 @@
  private void genMainTopPage() {
    htmlHeader(DynamicConstants.PRODUCT_NAME +
            " Configuration Reference - Main Top");
    // "Home" might be depend on where this is published.
    /*
    htmlBuff.append("<div class=\"breadcrumb\"><span class=\"pageactions\">" +
      "<a href=\"" + OpenDJHome + "\" target=\"_parent\">" +
      "<span style=\"font-size: 12px;\">&laquo;&nbsp;&nbsp;</span>" +
      "Back to " +
      DynamicConstants.PRODUCT_NAME + " Home</a></span>&nbsp;&nbsp;</div>\n");
    */
    htmlBuff.append("<div class=\"breadcrumb\"><span class=\"pageactions\">" +
            "&nbsp;&nbsp;</span>&nbsp;&nbsp;</div>\n");
    htmlBuff.append("<table class=\"titletable\" cellspacing=\"0\" " +
      "width=\"100%\">\n");
    htmlBuff.append("<tbody><tr>\n");
    htmlBuff.append("  <td><h2>"+
            DynamicConstants.PRODUCT_NAME +
            " Configuration Reference</h2></td>\n");
    /*
    htmlBuff.append("  <td valign=\"bottom\" width=\"10%\">" +
      "<a href=\"" + OpenDJHome + "\" target=\"_parent\">" +
      "<img src=\"opendj_logo_sm.png\" alt=\"OpenDJ Logo\" align=\"bottom\" " +
      "border=\"0\" height=\"33\" width=\"114\"></a></td>\n");
    */
    htmlBuff.append("  <td valign=\"bottom\" width=\"10%\">" +
            "<img src=\"opendj_logo_sm.png\" alt=\"OpenDJ Logo\" align=\"bottom\" " +
            "border=\"0\" height=\"33\" width=\"114\"></td>\n");
    htmlBuff.append("</tr>\n");
    htmlBuff.append("</tbody></table>\n");
@@ -1067,7 +1077,11 @@
      @Override
      public String visitACI(ACIPropertyDefinition prop, Void p) {
        return getLink("An ACI Syntax", aciSyntaxPage);
        // Rather than return a link that is coupled to a site location,
        // assume that readers can find ACI syntax in the documentation.
        // ACI syntax being difficult to understand and to explain,
        // it is better not to have to maintain a separate page, either.
        return "An ACI syntax"; // getLink("An ACI Syntax", aciSyntaxPage);
      }
      @Override