From 5f80f407080b2962c96d5b520f7c0ef2270090a6 Mon Sep 17 00:00:00 2001
From: Nicolas Capponi <nicolas.capponi@forgerock.com>
Date: Thu, 05 Feb 2015 11:09:22 +0000
Subject: [PATCH] OPENDJ-1741 Add maven plugin to generate custom manifest-classpath

---
 opendj-manifest-classpath-maven-plugin/src/main/java/org/forgerock/maven/package-info.java                  |   31 ++++++
 opendj-manifest-classpath-maven-plugin/pom.xml                                                              |   56 +++++++++++
 opendj-manifest-classpath-maven-plugin/src/main/java/org/forgerock/maven/GenerateManifestClassPathMojo.java |  196 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 283 insertions(+), 0 deletions(-)

diff --git a/opendj-manifest-classpath-maven-plugin/pom.xml b/opendj-manifest-classpath-maven-plugin/pom.xml
new file mode 100644
index 0000000..992bc65
--- /dev/null
+++ b/opendj-manifest-classpath-maven-plugin/pom.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+  xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <artifactId>opendj-project</artifactId>
+    <groupId>org.forgerock.opendj</groupId>
+    <version>3.0.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>opendj-manifest-classpath-maven-plugin</artifactId>
+  <version>1.0.0-SNAPSHOT</version>
+  <name>OpenDJ Manifest Classpath Maven Plugin</name>
+  <description>
+    Generation of manifest classpath, with classpath customization.
+  </description>
+  <packaging>maven-plugin</packaging>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-archiver</artifactId>
+      <version>2.6</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven.plugins</groupId>
+      <artifactId>maven-jar-plugin</artifactId>
+      <version>2.5</version>
+      <type>maven-plugin</type>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven.plugins</groupId>
+      <artifactId>maven-assembly-plugin</artifactId>
+      <version>2.5.3</version>
+      <type>maven-plugin</type>
+    </dependency>
+    <dependency>
+      <groupId>org.twdata.maven</groupId>
+      <artifactId>mojo-executor</artifactId>
+      <version>2.2.0</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-plugin-api</artifactId>
+      <version>2.0</version>
+    </dependency>
+    <!-- dependencies to annotations -->
+    <dependency>
+      <groupId>org.apache.maven.plugin-tools</groupId>
+      <artifactId>maven-plugin-annotations</artifactId>
+      <version>3.4</version>
+      <scope>provided</scope>
+    </dependency>
+  </dependencies>
+  
+</project>
diff --git a/opendj-manifest-classpath-maven-plugin/src/main/java/org/forgerock/maven/GenerateManifestClassPathMojo.java b/opendj-manifest-classpath-maven-plugin/src/main/java/org/forgerock/maven/GenerateManifestClassPathMojo.java
new file mode 100644
index 0000000..e3297c5
--- /dev/null
+++ b/opendj-manifest-classpath-maven-plugin/src/main/java/org/forgerock/maven/GenerateManifestClassPathMojo.java
@@ -0,0 +1,196 @@
+/*
+ * 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.maven;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.DependencyResolutionRequiredException;
+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.plugins.annotations.ResolutionScope;
+import org.apache.maven.project.MavenProject;
+
+/**
+ * Generate a class path suitable for the Class-Path header of a Manifest file, allowing to filter
+ * on included jars, using excludes/includes properties.
+ * <p>
+ * There is a single goal that generates a property given by 'classPathProperty' parameter, with the generated
+ * classpath as the value.
+ *
+ * @Checkstyle:ignoreFor 3
+ */
+@Mojo(name="generate", defaultPhase=LifecyclePhase.VALIDATE, requiresDependencyResolution=ResolutionScope.COMPILE_PLUS_RUNTIME)
+public final class GenerateManifestClassPathMojo extends AbstractMojo {
+
+    private static final int MAX_LINE_LENGTH = 72;
+    private static final String HEADER_CLASSPATH = "Class-Path:";
+
+    /**
+     * The Maven Project.
+     */
+    @Parameter(property="project", required=true, readonly=true)
+    private MavenProject project;
+
+    /**
+     * A property to set to the content of the generated classpath string.
+     */
+    @Parameter(required=true)
+    private String classPathProperty;
+
+    /**
+     * List of artifacts to exclude from the classpath. Each item must be of format "groupId:artifactId".
+     */
+    @Parameter
+    private List<String> excludes;
+
+    /**
+     * List of artifacts to include in the classpath. Each item must be of format "groupId:artifactId".
+     */
+    @Parameter
+    private List<String> includes;
+
+    /**
+     * Name of product jar, e.g. "OpenDJ"
+     */
+    @Parameter
+    private String productJarName;
+
+    /**
+     * List of supported locales, separated by a ","
+     * <p>
+     * Example: "fr,es,de"
+     */
+    @Parameter
+    private String supportedLocales;
+
+    /** {@inheritDoc} */
+    public void execute() throws MojoExecutionException, MojoFailureException {
+        try {
+            String classPath = getClasspath();
+            getLog().info(String.format("Setting the classpath property: [%s] (debug to see actual value)", classPathProperty));
+            getLog().debug(String.format("Setting the classpath property %s to:\n%s", classPathProperty, classPath));
+            project.getProperties().put(classPathProperty, classPath);
+        } catch (DependencyResolutionRequiredException e) {
+            getLog().error(
+                String.format("Unable to set the classpath property %s, an error occured", classPathProperty));
+            throw new MojoFailureException(e.getMessage());
+        }
+    }
+
+    /**
+     * Get the classpath.
+     * <p>
+     * The returned value is conform to Manifest Header syntax, where line length must be at most 72 bytes.
+     *
+     * @return the classpath string
+     * @throws DependencyResolutionRequiredException
+     */
+    private String getClasspath() throws DependencyResolutionRequiredException {
+        final List<String> classpathItems = getClasspathItems();
+        final StringBuilder classpath = new StringBuilder(HEADER_CLASSPATH);
+        for (String item : classpathItems) {
+            classpath.append(" ").append(item);
+        }
+        int index = MAX_LINE_LENGTH - 2;
+        while (index <= classpath.length()) {
+            classpath.insert(index, "\n ");
+            index += MAX_LINE_LENGTH - 1;
+        }
+        return classpath.toString();
+    }
+
+    @SuppressWarnings("unchecked")
+    private List<String> getClasspathItems() throws DependencyResolutionRequiredException {
+        final List<String> classpathItems = new ArrayList<String>();
+
+        // add project dependencies
+        for (String artifactFile : (List<String>) project.getRuntimeClasspathElements()) {
+            final File file = new File(artifactFile);
+            if (file.getAbsoluteFile().isFile()) {
+                final Artifact artifact = findArtifactWithFile(project.getArtifacts(), file);
+                if (isAccepted(artifact)) {
+                    final String artifactString = artifact.getArtifactId() + "." + artifact.getType();
+                    classpathItems.add(artifactString);
+                }
+            }
+        }
+        // add product jars, with localized versions
+        Collections.sort(classpathItems);
+        if (productJarName != null) {
+            if (supportedLocales != null) {
+                String[] locales = supportedLocales.split(",");
+                for (int i = locales.length-1; i >= 0; i--) {
+                    classpathItems.add(0, productJarName + "_" + locales[i] + ".jar");
+                }
+            }
+            classpathItems.add(0, productJarName + ".jar");
+        }
+        return classpathItems;
+    }
+
+    private boolean isAccepted(Artifact artifact) {
+        String artifactString = artifact.getGroupId() + ":" + artifact.getArtifactId();
+        if (includes != null) {
+            for (String included : includes) {
+                if (artifactString.equalsIgnoreCase(included)) {
+                    return true;
+                }
+            }
+            if (!includes.isEmpty()) {
+                return false;
+            }
+        }
+        if (excludes != null) {
+            for (String excluded : excludes) {
+                if (artifactString.equalsIgnoreCase(excluded)) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    private Artifact findArtifactWithFile(Set<Artifact> artifacts, File file) {
+        for (Artifact artifact : artifacts) {
+            if (artifact.getFile() != null) {
+                if (artifact.getFile().equals(file)) {
+                    return artifact;
+                }
+            }
+        }
+        return null;
+    }
+
+}
diff --git a/opendj-manifest-classpath-maven-plugin/src/main/java/org/forgerock/maven/package-info.java b/opendj-manifest-classpath-maven-plugin/src/main/java/org/forgerock/maven/package-info.java
new file mode 100644
index 0000000..31af947
--- /dev/null
+++ b/opendj-manifest-classpath-maven-plugin/src/main/java/org/forgerock/maven/package-info.java
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+/**
+ * Classes implementing the maven plugin for generation of jar manifest with flexible Class-Path header.
+ */
+package org.forgerock.maven;
+

--
Gitblit v1.10.0