/*
* JBoss, Home of Professional Open Source
* Copyright 2011, Red Hat, Inc. and/or its affiliates, and individual
* contributors by the @authors tag. See the copyright.txt in the
* distribution for a full listing of individual contributors.
*
* 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.jboss.solder.config.xml.test.common.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 versionRegex;
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;
// Hack, Needed to prevent matching jars with common prefix
this.versionRegex = "-[0-9]";
}
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 + fileSeparator;
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) + versionRegex + 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);
}
}