View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.eclipse.aether.internal.impl;
20  
21  import javax.inject.Inject;
22  import javax.inject.Named;
23  import javax.inject.Singleton;
24  
25  import java.util.ArrayList;
26  import java.util.List;
27  import java.util.ListIterator;
28  import java.util.stream.Collectors;
29  
30  import org.eclipse.aether.Keys;
31  import org.eclipse.aether.RepositoryCache;
32  import org.eclipse.aether.RepositorySystemSession;
33  import org.eclipse.aether.impl.RemoteRepositoryManager;
34  import org.eclipse.aether.impl.UpdatePolicyAnalyzer;
35  import org.eclipse.aether.repository.Authentication;
36  import org.eclipse.aether.repository.AuthenticationSelector;
37  import org.eclipse.aether.repository.MirrorSelector;
38  import org.eclipse.aether.repository.Proxy;
39  import org.eclipse.aether.repository.ProxySelector;
40  import org.eclipse.aether.repository.RemoteRepository;
41  import org.eclipse.aether.repository.RepositoryKeyFunction;
42  import org.eclipse.aether.repository.RepositoryPolicy;
43  import org.eclipse.aether.spi.connector.checksum.ChecksumPolicyProvider;
44  import org.eclipse.aether.spi.remoterepo.RepositoryKeyFunctionFactory;
45  import org.slf4j.Logger;
46  import org.slf4j.LoggerFactory;
47  
48  import static java.util.Objects.requireNonNull;
49  
50  /**
51   */
52  @Singleton
53  @Named
54  public class DefaultRemoteRepositoryManager implements RemoteRepositoryManager {
55  
56      private static final Logger LOGGER = LoggerFactory.getLogger(DefaultRemoteRepositoryManager.class);
57  
58      private final UpdatePolicyAnalyzer updatePolicyAnalyzer;
59  
60      private final ChecksumPolicyProvider checksumPolicyProvider;
61  
62      private final RepositoryKeyFunctionFactory repositoryKeyFunctionFactory;
63  
64      @Inject
65      public DefaultRemoteRepositoryManager(
66              UpdatePolicyAnalyzer updatePolicyAnalyzer,
67              ChecksumPolicyProvider checksumPolicyProvider,
68              RepositoryKeyFunctionFactory repositoryKeyFunctionFactory) {
69          this.updatePolicyAnalyzer = requireNonNull(updatePolicyAnalyzer, "update policy analyzer cannot be null");
70          this.checksumPolicyProvider = requireNonNull(checksumPolicyProvider, "checksum policy provider cannot be null");
71          this.repositoryKeyFunctionFactory =
72                  requireNonNull(repositoryKeyFunctionFactory, "repository key function factory cannot be null");
73      }
74  
75      @Override
76      public List<RemoteRepository> aggregateRepositories(
77              RepositorySystemSession session,
78              List<RemoteRepository> dominantRepositories,
79              List<RemoteRepository> recessiveRepositories,
80              boolean recessiveIsRaw) {
81          requireNonNull(session, "session cannot be null");
82          requireNonNull(dominantRepositories, "dominantRepositories cannot be null");
83          requireNonNull(recessiveRepositories, "recessiveRepositories cannot be null");
84          if (recessiveRepositories.isEmpty()) {
85              return dominantRepositories;
86          }
87  
88          RepositoryKeyFunction repositoryKeyFunction = repositoryKeyFunctionFactory.systemRepositoryKeyFunction(session);
89          MirrorSelector mirrorSelector = session.getMirrorSelector();
90          AuthenticationSelector authSelector = session.getAuthenticationSelector();
91          ProxySelector proxySelector = session.getProxySelector();
92  
93          List<RemoteRepository> result = new ArrayList<>(dominantRepositories);
94  
95          next:
96          for (RemoteRepository recessiveRepository : recessiveRepositories) {
97              RemoteRepository repository = recessiveRepository;
98  
99              if (recessiveIsRaw) {
100                 RemoteRepository mirrorRepository = mirrorSelector.getMirror(recessiveRepository);
101 
102                 if (mirrorRepository != null) {
103                     logMirror(session, recessiveRepository, mirrorRepository);
104                     repository = mirrorRepository;
105                 }
106             }
107 
108             String key = repositoryKeyFunction.apply(repository, null);
109 
110             for (ListIterator<RemoteRepository> it = result.listIterator(); it.hasNext(); ) {
111                 RemoteRepository dominantRepository = it.next();
112 
113                 if (key.equals(repositoryKeyFunction.apply(dominantRepository, null))) {
114                     if (!dominantRepository.getMirroredRepositories().isEmpty()
115                             && !repository.getMirroredRepositories().isEmpty()) {
116                         RemoteRepository mergedRepository =
117                                 mergeMirrors(session, repositoryKeyFunction, dominantRepository, repository);
118                         if (mergedRepository != dominantRepository) {
119                             it.set(mergedRepository);
120                         }
121                     }
122 
123                     continue next;
124                 }
125             }
126 
127             if (recessiveIsRaw) {
128                 RemoteRepository.Builder builder = null;
129                 Authentication auth = authSelector.getAuthentication(repository);
130                 if (auth != null) {
131                     builder = new RemoteRepository.Builder(repository);
132                     builder.setAuthentication(auth);
133                 }
134                 Proxy proxy = proxySelector.getProxy(repository);
135                 if (proxy != null) {
136                     if (builder == null) {
137                         builder = new RemoteRepository.Builder(repository);
138                     }
139                     builder.setProxy(proxy);
140                 }
141                 if (builder != null) {
142                     repository = builder.build();
143                 }
144             }
145 
146             result.add(repository);
147         }
148 
149         return result.stream()
150                 .map(r -> new RemoteRepository.Builder(r)
151                         .setIntent(RemoteRepository.Intent.RESOLUTION)
152                         .build())
153                 .collect(Collectors.toList());
154     }
155 
156     private void logMirror(RepositorySystemSession session, RemoteRepository original, RemoteRepository mirror) {
157         if (!LOGGER.isDebugEnabled()) {
158             return;
159         }
160         RepositoryCache cache = session.getCache();
161         if (cache != null) {
162             Object key = Keys.of(mirror.getId(), mirror.getUrl(), original.getId(), original.getUrl());
163             if (cache.get(session, key) != null) {
164                 return;
165             }
166             cache.put(session, key, Boolean.TRUE);
167         }
168         LOGGER.debug(
169                 "Using mirror {} ({}) for {} ({}).",
170                 mirror.getId(),
171                 mirror.getUrl(),
172                 original.getId(),
173                 original.getUrl());
174     }
175 
176     private RemoteRepository mergeMirrors(
177             RepositorySystemSession session,
178             RepositoryKeyFunction repositoryKeyFunction,
179             RemoteRepository dominant,
180             RemoteRepository recessive) {
181         RemoteRepository.Builder merged = null;
182         RepositoryPolicy releases = null, snapshots = null;
183 
184         next:
185         for (RemoteRepository rec : recessive.getMirroredRepositories()) {
186             String recKey = repositoryKeyFunction.apply(rec, null);
187 
188             for (RemoteRepository dom : dominant.getMirroredRepositories()) {
189                 if (recKey.equals(repositoryKeyFunction.apply(dom, null))) {
190                     continue next;
191                 }
192             }
193 
194             if (merged == null) {
195                 merged = new RemoteRepository.Builder(dominant);
196                 releases = dominant.getPolicy(false);
197                 snapshots = dominant.getPolicy(true);
198             }
199 
200             releases = merge(session, releases, rec.getPolicy(false), false);
201             snapshots = merge(session, snapshots, rec.getPolicy(true), false);
202 
203             merged.addMirroredRepository(rec);
204         }
205 
206         if (merged == null) {
207             return dominant;
208         }
209         return merged.setReleasePolicy(releases).setSnapshotPolicy(snapshots).build();
210     }
211 
212     @Override
213     public RepositoryPolicy getPolicy(
214             RepositorySystemSession session, RemoteRepository repository, boolean releases, boolean snapshots) {
215         requireNonNull(session, "session cannot be null");
216         requireNonNull(repository, "repository cannot be null");
217         RepositoryPolicy policy1 = releases ? repository.getPolicy(false) : null;
218         RepositoryPolicy policy2 = snapshots ? repository.getPolicy(true) : null;
219         return merge(session, policy1, policy2, true);
220     }
221 
222     private RepositoryPolicy merge(
223             RepositorySystemSession session, RepositoryPolicy policy1, RepositoryPolicy policy2, boolean globalPolicy) {
224         RepositoryPolicy policy;
225 
226         if (policy2 == null) {
227             if (globalPolicy) {
228                 policy = merge(
229                         policy1,
230                         session.getArtifactUpdatePolicy(),
231                         session.getMetadataUpdatePolicy(),
232                         session.getChecksumPolicy());
233             } else {
234                 policy = policy1;
235             }
236         } else if (policy1 == null) {
237             if (globalPolicy) {
238                 policy = merge(
239                         policy2,
240                         session.getArtifactUpdatePolicy(),
241                         session.getMetadataUpdatePolicy(),
242                         session.getChecksumPolicy());
243             } else {
244                 policy = policy2;
245             }
246         } else if (!policy2.isEnabled()) {
247             if (globalPolicy) {
248                 policy = merge(
249                         policy1,
250                         session.getArtifactUpdatePolicy(),
251                         session.getMetadataUpdatePolicy(),
252                         session.getChecksumPolicy());
253             } else {
254                 policy = policy1;
255             }
256         } else if (!policy1.isEnabled()) {
257             if (globalPolicy) {
258                 policy = merge(
259                         policy2,
260                         session.getArtifactUpdatePolicy(),
261                         session.getMetadataUpdatePolicy(),
262                         session.getChecksumPolicy());
263             } else {
264                 policy = policy2;
265             }
266         } else {
267             String checksums = session.getChecksumPolicy();
268             //noinspection StatementWithEmptyBody
269             if (globalPolicy && checksums != null && !checksums.isEmpty()) {
270                 // use global override
271             } else {
272                 checksums = checksumPolicyProvider.getEffectiveChecksumPolicy(
273                         session, policy1.getChecksumPolicy(), policy2.getChecksumPolicy());
274             }
275 
276             String artifactUpdates = session.getArtifactUpdatePolicy();
277             //noinspection StatementWithEmptyBody
278             if (globalPolicy && artifactUpdates != null && !artifactUpdates.isEmpty()) {
279                 // use global override
280             } else {
281                 artifactUpdates = updatePolicyAnalyzer.getEffectiveUpdatePolicy(
282                         session, policy1.getArtifactUpdatePolicy(), policy2.getArtifactUpdatePolicy());
283             }
284             String metadataUpdates = session.getMetadataUpdatePolicy();
285             if (globalPolicy && metadataUpdates != null && !metadataUpdates.isEmpty()) {
286                 // use global override
287             } else {
288                 metadataUpdates = updatePolicyAnalyzer.getEffectiveUpdatePolicy(
289                         session, policy1.getMetadataUpdatePolicy(), policy2.getMetadataUpdatePolicy());
290             }
291 
292             policy = new RepositoryPolicy(true, artifactUpdates, metadataUpdates, checksums);
293         }
294 
295         return policy;
296     }
297 
298     private RepositoryPolicy merge(
299             RepositoryPolicy policy, String artifactUpdates, String metadataUpdates, String checksums) {
300         if (policy != null) {
301             if (artifactUpdates == null || artifactUpdates.isEmpty()) {
302                 artifactUpdates = policy.getArtifactUpdatePolicy();
303             }
304             if (metadataUpdates == null || metadataUpdates.isEmpty()) {
305                 metadataUpdates = policy.getMetadataUpdatePolicy();
306             }
307             if (checksums == null || checksums.isEmpty()) {
308                 checksums = policy.getChecksumPolicy();
309             }
310             if (!policy.getArtifactUpdatePolicy().equals(artifactUpdates)
311                     || !policy.getMetadataUpdatePolicy().equals(metadataUpdates)
312                     || !policy.getChecksumPolicy().equals(checksums)) {
313                 policy = new RepositoryPolicy(policy.isEnabled(), artifactUpdates, metadataUpdates, checksums);
314             }
315         }
316         return policy;
317     }
318 }