001package org.apache.maven.project; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import java.io.File; 023import java.util.ArrayList; 024import java.util.Collections; 025import java.util.HashSet; 026import java.util.List; 027import java.util.Set; 028 029import com.google.common.base.Predicate; 030import com.google.common.collect.Iterables; 031 032import org.apache.maven.model.Parent; 033import org.apache.maven.model.Repository; 034import org.apache.maven.model.building.FileModelSource; 035import org.apache.maven.model.building.ModelSource; 036import org.apache.maven.model.resolution.InvalidRepositoryException; 037import org.apache.maven.model.resolution.ModelResolver; 038import org.apache.maven.model.resolution.UnresolvableModelException; 039import org.apache.maven.repository.internal.ArtifactDescriptorUtils; 040import org.eclipse.aether.RepositorySystem; 041import org.eclipse.aether.RepositorySystemSession; 042import org.eclipse.aether.RequestTrace; 043import org.eclipse.aether.artifact.Artifact; 044import org.eclipse.aether.artifact.DefaultArtifact; 045import org.eclipse.aether.impl.RemoteRepositoryManager; 046import org.eclipse.aether.repository.RemoteRepository; 047import org.eclipse.aether.resolution.ArtifactRequest; 048import org.eclipse.aether.resolution.ArtifactResolutionException; 049import org.eclipse.aether.resolution.VersionRangeRequest; 050import org.eclipse.aether.resolution.VersionRangeResolutionException; 051import org.eclipse.aether.resolution.VersionRangeResult; 052 053/** 054 * A model resolver to assist building of projects. This resolver gives priority to those repositories that have been 055 * declared in the POM. 056 * 057 * @author Benjamin Bentmann 058 */ 059public class ProjectModelResolver 060 implements ModelResolver 061{ 062 063 private final RepositorySystemSession session; 064 065 private final RequestTrace trace; 066 067 private final String context = "project"; 068 069 private List<RemoteRepository> repositories; 070 071 private List<RemoteRepository> pomRepositories; 072 073 private final List<RemoteRepository> externalRepositories; 074 075 private final RepositorySystem resolver; 076 077 private final RemoteRepositoryManager remoteRepositoryManager; 078 079 private final Set<String> repositoryIds; 080 081 private final ReactorModelPool modelPool; 082 083 private final ProjectBuildingRequest.RepositoryMerging repositoryMerging; 084 085 public ProjectModelResolver( RepositorySystemSession session, RequestTrace trace, RepositorySystem resolver, 086 RemoteRepositoryManager remoteRepositoryManager, List<RemoteRepository> repositories, 087 ProjectBuildingRequest.RepositoryMerging repositoryMerging, 088 ReactorModelPool modelPool ) 089 { 090 this.session = session; 091 this.trace = trace; 092 this.resolver = resolver; 093 this.remoteRepositoryManager = remoteRepositoryManager; 094 this.pomRepositories = new ArrayList<>(); 095 List<RemoteRepository> externalRepositories = new ArrayList<>(); 096 externalRepositories.addAll( repositories ); 097 this.externalRepositories = Collections.unmodifiableList( externalRepositories ); 098 this.repositories = new ArrayList<>(); 099 this.repositories.addAll( externalRepositories ); 100 this.repositoryMerging = repositoryMerging; 101 this.repositoryIds = new HashSet<>(); 102 this.modelPool = modelPool; 103 } 104 105 private ProjectModelResolver( ProjectModelResolver original ) 106 { 107 this.session = original.session; 108 this.trace = original.trace; 109 this.resolver = original.resolver; 110 this.remoteRepositoryManager = original.remoteRepositoryManager; 111 this.pomRepositories = new ArrayList<>( original.pomRepositories ); 112 this.externalRepositories = original.externalRepositories; 113 this.repositories = new ArrayList<>( original.repositories ); 114 this.repositoryMerging = original.repositoryMerging; 115 this.repositoryIds = new HashSet<>( original.repositoryIds ); 116 this.modelPool = original.modelPool; 117 } 118 119 public void addRepository( Repository repository ) 120 throws InvalidRepositoryException 121 { 122 addRepository( repository, false ); 123 } 124 125 @Override 126 public void addRepository( final Repository repository, boolean replace ) 127 throws InvalidRepositoryException 128 { 129 if ( !repositoryIds.add( repository.getId() ) ) 130 { 131 if ( !replace ) 132 { 133 return; 134 } 135 136 // Remove any previous repository with this Id 137 removeMatchingRepository( repositories, repository.getId() ); 138 removeMatchingRepository( pomRepositories, repository.getId() ); 139 } 140 141 List<RemoteRepository> newRepositories = 142 Collections.singletonList( ArtifactDescriptorUtils.toRemoteRepository( repository ) ); 143 144 if ( ProjectBuildingRequest.RepositoryMerging.REQUEST_DOMINANT.equals( repositoryMerging ) ) 145 { 146 repositories = remoteRepositoryManager.aggregateRepositories( session, repositories, newRepositories, 147 true ); 148 } 149 else 150 { 151 pomRepositories = 152 remoteRepositoryManager.aggregateRepositories( session, pomRepositories, newRepositories, true ); 153 repositories = 154 remoteRepositoryManager.aggregateRepositories( session, pomRepositories, externalRepositories, false ); 155 } 156 } 157 158 private static void removeMatchingRepository( Iterable<RemoteRepository> repositories, final String id ) 159 { 160 Iterables.removeIf( repositories, new Predicate<RemoteRepository>() 161 { 162 @Override 163 public boolean apply( RemoteRepository remoteRepository ) 164 { 165 return remoteRepository.getId().equals( id ); 166 } 167 } ); 168 } 169 170 public ModelResolver newCopy() 171 { 172 return new ProjectModelResolver( this ); 173 } 174 175 public ModelSource resolveModel( String groupId, String artifactId, String version ) 176 throws UnresolvableModelException 177 { 178 File pomFile = null; 179 180 if ( modelPool != null ) 181 { 182 pomFile = modelPool.get( groupId, artifactId, version ); 183 } 184 185 if ( pomFile == null ) 186 { 187 Artifact pomArtifact = new DefaultArtifact( groupId, artifactId, "", "pom", version ); 188 189 try 190 { 191 ArtifactRequest request = new ArtifactRequest( pomArtifact, repositories, context ); 192 request.setTrace( trace ); 193 pomArtifact = resolver.resolveArtifact( session, request ).getArtifact(); 194 } 195 catch ( ArtifactResolutionException e ) 196 { 197 throw new UnresolvableModelException( e.getMessage(), groupId, artifactId, version, e ); 198 } 199 200 pomFile = pomArtifact.getFile(); 201 } 202 203 return new FileModelSource( pomFile ); 204 } 205 206 public ModelSource resolveModel( Parent parent ) 207 throws UnresolvableModelException 208 { 209 Artifact artifact = new DefaultArtifact( parent.getGroupId(), parent.getArtifactId(), "", "pom", 210 parent.getVersion() ); 211 212 VersionRangeRequest versionRangeRequest = new VersionRangeRequest( artifact, repositories, context ); 213 versionRangeRequest.setTrace( trace ); 214 215 try 216 { 217 VersionRangeResult versionRangeResult = resolver.resolveVersionRange( session, versionRangeRequest ); 218 219 if ( versionRangeResult.getHighestVersion() == null ) 220 { 221 throw new UnresolvableModelException( "No versions matched the requested range '" + parent.getVersion() 222 + "'", parent.getGroupId(), parent.getArtifactId(), 223 parent.getVersion() ); 224 225 } 226 227 if ( versionRangeResult.getVersionConstraint() != null 228 && versionRangeResult.getVersionConstraint().getRange() != null 229 && versionRangeResult.getVersionConstraint().getRange().getUpperBound() == null ) 230 { 231 throw new UnresolvableModelException( "The requested version range '" + parent.getVersion() 232 + "' does not specify an upper bound", parent.getGroupId(), 233 parent.getArtifactId(), parent.getVersion() ); 234 235 } 236 237 parent.setVersion( versionRangeResult.getHighestVersion().toString() ); 238 } 239 catch ( VersionRangeResolutionException e ) 240 { 241 throw new UnresolvableModelException( e.getMessage(), parent.getGroupId(), parent.getArtifactId(), 242 parent.getVersion(), e ); 243 244 } 245 246 return resolveModel( parent.getGroupId(), parent.getArtifactId(), parent.getVersion() ); 247 } 248}