org.wisdom.maven.mojos.BundlePackagerMojo Maven / Gradle / Ivy
Show all versions of wisdom-maven-plugin Show documentation
/*
* #%L
* Wisdom-Framework
* %%
* Copyright (C) 2013 - 2014 Wisdom Framework
* %%
* 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.
* #L%
*/
package org.wisdom.maven.mojos;
import org.apache.commons.io.FileUtils;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.MojoExecutionException;
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.codehaus.plexus.archiver.AbstractArchiver;
import org.codehaus.plexus.archiver.tar.TarArchiver;
import org.codehaus.plexus.archiver.zip.ZipArchiver;
import org.wisdom.maven.ApplicationDistributionExtensions;
import org.wisdom.maven.Constants;
import org.wisdom.maven.WatchingException;
import org.wisdom.maven.osgi.BundlePackager;
import org.wisdom.maven.osgi.Reporter;
import org.wisdom.maven.utils.DefaultMaven2OsgiConverter;
import org.wisdom.maven.utils.PlexusLoggerWrapper;
import org.wisdom.maven.utils.WatcherUtils;
import java.io.File;
import java.io.IOException;
/**
* This mojo is responsible for the creation of the Wisdom application packages.
* Wisdom distinguishes two packages: the jar file, which actually is an OSGi bundle,
* and a zip file containing the whole server (including the jar file).
*
* The jar file is an OSGi bundle containing your Java classes and internal resources (from src/main/resources). By
* default, Wisdom packaging heuristics are applied, but you can customize the bundle packaging by providing the
* 'src/main/osgi/osgi.bnd' file. This file contains the BND instructions. If
* present heuristics are not used.
*
* The zip file contains a distributable zip file containing the whole server (including your application).
*
* In watch mode, only the jar files is re-created.
*/
@Mojo(name = "package", threadSafe = false,
requiresDependencyResolution = ResolutionScope.COMPILE,
requiresProject = true,
defaultPhase = LifecyclePhase.PACKAGE)
public class BundlePackagerMojo extends AbstractWisdomWatcherMojo implements Constants {
/**
* If set to {@literal true} disables the construction of the zip file containing the Wisdom distribution.
* This option is useful for components and services that are not 'complete' application just one brick that is
* used in another application.
*/
@Parameter(defaultValue = "false")
private boolean disableDistributionPackaging;
/**
* If set to {@literal false}, the distribution is packaged but not attached to the project. As a consequence it
* will neither be installed in the local repository, nor deploy to remove repository.
*
* If {@link #disableDistributionPackaging} is set to {@literal true}, this parameter is meaningless.
*/
@Parameter(defaultValue = "true")
private boolean attachDistribution;
/**
* If set to {@literal zip}, the distribution is packaged into a zip file.
*
* If set to {@literal targz}, the distribution is packaged into a tar.gz file.
*
* Currently supported : zip, targz
*/
@Parameter(defaultValue = "zip")
private ApplicationDistributionExtensions fileExtension;
/**
* Whether or not it should copy the created bundle to the wisdom directory in watch mode. Enabled by default. It
* can be useful to disable it if the project is a webjar and the 'bundle' should not be deployed.
*/
@Parameter(defaultValue = "true")
boolean deployBundleToWisdom;
/**
* Execute method creates application bundle. Also creates the application distribution if the
* {@link #wisdomDirectory} parameter is not set and if {@link #disableDistributionPackaging}
* is set to false.
*
* @throws MojoExecutionException if the bundle or the distribution cannot be created
* correctly, or if the resulting artifacts cannot be copied to their final destinations.
*/
@Override
public void execute() throws MojoExecutionException {
try {
createApplicationBundle();
if (!disableDistributionPackaging) {
if (wisdomDirectory != null) {
getLog().warn("Cannot create the distribution of " + project.getArtifactId()
+ " because it is using a remote Wisdom server (" + wisdomDirectory
.getAbsolutePath() + ").");
} else {
createApplicationDistribution();
}
} else {
getLog().debug("Creation of the zip file disabled");
}
} catch (Exception e) {
throw new MojoExecutionException("Cannot build wisdom application", e);
}
displayNonBundleLibraryWarning();
}
private void displayNonBundleLibraryWarning() {
File libs = new File(getWisdomRootDirectory(), "libs");
final String[] list = libs.list();
if (libs.isDirectory() && list.length != 0) {
StringBuilder buffer = new StringBuilder();
buffer.append("\n"
+ "||==== WARNING ====\n");
buffer.append(
"|| The current project contains non-bundle dependencies, \n" +
"|| these dependencies won't be copied in dependant project \n" +
"|| without being explicitly listed in the section of the pom.xml file:\n");
for (String file : list) {
buffer.append("|| * ").append(file).append("\n");
}
buffer.append("||=================");
getLog().warn(buffer.toString());
}
}
private void createApplicationBundle() throws IOException {
File finalFile = new File(this.buildDirectory, this.project.getArtifactId() + "-" + this.project
.getVersion() + ".jar");
BundlePackager.bundle(this.basedir, finalFile, new Reporter() {
@Override
public void error(String msg) {
getLog().error(msg);
}
@Override
public void warn(String msg) {
getLog().warn(msg);
}
});
// Declare the bundle as main project artifact.
Artifact mainArtifact = project.getArtifact();
mainArtifact.setFile(finalFile);
// Copy the build file to the application directory if enabled.
if (deployBundleToWisdom) {
deploy(finalFile);
} else {
getLog().info("Bundle not deployed to Wisdom - deployment disabled");
}
}
private void deploy(File bundle) throws IOException {
// The application bundle uses the Wisdom convention (bundle symbolic name - version.jar
File applicationBundle = new File(new File(getWisdomRootDirectory(), APPLICATION_DIR),
DefaultMaven2OsgiConverter.getBundleFileName(this.project));
// Write a small notice about the copy
getLog().info("Copying " + bundle.getName() + " to " + applicationBundle.getAbsolutePath());
FileUtils.copyFile(bundle, applicationBundle, true);
}
private void createApplicationDistribution() throws IOException {
File distFile = new File(this.buildDirectory, this.project.getArtifactId() + "-" + this.project
.getVersion() + "." + fileExtension.extensionName);
AbstractArchiver archiver;
if (fileExtension == ApplicationDistributionExtensions.zip) {
archiver = new ZipArchiver();
} else {
TarArchiver tarArchiver = new TarArchiver();
tarArchiver.setCompression(TarArchiver.TarCompressionMethod.gzip);
archiver = tarArchiver;
}
archiver.enableLogging(new PlexusLoggerWrapper(getLog()));
archiver.addDirectory(getWisdomRootDirectory(), new String[0], new String[]{
// Drop regular and test cache.
"*-cache/**",
"logs/**"});
archiver.setDestFile(distFile);
archiver.createArchive();
if (attachDistribution) {
projectHelper.attachArtifact(project, fileExtension.extensionName, distFile);
}
}
/**
* The bundle packaging has to be triggered when: a Java source file is modified,
* an internal resource is modified or the `osgi.bnd` file (containing BND instructions) is modified.
*
* @param file the file
* @return {@literal true} if an event on the given file should trigger the recreation of the bundle.
*/
@Override
public boolean accept(File file) {
return WatcherUtils.isInDirectory(file, WatcherUtils.getJavaSource(basedir))
|| WatcherUtils.isInDirectory(file, WatcherUtils.getResources(basedir))
|| file.getAbsolutePath().equals(new File(basedir, INSTRUCTIONS_FILE).getAbsolutePath());
}
/**
* On any change, we just repackage the bundle.
*
* @param file the created file.
* @return {@literal true} as the pipeline must continue its execution.
* @throws WatchingException if the bundle creation failed
*/
@Override
public boolean fileCreated(File file) throws WatchingException {
try {
createApplicationBundle();
} catch (Exception e) {
throw new WatchingException(e.getMessage(), file, e);
}
return true;
}
/**
* On any change, we just repackage the bundle.
*
* @param file the updated file.
* @return {@literal true} as the pipeline must continue its execution.
* @throws WatchingException if the bundle creation failed
*/
@Override
public boolean fileUpdated(File file) throws WatchingException {
return fileCreated(file);
}
/**
* On any change, we just repackage the bundle.
*
* @param file the deleted file.
* @return {@literal true} as the pipeline must continue its execution.
* @throws WatchingException if the bundle creation failed
*/
@Override
public boolean fileDeleted(File file) throws WatchingException {
return fileCreated(file);
}
}