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