/* * Fabric3 * Copyright (c) 2009-2015 Metaform Systems * * 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.fabric3.packager; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.Closeable; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Arrays; import java.util.Enumeration; import java.util.List; import java.util.jar.JarEntry; import java.util.jar.JarOutputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.apache.maven.model.Dependency; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.eclipse.aether.RepositorySystem; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.artifact.Artifact; import org.eclipse.aether.artifact.DefaultArtifact; import org.eclipse.aether.repository.RemoteRepository; import org.eclipse.aether.resolution.ArtifactRequest; import org.eclipse.aether.resolution.ArtifactResolutionException; import org.eclipse.aether.resolution.ArtifactResult; /** * Plugin that assembles a Fabric3 node runtime including extensions for deployment in WAR. * * @goal fabric3-packager * @phase generate-resources * @threadSafe */ @SuppressWarnings("JavaDoc") public class Fabric3PackagerMojo extends AbstractMojo { public static final String F3_ARTIFACT_ID = "org.fabric3"; public static final String F3_EXTENSIONS_JAR = "f3.extensions.jar"; private static final int BUFFER = 2048; /** * Directory where the app is built. * * @parameter property="project.build.directory" * @required */ public File buildDirectory; /** * WAR name. * * @parameter default-value="${project.build.finalName}" expression="${war.warName}" * @required */ public String warName; /** * The default version of the runtime to use. * * @parameter property="RELEASE" */ public String runtimeVersion; /** * Set of profiles for the runtime. * * @parameter */ public Dependency[] profiles = new Dependency[0]; /** * Set of extensions for the runtime. * * @parameter */ public Dependency[] extensions = new Dependency[0]; /** * @component */ public RepositorySystem repositorySystem; /** * The current repository/network configuration of Maven. * * @parameter default-value="${repositorySystemSession}" * @readonly */ public RepositorySystemSession session; /** * The project's remote repositories to use for the resolution of project dependencies. * * @parameter default-value="${project.remoteProjectRepositories}" * @readonly */ private List<RemoteRepository> projectRepositories; @SuppressWarnings("ResultOfMethodCallIgnored") public void execute() throws MojoExecutionException { addDefaultExtensions(); File libDirectory = new File(buildDirectory, warName + File.separator + "WEB-INF" + File.separator + "lib"); libDirectory.mkdirs(); File stagingDirectory = new File(buildDirectory, "f3"); stagingDirectory.mkdirs(); File extensionsDirectory = new File(stagingDirectory, "extensions"); extensionsDirectory.mkdir(); extractProfiles(stagingDirectory); resolveDependencies(extensions, extensionsDirectory); createExtensionsArchive(extensionsDirectory, libDirectory); Dependency[] dependencies = new Dependency[2]; dependencies[0] = new Dependency(); dependencies[0].setGroupId(F3_ARTIFACT_ID); dependencies[0].setArtifactId("fabric3-node"); dependencies[0].setVersion(runtimeVersion); dependencies[1] = new Dependency(); dependencies[1].setGroupId(F3_ARTIFACT_ID); dependencies[1].setArtifactId("fabric3-node-extensions"); dependencies[1].setVersion(runtimeVersion); resolveDependencies(dependencies, libDirectory); } private void addDefaultExtensions() { int length = extensions.length; extensions = Arrays.copyOf(extensions, length + 2); extensions[length] = new Dependency(); extensions[length].setGroupId(F3_ARTIFACT_ID); extensions[length].setArtifactId("fabric3-databinding-json"); extensions[length].setVersion(runtimeVersion); } /** * Resolves configured profiles and extracting their contents to the temporary extensions directory. * * @param extensionsDirectory the extensions directory * @throws MojoExecutionException if there is an error during extraction */ private void extractProfiles(File extensionsDirectory) throws MojoExecutionException { for (Dependency profile : profiles) { String groupId = profile.getGroupId(); String artifactId = profile.getArtifactId(); String version = profile.getVersion(); getLog().info("Resolving profile: " + groupId + ":" + artifactId); Artifact artifact = new DefaultArtifact(groupId, artifactId, "bin", "zip", version); try { ArtifactResult result = repositorySystem.resolveArtifact(session, new ArtifactRequest(artifact, projectRepositories, null)); File source = result.getArtifact().getFile(); extract(source, extensionsDirectory); } catch (ArtifactResolutionException e) { throw new MojoExecutionException(e.getMessage(), e); } } } /** * Resolves a dependency to the target directory. * * @param targetDirectory the target directory * @throws MojoExecutionException if there is an error during resolution */ private void resolveDependencies(Dependency[] dependencies, File targetDirectory) throws MojoExecutionException { for (Dependency extension : dependencies) { String groupId = extension.getGroupId(); String artifactId = extension.getArtifactId(); String version = extension.getVersion(); String type = extension.getType(); String classifier = extension.getClassifier(); getLog().info("Resolving dependency: " + groupId + ":" + artifactId); Artifact artifact = new DefaultArtifact(groupId, artifactId, classifier, type, version); ArtifactResult result; try { result = repositorySystem.resolveArtifact(session, new ArtifactRequest(artifact, projectRepositories, null)); } catch (ArtifactResolutionException e) { throw new MojoExecutionException(e.getMessage(), e); } File source = result.getArtifact().getFile(); InputStream sourceStream = null; OutputStream targetStream = null; try { sourceStream = new BufferedInputStream(new FileInputStream(source)); File targetFile = new File(targetDirectory, source.getName()); targetStream = new BufferedOutputStream(new FileOutputStream(targetFile)); copy(sourceStream, targetStream); } catch (IOException e) { throw new MojoExecutionException(e.getMessage(), e); } finally { close(targetStream); close(sourceStream); } } } /** * Extracts the contents of a zip file to a target directory. * * @param source the zip file * @param destination the target directory * @throws MojoExecutionException if there is an error during extraction */ @SuppressWarnings("ResultOfMethodCallIgnored") private void extract(File source, File destination) throws MojoExecutionException { ZipFile zipfile; try { zipfile = new ZipFile(source); } catch (IOException e) { throw new MojoExecutionException(e.getMessage(), e); } Enumeration enumeration = zipfile.entries(); while (enumeration.hasMoreElements()) { ZipEntry entry = (ZipEntry) enumeration.nextElement(); if (entry.isDirectory()) { new File(destination, entry.getName()).mkdirs(); } else { if (entry.getName().toUpperCase().endsWith(".MF")) { // ignore manifests continue; } InputStream sourceStream = null; OutputStream targetStream = null; try { sourceStream = new BufferedInputStream(zipfile.getInputStream(entry)); FileOutputStream fos = new FileOutputStream(new File(destination, entry.getName())); targetStream = new BufferedOutputStream(fos, BUFFER); copy(sourceStream, targetStream); targetStream.flush(); } catch (IOException e) { throw new MojoExecutionException(e.getMessage(), e); } finally { close(targetStream); close(sourceStream); } } } } private void createExtensionsArchive(File extensionsDirectory, File libDirectory) throws MojoExecutionException { JarOutputStream jarStream = null; try { File archive = new File(libDirectory, F3_EXTENSIONS_JAR); OutputStream os = new BufferedOutputStream(new FileOutputStream(archive)); jarStream = new JarOutputStream(os); for (File file : extensionsDirectory.listFiles()) { if (!file.getName().endsWith(".jar")) { continue; } JarEntry entry = new JarEntry(file.getName()); jarStream.putNextEntry(entry); copy(new FileInputStream(file), jarStream); } jarStream.flush(); } catch (IOException e) { throw new MojoExecutionException(e.getMessage(), e); } finally { close(jarStream); } } private int copy(InputStream input, OutputStream output) throws IOException { byte[] buffer = new byte[BUFFER]; int count = 0; int n; while (-1 != (n = input.read(buffer))) { output.write(buffer, 0, n); count += n; } return count; } private void close(Closeable closeable) { try { if (closeable != null) { closeable.close(); } } catch (IOException e) { getLog().error(e); } } }