Develop bootstrap maven plugin
Develop a maven plugin that can be used to package executable jar/war archives. The plugin is intended to be used as a drop-in replacement for the standard maven-jar-plugin. To use the plugin declare it with <extensions>true</extensions> then set the project type to 'executable-jar' or 'executable-war'. Configuration options for 'executable-war' generation are intentionally much more limited then the standard maven-war-plugin (for example overlays are not supported). It is anticipated that builds requiring complex configuration will continue to use the standard plugin in combination with a custom assembly. Issue: #52091115pull/7/head
parent
898bfe82bb
commit
19b392bb3d
@ -0,0 +1,136 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.bootstrap</groupId>
|
||||||
|
<artifactId>spring-bootstrap-parent</artifactId>
|
||||||
|
<version>0.5.0.BUILD-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<artifactId>spring-bootstrap-maven-plugin</artifactId>
|
||||||
|
<packaging>maven-plugin</packaging>
|
||||||
|
<properties>
|
||||||
|
<mavenVersion>3.0.5</mavenVersion>
|
||||||
|
</properties>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<archive>
|
||||||
|
<manifest>
|
||||||
|
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
|
||||||
|
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
|
||||||
|
</manifest>
|
||||||
|
</archive>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-plugin-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<goalPrefix>configurator</goalPrefix>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>default-descriptor</id>
|
||||||
|
<goals>
|
||||||
|
<goal>descriptor</goal>
|
||||||
|
</goals>
|
||||||
|
<phase>process-classes</phase>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>help-descriptor</id>
|
||||||
|
<goals>
|
||||||
|
<goal>helpmojo</goal>
|
||||||
|
</goals>
|
||||||
|
<phase>process-classes</phase>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-invoker-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<cloneProjectsTo>${project.build.directory}/it</cloneProjectsTo>
|
||||||
|
<settingsFile>src/it/settings.xml</settingsFile>
|
||||||
|
<localRepositoryPath>${project.build.directory}/local-repo</localRepositoryPath>
|
||||||
|
<postBuildHookScript>verify</postBuildHookScript>
|
||||||
|
<addTestClassPath>true</addTestClassPath>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>integration-test</id>
|
||||||
|
<goals>
|
||||||
|
<goal>install</goal>
|
||||||
|
<goal>run</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.maven</groupId>
|
||||||
|
<artifactId>maven-plugin-api</artifactId>
|
||||||
|
<version>${mavenVersion}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.maven</groupId>
|
||||||
|
<artifactId>maven-artifact</artifactId>
|
||||||
|
<version>${mavenVersion}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.maven</groupId>
|
||||||
|
<artifactId>maven-model</artifactId>
|
||||||
|
<version>${mavenVersion}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.maven</groupId>
|
||||||
|
<artifactId>maven-core</artifactId>
|
||||||
|
<version>${mavenVersion}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.maven</groupId>
|
||||||
|
<artifactId>maven-settings</artifactId>
|
||||||
|
<version>${mavenVersion}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.maven.plugin-tools</groupId>
|
||||||
|
<artifactId>maven-plugin-annotations</artifactId>
|
||||||
|
<version>3.2</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.maven</groupId>
|
||||||
|
<artifactId>maven-archiver</artifactId>
|
||||||
|
<version>2.5</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.ow2.asm</groupId>
|
||||||
|
<artifactId>asm</artifactId>
|
||||||
|
<version>4.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.codehaus.plexus</groupId>
|
||||||
|
<artifactId>plexus-archiver</artifactId>
|
||||||
|
<version>2.2</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.codehaus.plexus</groupId>
|
||||||
|
<artifactId>plexus-container-default</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.codehaus.plexus</groupId>
|
||||||
|
<artifactId>plexus-component-api</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>${project.groupId}</groupId>
|
||||||
|
<artifactId>spring-bootstrap-launcher</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>org.springframework.bootstrap.maven.it</groupId>
|
||||||
|
<artifactId>executable-jar</artifactId>
|
||||||
|
<version>0.0.1.BUILD-SNAPSHOT</version>
|
||||||
|
<packaging>executable-jar</packaging>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>@project.groupId@</groupId>
|
||||||
|
<artifactId>@project.artifactId@</artifactId>
|
||||||
|
<version>@project.version@</version>
|
||||||
|
<extensions>true</extensions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>@project.groupId@</groupId>
|
||||||
|
<artifactId>spring-bootstrap</artifactId>
|
||||||
|
<version>@project.version@</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.servlet</groupId>
|
||||||
|
<artifactId>javax.servlet-api</artifactId>
|
||||||
|
<version>3.0.1</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
@ -0,0 +1,8 @@
|
|||||||
|
package org.test;
|
||||||
|
|
||||||
|
public class SampleApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
import java.io.*;
|
||||||
|
import org.springframework.bootstrap.maven.*;
|
||||||
|
|
||||||
|
Verify.verifyJar(
|
||||||
|
new File( basedir, "target/executable-jar-0.0.1.BUILD-SNAPSHOT.jar" )
|
||||||
|
);
|
||||||
|
|
@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>org.springframework.bootstrap.maven.it</groupId>
|
||||||
|
<artifactId>executable-war</artifactId>
|
||||||
|
<version>0.0.1.BUILD-SNAPSHOT</version>
|
||||||
|
<packaging>executable-war</packaging>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>@project.groupId@</groupId>
|
||||||
|
<artifactId>@project.artifactId@</artifactId>
|
||||||
|
<version>@project.version@</version>
|
||||||
|
<extensions>true</extensions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>@project.groupId@</groupId>
|
||||||
|
<artifactId>spring-bootstrap</artifactId>
|
||||||
|
<version>@project.version@</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.servlet</groupId>
|
||||||
|
<artifactId>javax.servlet-api</artifactId>
|
||||||
|
<version>3.0.1</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
@ -0,0 +1,8 @@
|
|||||||
|
package org.test;
|
||||||
|
|
||||||
|
public class SampleApplication {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
<html></html>
|
@ -0,0 +1,7 @@
|
|||||||
|
import java.io.*;
|
||||||
|
import org.springframework.bootstrap.maven.*;
|
||||||
|
|
||||||
|
Verify.verifyWar(
|
||||||
|
new File( basedir, "target/executable-war-0.0.1.BUILD-SNAPSHOT.war" )
|
||||||
|
);
|
||||||
|
|
@ -0,0 +1,35 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<settings>
|
||||||
|
<profiles>
|
||||||
|
<profile>
|
||||||
|
<id>it-repo</id>
|
||||||
|
<activation>
|
||||||
|
<activeByDefault>true</activeByDefault>
|
||||||
|
</activation>
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>local.central</id>
|
||||||
|
<url>@localRepositoryUrl@</url>
|
||||||
|
<releases>
|
||||||
|
<enabled>true</enabled>
|
||||||
|
</releases>
|
||||||
|
<snapshots>
|
||||||
|
<enabled>true</enabled>
|
||||||
|
</snapshots>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
<pluginRepositories>
|
||||||
|
<pluginRepository>
|
||||||
|
<id>local.central</id>
|
||||||
|
<url>@localRepositoryUrl@</url>
|
||||||
|
<releases>
|
||||||
|
<enabled>true</enabled>
|
||||||
|
</releases>
|
||||||
|
<snapshots>
|
||||||
|
<enabled>true</enabled>
|
||||||
|
</snapshots>
|
||||||
|
</pluginRepository>
|
||||||
|
</pluginRepositories>
|
||||||
|
</profile>
|
||||||
|
</profiles>
|
||||||
|
</settings>
|
@ -0,0 +1,318 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2013 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.bootstrap.maven;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.maven.archiver.MavenArchiveConfiguration;
|
||||||
|
import org.apache.maven.archiver.MavenArchiver;
|
||||||
|
import org.apache.maven.artifact.Artifact;
|
||||||
|
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.Parameter;
|
||||||
|
import org.apache.maven.project.MavenProject;
|
||||||
|
import org.apache.maven.project.MavenProjectHelper;
|
||||||
|
import org.codehaus.plexus.archiver.Archiver;
|
||||||
|
import org.codehaus.plexus.archiver.jar.JarArchiver;
|
||||||
|
import org.codehaus.plexus.archiver.zip.ZipEntry;
|
||||||
|
import org.codehaus.plexus.archiver.zip.ZipFile;
|
||||||
|
import org.codehaus.plexus.archiver.zip.ZipResource;
|
||||||
|
import org.sonatype.aether.RepositorySystem;
|
||||||
|
import org.sonatype.aether.RepositorySystemSession;
|
||||||
|
import org.sonatype.aether.repository.RemoteRepository;
|
||||||
|
import org.sonatype.aether.resolution.ArtifactRequest;
|
||||||
|
import org.sonatype.aether.resolution.ArtifactResult;
|
||||||
|
import org.sonatype.aether.util.artifact.DefaultArtifact;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract base of MOJOs that package executable archives.
|
||||||
|
*
|
||||||
|
* @author Phillip Webb
|
||||||
|
*/
|
||||||
|
public abstract class AbstractExecutableArchiveMojo extends AbstractMojo {
|
||||||
|
|
||||||
|
private static final String[] DEFAULT_EXCLUDES = new String[] { "**/package.html" };
|
||||||
|
|
||||||
|
private static final String[] DEFAULT_INCLUDES = new String[] { "**/**" };
|
||||||
|
|
||||||
|
private static final String MAIN_CLASS_ATTRIBUTE = "Main-Class";
|
||||||
|
|
||||||
|
private static final String START_CLASS_ATTRIBUTE = "Start-Class";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Archiver used to create a JAR file.
|
||||||
|
*/
|
||||||
|
@Component(role = Archiver.class, hint = "jar")
|
||||||
|
private JarArchiver jarArchiver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maven project helper utils.
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
private MavenProjectHelper projectHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Aether repository system used to download artifacts.
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
private RepositorySystem repositorySystem;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Maven project.
|
||||||
|
*/
|
||||||
|
@Parameter(defaultValue = "${project}", readonly = true, required = true)
|
||||||
|
private MavenProject project;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Maven session.
|
||||||
|
*/
|
||||||
|
@Parameter(defaultValue = "${session}", readonly = true, required = true)
|
||||||
|
private MavenSession session;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Directory containing the generated archive.
|
||||||
|
*/
|
||||||
|
@Parameter(defaultValue = "${project.build.directory}", required = true)
|
||||||
|
private File outputDirectory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the generated archive.
|
||||||
|
*/
|
||||||
|
@Parameter(defaultValue = "${project.build.finalName}", required = true)
|
||||||
|
private String finalName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the main class. If not specified the first compiled class found that
|
||||||
|
* contains a 'main' method will be used.
|
||||||
|
*/
|
||||||
|
@Parameter
|
||||||
|
private String mainClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Classifier to add to the artifact generated. If given, the artifact will be
|
||||||
|
* attached. If this is not given,it will merely be written to the output directory
|
||||||
|
* according to the finalName.
|
||||||
|
*/
|
||||||
|
@Parameter
|
||||||
|
private String classifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of files to include. Specified as fileset patterns which are relative to the
|
||||||
|
* input directory whose contents is being packaged into the archive.
|
||||||
|
*/
|
||||||
|
@Parameter
|
||||||
|
private String[] includes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of files to exclude. Specified as fileset patterns which are relative to the
|
||||||
|
* input directory whose contents is being packaged into the archive.
|
||||||
|
*/
|
||||||
|
@Parameter
|
||||||
|
private String[] excludes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Directory containing the classes and resource files that should be packaged into
|
||||||
|
* the archive.
|
||||||
|
*/
|
||||||
|
@Parameter(defaultValue = "${project.build.outputDirectory}", required = true)
|
||||||
|
private File classesDirectrory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether creating the archive should be forced.
|
||||||
|
*/
|
||||||
|
@Parameter(property = "archive.forceCreation", defaultValue = "false")
|
||||||
|
private boolean forceCreation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current repository/network configuration of Maven.
|
||||||
|
*/
|
||||||
|
@Parameter(defaultValue = "${repositorySystemSession}", readonly = true)
|
||||||
|
private RepositorySystemSession repositorySystemSession;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type as defined in plexus components.xml
|
||||||
|
*/
|
||||||
|
protected abstract String getType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the file extension for the archive (e.g. 'jar').
|
||||||
|
*/
|
||||||
|
protected abstract String getExtension();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the destination of an {@link Artifact}.
|
||||||
|
* @param artifact the artifact
|
||||||
|
* @return the destination or {@code null} to exclude
|
||||||
|
*/
|
||||||
|
protected abstract String getArtifactDestination(Artifact artifact);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the launcher class that will be used.
|
||||||
|
*/
|
||||||
|
protected abstract String getLauncherClass();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute() throws MojoExecutionException, MojoFailureException {
|
||||||
|
File archiveFile = createArchive();
|
||||||
|
if (this.classifier == null || this.classifier.isEmpty()) {
|
||||||
|
this.project.getArtifact().setFile(archiveFile);
|
||||||
|
} else {
|
||||||
|
this.projectHelper.attachArtifact(this.project, getType(), this.classifier,
|
||||||
|
archiveFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private File createArchive() throws MojoExecutionException {
|
||||||
|
File archiveFile = getTargetFile();
|
||||||
|
MavenArchiver archiver = new MavenArchiver();
|
||||||
|
customizeArchiveConfiguration();
|
||||||
|
|
||||||
|
archiver.setArchiver(this.jarArchiver);
|
||||||
|
archiver.setOutputFile(archiveFile);
|
||||||
|
archiver.getArchiver().setRecompressAddedZips(false);
|
||||||
|
|
||||||
|
try {
|
||||||
|
addContent(archiver);
|
||||||
|
addLibs(archiver);
|
||||||
|
ZipFile zipFile = addLauncherClasses(archiver);
|
||||||
|
try {
|
||||||
|
archiver.createArchive(this.session, this.project, this.archive);
|
||||||
|
return archiveFile;
|
||||||
|
} finally {
|
||||||
|
zipFile.close();
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new MojoExecutionException("Error assembling archive", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private File getTargetFile() {
|
||||||
|
String classifier = (this.classifier == null ? "" : this.classifier.trim());
|
||||||
|
if (classifier.length() > 0 && !classifier.startsWith("-")) {
|
||||||
|
classifier = "-" + classifier;
|
||||||
|
}
|
||||||
|
return new File(this.outputDirectory, this.finalName + classifier + "."
|
||||||
|
+ getExtension());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void customizeArchiveConfiguration() throws MojoExecutionException {
|
||||||
|
this.archive.setForced(this.forceCreation);
|
||||||
|
String mainClass = this.mainClass;
|
||||||
|
if (mainClass == null) {
|
||||||
|
mainClass = this.archive.getManifestEntries().get(MAIN_CLASS_ATTRIBUTE);
|
||||||
|
}
|
||||||
|
if (mainClass == null) {
|
||||||
|
mainClass = MainClassFinder.findMainClass(this.classesDirectrory);
|
||||||
|
}
|
||||||
|
if (mainClass == null) {
|
||||||
|
throw new MojoExecutionException("Unable to find a suitable main class, "
|
||||||
|
+ "please add a 'mainClass' property");
|
||||||
|
}
|
||||||
|
this.archive.getManifestEntries().put(MAIN_CLASS_ATTRIBUTE, getLauncherClass());
|
||||||
|
this.archive.getManifestEntries().put(START_CLASS_ATTRIBUTE, mainClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void addContent(MavenArchiver archiver) {
|
||||||
|
if (this.classesDirectrory.exists()) {
|
||||||
|
archiver.getArchiver().addDirectory(this.classesDirectrory,
|
||||||
|
getClassesDirectoryPrefix(), getIncludes(), getExcludes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getClassesDirectoryPrefix() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final String[] getIncludes() {
|
||||||
|
if (this.includes != null && this.includes.length > 0) {
|
||||||
|
return this.includes;
|
||||||
|
}
|
||||||
|
return DEFAULT_INCLUDES;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final String[] getExcludes() {
|
||||||
|
if (this.excludes != null && this.excludes.length > 0) {
|
||||||
|
return this.excludes;
|
||||||
|
}
|
||||||
|
return DEFAULT_EXCLUDES;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addLibs(MavenArchiver archiver) {
|
||||||
|
for (Artifact artifact : this.project.getArtifacts()) {
|
||||||
|
if (artifact.getFile() != null) {
|
||||||
|
String dir = getArtifactDestination(artifact);
|
||||||
|
if (dir != null) {
|
||||||
|
archiver.getArchiver().addFile(artifact.getFile(),
|
||||||
|
dir + artifact.getFile().getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ZipFile addLauncherClasses(MavenArchiver archiver)
|
||||||
|
throws MojoExecutionException {
|
||||||
|
try {
|
||||||
|
ArtifactRequest request = new ArtifactRequest();
|
||||||
|
String version = getClass().getPackage().getImplementationVersion();
|
||||||
|
request.setArtifact(new DefaultArtifact(
|
||||||
|
"org.springframework.bootstrap:spring-bootstrap-launcher:" + version));
|
||||||
|
List<RemoteRepository> repositories = new ArrayList<RemoteRepository>();
|
||||||
|
repositories.addAll(this.project.getRemotePluginRepositories());
|
||||||
|
repositories.addAll(this.project.getRemoteProjectRepositories());
|
||||||
|
ArtifactResult result = this.repositorySystem.resolveArtifact(
|
||||||
|
this.repositorySystemSession, request);
|
||||||
|
if (result.getArtifact() == null) {
|
||||||
|
throw new MojoExecutionException("Unable to resolve launcher classes");
|
||||||
|
}
|
||||||
|
return addLauncherClasses(archiver, result.getArtifact().getFile());
|
||||||
|
} catch (Exception ex) {
|
||||||
|
if (ex instanceof MojoExecutionException) {
|
||||||
|
throw (MojoExecutionException) ex;
|
||||||
|
}
|
||||||
|
throw new MojoExecutionException("Unable to add launcher classes", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ZipFile addLauncherClasses(MavenArchiver archiver, File file)
|
||||||
|
throws IOException {
|
||||||
|
ZipFile zipFile = new ZipFile(file);
|
||||||
|
Enumeration<? extends ZipEntry> entries = zipFile.getEntries();
|
||||||
|
while (entries.hasMoreElements()) {
|
||||||
|
ZipEntry entry = entries.nextElement();
|
||||||
|
if (!entry.isDirectory() && !entry.getName().startsWith("/META-INF")) {
|
||||||
|
ZipResource zipResource = new ZipResource(zipFile, entry);
|
||||||
|
archiver.getArchiver().addResource(zipResource, entry.getName(), -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return zipFile;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2013 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.bootstrap.maven;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.maven.artifact.Artifact;
|
||||||
|
import org.apache.maven.plugins.annotations.LifecyclePhase;
|
||||||
|
import org.apache.maven.plugins.annotations.Mojo;
|
||||||
|
import org.apache.maven.plugins.annotations.ResolutionScope;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build an executable JAR file.
|
||||||
|
*
|
||||||
|
* @author Phillip Webb
|
||||||
|
*/
|
||||||
|
@Mojo(name = "executable-jar", defaultPhase = LifecyclePhase.PACKAGE, requiresProject = true, threadSafe = true, requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME, requiresDependencyCollection = ResolutionScope.COMPILE_PLUS_RUNTIME)
|
||||||
|
public class ExecutableJarMojo extends AbstractExecutableArchiveMojo {
|
||||||
|
|
||||||
|
private static final Set<String> LIB_SCOPES = new HashSet<String>(Arrays.asList(
|
||||||
|
"compile", "runtime", "provided"));
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getType() {
|
||||||
|
return "executable-jar";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getExtension() {
|
||||||
|
return "jar";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getArtifactDestination(Artifact artifact) {
|
||||||
|
if (LIB_SCOPES.contains(artifact.getScope())) {
|
||||||
|
return "lib/";
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getLauncherClass() {
|
||||||
|
return "org.springframework.bootstrap.launcher.JarLauncher";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2013 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.bootstrap.maven;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.maven.archiver.MavenArchiver;
|
||||||
|
import org.apache.maven.artifact.Artifact;
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build an executable WAR file.
|
||||||
|
*
|
||||||
|
* @author Phillip Webb
|
||||||
|
*/
|
||||||
|
@Mojo(name = "executable-war", defaultPhase = LifecyclePhase.PACKAGE, requiresProject = true, threadSafe = true, requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME, requiresDependencyCollection = ResolutionScope.COMPILE_PLUS_RUNTIME)
|
||||||
|
public class ExecutableWarMojo extends AbstractExecutableArchiveMojo {
|
||||||
|
|
||||||
|
// FIXME classes in the wrong place
|
||||||
|
|
||||||
|
private static final Map<String, String> SCOPE_DESTINATIONS;
|
||||||
|
static {
|
||||||
|
Map<String, String> map = new HashMap<String, String>();
|
||||||
|
map.put("compile", "WEB-INF/lib/");
|
||||||
|
map.put("runtime", "WEB-INF/lib/");
|
||||||
|
map.put("provided", "WEB-INF/lib-provided/");
|
||||||
|
SCOPE_DESTINATIONS = Collections.unmodifiableMap(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Single directory for extra files to include in the WAR. This is where you place
|
||||||
|
* your JSP files.
|
||||||
|
*/
|
||||||
|
@Parameter(defaultValue = "${basedir}/src/main/webapp", required = true)
|
||||||
|
private File warSourceDirectory;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getType() {
|
||||||
|
return "executable-war";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getExtension() {
|
||||||
|
return "war";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getArtifactDestination(Artifact artifact) {
|
||||||
|
return SCOPE_DESTINATIONS.get(artifact.getScope());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getClassesDirectoryPrefix() {
|
||||||
|
return "WEB-INF/classes/";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void addContent(MavenArchiver archiver) {
|
||||||
|
super.addContent(archiver);
|
||||||
|
if (this.warSourceDirectory.exists()) {
|
||||||
|
archiver.getArchiver().addDirectory(this.warSourceDirectory, getIncludes(),
|
||||||
|
getExcludes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getLauncherClass() {
|
||||||
|
return "org.springframework.bootstrap.launcher.WarLauncher";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,156 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2013 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.bootstrap.maven;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileFilter;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.Deque;
|
||||||
|
|
||||||
|
import org.objectweb.asm.ClassReader;
|
||||||
|
import org.objectweb.asm.ClassVisitor;
|
||||||
|
import org.objectweb.asm.MethodVisitor;
|
||||||
|
import org.objectweb.asm.Opcodes;
|
||||||
|
import org.objectweb.asm.Type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds any class with a {@code public static main} method by performing a breadth first
|
||||||
|
* directory search.
|
||||||
|
*
|
||||||
|
* @author Phillip Webb
|
||||||
|
*/
|
||||||
|
class MainClassFinder {
|
||||||
|
|
||||||
|
private static final String DOT_CLASS = ".class";
|
||||||
|
|
||||||
|
private static final Type STRING_ARRAY_TYPE = Type.getType(String[].class);
|
||||||
|
|
||||||
|
private static final Type MAIN_METHOD_TYPE = Type.getMethodType(Type.VOID_TYPE,
|
||||||
|
STRING_ARRAY_TYPE);
|
||||||
|
|
||||||
|
private static final String MAIN_METHOD_NAME = "main";
|
||||||
|
|
||||||
|
private static final FileFilter CLASS_FILE_FILTER = new FileFilter() {
|
||||||
|
@Override
|
||||||
|
public boolean accept(File file) {
|
||||||
|
return (file.isFile() && file.getName().endsWith(DOT_CLASS));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final FileFilter PACKAGE_FOLDER_FILTER = new FileFilter() {
|
||||||
|
@Override
|
||||||
|
public boolean accept(File file) {
|
||||||
|
return file.isDirectory() && !file.getName().startsWith(".");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public static String findMainClass(File root) {
|
||||||
|
File mainClassFile = findMainClassFile(root);
|
||||||
|
if (mainClassFile == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String mainClass = mainClassFile.getAbsolutePath().substring(
|
||||||
|
root.getAbsolutePath().length() + 1);
|
||||||
|
mainClass = mainClass.replace('/', '.');
|
||||||
|
mainClass = mainClass.replace('\\', '.');
|
||||||
|
mainClass = mainClass.substring(0, mainClass.length() - DOT_CLASS.length());
|
||||||
|
return mainClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static File findMainClassFile(File root) {
|
||||||
|
Deque<File> stack = new ArrayDeque<File>();
|
||||||
|
stack.push(root);
|
||||||
|
while (!stack.isEmpty()) {
|
||||||
|
File file = stack.pop();
|
||||||
|
if (isMainClassFile(file)) {
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
pushAllSorted(stack, file.listFiles(PACKAGE_FOLDER_FILTER));
|
||||||
|
pushAllSorted(stack, file.listFiles(CLASS_FILE_FILTER));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isMainClassFile(File file) {
|
||||||
|
try {
|
||||||
|
InputStream inputStream = new BufferedInputStream(new FileInputStream(file));
|
||||||
|
try {
|
||||||
|
ClassReader classReader = new ClassReader(inputStream);
|
||||||
|
MainMethodFinder mainMethodFinder = new MainMethodFinder();
|
||||||
|
classReader.accept(mainMethodFinder, ClassReader.SKIP_CODE);
|
||||||
|
return mainMethodFinder.isFound();
|
||||||
|
} finally {
|
||||||
|
inputStream.close();
|
||||||
|
}
|
||||||
|
} catch (IOException ex) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void pushAllSorted(Deque<File> stack, File[] files) {
|
||||||
|
Arrays.sort(files, new Comparator<File>() {
|
||||||
|
@Override
|
||||||
|
public int compare(File o1, File o2) {
|
||||||
|
return o1.getName().compareTo(o2.getName());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
for (File file : files) {
|
||||||
|
stack.push(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class MainMethodFinder extends ClassVisitor {
|
||||||
|
|
||||||
|
private boolean found;
|
||||||
|
|
||||||
|
public MainMethodFinder() {
|
||||||
|
super(Opcodes.ASM4);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MethodVisitor visitMethod(int access, String name, String desc,
|
||||||
|
String signature, String[] exceptions) {
|
||||||
|
if (isAccess(access, Opcodes.ACC_PUBLIC, Opcodes.ACC_STATIC)
|
||||||
|
&& MAIN_METHOD_NAME.equals(name)
|
||||||
|
&& MAIN_METHOD_TYPE.getDescriptor().equals(desc)) {
|
||||||
|
this.found = true;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isAccess(int access, int... requiredOpsCodes) {
|
||||||
|
for (int requiredOpsCode : requiredOpsCodes) {
|
||||||
|
if ((access & requiredOpsCode) == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFound() {
|
||||||
|
return this.found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
<component-set>
|
||||||
|
<components>
|
||||||
|
<component>
|
||||||
|
<role>org.apache.maven.artifact.handler.ArtifactHandler</role>
|
||||||
|
<role-hint>executable-war</role-hint>
|
||||||
|
<implementation>org.apache.maven.artifact.handler.DefaultArtifactHandler
|
||||||
|
</implementation>
|
||||||
|
<configuration>
|
||||||
|
<type>executable-jar</type>
|
||||||
|
<extension>jar</extension>
|
||||||
|
<language>java</language>
|
||||||
|
<addedToClasspath>true</addedToClasspath>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
|
<component>
|
||||||
|
<role>org.apache.maven.lifecycle.mapping.LifecycleMapping</role>
|
||||||
|
<role-hint>executable-jar</role-hint>
|
||||||
|
<implementation>org.apache.maven.lifecycle.mapping.DefaultLifecycleMapping
|
||||||
|
</implementation>
|
||||||
|
<configuration>
|
||||||
|
<lifecycles>
|
||||||
|
<lifecycle>
|
||||||
|
<id>default</id>
|
||||||
|
<phases>
|
||||||
|
<process-resources>org.apache.maven.plugins:maven-resources-plugin:resources</process-resources>
|
||||||
|
<compile>org.apache.maven.plugins:maven-compiler-plugin:compile</compile>
|
||||||
|
<process-test-resources>org.apache.maven.plugins:maven-resources-plugin:testResources</process-test-resources>
|
||||||
|
<test-compile>org.apache.maven.plugins:maven-compiler-plugin:testCompile</test-compile>
|
||||||
|
<test>org.apache.maven.plugins:maven-surefire-plugin:test</test>
|
||||||
|
<package>org.springframework.bootstrap:spring-bootstrap-maven-plugin:executable-jar</package>
|
||||||
|
<install>org.apache.maven.plugins:maven-install-plugin:install</install>
|
||||||
|
<deploy>org.apache.maven.plugins:maven-deploy-plugin:deploy</deploy>
|
||||||
|
</phases>
|
||||||
|
</lifecycle>
|
||||||
|
</lifecycles>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
|
<component>
|
||||||
|
<role>org.apache.maven.artifact.handler.ArtifactHandler</role>
|
||||||
|
<role-hint>executable-war</role-hint>
|
||||||
|
<implementation>org.apache.maven.artifact.handler.DefaultArtifactHandler
|
||||||
|
</implementation>
|
||||||
|
<configuration>
|
||||||
|
<type>executable-war</type>
|
||||||
|
<extension>war</extension>
|
||||||
|
<language>java</language>
|
||||||
|
<addedToClasspath>true</addedToClasspath>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
|
<component>
|
||||||
|
<role>org.apache.maven.lifecycle.mapping.LifecycleMapping</role>
|
||||||
|
<role-hint>executable-war</role-hint>
|
||||||
|
<implementation>org.apache.maven.lifecycle.mapping.DefaultLifecycleMapping
|
||||||
|
</implementation>
|
||||||
|
<configuration>
|
||||||
|
<lifecycles>
|
||||||
|
<lifecycle>
|
||||||
|
<id>default</id>
|
||||||
|
<phases>
|
||||||
|
<process-resources>org.apache.maven.plugins:maven-resources-plugin:resources</process-resources>
|
||||||
|
<compile>org.apache.maven.plugins:maven-compiler-plugin:compile</compile>
|
||||||
|
<process-test-resources>org.apache.maven.plugins:maven-resources-plugin:testResources</process-test-resources>
|
||||||
|
<test-compile>org.apache.maven.plugins:maven-compiler-plugin:testCompile</test-compile>
|
||||||
|
<test>org.apache.maven.plugins:maven-surefire-plugin:test</test>
|
||||||
|
<package>org.springframework.bootstrap:spring-bootstrap-maven-plugin:executable-war</package>
|
||||||
|
<install>org.apache.maven.plugins:maven-install-plugin:install</install>
|
||||||
|
<deploy>org.apache.maven.plugins:maven-deploy-plugin:deploy</deploy>
|
||||||
|
</phases>
|
||||||
|
</lifecycle>
|
||||||
|
</lifecycles>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
|
</components>
|
||||||
|
</component-set>
|
@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2013 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.bootstrap.maven;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
import org.codehaus.plexus.util.IOUtil;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.rules.TemporaryFolder;
|
||||||
|
import org.springframework.bootstrap.maven.sample.ClassWithMainMethod;
|
||||||
|
import org.springframework.bootstrap.maven.sample.ClassWithoutMainMethod;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link MainClassFinder}.
|
||||||
|
*
|
||||||
|
* @author Phillip Webb
|
||||||
|
*/
|
||||||
|
public class MainClassFinderTests {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public TemporaryFolder temporaryFolder = new TemporaryFolder();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void findMainClass() throws Exception {
|
||||||
|
File expected = copyToTemp("b.class", ClassWithMainMethod.class);
|
||||||
|
copyToTemp("a.class", ClassWithoutMainMethod.class);
|
||||||
|
File actual = MainClassFinder.findMainClassFile(this.temporaryFolder.getRoot());
|
||||||
|
assertThat(actual, equalTo(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void findMainClassInSubFolder() throws Exception {
|
||||||
|
File expected = copyToTemp("a/b/c/d.class", ClassWithMainMethod.class);
|
||||||
|
copyToTemp("a/b/c/e.class", ClassWithoutMainMethod.class);
|
||||||
|
copyToTemp("a/b/f.class", ClassWithoutMainMethod.class);
|
||||||
|
File actual = MainClassFinder.findMainClassFile(this.temporaryFolder.getRoot());
|
||||||
|
assertThat(actual, equalTo(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void usesBreadthFirst() throws Exception {
|
||||||
|
File expected = copyToTemp("a/b.class", ClassWithMainMethod.class);
|
||||||
|
copyToTemp("a/b/c/e.class", ClassWithMainMethod.class);
|
||||||
|
File actual = MainClassFinder.findMainClassFile(this.temporaryFolder.getRoot());
|
||||||
|
assertThat(actual, equalTo(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void findsClassName() throws Exception {
|
||||||
|
copyToTemp("org/test/MyApp.class", ClassWithMainMethod.class);
|
||||||
|
assertThat(MainClassFinder.findMainClass(this.temporaryFolder.getRoot()),
|
||||||
|
equalTo("org.test.MyApp"));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private File copyToTemp(String filename, Class<?> classToCopy) throws IOException {
|
||||||
|
String[] paths = filename.split("\\/");
|
||||||
|
File file = this.temporaryFolder.getRoot();
|
||||||
|
for (String path : paths) {
|
||||||
|
file = new File(file, path);
|
||||||
|
}
|
||||||
|
file.getParentFile().mkdirs();
|
||||||
|
InputStream inputStream = getClass().getResourceAsStream(
|
||||||
|
"/" + classToCopy.getName().replace(".", "/") + ".class");
|
||||||
|
OutputStream outputStream = new FileOutputStream(file);
|
||||||
|
try {
|
||||||
|
IOUtil.copy(inputStream, outputStream);
|
||||||
|
} finally {
|
||||||
|
outputStream.close();
|
||||||
|
}
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,161 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2013 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.bootstrap.maven;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.jar.Manifest;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipFile;
|
||||||
|
|
||||||
|
import org.springframework.bootstrap.launcher.JarLauncher;
|
||||||
|
import org.springframework.bootstrap.launcher.WarLauncher;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verification utility for use with maven-invoker-plugin verification scripts.
|
||||||
|
*
|
||||||
|
* @author Phillip Webb
|
||||||
|
*/
|
||||||
|
public class Verify {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
try {
|
||||||
|
verifyJar(new File(
|
||||||
|
"/Users/pwebb/projects/spring/spring-bootstrap/code/spring-bootstrap-maven-plugin/target/it/executable-jar/target/executable-jar-0.0.1.BUILD-SNAPSHOT.jar"));
|
||||||
|
} catch (Exception ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void verifyJar(File file) throws Exception {
|
||||||
|
new JarArchiveVerification(file).verify();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void verifyWar(File file) throws Exception {
|
||||||
|
new WarArchiveVerification(file).verify();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static abstract class AbstractArchiveVerification {
|
||||||
|
|
||||||
|
private File file;
|
||||||
|
|
||||||
|
public AbstractArchiveVerification(File file) {
|
||||||
|
this.file = file;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void verify() throws Exception {
|
||||||
|
assertTrue("Archive missing", this.file.exists());
|
||||||
|
assertTrue("Archive not a file", this.file.isFile());
|
||||||
|
|
||||||
|
ZipFile zipFile = new ZipFile(this.file);
|
||||||
|
Enumeration<? extends ZipEntry> entries = zipFile.entries();
|
||||||
|
Map<String, ZipEntry> zipMap = new HashMap<String, ZipEntry>();
|
||||||
|
while (entries.hasMoreElements()) {
|
||||||
|
ZipEntry zipEntry = entries.nextElement();
|
||||||
|
zipMap.put(zipEntry.getName(), zipEntry);
|
||||||
|
}
|
||||||
|
verifyZipEntries(zipFile, zipMap);
|
||||||
|
zipFile.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void verifyZipEntries(ZipFile zipFile, Map<String, ZipEntry> entries)
|
||||||
|
throws Exception {
|
||||||
|
verifyManifest(zipFile, entries.get("META-INF/MANIFEST.MF"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void verifyManifest(ZipFile zipFile, ZipEntry zipEntry) throws Exception {
|
||||||
|
Manifest manifest = new Manifest(zipFile.getInputStream(zipEntry));
|
||||||
|
verifyManifest(manifest);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void verifyManifest(Manifest manifest) throws Exception;
|
||||||
|
|
||||||
|
protected final void assertHasEntryNameStartingWith(
|
||||||
|
Map<String, ZipEntry> entries, String value) {
|
||||||
|
for (String name : entries.keySet()) {
|
||||||
|
if (name.startsWith(value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IllegalStateException("Expected entry starting with " + value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class JarArchiveVerification extends AbstractArchiveVerification {
|
||||||
|
|
||||||
|
public JarArchiveVerification(File file) {
|
||||||
|
super(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void verifyZipEntries(ZipFile zipFile, Map<String, ZipEntry> entries)
|
||||||
|
throws Exception {
|
||||||
|
super.verifyZipEntries(zipFile, entries);
|
||||||
|
assertHasEntryNameStartingWith(entries, "lib/spring-bootstrap");
|
||||||
|
assertHasEntryNameStartingWith(entries, "lib/spring-core");
|
||||||
|
assertHasEntryNameStartingWith(entries, "lib/javax.servlet-api-3.0.1.jar");
|
||||||
|
assertTrue("Unpacked launcher classes", entries.containsKey("org/"
|
||||||
|
+ "springframework/bootstrap/launcher/JarLauncher.class"));
|
||||||
|
assertTrue("Own classes", entries.containsKey("org/"
|
||||||
|
+ "test/SampleApplication.class"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void verifyManifest(Manifest manifest) throws Exception {
|
||||||
|
assertEquals(JarLauncher.class.getName(), manifest.getMainAttributes()
|
||||||
|
.getValue("Main-Class"));
|
||||||
|
assertEquals("org.test.SampleApplication", manifest.getMainAttributes()
|
||||||
|
.getValue("Start-Class"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class WarArchiveVerification extends AbstractArchiveVerification {
|
||||||
|
|
||||||
|
public WarArchiveVerification(File file) {
|
||||||
|
super(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void verifyZipEntries(ZipFile zipFile, Map<String, ZipEntry> entries)
|
||||||
|
throws Exception {
|
||||||
|
super.verifyZipEntries(zipFile, entries);
|
||||||
|
assertHasEntryNameStartingWith(entries, "WEB-INF/lib/spring-bootstrap");
|
||||||
|
assertHasEntryNameStartingWith(entries, "WEB-INF/lib/spring-core");
|
||||||
|
assertHasEntryNameStartingWith(entries,
|
||||||
|
"WEB-INF/lib-provided/javax.servlet-api-3.0.1.jar");
|
||||||
|
assertTrue("Unpacked launcher classes", entries.containsKey("org/"
|
||||||
|
+ "springframework/bootstrap/launcher/JarLauncher.class"));
|
||||||
|
assertTrue("Own classes", entries.containsKey("WEB-INF/classes/org/"
|
||||||
|
+ "test/SampleApplication.class"));
|
||||||
|
assertTrue("Web content", entries.containsKey("index.html"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void verifyManifest(Manifest manifest) throws Exception {
|
||||||
|
assertEquals(WarLauncher.class.getName(), manifest.getMainAttributes()
|
||||||
|
.getValue("Main-Class"));
|
||||||
|
assertEquals("org.test.SampleApplication", manifest.getMainAttributes()
|
||||||
|
.getValue("Start-Class"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2013 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.bootstrap.maven.sample;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sample class with a main method.
|
||||||
|
*
|
||||||
|
* @author Phillip Webb
|
||||||
|
*/
|
||||||
|
public class ClassWithMainMethod {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2013 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.bootstrap.maven.sample;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sample class without a main method.
|
||||||
|
*
|
||||||
|
* @author Phillip Webb
|
||||||
|
*/
|
||||||
|
public class ClassWithoutMainMethod {
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue