All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.rmannibucau.dita.maven.DitaRenderMojo Maven / Gradle / Ivy

The newest version!
package com.github.rmannibucau.dita.maven;

import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap;
import static java.util.concurrent.TimeUnit.MINUTES;
import static org.apache.maven.plugins.annotations.LifecyclePhase.PROCESS_SOURCES;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.Collection;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.stream.Stream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import org.apache.maven.execution.MavenSession;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.artifact.DefaultArtifact;
import org.eclipse.aether.impl.ArtifactResolver;
import org.eclipse.aether.resolution.ArtifactRequest;
import org.eclipse.aether.resolution.ArtifactResolutionException;
import org.eclipse.aether.resolution.ArtifactResult;

@Mojo(defaultPhase = PROCESS_SOURCES, name = "render")
public class DitaRenderMojo extends AbstractMojo {

    @Parameter(property = "dita.ditaDir", defaultValue = "${project.basedir}/src/main/dita")
    private File ditaDir;

    @Parameter(property = "dita.extensions", defaultValue = "ditamap")
    private Collection extensions;

    @Parameter(property = "dita.includes")
    private Collection includes;

    @Parameter(property = "dita.outputDir", defaultValue = "${project.build.directory}/dita/output")
    protected File outputDir;

    @Parameter(property = "dita.ditaTempDir", defaultValue = "${project.build.directory}/dita/temp")
    protected File ditaTempDir;

    @Parameter(property = "dita.transtype", defaultValue = "html5")
    private String transtype;

    @Parameter(property = "dita.cleanOnFailure", defaultValue = "true")
    private boolean cleanOnFailure;

    @Parameter(property = "dita.createDebugLog", defaultValue = "false")
    private boolean createDebugLog;

    @Parameter(property = "dita.parallelism", defaultValue = "-1")
    private int parallelism;

    @Parameter(property = "dita.properties")
    private Map properties;

    @Parameter(property = "dita.mode", defaultValue = "STRICT")
    private String mode;

    @Parameter(property = "dita.version", defaultValue = "3.0.2")
    private String ditaVersion;

    @Parameter(property = "dita.downloadUrl", defaultValue = "https://github.com/dita-ot/dita-ot/releases/download/$version/dita-ot-$version.zip")
    private String ditaDownloadUrl;

    @Parameter(property = "dita.cacheDistribution", defaultValue = "true")
    private boolean cacheDistribution;

    @Parameter(defaultValue = "${settings.localRepository}")
    private File localRepository;

    @Component
    private ArtifactResolver resolver;

    @Parameter(defaultValue = "${session}", readonly = true)
    private MavenSession session;

    @Override
    public void execute() throws MojoExecutionException, MojoFailureException {
        final File distribution;
        try {
            distribution = findDistribution();
        } catch (final MalformedURLException e) {
            throw new MojoExecutionException(e.getMessage(), e);
        }
        doExecute(distribution);
    }

    private void doExecute(final File distribution) {
        try (final URLClassLoader loader = new URLClassLoader(findClassLoaderUrls(distribution),
                Thread.currentThread().getContextClassLoader())) {

            final ProcessorCache processors = new ProcessorCache(loader, distribution, ditaTempDir, transtype, cleanOnFailure,
                    createDebugLog, mode, properties == null ? emptyMap() : properties, getLog());
            final Executor executor = parallelism == 0 ? Runnable::run
                    : Executors.newFixedThreadPool(parallelism < 0 ? Runtime.getRuntime().availableProcessors() : parallelism);
            final Path srcPath = ditaDir.toPath();
            final Semaphore semaphore = new Semaphore(0);
            int count = 0;
            try {
                count = Stream.of(Objects.requireNonNull(ditaDir.listFiles()))
                        .filter(f -> (includes != null && includes.contains(f.getName())) || (includes == null
                                || (extensions == null || extensions.stream().anyMatch(e -> f.getName().endsWith('.' + e)))))
                        .parallel().mapToInt(file -> {
                            executor.execute(() -> processors.withProcessor(processor -> {
                                final File output = new File(outputDir,
                                        srcPath.relativize(file.getParentFile().toPath()).toString());
                                getLog().info("Processing " + file.getAbsolutePath());

                                final Class pc = processor.getClass();
                                try {
                                    pc.getMethod("setInput", File.class).invoke(processor, file.getAbsoluteFile());
                                    pc.getMethod("setOutputDir", File.class).invoke(processor, output);
                                    pc.getMethod("run").invoke(processor);
                                } catch (final NoSuchMethodException | IllegalAccessException e) {
                                    throw new IllegalStateException(e);
                                } catch (final InvocationTargetException e) {
                                    throw new IllegalStateException(e.getTargetException());
                                } finally {
                                    semaphore.release();
                                }
                            }));
                            return 1;
                        }).sum();
            } finally {
                if (ExecutorService.class.isInstance(executor)) {
                    final ExecutorService es = ExecutorService.class.cast(executor);
                    es.shutdown();
                    try {
                        semaphore.acquire(count);
                        es.awaitTermination(1, MINUTES);
                    } catch (final InterruptedException e) {
                        Thread.currentThread().interrupt();
                    }
                }
            }
        } catch (final IOException e) {
            throw new IllegalStateException(e);
        }
    }

    private URL[] findClassLoaderUrls(final File distribution) {
        final File config = new File(distribution, "config");
        final File lib = new File(distribution, "lib");
        if (!config.isDirectory() || !lib.isDirectory()) {
            throw new IllegalStateException("No config or lib folder in " + distribution);
        }
        return Stream.concat(Stream.of(config, lib),
                Stream.of(Objects.requireNonNull(lib.listFiles((dir, name) -> name.endsWith(".jar"))))).map(f -> {
                    try {
                        return f.toURI().toURL();
                    } catch (final MalformedURLException e) {
                        throw new IllegalStateException(e);
                    }
                }).toArray(URL[]::new);
    }

    private File findDistribution() throws MalformedURLException, MojoExecutionException {
        final File downloadOutput = new File(ditaTempDir, "dita_distribution");
        if (downloadOutput.exists()) {
            return downloadOutput;
        }
        final File zip = findDistributionZip(new URL(ditaDownloadUrl.replace("$version", ditaVersion)), downloadOutput);
        unzip(zip, downloadOutput, true);
        return downloadOutput;
    }

    private File findDistributionZip(final URL url, final File downloadOutput) throws MojoExecutionException {
        File zip;
        final Artifact artifact = new DefaultArtifact("com.github.rmannibucau.dita.maven", "dita-distribution", "zip",
                ditaVersion);
        try {
            final ArtifactResult artifactResult = resolver.resolveArtifact(session.getRepositorySession(),
                    new ArtifactRequest(artifact, emptyList(), null));
            if (artifactResult.isMissing()) {
                throw new IllegalStateException("Didn't find dita distribution");
            }
            zip = artifactResult.getArtifact().getFile();
        } catch (final ArtifactResolutionException e) {
            zip = new File(downloadOutput.getParentFile(), downloadOutput.getName() + ".zip");
            zip.getParentFile().mkdirs();
            try (final InputStream source = url.openStream()) {
                Files.copy(source, zip.toPath(), StandardCopyOption.REPLACE_EXISTING);
            } catch (final IOException e1) {
                throw new MojoExecutionException(e1.getMessage(), e1);
            }

            if (cacheDistribution) {
                final File localLocation = new File(localRepository,
                        artifact.getGroupId().replace(".", "/") + '/' + artifact.getArtifactId() + '/' + artifact.getVersion()
                                + '/' + artifact.getArtifactId() + '-' + artifact.getVersion() + '.' + artifact.getExtension());
                localLocation.getParentFile().mkdirs();
                if (!localLocation.exists()) {
                    try {
                        Files.copy(zip.toPath(), localLocation.toPath(), StandardCopyOption.REPLACE_EXISTING);
                    } catch (final IOException e1) {
                        throw new MojoExecutionException(e1.getMessage(), e1);
                    }
                }
            }
        }
        return zip;
    }

    private void unzip(final File zipFile, final File destination, final boolean noparent) {
        getLog().info(String.format("Extracting '%s' to '%s'", zipFile.getAbsolutePath(), destination.getAbsolutePath()));
        try {
            final ZipInputStream in = new ZipInputStream(new BufferedInputStream(new FileInputStream(zipFile)));
            ZipEntry entry;
            while ((entry = in.getNextEntry()) != null) {
                String path = entry.getName();
                if (noparent) {
                    path = path.replaceFirst("^[^/]+/", "");
                }
                final File file = new File(destination, path);

                if (entry.isDirectory()) {
                    file.mkdirs();
                    continue;
                }

                file.getParentFile().mkdirs();
                Files.copy(in, file.toPath(), StandardCopyOption.REPLACE_EXISTING);
            }

            in.close();
        } catch (final Exception e) {
            throw new IllegalStateException("Unable to unzip " + zipFile.getAbsolutePath(), e);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy