/* * 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 legal/CDDLv1.0.txt. See the License for the * specific language governing permission and limitations under the License. * * When distributing Covered Software, include this CDDL Header Notice in each file and include * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL * Header, with the fields enclosed by brackets [] replaced by your own identifying * information: "Portions Copyright [year] [name of copyright owner]". * * Copyright 2015 ForgeRock AS. */ package org.forgerock.opendj.maven; import static java.lang.String.*; 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. *

* There is a single goal that generates a property given by 'classPathProperty' * parameter, with the generated classpath as the value. */ @Mojo(name = "generate-manifest", 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 excludes; /** * List of artifacts to include in the classpath. Each item must be of format "groupId:artifactId". */ @Parameter private List includes; /** * List of additional JARs to include in the classpath. Each item must be of format "file.jar". */ @Parameter private List additionalJars; /** * Name of product jar, e.g. "OpenDJ". */ @Parameter private String productJarName; /** * List of supported locales, separated by a ",". *

* Example: "fr,es,de" */ @Parameter private String supportedLocales; /** {@inheritDoc} */ @Override public void execute() throws MojoExecutionException, MojoFailureException { try { String classPath = getClasspath(); getLog().info( 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(), e); } } /** * Get the classpath. *

* 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 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(); } private List getClasspathItems() throws DependencyResolutionRequiredException { final List classpathItems = new ArrayList<>(); // add project dependencies for (String artifactFile : 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.getGroupId()+ "."+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"); } // add additional JARs if (additionalJars != null) { classpathItems.addAll(additionalJars); } return classpathItems; } private boolean isAccepted(Artifact artifact) { String artifactString = artifact.getGroupId() + ":" + artifact.getArtifactId(); if (includes != null) { if (containsIgnoreCase(includes, artifactString)) { return true; } if (!includes.isEmpty()) { return false; } } return !containsIgnoreCase(excludes, artifactString); } private boolean containsIgnoreCase(List strings, String toFind) { if (strings == null) { return false; } for (String s : strings) { if (toFind.equalsIgnoreCase(s)) { return true; } } return false; } private Artifact findArtifactWithFile(Set artifacts, File file) { for (Artifact artifact : artifacts) { if (artifact.getFile() != null && artifact.getFile().equals(file)) { return artifact; } } return null; } }