package org.jboss.seam.solder.test.util;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Resolves a maven artifact present on the test classpath.
*
* @author Stuart Douglas
*
*/
public class MavenArtifactResolver
{
public static File resolve(String groupId, String artifactId)
{
if (groupId == null)
{
throw new IllegalArgumentException("groupId cannot be null");
}
if (artifactId == null)
{
throw new IllegalArgumentException("artifactId cannot be null");
}
String path = new MavenArtifactResolver(groupId.trim(), artifactId.trim(), System.getProperty("java.class.path"), File.pathSeparatorChar, File.separatorChar).resolve();
if (path == null)
{
throw new IllegalArgumentException("Cannot locate artifact for " + groupId + ":" + artifactId);
}
return new File(path);
}
public static File resolve(String qualifiedArtifactId)
{
String[] segments = qualifiedArtifactId.split(":");
if (segments.length == 2)
{
return resolve(segments[0], segments[1]);
}
else
{
throw new IllegalArgumentException("Unable to parse " + qualifiedArtifactId + " as a groupId:artifactId");
}
}
private final String classPathSeparatorRegex;
private final char fileSeparator;
private final String groupId;
private final String artifactId;
private final String classPath;
MavenArtifactResolver(String groupId, String artifactId, String classPath, char pathSeparator, char fileSeparator)
{
this.groupId = groupId;
this.artifactId = artifactId;
this.classPath = classPath;
this.classPathSeparatorRegex = "[^" + pathSeparator + "]*";
this.fileSeparator = fileSeparator;
}
String resolve()
{
Matcher matches = createFullyQualifiedMatcher();
if (!matches.find())
{
matches = createUnqualifiedMatcher();
if (!matches.find())
{
matches = createTargetClassesMatcher();
if (!matches.find())
{
return null;
}
else
{
String fileName = scanForArtifact(matches);
if (fileName == null)
{
return null;
}
else
{
return fileName;
}
}
}
}
return matches.group(0);
}
private String scanForArtifact(Matcher targetClassesMatcher)
{
// Locate all target/classes in classpath and store the path to all files target/
List<String> paths = new ArrayList<String>();
do
{
String path = targetClassesMatcher.group();
File target = new File(path.substring(0, path.length() - 8));
if (target.exists())
{
if (!target.isDirectory())
{
throw new IllegalStateException("Found ${project.dir}/target/ but it is not a directory!");
}
for (File file : target.listFiles())
{
paths.add(file.getPath());
}
}
}
while (targetClassesMatcher.find());
return scanForArtifact(paths);
}
String scanForArtifact(List<String> paths)
{
Pattern pattern = Pattern.compile(artifactId + "-[\\d+\\.]+(?:[\\-\\.]\\p{Alnum}*)?.jar$");
for (String path : paths)
{
if (pattern.matcher(path).find())
{
return path;
}
}
return null;
}
/**
* Creates a matcher that returns any fully qualified matches of the form
* <code>com/acme/acme-core/1.0/acme-core-1.0.jar</code>. This will match
* artifacts on the classpath from the Maven repo.
*/
private Matcher createFullyQualifiedMatcher()
{
String pathString = groupId.replace('.', fileSeparator) + fileSeparator + artifactId;
Pattern p = Pattern.compile(classPathSeparatorRegex + Pattern.quote(pathString) + classPathSeparatorRegex, Pattern.CASE_INSENSITIVE);
return p.matcher(classPath);
}
/**
* Creates a matcher that returns any unqualified matches of the form
* <code>target/acme-foo-1.0.jar</code>. This will match artifacts on the
* classpath from the reactor.
*/
private Matcher createUnqualifiedMatcher()
{
Pattern p = Pattern.compile(classPathSeparatorRegex + Pattern.quote("target" + fileSeparator + artifactId) + classPathSeparatorRegex, Pattern.CASE_INSENSITIVE);
return p.matcher(classPath);
}
/**
* Creates a matcher that returns any unqualified matches of the form
* <code>target/acme-foo-1.0.jar</code>. This locates all
*
*/
private Matcher createTargetClassesMatcher()
{
Pattern p = Pattern.compile(classPathSeparatorRegex + Pattern.quote("target" + fileSeparator + "classes") + classPathSeparatorRegex, Pattern.CASE_INSENSITIVE);
return p.matcher(classPath);
}
}