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;
030
031import org.eclipse.aether.RepositoryCache;
032import org.eclipse.aether.RepositorySystemSession;
033import org.eclipse.aether.impl.RemoteRepositoryManager;
034import org.eclipse.aether.impl.UpdatePolicyAnalyzer;
035import org.eclipse.aether.repository.Authentication;
036import org.eclipse.aether.repository.AuthenticationSelector;
037import org.eclipse.aether.repository.MirrorSelector;
038import org.eclipse.aether.repository.Proxy;
039import org.eclipse.aether.repository.ProxySelector;
040import org.eclipse.aether.repository.RemoteRepository;
041import org.eclipse.aether.repository.RepositoryPolicy;
042import org.eclipse.aether.spi.connector.checksum.ChecksumPolicyProvider;
043import org.eclipse.aether.spi.locator.Service;
044import org.eclipse.aether.spi.locator.ServiceLocator;
045import org.eclipse.aether.spi.log.Logger;
046import org.eclipse.aether.spi.log.LoggerFactory;
047import org.eclipse.aether.spi.log.NullLoggerFactory;
048import org.eclipse.aether.util.StringUtils;
049
050/**
051 */
052@Named
053public class DefaultRemoteRepositoryManager
054    implements RemoteRepositoryManager, Service
055{
056
057    private static final class LoggedMirror
058    {
059
060        private final Object[] keys;
061
062        public LoggedMirror( RemoteRepository original, RemoteRepository mirror )
063        {
064            keys = new Object[] { mirror.getId(), mirror.getUrl(), original.getId(), original.getUrl() };
065        }
066
067        @Override
068        public boolean equals( Object obj )
069        {
070            if ( this == obj )
071            {
072                return true;
073            }
074            else if ( !( obj instanceof LoggedMirror ) )
075            {
076                return false;
077            }
078            LoggedMirror that = (LoggedMirror) obj;
079            return Arrays.equals( keys, that.keys );
080        }
081
082        @Override
083        public int hashCode()
084        {
085            return Arrays.hashCode( keys );
086        }
087
088    }
089
090    private Logger logger = NullLoggerFactory.LOGGER;
091
092    private UpdatePolicyAnalyzer updatePolicyAnalyzer;
093
094    private ChecksumPolicyProvider checksumPolicyProvider;
095
096    public DefaultRemoteRepositoryManager()
097    {
098        // enables default constructor
099    }
100
101    @Inject
102    DefaultRemoteRepositoryManager( UpdatePolicyAnalyzer updatePolicyAnalyzer,
103                                    ChecksumPolicyProvider checksumPolicyProvider, LoggerFactory loggerFactory )
104    {
105        setUpdatePolicyAnalyzer( updatePolicyAnalyzer );
106        setChecksumPolicyProvider( checksumPolicyProvider );
107        setLoggerFactory( loggerFactory );
108    }
109
110    public void initService( ServiceLocator locator )
111    {
112        setLoggerFactory( locator.getService( LoggerFactory.class ) );
113        setUpdatePolicyAnalyzer( locator.getService( UpdatePolicyAnalyzer.class ) );
114        setChecksumPolicyProvider( locator.getService( ChecksumPolicyProvider.class ) );
115    }
116
117    public DefaultRemoteRepositoryManager setLoggerFactory( LoggerFactory loggerFactory )
118    {
119        this.logger = NullLoggerFactory.getSafeLogger( loggerFactory, getClass() );
120        return this;
121    }
122
123    public DefaultRemoteRepositoryManager setUpdatePolicyAnalyzer( UpdatePolicyAnalyzer updatePolicyAnalyzer )
124    {
125        this.updatePolicyAnalyzer = requireNonNull( updatePolicyAnalyzer, "update policy analyzer cannot be null" );
126        return this;
127    }
128
129    public DefaultRemoteRepositoryManager setChecksumPolicyProvider( ChecksumPolicyProvider checksumPolicyProvider )
130    {
131        this.checksumPolicyProvider = requireNonNull( checksumPolicyProvider, "checksum policy provider cannot be null" );
132        return this;
133    }
134
135    public List<RemoteRepository> aggregateRepositories( RepositorySystemSession session,
136                                                         List<RemoteRepository> dominantRepositories,
137                                                         List<RemoteRepository> recessiveRepositories,
138                                                         boolean recessiveIsRaw )
139    {
140        if ( recessiveRepositories.isEmpty() )
141        {
142            return dominantRepositories;
143        }
144
145        MirrorSelector mirrorSelector = session.getMirrorSelector();
146        AuthenticationSelector authSelector = session.getAuthenticationSelector();
147        ProxySelector proxySelector = session.getProxySelector();
148
149        List<RemoteRepository> result = new ArrayList<RemoteRepository>( dominantRepositories );
150
151        next: for ( RemoteRepository recessiveRepository : recessiveRepositories )
152        {
153            RemoteRepository repository = recessiveRepository;
154
155            if ( recessiveIsRaw )
156            {
157                RemoteRepository mirrorRepository = mirrorSelector.getMirror( recessiveRepository );
158
159                if ( mirrorRepository != null )
160                {
161                    logMirror( session, recessiveRepository, mirrorRepository );
162                    repository = mirrorRepository;
163                }
164            }
165
166            String key = getKey( repository );
167
168            for ( ListIterator<RemoteRepository> it = result.listIterator(); it.hasNext(); )
169            {
170                RemoteRepository dominantRepository = it.next();
171
172                if ( key.equals( getKey( dominantRepository ) ) )
173                {
174                    if ( !dominantRepository.getMirroredRepositories().isEmpty()
175                        && !repository.getMirroredRepositories().isEmpty() )
176                    {
177                        RemoteRepository mergedRepository = mergeMirrors( session, dominantRepository, repository );
178                        if ( mergedRepository != dominantRepository )
179                        {
180                            it.set( mergedRepository );
181                        }
182                    }
183
184                    continue next;
185                }
186            }
187
188            if ( recessiveIsRaw )
189            {
190                RemoteRepository.Builder builder = null;
191                Authentication auth = authSelector.getAuthentication( repository );
192                if ( auth != null )
193                {
194                    builder = new RemoteRepository.Builder( repository );
195                    builder.setAuthentication( auth );
196                }
197                Proxy proxy = proxySelector.getProxy( repository );
198                if ( proxy != null )
199                {
200                    if ( builder == null )
201                    {
202                        builder = new RemoteRepository.Builder( repository );
203                    }
204                    builder.setProxy( proxy );
205                }
206                if ( builder != null )
207                {
208                    repository = builder.build();
209                }
210            }
211
212            result.add( repository );
213        }
214
215        return result;
216    }
217
218    private void logMirror( RepositorySystemSession session, RemoteRepository original, RemoteRepository mirror )
219    {
220        if ( !logger.isDebugEnabled() )
221        {
222            return;
223        }
224        RepositoryCache cache = session.getCache();
225        if ( cache != null )
226        {
227            Object key = new LoggedMirror( original, mirror );
228            if ( cache.get( session, key ) != null )
229            {
230                return;
231            }
232            cache.put( session, key, Boolean.TRUE );
233        }
234        logger.debug( "Using mirror " + mirror.getId() + " (" + mirror.getUrl() + ") for " + original.getId() + " ("
235            + original.getUrl() + ")." );
236    }
237
238    private String getKey( RemoteRepository repository )
239    {
240        return repository.getId();
241    }
242
243    private RemoteRepository mergeMirrors( RepositorySystemSession session, RemoteRepository dominant,
244                                           RemoteRepository recessive )
245    {
246        RemoteRepository.Builder merged = null;
247        RepositoryPolicy releases = null, snapshots = null;
248
249        next: for ( RemoteRepository rec : recessive.getMirroredRepositories() )
250        {
251            String recKey = getKey( rec );
252
253            for ( RemoteRepository dom : dominant.getMirroredRepositories() )
254            {
255                if ( recKey.equals( getKey( dom ) ) )
256                {
257                    continue next;
258                }
259            }
260
261            if ( merged == null )
262            {
263                merged = new RemoteRepository.Builder( dominant );
264                releases = dominant.getPolicy( false );
265                snapshots = dominant.getPolicy( true );
266            }
267
268            releases = merge( session, releases, rec.getPolicy( false ), false );
269            snapshots = merge( session, snapshots, rec.getPolicy( true ), false );
270
271            merged.addMirroredRepository( rec );
272        }
273
274        if ( merged == null )
275        {
276            return dominant;
277        }
278        return merged.setReleasePolicy( releases ).setSnapshotPolicy( snapshots ).build();
279    }
280
281    public RepositoryPolicy getPolicy( RepositorySystemSession session, RemoteRepository repository, boolean releases,
282                                       boolean snapshots )
283    {
284        RepositoryPolicy policy1 = releases ? repository.getPolicy( false ) : null;
285        RepositoryPolicy policy2 = snapshots ? repository.getPolicy( true ) : null;
286        RepositoryPolicy policy = merge( session, policy1, policy2, true );
287        return policy;
288    }
289
290    private RepositoryPolicy merge( RepositorySystemSession session, RepositoryPolicy policy1,
291                                    RepositoryPolicy policy2, boolean globalPolicy )
292    {
293        RepositoryPolicy policy;
294
295        if ( policy2 == null )
296        {
297            if ( globalPolicy )
298            {
299                policy = merge( policy1, session.getUpdatePolicy(), session.getChecksumPolicy() );
300            }
301            else
302            {
303                policy = policy1;
304            }
305        }
306        else if ( policy1 == null )
307        {
308            if ( globalPolicy )
309            {
310                policy = merge( policy2, session.getUpdatePolicy(), session.getChecksumPolicy() );
311            }
312            else
313            {
314                policy = policy2;
315            }
316        }
317        else if ( !policy2.isEnabled() )
318        {
319            if ( globalPolicy )
320            {
321                policy = merge( policy1, session.getUpdatePolicy(), session.getChecksumPolicy() );
322            }
323            else
324            {
325                policy = policy1;
326            }
327        }
328        else if ( !policy1.isEnabled() )
329        {
330            if ( globalPolicy )
331            {
332                policy = merge( policy2, session.getUpdatePolicy(), session.getChecksumPolicy() );
333            }
334            else
335            {
336                policy = policy2;
337            }
338        }
339        else
340        {
341            String checksums = session.getChecksumPolicy();
342            if ( globalPolicy && !StringUtils.isEmpty( checksums ) )
343            {
344                // use global override
345            }
346            else
347            {
348                checksums =
349                    checksumPolicyProvider.getEffectiveChecksumPolicy( session, policy1.getChecksumPolicy(),
350                                                                       policy2.getChecksumPolicy() );
351            }
352
353            String updates = session.getUpdatePolicy();
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}