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.Arrays;
27  import java.util.List;
28  import java.util.ListIterator;
29  import java.util.stream.Collectors;
30  
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 class LoggedMirror {
57  
58          private final Object[] keys;
59  
60          LoggedMirror(RemoteRepository original, RemoteRepository mirror) {
61              keys = new Object[] {mirror.getId(), mirror.getUrl(), original.getId(), original.getUrl()};
62          }
63  
64          @Override
65          public boolean equals(Object obj) {
66              if (this == obj) {
67                  return true;
68              } else if (!(obj instanceof LoggedMirror)) {
69                  return false;
70              }
71              LoggedMirror that = (LoggedMirror) obj;
72              return Arrays.equals(keys, that.keys);
73          }
74  
75          @Override
76          public int hashCode() {
77              return Arrays.hashCode(keys);
78          }
79      }
80  
81      private static final Logger LOGGER = LoggerFactory.getLogger(DefaultRemoteRepositoryManager.class);
82  
83      private final UpdatePolicyAnalyzer updatePolicyAnalyzer;
84  
85      private final ChecksumPolicyProvider checksumPolicyProvider;
86  
87      private final RepositoryKeyFunctionFactory repositoryKeyFunctionFactory;
88  
89      @Inject
90      public DefaultRemoteRepositoryManager(
91              UpdatePolicyAnalyzer updatePolicyAnalyzer,
92              ChecksumPolicyProvider checksumPolicyProvider,
93              RepositoryKeyFunctionFactory repositoryKeyFunctionFactory) {
94          this.updatePolicyAnalyzer = requireNonNull(updatePolicyAnalyzer, "update policy analyzer cannot be null");
95          this.checksumPolicyProvider = requireNonNull(checksumPolicyProvider, "checksum policy provider cannot be null");
96          this.repositoryKeyFunctionFactory =
97                  requireNonNull(repositoryKeyFunctionFactory, "repository key function factory cannot be null");
98      }
99  
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 }