/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 io.fares.classloader;
import java.io.File;
import java.io.PrintStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Set;
import java.util.LinkedHashSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.inject.Named;
import com.google.common.collect.Lists;
import com.google.inject.Inject;
import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
import org.eclipse.aether.DefaultRepositorySystemSession;
import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.graph.Dependency;
import org.eclipse.aether.graph.DependencyFilter;
import org.eclipse.aether.collection.CollectRequest;
import org.eclipse.aether.repository.LocalRepository;
import org.eclipse.aether.repository.Proxy;
import org.eclipse.aether.repository.RemoteRepository;
import org.eclipse.aether.repository.RepositoryPolicy;
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.util.artifact.JavaScopes;
import org.eclipse.aether.util.filter.DependencyFilterUtils;
import io.fares.aether.GuiceRepositorySystemFactory;
import io.fares.aether.LoggerStream;
import io.fares.aether.LoggingRepositoryListener;
import io.fares.aether.LoggingTransferListener;
@Named("AetherClasspathResolver")
public class AetherClasspathResolver implements ClasspathResolver {
protected final Logger LOG = Logger
.getLogger(getClass().getName());
@Inject
private RepositorySystem system;
private Proxy proxy;
private List<Artifact> artifacts = Collections.emptyList();
List<RemoteRepository> remoteRepositories = Collections.emptyList();
public RepositorySystem getRepositorySystem() {
if (system == null) {
system = GuiceRepositorySystemFactory.newRepositorySystem();
}
return system;
}
public void setRepositorySystem(RepositorySystem system) {
this.system = system;
}
public AetherClasspathResolver withRepositorySystem(RepositorySystem system) {
setRepositorySystem(system);
return this;
}
@Override
public Proxy getProxy() {
return proxy;
}
@Override
public void setProxy(Proxy proxy) {
this.proxy = proxy;
}
@Override
public AetherClasspathResolver withProxy(Proxy proxy) {
setProxy(proxy);
return this;
}
@Override
public List<Artifact> getArtifacts() {
return this.artifacts;
}
@Override
public void setArtifacts(List<Artifact> artifacts) {
if (artifacts != null) {
if (this.artifacts.isEmpty()) {
this.artifacts = artifacts;
} else {
this.artifacts.addAll(artifacts);
}
}
}
@Override
public ClasspathResolver addArtifacts(List<Artifact> artifacts) {
if (artifacts != null && !artifacts.isEmpty()) {
setArtifacts(artifacts);
}
return this;
}
@Override
public ClasspathResolver addArtifact(Artifact... artifacts) {
if (artifacts != null && artifacts.length > 0) {
setArtifacts(Arrays.asList(artifacts));
}
return this;
}
@Override
public List<RemoteRepository> getRemoteRepositories() {
return remoteRepositories;
}
@Override
public void setRemoteRepositories(List<RemoteRepository> repositories) {
if (repositories != null) {
// if proxy is set, we need to add proxy to all
if (proxy != null) {
if (this.remoteRepositories.isEmpty()) {
this.remoteRepositories = new ArrayList<RemoteRepository>(
repositories.size());
}
for (RemoteRepository repository : repositories) {
this.remoteRepositories.add(new RemoteRepository.Builder(
repository).setProxy(proxy).build());
}
} else {
// else we can just do the normal
if (this.remoteRepositories.isEmpty()) {
this.remoteRepositories = repositories;
} else {
this.remoteRepositories.addAll(repositories);
}
}
}
}
@Override
public ClasspathResolver addRemoteRepositories(
List<RemoteRepository> repositories) {
if (repositories != null && !repositories.isEmpty()) {
setRemoteRepositories(repositories);
}
return this;
}
@Override
public ClasspathResolver addRemoteRepository(
RemoteRepository... repositories) {
if (repositories != null && repositories.length > 0) {
setRemoteRepositories(Arrays.asList(repositories));
}
return this;
}
@Override
public List<URL> resolveClassPath() {
// first get system
RepositorySystem system = getRepositorySystem();
// get a session
DefaultRepositorySystemSession session = newRepositorySystemSession(system);
// then make all configured remote repositories
// hack for now add all artifacts as compile time dependencies as we
// want to run this thing obviously
List<Dependency> dependencies = new ArrayList<Dependency>(
artifacts.size());
for (Artifact artifact : artifacts) {
dependencies.add(new Dependency(artifact, JavaScopes.COMPILE));
}
CollectRequest collectRequest = new CollectRequest(dependencies, null,
getRemoteRepositories());
// lets get all dependencies
DependencyFilter classpathFilter = DependencyFilterUtils
.classpathFilter(JavaScopes.COMPILE);
// the final request for the repos
DependencyRequest dependencyRequest = new DependencyRequest(
collectRequest, classpathFilter);
try {
DependencyResult result = getRepositorySystem()
.resolveDependencies(session, dependencyRequest);
List<ArtifactResult> artifactResults = result.getArtifactResults();
// we will be using a hashset first to ensure we only add one
// element of each dependency
Set<URL> results = new LinkedHashSet<URL>();
for (ArtifactResult artifactResult : artifactResults) {
Artifact a = artifactResult.getArtifact();
// FIXME currently we can only add locally resolved artefacts
if (a.getFile() != null && a.getFile().exists()) {
// FIXME try/catch in a for loop ...
try {
URL depUrl = a.getFile().toURI().toURL();
results.add(depUrl);
} catch (MalformedURLException e) {
LOG.warning("Cannot resolve "
+ a.getFile().getAbsolutePath());
}
} else {
LOG.warning("Can't respove artefact "
+ (a.getFile() == null ? null : a.getFile()
.getAbsoluteFile()));
}
}
return Lists.newArrayList(results);
} catch (DependencyResolutionException e) {
throw new RuntimeException(e);
}
}
public DefaultRepositorySystemSession newRepositorySystemSession() {
return newRepositorySystemSession(getRepositorySystem());
}
private DefaultRepositorySystemSession newRepositorySystemSession(
RepositorySystem system) {
DefaultRepositorySystemSession session = MavenRepositorySystemUtils
.newSession();
// every container must have one
session.setLocalRepositoryManager(system.newLocalRepositoryManager(
session, findLocalRepository()));
// logging for the activity
PrintStream logger = new LoggerStream(LOG, Level.INFO);
session.setTransferListener(new LoggingTransferListener());
session.setRepositoryListener(new LoggingRepositoryListener());
// uncomment to generate dirty trees
// session.setDependencyGraphTransformer( null );
// ignore checksums on smartbear
session.setChecksumPolicy(RepositoryPolicy.CHECKSUM_POLICY_IGNORE);
return session;
}
public final String getBasedir() {
return System.getProperty("basedir", new File("").getAbsolutePath());
}
protected LocalRepository findLocalRepository() {
LocalRepository localRepo = null;
// first try M2_REPO
String repoHome = System.getenv("M2_REPO");
if (repoHome != null) {
File f = new File(repoHome);
if (f.exists()) {
localRepo = new LocalRepository(f);
}
}
// then user home
if (localRepo == null) {
String userHome = System.getProperty("user.home");
if (userHome != null) {
File fh = new File(userHome, ".m2" + File.separator
+ "repository");
if (fh.exists()) {
localRepo = new LocalRepository(fh);
}
}
}
// if all fails we'll just create one in target of the program
if (localRepo == null) {
localRepo = new LocalRepository("target/soapui-runner-repo");
}
return localRepo;
}
}