/* * JBoss, Home of Professional Open Source * Copyright 2013, Red Hat Middleware LLC, 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.shrinkwrap.resolver.impl.maven.bootstrap; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.maven.settings.Settings; import org.eclipse.aether.DefaultRepositorySystemSession; import org.eclipse.aether.RepositorySystem; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.collection.CollectRequest; import org.eclipse.aether.graph.Dependency; import org.eclipse.aether.graph.DependencyNode; import org.eclipse.aether.resolution.ArtifactRequest; 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.jboss.shrinkwrap.resolver.api.maven.MavenWorkingSession; import org.jboss.shrinkwrap.resolver.api.maven.coordinate.MavenDependency; import org.jboss.shrinkwrap.resolver.api.maven.filter.MavenResolutionFilter; import org.jboss.shrinkwrap.resolver.impl.maven.convert.MavenConverter; /** * Abstraction of the repository system for purposes of dependency resolution used by Maven * * @author <a href="mailto:kpiwko@redhat.com">Karel Piwko</a> * @author <a href="mailto:mmatloka@gmail.com">Michal Matloka</a> */ public class MavenRepositorySystem { private final RepositorySystem system; /** * Creates a Maven repository system */ public MavenRepositorySystem() { this.system = getRepositorySystem(); } /** * Spawns a working session from the repository system. This is used to as environment for execution of Maven * commands * * @param settings * A configuration of current session * @param legacyLocalRepository * Whether to ignore origin of artifacts in local repository; defaults to false * @return A working session spawned from the repository system. */ public DefaultRepositorySystemSession getSession(final Settings settings, boolean legacyLocalRepository) { DefaultRepositorySystemSession session = new DefaultRepositorySystemSession(); MavenManagerBuilder builder = new MavenManagerBuilder(system, settings); session.setLocalRepositoryManager(builder.localRepositoryManager(session, legacyLocalRepository)); session.setWorkspaceReader(builder.workspaceReader()); session.setTransferListener(builder.transferListerer()); session.setRepositoryListener(builder.repositoryListener()); session.setOffline(settings.isOffline()); session.setMirrorSelector(builder.mirrorSelector()); session.setProxySelector(builder.proxySelector()); session.setDependencyManager(builder.dependencyManager()); session.setArtifactDescriptorPolicy(builder.artifactRepositoryPolicy()); session.setDependencyTraverser(builder.dependencyTraverser()); session.setDependencyGraphTransformer(builder.dependencyGraphTransformer()); // set artifact stereotypes session.setArtifactTypeRegistry(builder.artifactTypeRegistry()); // set system properties for interpolation session.setSystemProperties(SecurityActions.getProperties()); session.setConfigProperties(SecurityActions.getProperties()); return session; } /** * Resolves artifact dependencies. * * The {@link ArtifactResult} contains a reference to a file in Maven local repository. * * @param repoSession The current Maven session * @param swrSession SWR Aether session abstraction * @param request The request to be computed * @param filters The filters of dependency results * @return A collection of artifacts which have built dependency tree from {@code request} * @throws DependencyResolutionException If a dependency could not be computed or collected */ public Collection<ArtifactResult> resolveDependencies(final RepositorySystemSession repoSession, final MavenWorkingSession swrSession, final CollectRequest request, final MavenResolutionFilter[] filters) throws DependencyResolutionException { final DependencyRequest depRequest = new DependencyRequest(request, new MavenResolutionFilterWrap(filters, Collections.unmodifiableList(new ArrayList<MavenDependency>(swrSession.getDependenciesForResolution())))); DependencyResult result = system.resolveDependencies(repoSession, depRequest); return result.getArtifactResults(); } /** * Resolves an artifact * * @param session The current Maven session * @param request The request to be computed * @return The artifact * @throws ArtifactResolutionException If the artifact could not be fetched */ public ArtifactResult resolveArtifact(final RepositorySystemSession session, final ArtifactRequest request) throws ArtifactResolutionException { return system.resolveArtifact(session, request); } /** * Resolves versions range * * @param session The current Maven session * @param request The request to be computed * @return version range result * @throws VersionRangeResolutionException * If the requested range could not be parsed. Note that an empty range does not raise an exception. * */ public VersionRangeResult resolveVersionRange(final RepositorySystemSession session, final VersionRangeRequest request) throws VersionRangeResolutionException { return system.resolveVersionRange(session, request); } /** * Finds a current implementation of repository system. A {@link RepositorySystem} is an entry point to dependency * resolution * * @return A repository system * @throws UnsupportedOperationException if {@link RepositorySystem} was not bootstrapped correctly */ private RepositorySystem getRepositorySystem() throws UnsupportedOperationException { final ShrinkWrapResolverServiceLocator locator = new ShrinkWrapResolverServiceLocator(); // if running from inside plugin, we required Maven 3.1.0 or newer // that happens because Maven handles Aether dependencies in plugins a special way so we can't provide our own // implementation, it is simply removed from classpath and not available at all // // locator will throw an exception if repository system cannot be set up return locator.getService(RepositorySystem.class); } } class MavenResolutionFilterWrap implements org.eclipse.aether.graph.DependencyFilter { private static final Logger log = Logger.getLogger(MavenResolutionFilterWrap.class.getName()); private final MavenResolutionFilter[] filters; private final List<MavenDependency> dependenciesForResolution; MavenResolutionFilterWrap(final MavenResolutionFilter[] filters, final List<MavenDependency> dependenciesForResolution) { assert filters != null : "filters must be specified, even if empty"; assert dependenciesForResolution != null : "declaredDependencies must be specified"; this.dependenciesForResolution = dependenciesForResolution; this.filters = filters; } /** * {@inheritDoc} * * @see org.eclipse.aether.graph.DependencyFilter#accept(org.eclipse.aether.graph.DependencyNode, java.util.List) */ @Override public boolean accept(final DependencyNode node, List<DependencyNode> parents) { Dependency dependency = node.getDependency(); if (dependency == null) { return false; } List<MavenDependency> ancestors = new ArrayList<MavenDependency>(); for (DependencyNode parent : parents) { Dependency parentDependency = parent.getDependency(); if (parentDependency != null) { ancestors.add(MavenConverter.fromDependency(parentDependency)); } } if (log.isLoggable(Level.FINER)) { log.log(Level.FINER, "Filtering {0} using {1} filters", new Object[] { dependency, filters.length }); } for (final MavenResolutionFilter filter : filters) { if (!filter.accepts(MavenConverter.fromDependency(dependency), dependenciesForResolution, ancestors)) { if (log.isLoggable(Level.FINER)) { log.log(Level.FINER, "Dependency {0} rejected by {1}", new Object[] { dependency, filter }); } return false; } } // All filters passed if (log.isLoggable(Level.FINER)) { log.log(Level.FINER, "Dependency {0} was accepted.", dependency); } return true; } }