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