All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.aries.plugin.eba.EbaMojo Maven / Gradle / Ivy

package org.apache.aries.plugin.eba;

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

import org.apache.maven.archiver.PomPropertiesUtil;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.resolver.filter.ScopeArtifactFilter;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.archiver.ArchiverException;
import org.codehaus.plexus.archiver.zip.ZipArchiver;
import org.codehaus.plexus.util.DirectoryScanner;
import org.codehaus.plexus.util.FileUtils;
import org.apache.maven.shared.osgi.DefaultMaven2OsgiConverter;
import org.apache.maven.shared.osgi.Maven2OsgiConverter;
import aQute.lib.osgi.Analyzer;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

/**
 * Builds Aries Enterprise Bundle Archive (eba) files.
 *
 * @version $Id: $
 * @goal eba
 * @phase package
 * @requiresDependencyResolution test
 */
public class EbaMojo
    extends AbstractMojo
{

    
	public static final String APPLICATION_MF_URI = "META-INF/APPLICATION.MF";

    private static final String[] DEFAULT_INCLUDES = {"**/**"};

    /**
     * Application manifest headers
     */
    private static final String MANIFEST_VERSION = "Manifest-Version";
    private static final String APPLICATION_MANIFESTVERSION = "Application-ManifestVersion";
    private static final String APPLICATION_SYMBOLICNAME = "Application-SymbolicName";
    private static final String APPLICATION_VERSION = "Application-Version";
    private static final String APPLICATION_NAME = "Application-Name";
    private static final String APPLICATION_DESCRIPTION = "Application-Description";
    private static final String APPLICATION_CONTENT = "Application-Content";
    private static final String APPLICATION_EXPORTSERVICE = "Application-ExportService";
    private static final String APPLICATION_IMPORTSERVICE = "Application-ImportService";
    private static final String APPLICATION_USEBUNDLE = "Use-Bundle";
    
    /**
     * Coverter for maven pom values to OSGi manifest values (pulled in from the maven-bundle-plugin)
     */
    private Maven2OsgiConverter maven2OsgiConverter = new DefaultMaven2OsgiConverter();
    
    /**
     * Single directory for extra files to include in the eba.
     *
     * @parameter expression="${basedir}/src/main/eba"
     * @required
     */
    private File ebaSourceDirectory;

    /**
     * The location of the APPLICATION.MF file to be used within the eba file.
     *
     * @parameter expression="${basedir}/src/main/eba/META-INF/APPLICATION.MF"
     */
    private File applicationManifestFile;

    /**
     * Specify if the generated jar file of this project should be
     * included in the eba file ; default is true.
     *
     * @parameter
     */
    private Boolean includeJar = Boolean.TRUE;

    /**
     * The location of the manifest file to be used within the eba file.
     *
     * @parameter expression="${basedir}/src/main/eba/META-INF/MANIFEST.MF"
     */
    private File manifestFile;

    /**
     * Directory that resources are copied to during the build.
     *
     * @parameter expression="${project.build.directory}/${project.build.finalName}"
     * @required
     */
    private String workDirectory;

    /**
     * Directory that remote-resources puts legal files.
     *
     * @parameter expression="${project.build.directory}/maven-shared-archive-resources"
     * @required
     */
    private String sharedResources;

    /**
     * The directory for the generated eba.
     *
     * @parameter expression="${project.build.directory}"
     * @required
     */
    private String outputDirectory;

    /**
     * The name of the eba file to generate.
     *
     * @parameter alias="ebaName" expression="${project.build.finalName}"
     * @required
     */
    private String finalName;

    /**
     * The maven project.
     *
     * @parameter expression="${project}"
     * @required
     * @readonly
     */
    private MavenProject project;

    /**
     * The Jar archiver.
     *
     * @component role="org.codehaus.plexus.archiver.Archiver" roleHint="zip"
     * @required
     */
    private ZipArchiver zipArchiver;

    /**
     * Whether to generate a manifest based on maven configuration.
     *
     * @parameter expression="${generateManifest}" default-value="false"
     */
    private boolean generateManifest;

    /**
     * Configuration for the plugin.
     *
     * @parameter
     */
    private Map instructions = new LinkedHashMap();;    
    
    /**
     * Adding pom.xml and pom.properties to the archive.
     *
     * @parameter expression="${addMavenDescriptor}" default-value="true"
     */
    private boolean addMavenDescriptor;

    /**
     * Include or not empty directories
     *
     * @parameter expression="${includeEmptyDirs}" default-value="true"
     */
    private boolean includeEmptyDirs;

    /**
     * Whether creating the archive should be forced.
     *
     * @parameter expression="${forceCreation}" default-value="false"
     */
    private boolean forceCreation;

    /**
     * Whether to follow transitive dependencies or use explicit dependencies.
     *
     * @parameter expression="${useTransitiveDependencies}" default-value="false"
     */
    private boolean useTransitiveDependencies;

    /**
     * Define which bundles to include in the archive.
     *   none - no bundles are included 
     *   applicationContent - direct dependencies go into the content
     *   all - direct and transitive dependencies go into the content 
     *
     * @parameter expression="${archiveContent}" default-value="applicationContent"
     */
    private String archiveContent;


    private File buildDir;


    public void execute()
        throws MojoExecutionException
    {
        getLog().debug( " ======= EbaMojo settings =======" );
        getLog().debug( "ebaSourceDirectory[" + ebaSourceDirectory + "]" );
        getLog().debug( "manifestFile[" + manifestFile + "]" );
        getLog().debug( "applicationManifestFile[" + applicationManifestFile + "]" );
        getLog().debug( "workDirectory[" + workDirectory + "]" );
        getLog().debug( "outputDirectory[" + outputDirectory + "]" );
        getLog().debug( "finalName[" + finalName + "]" );
        getLog().debug( "generateManifest[" + generateManifest + "]" );

        if (archiveContent == null) {
        	archiveContent = new String("applicationContent");
        }
        
        getLog().debug( "archiveContent[" + archiveContent + "]" );        
        getLog().info( "archiveContent[" + archiveContent + "]" );        
        
        zipArchiver.setIncludeEmptyDirs( includeEmptyDirs );
        zipArchiver.setCompress( true );
        zipArchiver.setForced( forceCreation );
        // Check if jar file is there and if requested, copy it
        try
        {
            if (includeJar.booleanValue()) {
                File generatedJarFile = new File( outputDirectory, finalName + ".jar" );
                if (generatedJarFile.exists()) {
                    getLog().info( "Including generated jar file["+generatedJarFile.getName()+"]");
                    zipArchiver.addFile(generatedJarFile, finalName + ".jar");
                }
            }
        }
        catch ( ArchiverException e )
        {
            throw new MojoExecutionException( "Error adding generated Jar file", e );

        }

        // Copy dependencies
        try
        {
            Set artifacts = null;
            if (useTransitiveDependencies) {
                // if use transitive is set (i.e. true) then we need to make sure archiveContent does not contradict (i.e. is set
                // to the same compatible value or is the default).
            	if ("none".equals(archiveContent)) {
                    throw new MojoExecutionException(" and  incompatibly configured.   is deprecated in favor of ." );            		
            	}
            	else {
                    artifacts = project.getArtifacts();            		
            	}
            } else {
            	// check that archiveContent is compatible
            	if ("applicationContent".equals(archiveContent)) {
                    artifacts = project.getDependencyArtifacts();            		
            	}
            	else {
                	// the only remaining options should be applicationContent="none"
                    getLog().info("archiveContent=none: application arvhive will not contain any bundles.");            		
            	}
            }
            if (artifacts != null) {
                for (Artifact artifact : artifacts) {

                    ScopeArtifactFilter filter = new ScopeArtifactFilter(Artifact.SCOPE_RUNTIME);
                    if (!artifact.isOptional() && filter.include(artifact)) {
                        getLog().info("Copying artifact[" + artifact.getGroupId() + ", " + artifact.getId() + ", " +
                                artifact.getScope() + "]");
                        zipArchiver.addFile(artifact.getFile(), artifact.getArtifactId() + "-" + artifact.getVersion() + "." + (artifact.getType() == null ? "jar" : artifact.getType()));
                    }
                }            	
            }
        }
        catch ( ArchiverException e )
        {
            throw new MojoExecutionException( "Error copying EBA dependencies", e );
        }

        // Copy source files
        try
        {
            File ebaSourceDir = ebaSourceDirectory;
            if ( ebaSourceDir.exists() )
            {
                getLog().info( "Copy eba resources to " + getBuildDir().getAbsolutePath() );

                DirectoryScanner scanner = new DirectoryScanner();
                scanner.setBasedir( ebaSourceDir.getAbsolutePath() );
                scanner.setIncludes( DEFAULT_INCLUDES );
                scanner.addDefaultExcludes();
                scanner.scan();

                String[] dirs = scanner.getIncludedDirectories();

                for ( int j = 0; j < dirs.length; j++ )
                {
                    new File( getBuildDir(), dirs[j] ).mkdirs();
                }

                String[] files = scanner.getIncludedFiles();

                for ( int j = 0; j < files.length; j++ )
                {
                    File targetFile = new File( getBuildDir(), files[j] );

                    targetFile.getParentFile().mkdirs();

                    File file = new File( ebaSourceDir, files[j] );
                    FileUtils.copyFileToDirectory( file, targetFile.getParentFile() );
                }
            }
        }
        catch ( Exception e )
        {
            throw new MojoExecutionException( "Error copying EBA resources", e );
        }

        // Include custom manifest if necessary
        try
        {
            if (!generateManifest) {
            	includeCustomApplicationManifestFile();
            }
        }
        catch ( IOException e )
        {
            throw new MojoExecutionException( "Error copying APPLICATION.MF file", e );
        }

		// Generate application manifest if requested
		if (generateManifest) {
			String fileName = new String(getBuildDir() + "/"
					+ APPLICATION_MF_URI);
			File appMfFile = new File(fileName);

			try {
				// Delete any old manifest
				if (appMfFile.exists()) {
					FileUtils.fileDelete(fileName);
				}

				appMfFile.getParentFile().mkdirs();
				if (appMfFile.createNewFile()) {
					writeApplicationManifest(fileName);
				}
			} catch (java.io.IOException e) {
				throw new MojoExecutionException(
						"Error generating APPLICATION.MF file: " + fileName, e);
			}
		}
        
        // Check if connector deployment descriptor is there
        File ddFile = new File( getBuildDir(), APPLICATION_MF_URI);
        if ( !ddFile.exists() )
        {
            getLog().warn(
                "Application manifest: " + ddFile.getAbsolutePath() + " does not exist." );
        }

        try
        {
            if (addMavenDescriptor) {
                if (project.getArtifact().isSnapshot()) {
                    project.setVersion(project.getArtifact().getVersion());
                }

                String groupId = project.getGroupId();

                String artifactId = project.getArtifactId();

                zipArchiver.addFile(project.getFile(), "META-INF/maven/" + groupId + "/" + artifactId + "/pom.xml");
                PomPropertiesUtil pomPropertiesUtil = new PomPropertiesUtil();
                File dir = new File(project.getBuild().getDirectory(), "maven-zip-plugin");
                File pomPropertiesFile = new File(dir, "pom.properties");
                pomPropertiesUtil.createPomProperties(project, zipArchiver, pomPropertiesFile, forceCreation);
            }
            File ebaFile = new File( outputDirectory, finalName + ".eba" );
            zipArchiver.setDestFile(ebaFile);

            File buildDir = getBuildDir();
            if (buildDir.isDirectory()) {
                zipArchiver.addDirectory(buildDir);
            }
            //include legal files if any
            File sharedResourcesDir = new File(sharedResources);
            if (sharedResourcesDir.isDirectory()) {
                zipArchiver.addDirectory(sharedResourcesDir);
            }
            zipArchiver.createArchive();

            project.getArtifact().setFile( ebaFile );
        }
        catch ( Exception e )
        {
            throw new MojoExecutionException( "Error assembling eba", e );
        }
    }

	private void writeApplicationManifest(String fileName)
			throws MojoExecutionException {
		try {
			// TODO: add support for dependency version ranges. Need to pick
			// them up from the pom and convert them to OSGi version ranges.
			FileUtils.fileAppend(fileName, MANIFEST_VERSION + ": " + "1" + "\n");
			FileUtils.fileAppend(fileName, APPLICATION_MANIFESTVERSION + ": " + "1" + "\n");
			FileUtils.fileAppend(fileName, APPLICATION_SYMBOLICNAME + ": "
					+ getApplicationSymbolicName(project.getArtifact()) + "\n");
			FileUtils.fileAppend(fileName, APPLICATION_VERSION + ": "
					+ getApplicationVersion() + "\n");
			FileUtils.fileAppend(fileName, APPLICATION_NAME + ": " + project.getName() + "\n");
			FileUtils.fileAppend(fileName, APPLICATION_DESCRIPTION + ": "
					+ project.getDescription() + "\n");

			// Write the APPLICATION-CONTENT
			// TODO: check that the dependencies are bundles (currently, the converter
			// will throw an exception)
			Set artifacts;
			if (useTransitiveDependencies) {
				artifacts = project.getArtifacts();
			} else {
				artifacts = project.getDependencyArtifacts();
			}
			artifacts = selectArtifacts(artifacts);
			Iterator iter = artifacts.iterator();

			FileUtils.fileAppend(fileName, APPLICATION_CONTENT + ": ");
			if (iter.hasNext()) {
				Artifact artifact = iter.next();
				FileUtils.fileAppend(fileName, maven2OsgiConverter
						.getBundleSymbolicName(artifact)
						+ ";version=\""
						+ Analyzer.cleanupVersion(artifact.getVersion())
//						+ maven2OsgiConverter.getVersion(artifact.getVersion())
						+ "\"");
			}
			while (iter.hasNext()) {
				Artifact artifact = iter.next();
				FileUtils.fileAppend(fileName, ",\n "
						+ maven2OsgiConverter.getBundleSymbolicName(artifact)
						+ ";version=\""
						+ Analyzer.cleanupVersion(artifact.getVersion())
//						+ maven2OsgiConverter.getVersion(artifact.getVersion())
						+ "\"");
			}

			FileUtils.fileAppend(fileName, "\n");

			// Add any service imports or exports
			if (instructions.containsKey(APPLICATION_EXPORTSERVICE)) {
				FileUtils.fileAppend(fileName, APPLICATION_EXPORTSERVICE + ": "
						+ instructions.get(APPLICATION_EXPORTSERVICE) + "\n");
			}
			if (instructions.containsKey(APPLICATION_IMPORTSERVICE)) {
				FileUtils.fileAppend(fileName, APPLICATION_IMPORTSERVICE + ": "
						+ instructions.get(APPLICATION_IMPORTSERVICE) + "\n");
			}
			if (instructions.containsKey(APPLICATION_USEBUNDLE)) {
				FileUtils.fileAppend(fileName, APPLICATION_USEBUNDLE + ": "
						+ instructions.get(APPLICATION_USEBUNDLE) + "\n");
			}
                        // Add any use bundle entry

		} catch (Exception e) {
			throw new MojoExecutionException(
					"Error writing dependencies into APPLICATION.MF", e);
		}

	}
    
    // The maven2OsgiConverter assumes the artifact is a jar so we need our own
	// This uses the same fallback scheme as the converter
    private String getApplicationSymbolicName(Artifact artifact) {
		if (instructions.containsKey(APPLICATION_SYMBOLICNAME)) {
			return instructions.get(APPLICATION_SYMBOLICNAME).toString();
		}
    	return artifact.getGroupId() + "." + artifact.getArtifactId();
    }
    
    private String getApplicationVersion() {
        if (instructions.containsKey(APPLICATION_VERSION)) {
            return instructions.get(APPLICATION_VERSION).toString();
        }
        return aQute.lib.osgi.Analyzer.cleanupVersion(project.getVersion());
    }
    
    protected File getBuildDir()
    {
        if ( buildDir == null )
        {
            buildDir = new File( workDirectory );
        }
        return buildDir;
    }

    private void includeCustomApplicationManifestFile()
        throws IOException
    {
        if (applicationManifestFile == null) {
            throw new NullPointerException("Application manifest file location not set.  Use true if you want it to be generated.");
        }
        File appMfFile = applicationManifestFile;
        if (appMfFile.exists()) {
            getLog().info( "Using APPLICATION.MF "+ applicationManifestFile);
            File metaInfDir = new File(getBuildDir(), "META-INF");
            FileUtils.copyFileToDirectory( appMfFile, metaInfDir);
        }
    }
    
    /**
     * Return artifacts in 'compile' or 'runtime' scope only.   
     */
    private Set selectArtifacts(Set artifacts) 
    {
        Set selected = new LinkedHashSet();
        for (Artifact artifact : artifacts) {
            String scope = artifact.getScope();
            if (scope == null 
                || Artifact.SCOPE_COMPILE.equals(scope)
                || Artifact.SCOPE_RUNTIME.equals(scope)) {
                selected.add(artifact);
            }
        }
        return selected;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy