/**
* 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 org.apache.openejb.resolver.maven;
import org.apache.maven.repository.internal.DefaultArtifactDescriptorReader;
import org.apache.maven.repository.internal.DefaultVersionRangeResolver;
import org.apache.maven.repository.internal.DefaultVersionResolver;
import org.apache.maven.repository.internal.MavenRepositorySystemSession;
import org.apache.openejb.loader.IO;
import org.ops4j.pax.url.maven.commons.MavenConfigurationImpl;
import org.ops4j.pax.url.maven.commons.MavenRepositoryURL;
import org.sonatype.aether.RepositoryException;
import org.sonatype.aether.RepositorySystem;
import org.sonatype.aether.RepositorySystemSession;
import org.sonatype.aether.artifact.Artifact;
import org.sonatype.aether.connector.wagon.WagonProvider;
import org.sonatype.aether.connector.wagon.WagonRepositoryConnectorFactory;
import org.sonatype.aether.impl.ArtifactDescriptorReader;
import org.sonatype.aether.impl.DependencyCollector;
import org.sonatype.aether.impl.Deployer;
import org.sonatype.aether.impl.Installer;
import org.sonatype.aether.impl.MetadataResolver;
import org.sonatype.aether.impl.SyncContextFactory;
import org.sonatype.aether.impl.VersionRangeResolver;
import org.sonatype.aether.impl.VersionResolver;
import org.sonatype.aether.impl.internal.DefaultDependencyCollector;
import org.sonatype.aether.impl.internal.DefaultDeployer;
import org.sonatype.aether.impl.internal.DefaultInstaller;
import org.sonatype.aether.impl.internal.DefaultMetadataResolver;
import org.sonatype.aether.impl.internal.DefaultServiceLocator;
import org.sonatype.aether.impl.internal.DefaultSyncContextFactory;
import org.sonatype.aether.impl.internal.SimpleLocalRepositoryManagerFactory;
import org.sonatype.aether.installation.InstallRequest;
import org.sonatype.aether.repository.Authentication;
import org.sonatype.aether.repository.LocalRepository;
import org.sonatype.aether.repository.MirrorSelector;
import org.sonatype.aether.repository.Proxy;
import org.sonatype.aether.repository.ProxySelector;
import org.sonatype.aether.repository.RemoteRepository;
import org.sonatype.aether.resolution.ArtifactRequest;
import org.sonatype.aether.resolution.VersionRangeRequest;
import org.sonatype.aether.resolution.VersionRangeResolutionException;
import org.sonatype.aether.resolution.VersionRangeResult;
import org.sonatype.aether.spi.connector.RepositoryConnectorFactory;
import org.sonatype.aether.spi.localrepo.LocalRepositoryManagerFactory;
import org.sonatype.aether.spi.log.Logger;
import org.sonatype.aether.spi.log.NullLogger;
import org.sonatype.aether.util.artifact.DefaultArtifact;
import org.sonatype.aether.util.repository.DefaultMirrorSelector;
import org.sonatype.aether.util.repository.DefaultProxySelector;
import org.sonatype.aether.version.Version;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class AetherBasedResolver {
private static final String LATEST_VERSION_RANGE = "(0.0,]";
private static final String REPO_TYPE = "default";
final private RepositorySystem m_repoSystem;
final private List<RemoteRepository> m_remoteRepos;
final private MavenConfigurationImpl m_config;
final private MirrorSelector m_mirrorSelector;
final private ProxySelector m_proxySelector;
final private MavenRepositoryURL m_repositoryUrl;
/**
* Create a AetherBasedResolver
*
*
* @param configuration (must be not null)
* @param repositoryURL
* @throws java.net.MalformedURLException in case of url problems in configuration.
*/
public AetherBasedResolver(final MavenConfigurationImpl configuration, MavenRepositoryURL repositoryURL) throws MalformedURLException {
m_repoSystem = newRepositorySystem();
m_config = configuration;
m_remoteRepos = selectRepositories(getRemoteRepositories(configuration));
m_mirrorSelector = selectMirrors();
m_proxySelector = selectProxies();
m_repositoryUrl = repositoryURL;
assignProxyAndMirrors();
}
private void assignProxyAndMirrors() {
Map<String, List<String>> map = new HashMap<String, List<String>>();
Map<String, RemoteRepository> naming = new HashMap<String, RemoteRepository>();
for (RemoteRepository r : m_remoteRepos) {
naming.put(r.getId(), r);
r.setProxy(m_proxySelector.getProxy(r));
RemoteRepository mirror = m_mirrorSelector.getMirror(r);
if (mirror != null) {
String key = mirror.getId();
naming.put(key, mirror);
if (!map.containsKey(key)) {
map.put(key, new ArrayList<String>());
}
List<String> mirrored = map.get(key);
mirrored.add(r.getId());
}
}
for (String mirrorId : map.keySet()) {
RemoteRepository mirror = naming.get(mirrorId);
List<RemoteRepository> mirroedRepos = new ArrayList<RemoteRepository>();
for (String rep : map.get(mirrorId)) {
mirroedRepos.add(naming.get(rep));
}
mirror.setMirroredRepositories(mirroedRepos);
m_remoteRepos.removeAll(mirroedRepos);
m_remoteRepos.add(0, mirror);
}
}
private List<MavenRepositoryURL> getRemoteRepositories(MavenConfigurationImpl configuration)
throws MalformedURLException {
List<MavenRepositoryURL> r = new ArrayList<MavenRepositoryURL>();
for (MavenRepositoryURL s : configuration.getRepositories()) {
r.add(s);
}
if (m_repositoryUrl != null) {
// 0 should be local so add it just after to downlad the dependency quicker
r.add(r.size() == 0 ? 0 : 1, m_repositoryUrl);
}
r.add(new MavenRepositoryURL("https://repository.apache.org/content/repositories/snapshots/@snapshots@id=apache-snapshot"));
r.add(new MavenRepositoryURL("https://repository.apache.org/content/repositories/releases/@id=apache-release"));
return r;
}
private ProxySelector selectProxies() {
DefaultProxySelector proxySelector = new DefaultProxySelector();
Map<String, Map<String, String>> proxies = m_config.getProxySettings();
for (Map<String, String> proxy : proxies.values()) {
//The fields are user, pass, host, port, nonProxyHosts, protocol.
String nonProxyHosts = proxy.get("nonProxyHosts");
Proxy proxyObj = new Proxy(proxy.get("protocol"),
proxy.get("host"),
toInt(proxy.get("port")),
getAuthentication(proxy)
);
proxySelector.add(proxyObj, nonProxyHosts);
}
return proxySelector;
}
private MirrorSelector selectMirrors() {
// configure mirror
DefaultMirrorSelector selector = new DefaultMirrorSelector();
Map<String, Map<String, String>> mirrors = m_config.getMirrors();
for (String mirrorName : mirrors.keySet()) {
Map<String, String> mirror = mirrors.get(mirrorName);
//The fields are id, url, mirrorOf, layout, mirrorOfLayouts.
String mirrorOf = mirror.get("mirrorOf");
String url = mirror.get("url");
// type can be null in this implementation (1.11)
selector.add(mirrorName, url, null, false, mirrorOf, "*");
}
return selector;
/**
Set<RemoteRepository> mirrorRepoList = new HashSet<RemoteRepository>();
for (RemoteRepository r : m_remoteRepos) {
RemoteRepository mirrorRepo = mirrorSelector.getMirror(r);
if (mirrorRepo != null)
{
mirrorRepoList.add(mirrorRepo);
}
}
return mirrorRepoList;
**/
}
private List<RemoteRepository> selectRepositories(List<MavenRepositoryURL> repos) {
List<RemoteRepository> list = new ArrayList<RemoteRepository>();
for (MavenRepositoryURL r : repos) {
list.add(new RemoteRepository(r.getId(), REPO_TYPE, r.getURL().toExternalForm()));
}
return list;
}
public InputStream resolve(String groupId, String artifactId, String classifier, String extension, String version) throws IOException {
// version = mapLatestToRange( version );
final RepositorySystemSession session = newSession();
Artifact artifact = new DefaultArtifact(groupId, artifactId, classifier, extension, version);
File resolved = resolve(session, artifact);
return IO.read(resolved);
}
public VersionRangeResult resolveVersions(String groupId, String artifactId, String classifier, String extension, String version) {
final RepositorySystemSession session = newSession();
Artifact artifact = new DefaultArtifact(groupId, artifactId, classifier, extension, version);
if (artifact.getVersion().equals("LATEST")) {
artifact = artifact.setVersion(LATEST_VERSION_RANGE);
}
final VersionRangeRequest request = new VersionRangeRequest(artifact, m_remoteRepos, null);
try {
return m_repoSystem.resolveVersionRange(session, request);
} catch (VersionRangeResolutionException e) {
final VersionRangeResult result = new VersionRangeResult(request);
result.setVersions(Arrays.asList((Version) new VersionImpl(version)));
return result;
}
}
private File resolve(RepositorySystemSession session, Artifact artifact)
throws IOException {
try {
artifact = resolveLatestVersionRange(session, artifact);
artifact = m_repoSystem.resolveArtifact(session, new ArtifactRequest(artifact, m_remoteRepos, null)).getArtifact();
if (artifact != null) {
final InstallRequest request = new InstallRequest();
request.addArtifact(artifact);
m_repoSystem.install(session, request);
}
return artifact.getFile();
} catch (RepositoryException e) {
throw new IOException("Aether Error.", e);
}
}
/**
* Tries to resolve versions = LATEST using an open range version query.
* If it succeeds, version of artifact is set to the highest available version.
*
* @param session to be used.
* @param artifact to be used
* @return an artifact with version set properly (highest if available)
* @throws org.sonatype.aether.resolution.VersionRangeResolutionException
* in case of resolver errors.
*/
private Artifact resolveLatestVersionRange(RepositorySystemSession session, Artifact artifact)
throws VersionRangeResolutionException {
if (artifact.getVersion().equals("LATEST")) {
artifact = artifact.setVersion(LATEST_VERSION_RANGE);
VersionRangeResult versionResult = m_repoSystem.resolveVersionRange(session, new VersionRangeRequest(artifact, m_remoteRepos, null));
if (versionResult != null) {
Version v = versionResult.getHighestVersion();
if (v != null) {
artifact = artifact.setVersion(v.toString());
} else {
throw new VersionRangeResolutionException(versionResult, "Not highest version found for " + artifact);
}
}
}
return artifact;
}
private RepositorySystemSession newSession() {
assert m_config != null : "local repository cannot be null";
File local = m_config.getLocalRepository().getFile();
MavenRepositorySystemSession session = new MavenRepositorySystemSession();
LocalRepository localRepo = new LocalRepository(local);
session.setLocalRepositoryManager(m_repoSystem.newLocalRepositoryManager(localRepo));
session.setMirrorSelector(m_mirrorSelector);
session.setProxySelector(m_proxySelector);
return session;
}
private Authentication getAuthentication(Map<String, String> proxy) {
// user, pass
if (proxy.containsKey("user")) {
return new Authentication(proxy.get("user"), proxy.get("pass"));
}
return null;
}
private int toInt(String intStr) {
return Integer.parseInt(intStr);
}
private RepositorySystem newRepositorySystem() {
DefaultServiceLocator locator = new DefaultServiceLocator();
locator.addService(VersionResolver.class, DefaultVersionResolver.class);
locator.addService(ArtifactDescriptorReader.class, DefaultArtifactDescriptorReader.class);
locator.addService(VersionRangeResolver.class, DefaultVersionRangeResolver.class);
locator.addService(MetadataResolver.class, DefaultMetadataResolver.class);
locator.addService(ArtifactDescriptorReader.class, DefaultArtifactDescriptorReader.class);
locator.addService(DependencyCollector.class, DefaultDependencyCollector.class);
locator.addService(Installer.class, DefaultInstaller.class);
locator.addService(Deployer.class, DefaultDeployer.class);
locator.addService(SyncContextFactory.class, DefaultSyncContextFactory.class);
locator.setServices(WagonProvider.class, new ManualWagonProvider());
locator.addService(RepositoryConnectorFactory.class, WagonRepositoryConnectorFactory.class);
locator.setService(LocalRepositoryManagerFactory.class, SimpleLocalRepositoryManagerFactory.class);
locator.setService(Logger.class, NullLogger.class);
return locator.getService(RepositorySystem.class);
}
private static class VersionImpl implements Version {
private final String version;
private VersionImpl(String version) {
this.version = version;
}
@Override
public String toString() {
return version;
}
@Override
public int compareTo(final Version v) {
return 0;
}
}
}