001package org.eclipse.aether.internal.impl; 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.util.ArrayList; 023import java.util.Arrays; 024import java.util.List; 025import java.util.ListIterator; 026import static java.util.Objects.requireNonNull; 027 028import javax.inject.Inject; 029import javax.inject.Named; 030 031import org.apache.commons.lang3.StringUtils; 032import org.eclipse.aether.RepositoryCache; 033import org.eclipse.aether.RepositorySystemSession; 034import org.eclipse.aether.impl.RemoteRepositoryManager; 035import org.eclipse.aether.impl.UpdatePolicyAnalyzer; 036import org.eclipse.aether.repository.Authentication; 037import org.eclipse.aether.repository.AuthenticationSelector; 038import org.eclipse.aether.repository.MirrorSelector; 039import org.eclipse.aether.repository.Proxy; 040import org.eclipse.aether.repository.ProxySelector; 041import org.eclipse.aether.repository.RemoteRepository; 042import org.eclipse.aether.repository.RepositoryPolicy; 043import org.eclipse.aether.spi.connector.checksum.ChecksumPolicyProvider; 044import org.eclipse.aether.spi.locator.Service; 045import org.eclipse.aether.spi.locator.ServiceLocator; 046import org.slf4j.Logger; 047import org.slf4j.LoggerFactory; 048 049/** 050 */ 051@Named 052public class DefaultRemoteRepositoryManager 053 implements RemoteRepositoryManager, Service 054{ 055 056 private static final class LoggedMirror 057 { 058 059 private final Object[] keys; 060 061 LoggedMirror( RemoteRepository original, RemoteRepository mirror ) 062 { 063 keys = new Object[] { mirror.getId(), mirror.getUrl(), original.getId(), original.getUrl() }; 064 } 065 066 @Override 067 public boolean equals( Object obj ) 068 { 069 if ( this == obj ) 070 { 071 return true; 072 } 073 else if ( !( obj instanceof LoggedMirror ) ) 074 { 075 return false; 076 } 077 LoggedMirror that = (LoggedMirror) obj; 078 return Arrays.equals( keys, that.keys ); 079 } 080 081 @Override 082 public int hashCode() 083 { 084 return Arrays.hashCode( keys ); 085 } 086 087 } 088 089 private static final Logger LOGGER = LoggerFactory.getLogger( DefaultRemoteRepositoryManager.class ); 090 091 private UpdatePolicyAnalyzer updatePolicyAnalyzer; 092 093 private ChecksumPolicyProvider checksumPolicyProvider; 094 095 public DefaultRemoteRepositoryManager() 096 { 097 // enables default constructor 098 } 099 100 @Inject 101 DefaultRemoteRepositoryManager( UpdatePolicyAnalyzer updatePolicyAnalyzer, 102 ChecksumPolicyProvider checksumPolicyProvider ) 103 { 104 setUpdatePolicyAnalyzer( updatePolicyAnalyzer ); 105 setChecksumPolicyProvider( checksumPolicyProvider ); 106 } 107 108 public void initService( ServiceLocator locator ) 109 { 110 setUpdatePolicyAnalyzer( locator.getService( UpdatePolicyAnalyzer.class ) ); 111 setChecksumPolicyProvider( locator.getService( ChecksumPolicyProvider.class ) ); 112 } 113 114 public DefaultRemoteRepositoryManager setUpdatePolicyAnalyzer( UpdatePolicyAnalyzer updatePolicyAnalyzer ) 115 { 116 this.updatePolicyAnalyzer = requireNonNull( updatePolicyAnalyzer, "update policy analyzer cannot be null" ); 117 return this; 118 } 119 120 public DefaultRemoteRepositoryManager setChecksumPolicyProvider( ChecksumPolicyProvider checksumPolicyProvider ) 121 { 122 this.checksumPolicyProvider = requireNonNull( 123 checksumPolicyProvider, "checksum policy provider cannot be null" ); 124 return this; 125 } 126 127 public List<RemoteRepository> aggregateRepositories( RepositorySystemSession session, 128 List<RemoteRepository> dominantRepositories, 129 List<RemoteRepository> recessiveRepositories, 130 boolean recessiveIsRaw ) 131 { 132 if ( recessiveRepositories.isEmpty() ) 133 { 134 return dominantRepositories; 135 } 136 137 MirrorSelector mirrorSelector = session.getMirrorSelector(); 138 AuthenticationSelector authSelector = session.getAuthenticationSelector(); 139 ProxySelector proxySelector = session.getProxySelector(); 140 141 List<RemoteRepository> result = new ArrayList<>( dominantRepositories ); 142 143 next: for ( RemoteRepository recessiveRepository : recessiveRepositories ) 144 { 145 RemoteRepository repository = recessiveRepository; 146 147 if ( recessiveIsRaw ) 148 { 149 RemoteRepository mirrorRepository = mirrorSelector.getMirror( recessiveRepository ); 150 151 if ( mirrorRepository != null ) 152 { 153 logMirror( session, recessiveRepository, mirrorRepository ); 154 repository = mirrorRepository; 155 } 156 } 157 158 String key = getKey( repository ); 159 160 for ( ListIterator<RemoteRepository> it = result.listIterator(); it.hasNext(); ) 161 { 162 RemoteRepository dominantRepository = it.next(); 163 164 if ( key.equals( getKey( dominantRepository ) ) ) 165 { 166 if ( !dominantRepository.getMirroredRepositories().isEmpty() 167 && !repository.getMirroredRepositories().isEmpty() ) 168 { 169 RemoteRepository mergedRepository = mergeMirrors( session, dominantRepository, repository ); 170 if ( mergedRepository != dominantRepository ) 171 { 172 it.set( mergedRepository ); 173 } 174 } 175 176 continue next; 177 } 178 } 179 180 if ( recessiveIsRaw ) 181 { 182 RemoteRepository.Builder builder = null; 183 Authentication auth = authSelector.getAuthentication( repository ); 184 if ( auth != null ) 185 { 186 builder = new RemoteRepository.Builder( repository ); 187 builder.setAuthentication( auth ); 188 } 189 Proxy proxy = proxySelector.getProxy( repository ); 190 if ( proxy != null ) 191 { 192 if ( builder == null ) 193 { 194 builder = new RemoteRepository.Builder( repository ); 195 } 196 builder.setProxy( proxy ); 197 } 198 if ( builder != null ) 199 { 200 repository = builder.build(); 201 } 202 } 203 204 result.add( repository ); 205 } 206 207 return result; 208 } 209 210 private void logMirror( RepositorySystemSession session, RemoteRepository original, RemoteRepository mirror ) 211 { 212 if ( !LOGGER.isDebugEnabled() ) 213 { 214 return; 215 } 216 RepositoryCache cache = session.getCache(); 217 if ( cache != null ) 218 { 219 Object key = new LoggedMirror( original, mirror ); 220 if ( cache.get( session, key ) != null ) 221 { 222 return; 223 } 224 cache.put( session, key, Boolean.TRUE ); 225 } 226 LOGGER.debug( "Using mirror {} ({}) for {} ({}).", 227 mirror.getId(), mirror.getUrl(), original.getId(), original.getUrl() ); 228 } 229 230 private String getKey( RemoteRepository repository ) 231 { 232 return repository.getId(); 233 } 234 235 private RemoteRepository mergeMirrors( RepositorySystemSession session, RemoteRepository dominant, 236 RemoteRepository recessive ) 237 { 238 RemoteRepository.Builder merged = null; 239 RepositoryPolicy releases = null, snapshots = null; 240 241 next: for ( RemoteRepository rec : recessive.getMirroredRepositories() ) 242 { 243 String recKey = getKey( rec ); 244 245 for ( RemoteRepository dom : dominant.getMirroredRepositories() ) 246 { 247 if ( recKey.equals( getKey( dom ) ) ) 248 { 249 continue next; 250 } 251 } 252 253 if ( merged == null ) 254 { 255 merged = new RemoteRepository.Builder( dominant ); 256 releases = dominant.getPolicy( false ); 257 snapshots = dominant.getPolicy( true ); 258 } 259 260 releases = merge( session, releases, rec.getPolicy( false ), false ); 261 snapshots = merge( session, snapshots, rec.getPolicy( true ), false ); 262 263 merged.addMirroredRepository( rec ); 264 } 265 266 if ( merged == null ) 267 { 268 return dominant; 269 } 270 return merged.setReleasePolicy( releases ).setSnapshotPolicy( snapshots ).build(); 271 } 272 273 public RepositoryPolicy getPolicy( RepositorySystemSession session, RemoteRepository repository, boolean releases, 274 boolean snapshots ) 275 { 276 RepositoryPolicy policy1 = releases ? repository.getPolicy( false ) : null; 277 RepositoryPolicy policy2 = snapshots ? repository.getPolicy( true ) : null; 278 return merge( session, policy1, policy2, true ); 279 } 280 281 private RepositoryPolicy merge( RepositorySystemSession session, RepositoryPolicy policy1, 282 RepositoryPolicy policy2, boolean globalPolicy ) 283 { 284 RepositoryPolicy policy; 285 286 if ( policy2 == null ) 287 { 288 if ( globalPolicy ) 289 { 290 policy = merge( policy1, session.getUpdatePolicy(), session.getChecksumPolicy() ); 291 } 292 else 293 { 294 policy = policy1; 295 } 296 } 297 else if ( policy1 == null ) 298 { 299 if ( globalPolicy ) 300 { 301 policy = merge( policy2, session.getUpdatePolicy(), session.getChecksumPolicy() ); 302 } 303 else 304 { 305 policy = policy2; 306 } 307 } 308 else if ( !policy2.isEnabled() ) 309 { 310 if ( globalPolicy ) 311 { 312 policy = merge( policy1, session.getUpdatePolicy(), session.getChecksumPolicy() ); 313 } 314 else 315 { 316 policy = policy1; 317 } 318 } 319 else if ( !policy1.isEnabled() ) 320 { 321 if ( globalPolicy ) 322 { 323 policy = merge( policy2, session.getUpdatePolicy(), session.getChecksumPolicy() ); 324 } 325 else 326 { 327 policy = policy2; 328 } 329 } 330 else 331 { 332 String checksums = session.getChecksumPolicy(); 333 //noinspection StatementWithEmptyBody 334 if ( globalPolicy && !StringUtils.isEmpty( checksums ) ) 335 { 336 // use global override 337 } 338 else 339 { 340 checksums = 341 checksumPolicyProvider.getEffectiveChecksumPolicy( session, policy1.getChecksumPolicy(), 342 policy2.getChecksumPolicy() ); 343 } 344 345 String updates = session.getUpdatePolicy(); 346 //noinspection StatementWithEmptyBody 347 if ( globalPolicy && !StringUtils.isEmpty( updates ) ) 348 { 349 // use global override 350 } 351 else 352 { 353 updates = 354 updatePolicyAnalyzer.getEffectiveUpdatePolicy( session, policy1.getUpdatePolicy(), 355 policy2.getUpdatePolicy() ); 356 } 357 358 policy = new RepositoryPolicy( true, updates, checksums ); 359 } 360 361 return policy; 362 } 363 364 private RepositoryPolicy merge( RepositoryPolicy policy, String updates, String checksums ) 365 { 366 if ( policy != null ) 367 { 368 if ( StringUtils.isEmpty( updates ) ) 369 { 370 updates = policy.getUpdatePolicy(); 371 } 372 if ( StringUtils.isEmpty( checksums ) ) 373 { 374 checksums = policy.getChecksumPolicy(); 375 } 376 if ( !policy.getUpdatePolicy().equals( updates ) || !policy.getChecksumPolicy().equals( checksums ) ) 377 { 378 policy = new RepositoryPolicy( policy.isEnabled(), updates, checksums ); 379 } 380 } 381 return policy; 382 } 383 384}