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-<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-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.pngopendj-doc-maven-plugin/src/main/resources/config-ref/pageaction.gifopendj-doc-maven-plugin/src/main/resources/config-ref/tab_deselected.jpgopendj-doc-maven-plugin/src/main/resources/config-ref/tab_selected.gifopendj-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;\">« </span>" + "Back to " + DynamicConstants.PRODUCT_NAME + " Home</a></span> </div>\n"); */ htmlBuff.append("<div class=\"breadcrumb\"><span class=\"pageactions\">" + " </span> </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