org.forgerock.openicf.maven.DocBookResourceMojo.java Source code

Java tutorial

Introduction

Here is the source code for org.forgerock.openicf.maven.DocBookResourceMojo.java

Source

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2012-2014 ForgeRock AS. All Rights Reserved
 *
 * The contents of this file are subject to the terms
 * of the Common Development and Distribution License
 * (the License). You may not use this file except in
 * compliance with the License.
 *
 * You can obtain a copy of the License at
 * http://forgerock.org/license/CDDLv1.0.html
 * See the License for the specific language governing
 * permission and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL
 * Header Notice in each file and include the License file
 * at http://forgerock.org/license/CDDLv1.0.html
 * If applicable, add the following below the CDDL Header,
 * with the fields enclosed by brackets [] replaced by
 * your own identifying information:
 * "Portions Copyrighted [year] [name of copyright owner]"
 */

package org.forgerock.openicf.maven;

import java.io.File;
import java.io.FileFilter;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.security.CodeSource;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import org.apache.maven.archiver.MavenArchiveConfiguration;
import org.apache.maven.archiver.MavenArchiver;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.DependencyResolutionRequiredException;
import org.apache.maven.artifact.handler.ArtifactHandler;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.model.Resource;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecution;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.resources.remote.BundleRemoteResourcesMojo;
import org.apache.maven.plugin.resources.remote.RemoteResourcesBundle;
import org.apache.maven.plugin.resources.remote.io.xpp3.RemoteResourcesBundleXpp3Writer;
import org.apache.maven.plugins.annotations.Component;
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.plugins.annotations.ResolutionScope;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.MavenProjectHelper;
import org.apache.maven.shared.filtering.MavenFileFilter;
import org.apache.maven.shared.filtering.MavenFilteringException;
import org.apache.maven.shared.filtering.MavenResourcesExecution;
import org.apache.velocity.context.Context;
import org.codehaus.plexus.archiver.Archiver;
import org.codehaus.plexus.archiver.ArchiverException;
import org.codehaus.plexus.archiver.jar.JarArchiver;
import org.codehaus.plexus.archiver.jar.ManifestException;
import org.codehaus.plexus.i18n.I18N;
import org.codehaus.plexus.util.DirectoryScanner;
import org.codehaus.plexus.util.FileUtils;
import org.codehaus.plexus.util.IOUtil;
import org.codehaus.plexus.util.StringUtils;
import org.codehaus.plexus.velocity.VelocityComponent;
import org.identityconnectors.common.l10n.CurrentLocale;
import org.identityconnectors.framework.api.RemoteFrameworkConnectionInfo;

/**
 * A DocBookResourceMojo generate the DocBook xml.
 * <p/>
 * To debug execute this command:
 * {@code mvnDebug org.forgerock.maven.plugins:openicf-maven-plugin:docbkx}
 *
 * @author Laszlo Hordos
 */
@Mojo(name = "docbkx", defaultPhase = LifecyclePhase.PACKAGE, threadSafe = true, requiresDependencyResolution = ResolutionScope.TEST, configurator = "override")
public class DocBookResourceMojo extends AbstractMojo implements ConnectorMojoBridge {

    private static final String[] DEFAULT_INCLUDES = new String[] { "**/*.txt", "**/*.vm", };

    /**
     * The Maven Session Object
     */
    @Parameter(property = "session", readonly = true)
    protected MavenSession session;

    /**
     */
    @Parameter(defaultValue = "${project.artifact}", required = true, readonly = true)
    private Artifact artifact;

    /**
     * Encoding of the bundle.
     */
    @Parameter(defaultValue = "${project.build.sourceEncoding}")
    private String sourceEncoding;

    /**
     * The current project base directory.
     */
    @Parameter(defaultValue = "${basedir}", readonly = true, required = true)
    protected File basedir;

    /**
     * The directory which contains the resources you want packaged up in this
     * resource bundle.
     */
    @Parameter(defaultValue = "${basedir}/src/main/resources")
    private File resourcesDirectory;

    /**
     * The directory where you want the resource xml-s written to.
     */
    @Parameter(defaultValue = "${project.build.outputDirectory}", required = true, readonly = true)
    private File buildOutputDirectory;

    public File getBuildOutputDirectory() {
        return buildOutputDirectory;
    }

    /**
     * Directory that contains the template.
     */
    @Parameter(property = "openicf.templateDirectory", defaultValue = "org/forgerock/openicf/maven")
    private String templateDirectory;

    /**
     * The directory which contains the resources you want packaged up in this
     * resource bundle.
     */
    @Parameter(defaultValue = "${basedir}/src/main/docbkx")
    private File docbkxDirectory;

    @Parameter(property = "openicf.failOnError", defaultValue = "true")
    protected boolean failOnError;

    /**
     * Specifies the directory where the generated jar file will be put.
     */
    @Parameter(property = "project.build.directory")
    private String buildDirectory;

    /**
     * Specifies the filename that will be used for the generated jar file.
     * Please note that <code>-docbkx</code> will be appended to the file name.
     */
    @Parameter(property = "project.build.finalName")
    private String finalName;

    /**
     * Specifies whether to attach the generated artifact to the project helper. <br/>
     */
    @Parameter(property = "attach", defaultValue = "true")
    private boolean attach;

    /**
     * The archive configuration to use. See <a
     * href="http://maven.apache.org/shared/maven-archiver/index.html">Maven
     * Archiver Reference</a>.
     */
    @Parameter
    private MavenArchiveConfiguration archive = new MavenArchiveConfiguration();

    /**
     * A list of files to include. Can contain ant-style wildcards and double
     * wildcards. The default includes are
     * <code>**&#47;*.txt   **&#47;*.vm</code>
     */
    @Parameter
    private String[] includes;

    public String[] getIncludes() {
        return includes;
    }

    /**
     * A list of files to exclude. Can contain ant-style wildcards and double
     * wildcards.
     */
    @Parameter
    private String[] excludes;

    public String[] getExcludes() {
        return excludes;
    }

    /**
     * Set this to 'true' to bypass artifact deploy
     *
     * @since 1.0.0
     */
    @Parameter(property = "maven.openicf.skip", defaultValue = "false")
    private boolean skip;

    @Parameter
    private PropertyBag configurationProperties;

    public PropertyBag getConfigurationProperties() {
        return configurationProperties;
    }

    @Parameter
    private RemoteFrameworkConnectionInfo remoteFrameworkConnectionInfo;

    public RemoteFrameworkConnectionInfo getRemoteFrameworkConnectionInfo() {
        return remoteFrameworkConnectionInfo;
    }

    @Parameter(defaultValue = "${mojoExecution}")
    MojoExecution execution;

    // ----------------------------------------------------------------------
    // Mojo components
    // ----------------------------------------------------------------------

    /**
     * Used for attaching the artifact in the project.
     */
    @Component
    private MavenProjectHelper projectHelper;

    /**
     * The Jar achiver.
     */
    @Component(role = Archiver.class, hint = "jar")
    private JarArchiver jarArchiver;

    /**
     * The Maven Project
     */
    @Component
    private MavenProject project;

    /**
     * Velocity Component.
     */
    @Component()
    private VelocityComponent velocity;

    @Component()
    private MavenFileFilter fileFilter;

    /**
     * @plexus.requirement
     */
    private I18N i18n;

    public File getBasedir() {
        return basedir;
    }

    public String getSourceEncoding() {
        return sourceEncoding;
    }

    public String getTemplateDirectory() {
        return templateDirectory;
    }

    public I18N getI18N() {
        return i18n;
    }

    public MavenProject getMavenProject() {
        return project;
    }

    public void generate(ConnectorDocBuilder builder, Context context, String connectorName)
            throws MojoExecutionException {
        try {
            File rootDirectory = new File(buildDirectory, "openicf-docbkx/" + getTargetDirectoryName());

            Map<String, String> fileSetDictionary = new LinkedHashMap<String, String>();
            fileSetDictionary.put("sec-reference.xml.vm", "sec-reference-%s.xml");
            fileSetDictionary.put("sec-implemented-interfaces.xml.vm", "sec-implemented-interfaces-%s.xml");
            fileSetDictionary.put("sec-config-properties.xml.vm", "sec-config-properties-%s.xml");
            fileSetDictionary.put("sec-schema.xml.vm", "sec-schema-%s.xml");
            fileSetDictionary.put("chap-config.xml.vm", "chap-config-%s.xml");

            for (Map.Entry<String, String> entry : fileSetDictionary.entrySet()) {
                generateDocument(builder, context, connectorName, rootDirectory, entry.getKey());
            }
        } catch (IOException e) {
            getLog().error(e);
            throw new MojoExecutionException("Failed to generate DocBook", e);
        }
    }

    protected void generateDocument(ConnectorDocBuilder builder, Context context, String connectorName,
            File rootDirectory, String templateFile) throws IOException, MojoExecutionException {
        if (null == context.get("schema") && templateFile.contains("-schema")) {
            return;
        }
        String key = templateFile.substring(templateFile.lastIndexOf("/") + 1, templateFile.indexOf('.'));
        String fileName = key + "-" + connectorName + ".xml";
        File configDoc = new File(rootDirectory, fileName);

        FileUtils.mkdir(configDoc.getParentFile().getAbsolutePath());

        FileWriter writer = new FileWriter(configDoc);
        builder.processTemplate(velocity.getEngine(), context, templateFile, writer);
        writer.flush();
        writer.close();
        context.put(key, fileName);
    }

    protected String getTargetDirectoryName() {
        if (null == execution || execution.getExecutionId().equals("default")) {
            return artifact.getArtifactId() + "-" + artifact.getVersion();
        } else {
            return artifact.getArtifactId() + "-" + artifact.getVersion() + "/" + execution.getExecutionId();
        }
    }

    public void execute() throws MojoExecutionException, MojoFailureException {
        if (skip) {
            getLog().info("Skipping DocBook generation");
            return;
        }

        if (!("pom".equalsIgnoreCase(project.getPackaging()))) {
            ArtifactHandler artifactHandler = project.getArtifact().getArtifactHandler();
            if (!"java".equals(artifactHandler.getLanguage())) {
                getLog().info(
                        "Not executing DocBook report as the project is not a Java classpath-capable package");
                return;
            }
        }

        try {

            if (!docbkxDirectory.exists()) {
                getLog().info("Not executing DocBook report as the project does not have DocBook source");
                return;
            }

            File rootDirectory = new File(buildDirectory,
                    "openicf-docbkx/" + artifact.getArtifactId() + "-" + artifact.getVersion());
            try {
                FileUtils.mkdir(rootDirectory.getAbsolutePath());

                MavenResourcesExecution mre = new MavenResourcesExecution();
                mre.setMavenProject(getMavenProject());
                mre.setEscapeWindowsPaths(true);
                mre.setMavenSession(session);
                mre.setInjectProjectBuildFilters(true);

                List<FileUtils.FilterWrapper> filterWrappers = null;
                try {
                    filterWrappers = fileFilter.getDefaultFilterWrappers(mre);
                } catch (MavenFilteringException e) {
                    filterWrappers = Collections.emptyList();
                }

                if (docbkxDirectory.exists()) {
                    final List<String> includes = FileUtils.getFileAndDirectoryNames(docbkxDirectory, "**",
                            StringUtils.join(DirectoryScanner.DEFAULTEXCLUDES, ",") + ",**/*.xml", true, false,
                            true, true);

                    org.apache.commons.io.FileUtils.copyDirectory(docbkxDirectory, rootDirectory, new FileFilter() {
                        public boolean accept(File pathname) {
                            return includes.contains(pathname.getPath());
                        }
                    });

                    List<File> files = FileUtils.getFiles(docbkxDirectory, "**/*.xml", null);

                    for (File file : files) {
                        try {
                            fileFilter.copyFile(file, new File(rootDirectory, file.getName()), true, filterWrappers,
                                    getSourceEncoding());
                        } catch (MavenFilteringException e) {
                            throw new MojoExecutionException(e.getMessage(), e);
                        }
                    }
                }

                File sharedRoot = rootDirectory.getParentFile();

                CodeSource src = getClass().getProtectionDomain().getCodeSource();
                if (src != null) {
                    final ZipInputStream zip = new ZipInputStream(src.getLocation().openStream());
                    ZipEntry entry = null;
                    while ((entry = zip.getNextEntry()) != null) {
                        String name = entry.getName();
                        if (entry.getName().startsWith("shared")) {

                            File destination = new File(sharedRoot, name);
                            if (entry.isDirectory()) {
                                if (!destination.exists()) {
                                    destination.mkdirs();
                                }
                            } else {
                                if (!destination.exists()) {
                                    FileOutputStream output = null;
                                    try {
                                        output = new FileOutputStream(destination);
                                        IOUtil.copy(zip, output);
                                    } finally {
                                        IOUtil.close(output);
                                    }
                                }
                            }
                        }
                    }
                    zip.closeEntry();
                    zip.close();
                }
            } catch (IOException e) {
                throw new MojoExecutionException("Error copy DocBook resources.", e);
            }

            // Generate Config and Schema DocBook Chapter
            CurrentLocale.set(Locale.ENGLISH);
            ConnectorDocBuilder generator = new ConnectorDocBuilder(this);
            generator.executeReport();

            // Look at the content of the resourcesDirectory and create a
            // manifest
            // of the files
            // so that velocity can easily process any resources inside the JAR
            // that
            // need to be processed.

            if (attach) {
                RemoteResourcesBundle remoteResourcesBundle = new RemoteResourcesBundle();
                remoteResourcesBundle.setSourceEncoding(getSourceEncoding());

                DirectoryScanner scanner = new DirectoryScanner();
                scanner.setBasedir(new File(buildDirectory, "openicf-docbkx/"));
                // scanner.setIncludes(new String[] { docFolder + "/**" });
                scanner.addDefaultExcludes();
                scanner.scan();

                List<String> includedFiles = Arrays.asList(scanner.getIncludedFiles());

                if (resourcesDirectory.exists()) {
                    scanner = new DirectoryScanner();
                    scanner.setBasedir(resourcesDirectory);
                    if (includes != null && includes.length != 0) {
                        scanner.setIncludes(includes);
                    } else {
                        scanner.setIncludes(DEFAULT_INCLUDES);
                    }

                    if (excludes != null && excludes.length != 0) {
                        scanner.setExcludes(excludes);
                    }

                    scanner.addDefaultExcludes();
                    scanner.scan();
                    includedFiles.addAll(Arrays.asList(scanner.getIncludedFiles()));
                }
                for (String resource : includedFiles) {
                    remoteResourcesBundle.addRemoteResource(StringUtils.replace(resource, '\\', '/'));
                }

                RemoteResourcesBundleXpp3Writer w = new RemoteResourcesBundleXpp3Writer();

                try {
                    File f = new File(buildDirectory,
                            "openicf-docbkx/" + BundleRemoteResourcesMojo.RESOURCES_MANIFEST);

                    FileUtils.mkdir(f.getParentFile().getAbsolutePath());

                    Writer writer = new FileWriter(f);

                    w.write(writer, remoteResourcesBundle);
                } catch (IOException e) {
                    throw new MojoExecutionException("Error creating remote resources manifest.", e);
                }

                File outputFile = generateArchive(new File(buildDirectory, "openicf-docbkx/"),
                        finalName + "-docbkx.jar");

                projectHelper.attachArtifact(project, "jar", "docbkx", outputFile);
            } else {
                getLog().info("NOT adding DocBook to attached artifacts list.");
            }
        } catch (ArchiverException e) {
            failOnError("ArchiverException: Error while creating archive", e);
        } catch (IOException e) {
            failOnError("IOException: Error while creating archive", e);
        } catch (RuntimeException e) {
            failOnError("RuntimeException: Error while creating archive", e);
        }
    }

    /**
     * Method that creates the jar file
     *
     * @param docbkxFiles
     *            the directory where the generated jar file will be put
     * @param jarFileName
     *            the filename of the generated jar file
     * @return a File object that contains the generated jar file
     * @throws ArchiverException
     *             if any
     * @throws IOException
     *             if any
     */
    private File generateArchive(File docbkxFiles, String jarFileName) throws ArchiverException, IOException {
        File docbkxJar = new File(buildDirectory, jarFileName);

        if (docbkxJar.exists()) {
            docbkxJar.delete();
        }

        MavenArchiver archiver = new MavenArchiver();
        archiver.setArchiver(jarArchiver);
        archiver.setOutputFile(docbkxJar);

        if (!docbkxFiles.exists()) {
            getLog().warn("JAR will be empty - no content was marked for inclusion!");
        } else {
            archiver.getArchiver().addDirectory(docbkxFiles);
        }

        List<Resource> resources = project.getBuild().getResources();

        for (Resource r : resources) {
            if (r.getDirectory().endsWith("maven-shared-archive-resources")) {
                archiver.getArchiver().addDirectory(new File(r.getDirectory()));
            }
        }

        try {
            archive.setAddMavenDescriptor(false);
            archiver.createArchive(session, project, archive);
        } catch (ManifestException e) {
            throw new ArchiverException("ManifestException: " + e.getMessage(), e);
        } catch (DependencyResolutionRequiredException e) {
            throw new ArchiverException("DependencyResolutionRequiredException: " + e.getMessage(), e);
        }

        return docbkxJar;
    }

    protected void failOnError(String prefix, Exception e) throws MojoExecutionException {
        if (failOnError) {
            if (e instanceof RuntimeException) {
                throw (RuntimeException) e;
            }
            throw new MojoExecutionException(prefix + ": " + e.getMessage(), e);
        }

        getLog().error(prefix + ": " + e.getMessage(), e);
    }
}