blob: 7d107a85b817c2b9dc4a660e75f95e0770aeac50 [file] [log] [blame]
/*
* 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.
*/
package org.apache.felix.bundleplugin;
import java.io.File;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.MojoExecutionException;
import aQute.lib.osgi.Analyzer;
import aQute.lib.osgi.Instruction;
import aQute.lib.osgi.header.OSGiHeader;
/**
* Add BND directives to embed selected dependencies inside a bundle
*
* @author stuart.mcculloch@jayway.net (Stuart McCulloch)
*/
public class DependencyEmbedder
{
public static String EMBED_DEPENDENCY = "Embed-Dependency";
public static String EMBED_DIRECTORY = "Embed-Directory";
public static String EMBED_STRIP_GROUP = "Embed-StripGroup";
public static String EMBED_STRIP_VERSION = "Embed-StripVersion";
public static String EMBED_TRANSITIVE = "Embed-Transitive";
/**
* Dependency artifacts.
*/
private final Collection dependencyArtifacts;
/**
* Inlined artifacts.
*/
private final Collection inlinedArtifacts;
/**
* Embedded artifacts.
*/
private final Collection embeddedArtifacts;
public DependencyEmbedder(Collection dependencyArtifacts)
{
this.dependencyArtifacts = dependencyArtifacts;
this.inlinedArtifacts = new HashSet();
this.embeddedArtifacts = new HashSet();
}
public void processHeaders(Properties properties)
throws MojoExecutionException
{
this.inlinedArtifacts.clear();
this.embeddedArtifacts.clear();
String embedDependencyHeader = properties.getProperty(EMBED_DEPENDENCY);
if (null != embedDependencyHeader && embedDependencyHeader.length() > 0)
{
Map embedInstructions = OSGiHeader.parseHeader(embedDependencyHeader);
this.processEmbedInstructions(embedInstructions);
for (Iterator i = this.inlinedArtifacts.iterator(); i.hasNext();)
{
DependencyEmbedder.inlineDependency(properties, (Artifact)i.next());
}
for (Iterator i = this.embeddedArtifacts.iterator(); i.hasNext();)
{
DependencyEmbedder.embedDependency(properties, (Artifact)i.next());
}
}
}
protected static abstract class DependencyFilter
{
Instruction instruction;
String defaultValue;
public DependencyFilter(String expression)
{
this(expression, "");
}
public DependencyFilter(String expression, String defaultValue)
{
this.instruction = Instruction.getPattern(expression);
this.defaultValue = defaultValue;
}
public void filter(Collection dependencies)
{
for (Iterator i = dependencies.iterator(); i.hasNext();)
{
if (false == matches((Artifact)i.next()))
{
i.remove();
}
}
}
abstract boolean matches(Artifact dependency);
boolean matches(String text)
{
if (null == text)
{
text = defaultValue;
}
boolean result = this.instruction.matches(text);
return this.instruction.isNegated() ? !result : result;
}
}
protected void processEmbedInstructions(Map embedInstructions)
throws MojoExecutionException
{
DependencyFilter filter;
for (Iterator clauseIterator = embedInstructions.entrySet().iterator(); clauseIterator.hasNext();)
{
boolean inline = false;
// must use a fresh *modifiable* collection for each unique clause
Collection filteredDependencies = new HashSet(this.dependencyArtifacts);
// CLAUSE: REGEXP --> { ATTRIBUTE MAP }
Map.Entry clause = (Map.Entry)clauseIterator.next();
filter = new DependencyFilter((String)clause.getKey())
{
boolean matches(Artifact dependency)
{
return super.matches(dependency.getArtifactId());
}
};
// FILTER ON MAIN CLAUSE
filter.filter(filteredDependencies);
for (Iterator attrIterator = ((Map)clause.getValue()).entrySet().iterator(); attrIterator.hasNext();)
{
// ATTRIBUTE: KEY --> REGEXP
Map.Entry attr = (Map.Entry)attrIterator.next();
if ("groupId".equals(attr.getKey()))
{
filter = new DependencyFilter((String)attr.getValue())
{
boolean matches(Artifact dependency)
{
return super.matches(dependency.getGroupId());
}
};
}
else if ("artifactId".equals(attr.getKey()))
{
filter = new DependencyFilter((String)attr.getValue())
{
boolean matches(Artifact dependency)
{
return super.matches(dependency.getArtifactId());
}
};
}
else if ("version".equals(attr.getKey()))
{
filter = new DependencyFilter((String)attr.getValue())
{
boolean matches(Artifact dependency)
{
try
{
// use the symbolic version if available (ie. 1.0.0-SNAPSHOT)
return super.matches(dependency.getSelectedVersion().toString());
}
catch (Exception e)
{
return super.matches(dependency.getVersion());
}
}
};
}
else if ("scope".equals(attr.getKey()))
{
filter = new DependencyFilter((String)attr.getValue(), "compile")
{
boolean matches(Artifact dependency)
{
return super.matches(dependency.getScope());
}
};
}
else if ("type".equals(attr.getKey()))
{
filter = new DependencyFilter((String)attr.getValue(), "jar")
{
boolean matches(Artifact dependency)
{
return super.matches(dependency.getType());
}
};
}
else if ("classifier".equals(attr.getKey()))
{
filter = new DependencyFilter((String)attr.getValue())
{
boolean matches(Artifact dependency)
{
return super.matches(dependency.getClassifier());
}
};
}
else if ("optional".equals(attr.getKey()))
{
filter = new DependencyFilter((String)attr.getValue(), "false")
{
boolean matches(Artifact dependency)
{
return super.matches(""+dependency.isOptional());
}
};
}
else if ("inline".equals(attr.getKey()))
{
inline = Boolean.valueOf((String)attr.getValue()).booleanValue();
continue;
}
else
{
throw new MojoExecutionException("Unexpected attribute " + attr.getKey());
}
// FILTER ON EACH ATTRIBUTE
filter.filter(filteredDependencies);
}
if (inline)
{
this.inlinedArtifacts.addAll(filteredDependencies);
}
else
{
this.embeddedArtifacts.addAll(filteredDependencies);
}
}
// remove any inlined artifacts from the embedded list
this.embeddedArtifacts.removeAll(this.inlinedArtifacts);
}
public static void embedDependency(Properties properties, Artifact dependency)
{
File jarFile = dependency.getFile();
if (null != jarFile && jarFile.exists())
{
String bundleClassPath = properties.getProperty(Analyzer.BUNDLE_CLASSPATH);
String includeResource = properties.getProperty(Analyzer.INCLUDE_RESOURCE);
if (null == bundleClassPath)
{
bundleClassPath = ".,";
}
else if (bundleClassPath.length() > 0)
{
bundleClassPath += ",";
}
if (null == includeResource)
{
includeResource = "";
}
else if (includeResource.length() > 0)
{
includeResource += ",";
}
String embedDirectory = properties.getProperty(EMBED_DIRECTORY);
String embedStripGroup = properties.getProperty(EMBED_STRIP_GROUP);
String embedStripVersion = properties.getProperty(EMBED_STRIP_VERSION);
if ("".equals(embedDirectory) || ".".equals(embedDirectory))
{
embedDirectory = null;
}
if (false == Boolean.valueOf(embedStripGroup).booleanValue())
{
embedDirectory = new File(embedDirectory, dependency.getGroupId()).getPath();
}
File targetFile;
if (Boolean.valueOf(embedStripVersion).booleanValue())
{
targetFile = new File(embedDirectory, dependency.getArtifactId() + ".jar");
}
else
{
targetFile = new File(embedDirectory, jarFile.getName());
}
bundleClassPath += targetFile;
includeResource += targetFile + "=" + jarFile;
properties.setProperty(Analyzer.BUNDLE_CLASSPATH, bundleClassPath);
properties.setProperty(Analyzer.INCLUDE_RESOURCE, includeResource);
}
}
public static void inlineDependency(Properties properties, Artifact dependency)
{
File jarFile = dependency.getFile();
if (null != jarFile && jarFile.exists())
{
String includeResource = properties.getProperty(Analyzer.INCLUDE_RESOURCE);
if (null == includeResource)
{
includeResource = "";
}
else if (includeResource.length() > 0)
{
includeResource += ",";
}
includeResource += "@" + jarFile;
properties.setProperty(Analyzer.INCLUDE_RESOURCE, includeResource);
}
}
public Collection getInlinedArtifacts()
{
return this.inlinedArtifacts;
}
public Collection getEmbeddedArtifacts()
{
return this.embeddedArtifacts;
}
}