001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.eclipse.aether.internal.impl; 020 021import javax.inject.Inject; 022import javax.inject.Named; 023import javax.inject.Singleton; 024 025import java.util.ArrayList; 026import java.util.Arrays; 027import java.util.List; 028import java.util.ListIterator; 029import java.util.stream.Collectors; 030 031import org.eclipse.aether.RepositoryCache; 032import org.eclipse.aether.RepositorySystemSession; 033import org.eclipse.aether.impl.RemoteRepositoryManager; 034import org.eclipse.aether.impl.UpdatePolicyAnalyzer; 035import org.eclipse.aether.repository.Authentication; 036import org.eclipse.aether.repository.AuthenticationSelector; 037import org.eclipse.aether.repository.MirrorSelector; 038import org.eclipse.aether.repository.Proxy; 039import org.eclipse.aether.repository.ProxySelector; 040import org.eclipse.aether.repository.RemoteRepository; 041import org.eclipse.aether.repository.RepositoryKeyFunction; 042import org.eclipse.aether.repository.RepositoryPolicy; 043import org.eclipse.aether.spi.connector.checksum.ChecksumPolicyProvider; 044import org.eclipse.aether.spi.remoterepo.RepositoryKeyFunctionFactory; 045import org.slf4j.Logger; 046import org.slf4j.LoggerFactory; 047 048import static java.util.Objects.requireNonNull; 049 050/** 051 */ 052@Singleton 053@Named 054public class DefaultRemoteRepositoryManager implements RemoteRepositoryManager { 055 056 private static final class LoggedMirror { 057 058 private final Object[] keys; 059 060 LoggedMirror(RemoteRepository original, RemoteRepository mirror) { 061 keys = new Object[] {mirror.getId(), mirror.getUrl(), original.getId(), original.getUrl()}; 062 } 063 064 @Override 065 public boolean equals(Object obj) { 066 if (this == obj) { 067 return true; 068 } else if (!(obj instanceof LoggedMirror)) { 069 return false; 070 } 071 LoggedMirror that = (LoggedMirror) obj; 072 return Arrays.equals(keys, that.keys); 073 } 074 075 @Override 076 public int hashCode() { 077 return Arrays.hashCode(keys); 078 } 079 } 080 081 private static final Logger LOGGER = LoggerFactory.getLogger(DefaultRemoteRepositoryManager.class); 082 083 private final UpdatePolicyAnalyzer updatePolicyAnalyzer; 084 085 private final ChecksumPolicyProvider checksumPolicyProvider; 086 087 private final RepositoryKeyFunctionFactory repositoryKeyFunctionFactory; 088 089 @Inject 090 public DefaultRemoteRepositoryManager( 091 UpdatePolicyAnalyzer updatePolicyAnalyzer, 092 ChecksumPolicyProvider checksumPolicyProvider, 093 RepositoryKeyFunctionFactory repositoryKeyFunctionFactory) { 094 this.updatePolicyAnalyzer = requireNonNull(updatePolicyAnalyzer, "update policy analyzer cannot be null"); 095 this.checksumPolicyProvider = requireNonNull(checksumPolicyProvider, "checksum policy provider cannot be null"); 096 this.repositoryKeyFunctionFactory = 097 requireNonNull(repositoryKeyFunctionFactory, "repository key function factory cannot be null"); 098 } 099 100 @Override 101 public List<RemoteRepository> aggregateRepositories( 102 RepositorySystemSession session, 103 List<RemoteRepository> dominantRepositories, 104 List<RemoteRepository> recessiveRepositories, 105 boolean recessiveIsRaw) { 106 requireNonNull(session, "session cannot be null"); 107 requireNonNull(dominantRepositories, "dominantRepositories cannot be null"); 108 requireNonNull(recessiveRepositories, "recessiveRepositories cannot be null"); 109 if (recessiveRepositories.isEmpty()) { 110 return dominantRepositories; 111 } 112 113 RepositoryKeyFunction repositoryKeyFunction = repositoryKeyFunctionFactory.systemRepositoryKeyFunction(session); 114 MirrorSelector mirrorSelector = session.getMirrorSelector(); 115 AuthenticationSelector authSelector = session.getAuthenticationSelector(); 116 ProxySelector proxySelector = session.getProxySelector(); 117 118 List<RemoteRepository> result = new ArrayList<>(dominantRepositories); 119 120 next: 121 for (RemoteRepository recessiveRepository : recessiveRepositories) { 122 RemoteRepository repository = recessiveRepository; 123 124 if (recessiveIsRaw) { 125 RemoteRepository mirrorRepository = mirrorSelector.getMirror(recessiveRepository); 126 127 if (mirrorRepository != null) { 128 logMirror(session, recessiveRepository, mirrorRepository); 129 repository = mirrorRepository; 130 } 131 } 132 133 String key = repositoryKeyFunction.apply(repository, null); 134 135 for (ListIterator<RemoteRepository> it = result.listIterator(); it.hasNext(); ) { 136 RemoteRepository dominantRepository = it.next(); 137 138 if (key.equals(repositoryKeyFunction.apply(dominantRepository, null))) { 139 if (!dominantRepository.getMirroredRepositories().isEmpty() 140 && !repository.getMirroredRepositories().isEmpty()) { 141 RemoteRepository mergedRepository = 142 mergeMirrors(session, repositoryKeyFunction, dominantRepository, repository); 143 if (mergedRepository != dominantRepository) { 144 it.set(mergedRepository); 145 } 146 } 147 148 continue next; 149 } 150 } 151 152 if (recessiveIsRaw) { 153 RemoteRepository.Builder builder = null; 154 Authentication auth = authSelector.getAuthentication(repository); 155 if (auth != null) { 156 builder = new RemoteRepository.Builder(repository); 157 builder.setAuthentication(auth); 158 } 159 Proxy proxy = proxySelector.getProxy(repository); 160 if (proxy != null) { 161 if (builder == null) { 162 builder = new RemoteRepository.Builder(repository); 163 } 164 builder.setProxy(proxy); 165 } 166 if (builder != null) { 167 repository = builder.build(); 168 } 169 } 170 171 result.add(repository); 172 } 173 174 return result.stream() 175 .map(r -> new RemoteRepository.Builder(r) 176 .setIntent(RemoteRepository.Intent.RESOLUTION) 177 .build()) 178 .collect(Collectors.toList()); 179 } 180 181 private void logMirror(RepositorySystemSession session, RemoteRepository original, RemoteRepository mirror) { 182 if (!LOGGER.isDebugEnabled()) { 183 return; 184 } 185 RepositoryCache cache = session.getCache(); 186 if (cache != null) { 187 Object key = new LoggedMirror(original, mirror); 188 if (cache.get(session, key) != null) { 189 return; 190 } 191 cache.put(session, key, Boolean.TRUE); 192 } 193 LOGGER.debug( 194 "Using mirror {} ({}) for {} ({}).", 195 mirror.getId(), 196 mirror.getUrl(), 197 original.getId(), 198 original.getUrl()); 199 } 200 201 private RemoteRepository mergeMirrors( 202 RepositorySystemSession session, 203 RepositoryKeyFunction repositoryKeyFunction, 204 RemoteRepository dominant, 205 RemoteRepository recessive) { 206 RemoteRepository.Builder merged = null; 207 RepositoryPolicy releases = null, snapshots = null; 208 209 next: 210 for (RemoteRepository rec : recessive.getMirroredRepositories()) { 211 String recKey = repositoryKeyFunction.apply(rec, null); 212 213 for (RemoteRepository dom : dominant.getMirroredRepositories()) { 214 if (recKey.equals(repositoryKeyFunction.apply(dom, null))) { 215 continue next; 216 } 217 } 218 219 if (merged == null) { 220 merged = new RemoteRepository.Builder(dominant); 221 releases = dominant.getPolicy(false); 222 snapshots = dominant.getPolicy(true); 223 } 224 225 releases = merge(session, releases, rec.getPolicy(false), false); 226 snapshots = merge(session, snapshots, rec.getPolicy(true), false); 227 228 merged.addMirroredRepository(rec); 229 } 230 231 if (merged == null) { 232 return dominant; 233 } 234 return merged.setReleasePolicy(releases).setSnapshotPolicy(snapshots).build(); 235 } 236 237 @Override 238 public RepositoryPolicy getPolicy( 239 RepositorySystemSession session, RemoteRepository repository, boolean releases, boolean snapshots) { 240 requireNonNull(session, "session cannot be null"); 241 requireNonNull(repository, "repository cannot be null"); 242 RepositoryPolicy policy1 = releases ? repository.getPolicy(false) : null; 243 RepositoryPolicy policy2 = snapshots ? repository.getPolicy(true) : null; 244 return merge(session, policy1, policy2, true); 245 } 246 247 private RepositoryPolicy merge( 248 RepositorySystemSession session, RepositoryPolicy policy1, RepositoryPolicy policy2, boolean globalPolicy) { 249 RepositoryPolicy policy; 250 251 if (policy2 == null) { 252 if (globalPolicy) { 253 policy = merge( 254 policy1, 255 session.getArtifactUpdatePolicy(), 256 session.getMetadataUpdatePolicy(), 257 session.getChecksumPolicy()); 258 } else { 259 policy = policy1; 260 } 261 } else if (policy1 == null) { 262 if (globalPolicy) { 263 policy = merge( 264 policy2, 265 session.getArtifactUpdatePolicy(), 266 session.getMetadataUpdatePolicy(), 267 session.getChecksumPolicy()); 268 } else { 269 policy = policy2; 270 } 271 } else if (!policy2.isEnabled()) { 272 if (globalPolicy) { 273 policy = merge( 274 policy1, 275 session.getArtifactUpdatePolicy(), 276 session.getMetadataUpdatePolicy(), 277 session.getChecksumPolicy()); 278 } else { 279 policy = policy1; 280 } 281 } else if (!policy1.isEnabled()) { 282 if (globalPolicy) { 283 policy = merge( 284 policy2, 285 session.getArtifactUpdatePolicy(), 286 session.getMetadataUpdatePolicy(), 287 session.getChecksumPolicy()); 288 } else { 289 policy = policy2; 290 } 291 } else { 292 String checksums = session.getChecksumPolicy(); 293 //noinspection StatementWithEmptyBody 294 if (globalPolicy && checksums != null && !checksums.isEmpty()) { 295 // use global override 296 } else { 297 checksums = checksumPolicyProvider.getEffectiveChecksumPolicy( 298 session, policy1.getChecksumPolicy(), policy2.getChecksumPolicy()); 299 } 300 301 String artifactUpdates = session.getArtifactUpdatePolicy(); 302 //noinspection StatementWithEmptyBody 303 if (globalPolicy && artifactUpdates != null && !artifactUpdates.isEmpty()) { 304 // use global override 305 } else { 306 artifactUpdates = updatePolicyAnalyzer.getEffectiveUpdatePolicy( 307 session, policy1.getArtifactUpdatePolicy(), policy2.getArtifactUpdatePolicy()); 308 } 309 String metadataUpdates = session.getMetadataUpdatePolicy(); 310 if (globalPolicy && metadataUpdates != null && !metadataUpdates.isEmpty()) { 311 // use global override 312 } else { 313 metadataUpdates = updatePolicyAnalyzer.getEffectiveUpdatePolicy( 314 session, policy1.getMetadataUpdatePolicy(), policy2.getMetadataUpdatePolicy()); 315 } 316 317 policy = new RepositoryPolicy(true, artifactUpdates, metadataUpdates, checksums); 318 } 319 320 return policy; 321 } 322 323 private RepositoryPolicy merge( 324 RepositoryPolicy policy, String artifactUpdates, String metadataUpdates, String checksums) { 325 if (policy != null) { 326 if (artifactUpdates == null || artifactUpdates.isEmpty()) { 327 artifactUpdates = policy.getArtifactUpdatePolicy(); 328 } 329 if (metadataUpdates == null || metadataUpdates.isEmpty()) { 330 metadataUpdates = policy.getMetadataUpdatePolicy(); 331 } 332 if (checksums == null || checksums.isEmpty()) { 333 checksums = policy.getChecksumPolicy(); 334 } 335 if (!policy.getArtifactUpdatePolicy().equals(artifactUpdates) 336 || !policy.getMetadataUpdatePolicy().equals(metadataUpdates) 337 || !policy.getChecksumPolicy().equals(checksums)) { 338 policy = new RepositoryPolicy(policy.isEnabled(), artifactUpdates, metadataUpdates, checksums); 339 } 340 } 341 return policy; 342 } 343}