001package org.eclipse.aether.internal.impl;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 * 
012 *  http://www.apache.org/licenses/LICENSE-2.0
013 * 
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import java.util.ArrayList;
023import java.util.Arrays;
024import java.util.List;
025import java.util.ListIterator;
026import static java.util.Objects.requireNonNull;
027
028import javax.inject.Inject;
029import javax.inject.Named;
030import javax.inject.Singleton;
031
032import org.apache.commons.lang3.StringUtils;
033import org.eclipse.aether.RepositoryCache;
034import org.eclipse.aether.RepositorySystemSession;
035import org.eclipse.aether.impl.RemoteRepositoryManager;
036import org.eclipse.aether.impl.UpdatePolicyAnalyzer;
037import org.eclipse.aether.repository.Authentication;
038import org.eclipse.aether.repository.AuthenticationSelector;
039import org.eclipse.aether.repository.MirrorSelector;
040import org.eclipse.aether.repository.Proxy;
041import org.eclipse.aether.repository.ProxySelector;
042import org.eclipse.aether.repository.RemoteRepository;
043import org.eclipse.aether.repository.RepositoryPolicy;
044import org.eclipse.aether.spi.connector.checksum.ChecksumPolicyProvider;
045import org.eclipse.aether.spi.locator.Service;
046import org.eclipse.aether.spi.locator.ServiceLocator;
047import org.slf4j.Logger;
048import org.slf4j.LoggerFactory;
049
050/**
051 */
052@Singleton
053@Named
054public class DefaultRemoteRepositoryManager
055    implements RemoteRepositoryManager, Service
056{
057
058    private static final class LoggedMirror
059    {
060
061        private final Object[] keys;
062
063        LoggedMirror( RemoteRepository original, RemoteRepository mirror )
064        {
065            keys = new Object[] { mirror.getId(), mirror.getUrl(), original.getId(), original.getUrl() };
066        }
067
068        @Override
069        public boolean equals( Object obj )
070        {
071            if ( this == obj )
072            {
073                return true;
074            }
075            else if ( !( obj instanceof LoggedMirror ) )
076            {
077                return false;
078            }
079            LoggedMirror that = (LoggedMirror) obj;
080            return Arrays.equals( keys, that.keys );
081        }
082
083        @Override
084        public int hashCode()
085        {
086            return Arrays.hashCode( keys );
087        }
088
089    }
090
091    private static final Logger LOGGER = LoggerFactory.getLogger( DefaultRemoteRepositoryManager.class );
092
093    private UpdatePolicyAnalyzer updatePolicyAnalyzer;
094
095    private ChecksumPolicyProvider checksumPolicyProvider;
096
097    public DefaultRemoteRepositoryManager()
098    {
099        // enables default constructor
100    }
101
102    @Inject
103    DefaultRemoteRepositoryManager( UpdatePolicyAnalyzer updatePolicyAnalyzer,
104                                    ChecksumPolicyProvider checksumPolicyProvider )
105    {
106        setUpdatePolicyAnalyzer( updatePolicyAnalyzer );
107        setChecksumPolicyProvider( checksumPolicyProvider );
108    }
109
110    public void initService( ServiceLocator locator )
111    {
112        setUpdatePolicyAnalyzer( locator.getService( UpdatePolicyAnalyzer.class ) );
113        setChecksumPolicyProvider( locator.getService( ChecksumPolicyProvider.class ) );
114    }
115
116    public DefaultRemoteRepositoryManager setUpdatePolicyAnalyzer( UpdatePolicyAnalyzer updatePolicyAnalyzer )
117    {
118        this.updatePolicyAnalyzer = requireNonNull( updatePolicyAnalyzer, "update policy analyzer cannot be null" );
119        return this;
120    }
121
122    public DefaultRemoteRepositoryManager setChecksumPolicyProvider( ChecksumPolicyProvider checksumPolicyProvider )
123    {
124        this.checksumPolicyProvider = requireNonNull(
125                checksumPolicyProvider, "checksum policy provider cannot be null" );
126        return this;
127    }
128
129    public List<RemoteRepository> aggregateRepositories( RepositorySystemSession session,
130                                                         List<RemoteRepository> dominantRepositories,
131                                                         List<RemoteRepository> recessiveRepositories,
132                                                         boolean recessiveIsRaw )
133    {
134        requireNonNull( session, "session cannot be null" );
135        requireNonNull( dominantRepositories, "dominantRepositories cannot be null" );
136        requireNonNull( recessiveRepositories, "recessiveRepositories cannot be null" );
137        if ( recessiveRepositories.isEmpty() )
138        {
139            return dominantRepositories;
140        }
141
142        MirrorSelector mirrorSelector = session.getMirrorSelector();
143        AuthenticationSelector authSelector = session.getAuthenticationSelector();
144        ProxySelector proxySelector = session.getProxySelector();
145
146        List<RemoteRepository> result = new ArrayList<>( dominantRepositories );
147
148        next: for ( RemoteRepository recessiveRepository : recessiveRepositories )
149        {
150            RemoteRepository repository = recessiveRepository;
151
152            if ( recessiveIsRaw )
153            {
154                RemoteRepository mirrorRepository = mirrorSelector.getMirror( recessiveRepository );
155
156                if ( mirrorRepository != null )
157                {
158                    logMirror( session, recessiveRepository, mirrorRepository );
159                    repository = mirrorRepository;
160                }
161            }
162
163            String key = getKey( repository );
164
165            for ( ListIterator<RemoteRepository> it = result.listIterator(); it.hasNext(); )
166            {
167                RemoteRepository dominantRepository = it.next();
168
169                if ( key.equals( getKey( dominantRepository ) ) )
170                {
171                    if ( !dominantRepository.getMirroredRepositories().isEmpty()
172                        && !repository.getMirroredRepositories().isEmpty() )
173                    {
174                        RemoteRepository mergedRepository = mergeMirrors( session, dominantRepository, repository );
175                        if ( mergedRepository != dominantRepository )
176                        {
177                            it.set( mergedRepository );
178                        }
179                    }
180
181                    continue next;
182                }
183            }
184
185            if ( recessiveIsRaw )
186            {
187                RemoteRepository.Builder builder = null;
188                Authentication auth = authSelector.getAuthentication( repository );
189                if ( auth != null )
190                {
191                    builder = new RemoteRepository.Builder( repository );
192                    builder.setAuthentication( auth );
193                }
194                Proxy proxy = proxySelector.getProxy( repository );
195                if ( proxy != null )
196                {
197                    if ( builder == null )
198                    {
199                        builder = new RemoteRepository.Builder( repository );
200                    }
201                    builder.setProxy( proxy );
202                }
203                if ( builder != null )
204                {
205                    repository = builder.build();
206                }
207            }
208
209            result.add( repository );
210        }
211
212        return result;
213    }
214
215    private void logMirror( RepositorySystemSession session, RemoteRepository original, RemoteRepository mirror )
216    {
217        if ( !LOGGER.isDebugEnabled() )
218        {
219            return;
220        }
221        RepositoryCache cache = session.getCache();
222        if ( cache != null )
223        {
224            Object key = new LoggedMirror( original, mirror );
225            if ( cache.get( session, key ) != null )
226            {
227                return;
228            }
229            cache.put( session, key, Boolean.TRUE );
230        }
231        LOGGER.debug( "Using mirror {} ({}) for {} ({}).",
232                mirror.getId(), mirror.getUrl(), original.getId(), original.getUrl() );
233    }
234
235    private String getKey( RemoteRepository repository )
236    {
237        return repository.getId();
238    }
239
240    private RemoteRepository mergeMirrors( RepositorySystemSession session, RemoteRepository dominant,
241                                           RemoteRepository recessive )
242    {
243        RemoteRepository.Builder merged = null;
244        RepositoryPolicy releases = null, snapshots = null;
245
246        next: for ( RemoteRepository rec : recessive.getMirroredRepositories() )
247        {
248            String recKey = getKey( rec );
249
250            for ( RemoteRepository dom : dominant.getMirroredRepositories() )
251            {
252                if ( recKey.equals( getKey( dom ) ) )
253                {
254                    continue next;
255                }
256            }
257
258            if ( merged == null )
259            {
260                merged = new RemoteRepository.Builder( dominant );
261                releases = dominant.getPolicy( false );
262                snapshots = dominant.getPolicy( true );
263            }
264
265            releases = merge( session, releases, rec.getPolicy( false ), false );
266            snapshots = merge( session, snapshots, rec.getPolicy( true ), false );
267
268            merged.addMirroredRepository( rec );
269        }
270
271        if ( merged == null )
272        {
273            return dominant;
274        }
275        return merged.setReleasePolicy( releases ).setSnapshotPolicy( snapshots ).build();
276    }
277
278    public RepositoryPolicy getPolicy( RepositorySystemSession session, RemoteRepository repository, boolean releases,
279                                       boolean snapshots )
280    {
281        requireNonNull( session, "session cannot be null" );
282        requireNonNull( repository, "repository cannot be null" );
283        RepositoryPolicy policy1 = releases ? repository.getPolicy( false ) : null;
284        RepositoryPolicy policy2 = snapshots ? repository.getPolicy( true ) : null;
285        return merge( session, policy1, policy2, true );
286    }
287
288    private RepositoryPolicy merge( RepositorySystemSession session, RepositoryPolicy policy1,
289                                    RepositoryPolicy policy2, boolean globalPolicy )
290    {
291        RepositoryPolicy policy;
292
293        if ( policy2 == null )
294        {
295            if ( globalPolicy )
296            {
297                policy = merge( policy1, session.getUpdatePolicy(), session.getChecksumPolicy() );
298            }
299            else
300            {
301                policy = policy1;
302            }
303        }
304        else if ( policy1 == null )
305        {
306            if ( globalPolicy )
307            {
308                policy = merge( policy2, session.getUpdatePolicy(), session.getChecksumPolicy() );
309            }
310            else
311            {
312                policy = policy2;
313            }
314        }
315        else if ( !policy2.isEnabled() )
316        {
317            if ( globalPolicy )
318            {
319                policy = merge( policy1, session.getUpdatePolicy(), session.getChecksumPolicy() );
320            }
321            else
322            {
323                policy = policy1;
324            }
325        }
326        else if ( !policy1.isEnabled() )
327        {
328            if ( globalPolicy )
329            {
330                policy = merge( policy2, session.getUpdatePolicy(), session.getChecksumPolicy() );
331            }
332            else
333            {
334                policy = policy2;
335            }
336        }
337        else
338        {
339            String checksums = session.getChecksumPolicy();
340            //noinspection StatementWithEmptyBody
341            if ( globalPolicy && !StringUtils.isEmpty( checksums ) )
342            {
343                // use global override
344            }
345            else
346            {
347                checksums =
348                    checksumPolicyProvider.getEffectiveChecksumPolicy( session, policy1.getChecksumPolicy(),
349                                                                       policy2.getChecksumPolicy() );
350            }
351
352            String updates = session.getUpdatePolicy();
353            //noinspection StatementWithEmptyBody
354            if ( globalPolicy && !StringUtils.isEmpty( updates ) )
355            {
356                // use global override
357            }
358            else
359            {
360                updates =
361                    updatePolicyAnalyzer.getEffectiveUpdatePolicy( session, policy1.getUpdatePolicy(),
362                                                                   policy2.getUpdatePolicy() );
363            }
364
365            policy = new RepositoryPolicy( true, updates, checksums );
366        }
367
368        return policy;
369    }
370
371    private RepositoryPolicy merge( RepositoryPolicy policy, String updates, String checksums )
372    {
373        if ( policy != null )
374        {
375            if ( StringUtils.isEmpty( updates ) )
376            {
377                updates = policy.getUpdatePolicy();
378            }
379            if ( StringUtils.isEmpty( checksums ) )
380            {
381                checksums = policy.getChecksumPolicy();
382            }
383            if ( !policy.getUpdatePolicy().equals( updates ) || !policy.getChecksumPolicy().equals( checksums ) )
384            {
385                policy = new RepositoryPolicy( policy.isEnabled(), updates, checksums );
386            }
387        }
388        return policy;
389    }
390
391}