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