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