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

Mark Craig
28.15.2015 4dd16cd3715e42acc1ec2f9d9d894ceef4507be4
opendj-sdk/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-sdk/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");
        commands.add(getClassPath(toolsClassLoader));
        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-sdk/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-sdk/opendj-doc-maven-plugin/src/main/resources/config-ref/duration-syntax.html
opendj-sdk/opendj-doc-maven-plugin/src/main/resources/config-ref/opendj-config.css
opendj-sdk/opendj-doc-maven-plugin/src/main/resources/config-ref/opendj_logo_sm.png

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

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

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

opendj-sdk/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-sdk/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-sdk/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