/*
* Copyright 2014 NAVER Corp.
* 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 com.navercorp.pinpoint.test.plugin;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
import org.eclipse.aether.DefaultRepositorySystemSession;
import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.artifact.DefaultArtifact;
import org.eclipse.aether.collection.CollectRequest;
import org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory;
import org.eclipse.aether.graph.Dependency;
import org.eclipse.aether.graph.DependencyFilter;
import org.eclipse.aether.impl.DefaultServiceLocator;
import org.eclipse.aether.repository.LocalRepository;
import org.eclipse.aether.repository.RemoteRepository;
import org.eclipse.aether.resolution.ArtifactResolutionException;
import org.eclipse.aether.resolution.ArtifactResult;
import org.eclipse.aether.resolution.DependencyRequest;
import org.eclipse.aether.resolution.DependencyResolutionException;
import org.eclipse.aether.resolution.DependencyResult;
import org.eclipse.aether.resolution.VersionRangeRequest;
import org.eclipse.aether.resolution.VersionRangeResolutionException;
import org.eclipse.aether.resolution.VersionRangeResult;
import org.eclipse.aether.spi.connector.RepositoryConnectorFactory;
import org.eclipse.aether.spi.connector.transport.TransporterFactory;
import org.eclipse.aether.transport.file.FileTransporterFactory;
import org.eclipse.aether.transport.http.HttpTransporterFactory;
import org.eclipse.aether.util.artifact.JavaScopes;
import org.eclipse.aether.util.filter.DependencyFilterUtils;
import org.eclipse.aether.version.Version;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import com.navercorp.pinpoint.bootstrap.PinpointBootStrap;
import com.navercorp.pinpoint.common.util.SimpleProperty;
import com.navercorp.pinpoint.common.util.SystemProperty;
/**
* @author Jongho Moon
*
*/
public class DependencyResolver {
private static final String FOLLOW_PRECEEDING = "FOLLOW_PRECEEDING";
private static final String DEFAULT_LOCAL_REPOSITORY = "target/local-repo";
private static final Logger logger = Logger.getLogger(PinpointBootStrap.class.getName());
private static final SimpleProperty SYSTEM_PROPERTY = SystemProperty.INSTANCE;
private final List<RemoteRepository> repositories;
private final RepositorySystem system;
private final RepositorySystemSession session;
private static RepositorySystem newRepositorySystem() {
DefaultServiceLocator locator = MavenRepositorySystemUtils.newServiceLocator();
locator.addService(RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class);
locator.addService(TransporterFactory.class, FileTransporterFactory.class);
locator.addService(TransporterFactory.class, HttpTransporterFactory.class);
locator.setErrorHandler(new DefaultServiceLocator.ErrorHandler() {
@Override
public void serviceCreationFailed(Class<?> type, Class<?> impl, Throwable exception) {
exception.printStackTrace();
}
});
return locator.getService(RepositorySystem.class);
}
private static DefaultRepositorySystemSession newRepositorySystemSession(RepositorySystem system) {
DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession();
String localRepositoryPath = resolveLocalRepository();
logger.info("Local repository: " + localRepositoryPath);
LocalRepository localRepository = new LocalRepository(localRepositoryPath);
session.setLocalRepositoryManager(system.newLocalRepositoryManager(session, localRepository));
return session;
}
private static String resolveLocalRepository() {
String userHome = SYSTEM_PROPERTY.getProperty("user.home");
if (userHome == null) {
logger.fine("Cannot find user.home property. Use default local repository");
return DEFAULT_LOCAL_REPOSITORY;
}
File mavenHomeDir = new File(userHome, ".m2");
if (!mavenHomeDir.exists() || !mavenHomeDir.isDirectory()) {
logger.fine("Cannot find maven home directory " + mavenHomeDir + ". Use default local repository");
return DEFAULT_LOCAL_REPOSITORY;
}
File localRepository = new File(mavenHomeDir, "repository");
File mavenConfigFile = new File(mavenHomeDir, "settings.xml");
if (mavenConfigFile.exists() && mavenConfigFile.isFile()) {
try {
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document document = builder.parse(mavenConfigFile);
NodeList nodeList = document.getElementsByTagName("localRepository");
if (nodeList.getLength() != 0) {
Node node = nodeList.item(0);
localRepository = new File(node.getTextContent());
logger.fine("Use local repository " + localRepository + " configured at " + mavenConfigFile);
}
} catch (Exception e) {
logger.log(Level.INFO, "Fail to read maven configuration file: " + mavenConfigFile + ". Use default local repository", e);
}
}
if (localRepository.exists() && localRepository.isDirectory()) {
return localRepository.getAbsolutePath();
}
logger.fine("Local repository " + localRepository + " is not exists. Use default local repository");
return DEFAULT_LOCAL_REPOSITORY;
}
private static List<RemoteRepository> newRepositories(String...urls) {
List<RemoteRepository> repositories = new ArrayList<RemoteRepository>(urls.length + 1);
repositories.add(new RemoteRepository.Builder("central", "default", "http://central.maven.org/maven2/").build());
for (String url : urls) {
repositories.add(new RemoteRepository.Builder(null, "default", url).build());
}
return repositories;
}
public static DependencyResolver get(String... repositoryUrls) {
RepositorySystem system = newRepositorySystem();
RepositorySystemSession session = newRepositorySystemSession(system);
List<RemoteRepository> repositories = newRepositories(repositoryUrls);
return new DependencyResolver(system, session, repositories);
}
public DependencyResolver(RepositorySystem system, RepositorySystemSession session, List<RemoteRepository> repositories) {
this.system = system;
this.session = session;
this.repositories = repositories;
}
public List<Version> getVersions(Artifact artifact) throws VersionRangeResolutionException {
VersionRangeRequest rangeRequest = new VersionRangeRequest();
rangeRequest.setArtifact( artifact );
rangeRequest.setRepositories( repositories );
VersionRangeResult rangeResult = system.resolveVersionRange( session, rangeRequest );
List<Version> versions = new ArrayList<Version>(rangeResult.getVersions());
Collections.sort(versions);
return versions;
}
public List<File> resolveArtifactsAndDependencies(List<Artifact> artifacts) throws ArtifactResolutionException, DependencyResolutionException {
List<Dependency> dependencies = new ArrayList<Dependency>();
for (Artifact artifact : artifacts) {
dependencies.add(new Dependency(artifact, JavaScopes.RUNTIME));
}
CollectRequest collectRequest = new CollectRequest((Dependency)null, dependencies, repositories);
DependencyFilter classpathFilter = DependencyFilterUtils.classpathFilter(JavaScopes.RUNTIME);
DependencyRequest dependencyRequest = new DependencyRequest(collectRequest, classpathFilter);
DependencyResult result = system.resolveDependencies(session, dependencyRequest);
List<File> files = new ArrayList<File>();
for (ArtifactResult artifactResult : result.getArtifactResults()) {
files.add(artifactResult.getArtifact().getFile());
}
return files;
}
public String getNewestVersion(String groupId, String artifactId) throws VersionRangeResolutionException {
Artifact artifact = new DefaultArtifact(groupId, artifactId, "jar", "[0,)");
VersionRangeRequest rangeRequest = new VersionRangeRequest();
rangeRequest.setArtifact(artifact);
rangeRequest.setRepositories(repositories);
VersionRangeResult rangeResult = system.resolveVersionRange( session, rangeRequest );
Version newestVersion = rangeResult.getHighestVersion();
return newestVersion.toString();
}
public Map<String, List<Artifact>> resolveDependencySets(String... artifacts) {
List<List<Artifact>> companions = new ArrayList<List<Artifact>>();
List<Artifact> lastCompanion = null;
for (String a : artifacts) {
int first = a.indexOf(':');
if (first == -1) {
throw new IllegalArgumentException("Bad artifact coordinates: " + a + ", artifacts: " + Arrays.deepToString(artifacts));
}
int second = a.indexOf(':', first + 1);
if (second == -1) {
a += ":" + FOLLOW_PRECEEDING;
}
DefaultArtifact artifact = new DefaultArtifact(a);
if (FOLLOW_PRECEEDING.equals(artifact.getVersion())) {
if (lastCompanion != null) {
lastCompanion.add(artifact);
} else {
throw new IllegalArgumentException("Version is not specified: " + a + ", artifacts: " + Arrays.deepToString(artifacts));
}
} else {
lastCompanion = new ArrayList<Artifact>();
lastCompanion.add(artifact);
companions.add(lastCompanion);
}
}
List<List<List<Artifact>>> xxx = new ArrayList<List<List<Artifact>>>();
for (List<Artifact> companion : companions) {
Artifact representative = companion.get(0);
List<Version> versions;
try {
versions = getVersions(representative);
} catch (VersionRangeResolutionException e) {
throw new IllegalArgumentException("Fail to resolve version of: " + representative);
}
if (versions.isEmpty()) {
throw new IllegalArgumentException("No version in the given range: " + representative);
}
List<List<Artifact>> companionVersions = new ArrayList<List<Artifact>>(versions.size());
for (Version version : versions) {
List<Artifact> companionVersion = new ArrayList<Artifact>(companion.size());
for (Artifact artifact : companion) {
companionVersion.add(new DefaultArtifact(artifact.getGroupId(), artifact.getArtifactId(), artifact.getClassifier(), artifact.getExtension(), version.toString()));
}
companionVersions.add(companionVersion);
}
xxx.add(companionVersions);
}
Map<String, List<Artifact>> result = combination(xxx);
return result;
}
private Map<String, List<Artifact>> combination(List<List<List<Artifact>>> groups) {
if (groups.size() == 1) {
Map<String, List<Artifact>> result = new HashMap<String, List<Artifact>>();
List<List<Artifact>> group = groups.get(0);
if (group.size() == 1) {
result.put("", group.get(0));
} else {
for (List<Artifact> aCase : group) {
Artifact representative = aCase.get(0);
result.put(representative.getArtifactId() + "-" + representative.getVersion(), aCase);
}
}
return result;
}
List<List<Artifact>> thisGroup = groups.get(0);
Map<String, List<Artifact>> sub = combination(groups.subList(1, groups.size()));
Map<String, List<Artifact>> result = new HashMap<String, List<Artifact>>();
if (thisGroup.size() == 1) {
List<Artifact> thisArtifacts = thisGroup.get(0);
for (Entry<String, List<Artifact>> subEntry : sub.entrySet()) {
List<Artifact> subArtifacts = subEntry.getValue();
List<Artifact> t = new ArrayList<Artifact>(thisArtifacts.size() + subArtifacts.size());
t.addAll(thisArtifacts);
t.addAll(subArtifacts);
result.put(subEntry.getKey(), t);
}
} else {
for (List<Artifact> thisArtifacts : thisGroup) {
Artifact representative = thisArtifacts.get(0);
String thisKey = representative.getArtifactId() + "-" + representative.getVersion();
for (Entry<String, List<Artifact>> subEntry : sub.entrySet()) {
List<Artifact> subArtifacts = subEntry.getValue();
List<Artifact> t = new ArrayList<Artifact>(thisArtifacts.size() + subArtifacts.size());
t.addAll(thisArtifacts);
t.addAll(subArtifacts);
String subKey = subEntry.getKey();
String key = subKey.isEmpty() ? thisKey : thisKey + ", " + subKey;
result.put(key, t);
}
}
}
return result;
}
public static void main(String args[]) throws Exception {
DependencyResolver resolver = DependencyResolver.get("http://maven.cubrid.org");
Map<String, List<Artifact>> sets = resolver.resolveDependencySets("org.eclipse.aether:aether-util:[0,)", "org.eclipse.aether:aether-spi", "cubrid:cubrid-jdbc:[8.0,)");
int i = 0;
for (Entry<String, List<Artifact>> set : sets.entrySet()) {
System.out.println(i++);
List<File> results = resolver.resolveArtifactsAndDependencies(set.getValue());
System.out.println(set.getKey() + ":");
for (File result : results) {
System.out.println(result);
}
}
}
}