/* * 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); } }