/*
* Copyright 2011 Henry Coles
*
* 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.pitest.maven;
import java.io.IOException;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
import org.apache.maven.artifact.Artifact;
import org.pitest.functional.F;
import org.pitest.functional.FCollection;
import org.pitest.functional.predicate.Predicate;
import org.pitest.mutationtest.config.PluginServices;
import org.pitest.plugin.ClientClasspathPlugin;
import org.pitest.util.Log;
import org.pitest.util.PitError;
import org.pitest.util.StringUtil;
public class DependencyFilter implements Predicate<Artifact> {
private final Set<GroupIdPair> groups = new HashSet<GroupIdPair>();
public DependencyFilter(PluginServices plugins) {
final Iterable<? extends ClientClasspathPlugin> runtimePlugins = plugins
.findClientClasspathPlugins();
FCollection.mapTo(runtimePlugins, artifactToPair(), this.groups);
findVendorIdForGroups();
}
private static F<ClientClasspathPlugin, GroupIdPair> artifactToPair() {
return new F<ClientClasspathPlugin, GroupIdPair>() {
@Override
public GroupIdPair apply(final ClientClasspathPlugin a) {
final Package p = a.getClass().getPackage();
final GroupIdPair g = new GroupIdPair(p.getImplementationVendor(),
p.getImplementationTitle());
if (g.id == null) {
reportBadPlugin("title", a);
}
if (g.group == null) {
reportBadPlugin("vendor", a);
}
return g;
}
private void reportBadPlugin(final String missingProperty,
final ClientClasspathPlugin a) {
final Class<?> clss = a.getClass();
throw new PitError("No implementation " + missingProperty
+ " in manifest of plugin jar for " + clss + " in "
+ clss.getProtectionDomain().getCodeSource().getLocation());
}
};
}
/**
* Changes the (Implementation-Vendor,Implementation-Title) pairs
* by the corresponding (Implementation-Vendor-Id, Implementation-Title) pair
* when the Implementation-Vendor-Id is available.
* Targets the fact that, by default, project.groupId is assigned to Implementation-Vendor-Id
* and project.organization.name is assigned to Implementation-Vendor on the META-INF/MANIFEST.MF file.
*/
private void findVendorIdForGroups() {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
try {
//Checks every META-INF/MANIFEST.MF file found in the classpath
Enumeration<URL> urls = loader.getResources("META-INF/MANIFEST.MF");
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
Manifest manifest = new Manifest(url.openStream());
Attributes attributes = manifest.getMainAttributes();
String vendor = attributes.getValue("Implementation-Vendor");
String vendorId = attributes.getValue("Implementation-Vendor-Id");
String id = attributes.getValue("Implementation-Title");
if (StringUtil.isNullOrEmpty(vendor) || StringUtil.isNullOrEmpty(vendorId) || StringUtil.isNullOrEmpty(id)) {
continue;
}
GroupIdPair query = new GroupIdPair(vendor, id);
if (groups.contains(query)) {
groups.remove(query);
groups.add(new GroupIdPair(vendorId, id));
}
}
} catch (IOException exc) {
Log.getLogger().fine("An exception was thrown while looking for manifest files. Message: " + exc.getMessage());
}
}
@Override
public Boolean apply(final Artifact a) {
final GroupIdPair p = new GroupIdPair(a.getGroupId(), a.getArtifactId());
return this.groups.contains(p);
}
private static class GroupIdPair {
private final String group;
private final String id;
GroupIdPair(final String group, final String id) {
this.group = group;
this.id = id;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = (prime * result)
+ ((this.group == null) ? 0 : this.group.hashCode());
result = (prime * result) + ((this.id == null) ? 0 : this.id.hashCode());
return result;
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final GroupIdPair other = (GroupIdPair) obj;
if (this.group == null) {
if (other.group != null) {
return false;
}
} else if (!this.group.equals(other.group)) {
return false;
}
if (this.id == null) {
if (other.id != null) {
return false;
}
} else if (!this.id.equals(other.id)) {
return false;
}
return true;
}
}
}