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.eclipse.aether.spi.locator.Service;
43  import org.eclipse.aether.spi.locator.ServiceLocator;
44  import org.slf4j.Logger;
45  import org.slf4j.LoggerFactory;
46  
47  import static java.util.Objects.requireNonNull;
48  
49  /**
50   */
51  @Singleton
52  @Named
53  public class DefaultRemoteRepositoryManager implements RemoteRepositoryManager, Service {
54  
55      private static final class LoggedMirror {
56  
57          private final Object[] keys;
58  
59          LoggedMirror(RemoteRepository original, RemoteRepository mirror) {
60              keys = new Object[] {mirror.getId(), mirror.getUrl(), original.getId(), original.getUrl()};
61          }
62  
63          @Override
64          public boolean equals(Object obj) {
65              if (this == obj) {
66                  return true;
67              } else if (!(obj instanceof LoggedMirror)) {
68                  return false;
69              }
70              LoggedMirror that = (LoggedMirror) obj;
71              return Arrays.equals(keys, that.keys);
72          }
73  
74          @Override
75          public int hashCode() {
76              return Arrays.hashCode(keys);
77          }
78      }
79  
80      private static final Logger LOGGER = LoggerFactory.getLogger(DefaultRemoteRepositoryManager.class);
81  
82      private UpdatePolicyAnalyzer updatePolicyAnalyzer;
83  
84      private ChecksumPolicyProvider checksumPolicyProvider;
85  
86      @Deprecated
87      public DefaultRemoteRepositoryManager() {
88          // enables default constructor
89      }
90  
91      @Inject
92      public DefaultRemoteRepositoryManager(
93              UpdatePolicyAnalyzer updatePolicyAnalyzer, ChecksumPolicyProvider checksumPolicyProvider) {
94          setUpdatePolicyAnalyzer(updatePolicyAnalyzer);
95          setChecksumPolicyProvider(checksumPolicyProvider);
96      }
97  
98      public void initService(ServiceLocator locator) {
99          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 }