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  
30  import org.eclipse.aether.RepositoryCache;
31  import org.eclipse.aether.RepositorySystemSession;
32  import org.eclipse.aether.impl.RemoteRepositoryManager;
33  import org.eclipse.aether.impl.UpdatePolicyAnalyzer;
34  import org.eclipse.aether.repository.Authentication;
35  import org.eclipse.aether.repository.AuthenticationSelector;
36  import org.eclipse.aether.repository.MirrorSelector;
37  import org.eclipse.aether.repository.Proxy;
38  import org.eclipse.aether.repository.ProxySelector;
39  import org.eclipse.aether.repository.RemoteRepository;
40  import org.eclipse.aether.repository.RepositoryPolicy;
41  import org.eclipse.aether.spi.connector.checksum.ChecksumPolicyProvider;
42  import org.slf4j.Logger;
43  import org.slf4j.LoggerFactory;
44  
45  import static java.util.Objects.requireNonNull;
46  
47  /**
48   */
49  @Singleton
50  @Named
51  public class DefaultRemoteRepositoryManager implements RemoteRepositoryManager {
52  
53      private static final class LoggedMirror {
54  
55          private final Object[] keys;
56  
57          LoggedMirror(RemoteRepository original, RemoteRepository mirror) {
58              keys = new Object[] {mirror.getId(), mirror.getUrl(), original.getId(), original.getUrl()};
59          }
60  
61          @Override
62          public boolean equals(Object obj) {
63              if (this == obj) {
64                  return true;
65              } else if (!(obj instanceof LoggedMirror)) {
66                  return false;
67              }
68              LoggedMirror that = (LoggedMirror) obj;
69              return Arrays.equals(keys, that.keys);
70          }
71  
72          @Override
73          public int hashCode() {
74              return Arrays.hashCode(keys);
75          }
76      }
77  
78      private static final Logger LOGGER = LoggerFactory.getLogger(DefaultRemoteRepositoryManager.class);
79  
80      private final UpdatePolicyAnalyzer updatePolicyAnalyzer;
81  
82      private final ChecksumPolicyProvider checksumPolicyProvider;
83  
84      @Inject
85      public DefaultRemoteRepositoryManager(
86              UpdatePolicyAnalyzer updatePolicyAnalyzer, ChecksumPolicyProvider checksumPolicyProvider) {
87          this.updatePolicyAnalyzer = requireNonNull(updatePolicyAnalyzer, "update policy analyzer cannot be null");
88          this.checksumPolicyProvider = requireNonNull(checksumPolicyProvider, "checksum policy provider cannot be null");
89      }
90  
91      @Override
92      public List<RemoteRepository> aggregateRepositories(
93              RepositorySystemSession session,
94              List<RemoteRepository> dominantRepositories,
95              List<RemoteRepository> recessiveRepositories,
96              boolean recessiveIsRaw) {
97          requireNonNull(session, "session cannot be null");
98          requireNonNull(dominantRepositories, "dominantRepositories cannot be null");
99          requireNonNull(recessiveRepositories, "recessiveRepositories cannot be null");
100         if (recessiveRepositories.isEmpty()) {
101             return dominantRepositories;
102         }
103 
104         MirrorSelector mirrorSelector = session.getMirrorSelector();
105         AuthenticationSelector authSelector = session.getAuthenticationSelector();
106         ProxySelector proxySelector = session.getProxySelector();
107 
108         List<RemoteRepository> result = new ArrayList<>(dominantRepositories);
109 
110         next:
111         for (RemoteRepository recessiveRepository : recessiveRepositories) {
112             RemoteRepository repository = recessiveRepository;
113 
114             if (recessiveIsRaw) {
115                 RemoteRepository mirrorRepository = mirrorSelector.getMirror(recessiveRepository);
116 
117                 if (mirrorRepository != null) {
118                     logMirror(session, recessiveRepository, mirrorRepository);
119                     repository = mirrorRepository;
120                 }
121             }
122 
123             String key = getKey(repository);
124 
125             for (ListIterator<RemoteRepository> it = result.listIterator(); it.hasNext(); ) {
126                 RemoteRepository dominantRepository = it.next();
127 
128                 if (key.equals(getKey(dominantRepository))) {
129                     if (!dominantRepository.getMirroredRepositories().isEmpty()
130                             && !repository.getMirroredRepositories().isEmpty()) {
131                         RemoteRepository mergedRepository = mergeMirrors(session, dominantRepository, repository);
132                         if (mergedRepository != dominantRepository) {
133                             it.set(mergedRepository);
134                         }
135                     }
136 
137                     continue next;
138                 }
139             }
140 
141             if (recessiveIsRaw) {
142                 RemoteRepository.Builder builder = null;
143                 Authentication auth = authSelector.getAuthentication(repository);
144                 if (auth != null) {
145                     builder = new RemoteRepository.Builder(repository);
146                     builder.setAuthentication(auth);
147                 }
148                 Proxy proxy = proxySelector.getProxy(repository);
149                 if (proxy != null) {
150                     if (builder == null) {
151                         builder = new RemoteRepository.Builder(repository);
152                     }
153                     builder.setProxy(proxy);
154                 }
155                 if (builder != null) {
156                     repository = builder.build();
157                 }
158             }
159 
160             result.add(repository);
161         }
162 
163         return result;
164     }
165 
166     private void logMirror(RepositorySystemSession session, RemoteRepository original, RemoteRepository mirror) {
167         if (!LOGGER.isDebugEnabled()) {
168             return;
169         }
170         RepositoryCache cache = session.getCache();
171         if (cache != null) {
172             Object key = new LoggedMirror(original, mirror);
173             if (cache.get(session, key) != null) {
174                 return;
175             }
176             cache.put(session, key, Boolean.TRUE);
177         }
178         LOGGER.debug(
179                 "Using mirror {} ({}) for {} ({}).",
180                 mirror.getId(),
181                 mirror.getUrl(),
182                 original.getId(),
183                 original.getUrl());
184     }
185 
186     private String getKey(RemoteRepository repository) {
187         return repository.getId();
188     }
189 
190     private RemoteRepository mergeMirrors(
191             RepositorySystemSession session, RemoteRepository dominant, RemoteRepository recessive) {
192         RemoteRepository.Builder merged = null;
193         RepositoryPolicy releases = null, snapshots = null;
194 
195         next:
196         for (RemoteRepository rec : recessive.getMirroredRepositories()) {
197             String recKey = getKey(rec);
198 
199             for (RemoteRepository dom : dominant.getMirroredRepositories()) {
200                 if (recKey.equals(getKey(dom))) {
201                     continue next;
202                 }
203             }
204 
205             if (merged == null) {
206                 merged = new RemoteRepository.Builder(dominant);
207                 releases = dominant.getPolicy(false);
208                 snapshots = dominant.getPolicy(true);
209             }
210 
211             releases = merge(session, releases, rec.getPolicy(false), false);
212             snapshots = merge(session, snapshots, rec.getPolicy(true), false);
213 
214             merged.addMirroredRepository(rec);
215         }
216 
217         if (merged == null) {
218             return dominant;
219         }
220         return merged.setReleasePolicy(releases).setSnapshotPolicy(snapshots).build();
221     }
222 
223     @Override
224     public RepositoryPolicy getPolicy(
225             RepositorySystemSession session, RemoteRepository repository, boolean releases, boolean snapshots) {
226         requireNonNull(session, "session cannot be null");
227         requireNonNull(repository, "repository cannot be null");
228         RepositoryPolicy policy1 = releases ? repository.getPolicy(false) : null;
229         RepositoryPolicy policy2 = snapshots ? repository.getPolicy(true) : null;
230         return merge(session, policy1, policy2, true);
231     }
232 
233     private RepositoryPolicy merge(
234             RepositorySystemSession session, RepositoryPolicy policy1, RepositoryPolicy policy2, boolean globalPolicy) {
235         RepositoryPolicy policy;
236 
237         if (policy2 == null) {
238             if (globalPolicy) {
239                 policy = merge(
240                         policy1,
241                         session.getArtifactUpdatePolicy(),
242                         session.getMetadataUpdatePolicy(),
243                         session.getChecksumPolicy());
244             } else {
245                 policy = policy1;
246             }
247         } else if (policy1 == null) {
248             if (globalPolicy) {
249                 policy = merge(
250                         policy2,
251                         session.getArtifactUpdatePolicy(),
252                         session.getMetadataUpdatePolicy(),
253                         session.getChecksumPolicy());
254             } else {
255                 policy = policy2;
256             }
257         } else if (!policy2.isEnabled()) {
258             if (globalPolicy) {
259                 policy = merge(
260                         policy1,
261                         session.getArtifactUpdatePolicy(),
262                         session.getMetadataUpdatePolicy(),
263                         session.getChecksumPolicy());
264             } else {
265                 policy = policy1;
266             }
267         } else if (!policy1.isEnabled()) {
268             if (globalPolicy) {
269                 policy = merge(
270                         policy2,
271                         session.getArtifactUpdatePolicy(),
272                         session.getMetadataUpdatePolicy(),
273                         session.getChecksumPolicy());
274             } else {
275                 policy = policy2;
276             }
277         } else {
278             String checksums = session.getChecksumPolicy();
279             //noinspection StatementWithEmptyBody
280             if (globalPolicy && checksums != null && !checksums.isEmpty()) {
281                 // use global override
282             } else {
283                 checksums = checksumPolicyProvider.getEffectiveChecksumPolicy(
284                         session, policy1.getChecksumPolicy(), policy2.getChecksumPolicy());
285             }
286 
287             String artifactUpdates = session.getArtifactUpdatePolicy();
288             //noinspection StatementWithEmptyBody
289             if (globalPolicy && artifactUpdates != null && !artifactUpdates.isEmpty()) {
290                 // use global override
291             } else {
292                 artifactUpdates = updatePolicyAnalyzer.getEffectiveUpdatePolicy(
293                         session, policy1.getArtifactUpdatePolicy(), policy2.getArtifactUpdatePolicy());
294             }
295             String metadataUpdates = session.getMetadataUpdatePolicy();
296             if (globalPolicy && metadataUpdates != null && !metadataUpdates.isEmpty()) {
297                 // use global override
298             } else {
299                 metadataUpdates = updatePolicyAnalyzer.getEffectiveUpdatePolicy(
300                         session, policy1.getMetadataUpdatePolicy(), policy2.getMetadataUpdatePolicy());
301             }
302 
303             policy = new RepositoryPolicy(true, artifactUpdates, metadataUpdates, checksums);
304         }
305 
306         return policy;
307     }
308 
309     private RepositoryPolicy merge(
310             RepositoryPolicy policy, String artifactUpdates, String metadataUpdates, String checksums) {
311         if (policy != null) {
312             if (artifactUpdates == null || artifactUpdates.isEmpty()) {
313                 artifactUpdates = policy.getArtifactUpdatePolicy();
314             }
315             if (metadataUpdates == null || metadataUpdates.isEmpty()) {
316                 metadataUpdates = policy.getMetadataUpdatePolicy();
317             }
318             if (checksums == null || checksums.isEmpty()) {
319                 checksums = policy.getChecksumPolicy();
320             }
321             if (!policy.getArtifactUpdatePolicy().equals(artifactUpdates)
322                     || !policy.getMetadataUpdatePolicy().equals(metadataUpdates)
323                     || !policy.getChecksumPolicy().equals(checksums)) {
324                 policy = new RepositoryPolicy(policy.isEnabled(), artifactUpdates, metadataUpdates, checksums);
325             }
326         }
327         return policy;
328     }
329 }