001package org.apache.maven.bridge;
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.io.File;
023import java.net.MalformedURLException;
024import java.net.URL;
025import java.util.ArrayList;
026import java.util.Collections;
027import java.util.HashSet;
028import java.util.List;
029import java.util.Map;
030import java.util.Set;
031
032import org.apache.maven.RepositoryUtils;
033import org.apache.maven.artifact.Artifact;
034import org.apache.maven.artifact.DefaultArtifact;
035import org.apache.maven.artifact.InvalidRepositoryException;
036import org.apache.maven.artifact.handler.ArtifactHandler;
037import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
038import org.apache.maven.artifact.repository.ArtifactRepository;
039import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
040import org.apache.maven.artifact.repository.Authentication;
041import org.apache.maven.artifact.repository.MavenArtifactRepository;
042import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
043import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout2;
044import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
045import org.apache.maven.artifact.resolver.filter.ExcludesArtifactFilter;
046import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
047import org.apache.maven.artifact.versioning.VersionRange;
048import org.apache.maven.execution.MavenExecutionRequest;
049import org.apache.maven.model.Dependency;
050import org.apache.maven.model.Exclusion;
051import org.apache.maven.model.Plugin;
052import org.apache.maven.repository.Proxy;
053import org.apache.maven.repository.RepositorySystem;
054import org.apache.maven.settings.Mirror;
055import org.codehaus.plexus.component.annotations.Component;
056import org.codehaus.plexus.component.annotations.Requirement;
057import org.codehaus.plexus.util.StringUtils;
058import org.eclipse.aether.RepositorySystemSession;
059import org.eclipse.aether.repository.AuthenticationContext;
060import org.eclipse.aether.repository.AuthenticationSelector;
061import org.eclipse.aether.repository.ProxySelector;
062import org.eclipse.aether.repository.RemoteRepository;
063
064/**
065 * @author Jason van Zyl
066 */
067@Component( role = MavenRepositorySystem.class, hint = "default" )
068public class MavenRepositorySystem
069{
070    @Requirement
071    private ArtifactHandlerManager artifactHandlerManager;
072
073    @Requirement( role = ArtifactRepositoryLayout.class )
074    private Map<String, ArtifactRepositoryLayout> layouts;
075
076    // DefaultProjectBuilder
077    public Artifact createArtifact( String groupId, String artifactId, String version, String scope, String type )
078    {
079        return XcreateArtifact( groupId, artifactId, version, scope, type );
080    }
081
082    // DefaultProjectBuilder
083    public Artifact createProjectArtifact( String groupId, String artifactId, String metaVersionId )
084    {
085        return XcreateProjectArtifact( groupId, artifactId, metaVersionId );
086    }
087
088    // DefaultProjectBuilder
089    public Artifact createDependencyArtifact( Dependency d )
090    {
091        if ( d.getVersion() == null )
092        {
093            return null;
094        }
095
096        VersionRange versionRange;
097        try
098        {
099            versionRange = VersionRange.createFromVersionSpec( d.getVersion() );
100        }
101        catch ( InvalidVersionSpecificationException e )
102        {
103            return null;
104        }
105
106        Artifact artifact =
107            XcreateDependencyArtifact( d.getGroupId(), d.getArtifactId(), versionRange, d.getType(),
108                                                      d.getClassifier(), d.getScope(), d.isOptional() );
109
110        if ( Artifact.SCOPE_SYSTEM.equals( d.getScope() ) && d.getSystemPath() != null )
111        {
112            artifact.setFile( new File( d.getSystemPath() ) );
113        }
114
115        if ( !d.getExclusions().isEmpty() )
116        {
117            List<String> exclusions = new ArrayList<>();
118
119            for ( Exclusion exclusion : d.getExclusions() )
120            {
121                exclusions.add( exclusion.getGroupId() + ':' + exclusion.getArtifactId() );
122            }
123
124            artifact.setDependencyFilter( new ExcludesArtifactFilter( exclusions ) );
125        }
126
127        return artifact;
128    }
129
130    // DefaultProjectBuilder
131    public Artifact createExtensionArtifact( String groupId, String artifactId, String version )
132    {
133        VersionRange versionRange;
134        try
135        {
136            versionRange = VersionRange.createFromVersionSpec( version );
137        }
138        catch ( InvalidVersionSpecificationException e )
139        {
140            return null;
141        }
142
143        return XcreateExtensionArtifact( groupId, artifactId, versionRange );
144    }
145
146    // DefaultProjectBuilder
147    public Artifact createParentArtifact( String groupId, String artifactId, String version )
148    {
149        return XcreateParentArtifact( groupId, artifactId, version );
150    }
151
152    // DefaultProjectBuilder
153    public Artifact createPluginArtifact( Plugin plugin )
154    {
155        VersionRange versionRange;
156        try
157        {
158            String version = plugin.getVersion();
159            if ( StringUtils.isEmpty( version ) )
160            {
161                version = "RELEASE";
162            }
163            versionRange = VersionRange.createFromVersionSpec( version );
164        }
165        catch ( InvalidVersionSpecificationException e )
166        {
167            return null;
168        }
169
170        return XcreatePluginArtifact( plugin.getGroupId(), plugin.getArtifactId(), versionRange );
171    }
172
173    public void injectMirror( List<ArtifactRepository> repositories, List<Mirror> mirrors )
174    {
175        if ( repositories != null && mirrors != null )
176        {
177            for ( ArtifactRepository repository : repositories )
178            {
179                Mirror mirror = getMirror( repository, mirrors );
180                injectMirror( repository, mirror );
181            }
182        }
183    }
184
185    private Mirror getMirror( RepositorySystemSession session, ArtifactRepository repository )
186    {
187        if ( session != null )
188        {
189            org.eclipse.aether.repository.MirrorSelector selector = session.getMirrorSelector();
190            if ( selector != null )
191            {
192                RemoteRepository repo = selector.getMirror( RepositoryUtils.toRepo( repository ) );
193                if ( repo != null )
194                {
195                    Mirror mirror = new Mirror();
196                    mirror.setId( repo.getId() );
197                    mirror.setUrl( repo.getUrl() );
198                    mirror.setLayout( repo.getContentType() );
199                    return mirror;
200                }
201            }
202        }
203        return null;
204    }
205
206    public void injectMirror( RepositorySystemSession session, List<ArtifactRepository> repositories )
207    {
208        if ( repositories != null && session != null )
209        {
210            for ( ArtifactRepository repository : repositories )
211            {
212                Mirror mirror = getMirror( session, repository );
213                injectMirror( repository, mirror );
214            }
215        }
216    }
217
218    private void injectMirror( ArtifactRepository repository, Mirror mirror )
219    {
220        if ( mirror != null )
221        {
222            ArtifactRepository original =
223                createArtifactRepository( repository.getId(), repository.getUrl(), repository.getLayout(),
224                                          repository.getSnapshots(), repository.getReleases() );
225
226            repository.setMirroredRepositories( Collections.singletonList( original ) );
227
228            repository.setId( mirror.getId() );
229            repository.setUrl( mirror.getUrl() );
230
231            if ( StringUtils.isNotEmpty( mirror.getLayout() ) )
232            {
233                repository.setLayout( getLayout( mirror.getLayout() ) );
234            }
235        }
236    }
237
238    private Authentication getAuthentication( RepositorySystemSession session, ArtifactRepository repository )
239    {
240        if ( session != null )
241        {
242            AuthenticationSelector selector = session.getAuthenticationSelector();
243            if ( selector != null )
244            {
245                RemoteRepository repo = RepositoryUtils.toRepo( repository );
246                org.eclipse.aether.repository.Authentication auth = selector.getAuthentication( repo );
247                if ( auth != null )
248                {
249                    repo = new RemoteRepository.Builder( repo ).setAuthentication( auth ).build();
250                    AuthenticationContext authCtx = AuthenticationContext.forRepository( session, repo );
251                    Authentication result =
252                        new Authentication( authCtx.get( AuthenticationContext.USERNAME ),
253                                            authCtx.get( AuthenticationContext.PASSWORD ) );
254                    result.setPrivateKey( authCtx.get( AuthenticationContext.PRIVATE_KEY_PATH ) );
255                    result.setPassphrase( authCtx.get( AuthenticationContext.PRIVATE_KEY_PASSPHRASE ) );
256                    authCtx.close();
257                    return result;
258                }
259            }
260        }
261        return null;
262    }
263
264    public void injectAuthentication( RepositorySystemSession session, List<ArtifactRepository> repositories )
265    {
266        if ( repositories != null && session != null )
267        {
268            for ( ArtifactRepository repository : repositories )
269            {
270                repository.setAuthentication( getAuthentication( session, repository ) );
271            }
272        }
273    }
274
275    private Proxy getProxy( RepositorySystemSession session, ArtifactRepository repository )
276    {
277        if ( session != null )
278        {
279            ProxySelector selector = session.getProxySelector();
280            if ( selector != null )
281            {
282                RemoteRepository repo = RepositoryUtils.toRepo( repository );
283                org.eclipse.aether.repository.Proxy proxy = selector.getProxy( repo );
284                if ( proxy != null )
285                {
286                    Proxy p = new Proxy();
287                    p.setHost( proxy.getHost() );
288                    p.setProtocol( proxy.getType() );
289                    p.setPort( proxy.getPort() );
290                    if ( proxy.getAuthentication() != null )
291                    {
292                        repo = new RemoteRepository.Builder( repo ).setProxy( proxy ).build();
293                        AuthenticationContext authCtx = AuthenticationContext.forProxy( session, repo );
294                        p.setUserName( authCtx.get( AuthenticationContext.USERNAME ) );
295                        p.setPassword( authCtx.get( AuthenticationContext.PASSWORD ) );
296                        p.setNtlmDomain( authCtx.get( AuthenticationContext.NTLM_DOMAIN ) );
297                        p.setNtlmHost( authCtx.get( AuthenticationContext.NTLM_WORKSTATION ) );
298                        authCtx.close();
299                    }
300                    return p;
301                }
302            }
303        }
304        return null;
305    }
306
307    public void injectProxy( RepositorySystemSession session, List<ArtifactRepository> repositories )
308    {
309        if ( repositories != null && session != null )
310        {
311            for ( ArtifactRepository repository : repositories )
312            {
313                repository.setProxy( getProxy( session, repository ) );
314            }
315        }
316    }
317
318    private ArtifactRepositoryLayout getLayout( String id )
319    {
320        ArtifactRepositoryLayout layout = layouts.get( id );
321
322        return layout;
323    }
324
325
326    //
327    // Taken from LegacyRepositorySystem
328    //
329
330    public static org.apache.maven.model.Repository fromSettingsRepository( org.apache.maven.settings.Repository
331                                                                            settingsRepository )
332    {
333        org.apache.maven.model.Repository modelRepository = new org.apache.maven.model.Repository();
334        modelRepository.setId( settingsRepository.getId() );
335        modelRepository.setLayout( settingsRepository.getLayout() );
336        modelRepository.setName( settingsRepository.getName() );
337        modelRepository.setUrl( settingsRepository.getUrl() );
338        modelRepository.setReleases( fromSettingsRepositoryPolicy( settingsRepository.getReleases() ) );
339        modelRepository.setSnapshots( fromSettingsRepositoryPolicy( settingsRepository.getSnapshots() ) );
340        return modelRepository;
341    }
342
343    public static org.apache.maven.model.RepositoryPolicy fromSettingsRepositoryPolicy(
344                                                 org.apache.maven.settings.RepositoryPolicy settingsRepositoryPolicy )
345    {
346        org.apache.maven.model.RepositoryPolicy modelRepositoryPolicy = new org.apache.maven.model.RepositoryPolicy();
347        if ( settingsRepositoryPolicy != null )
348        {
349            modelRepositoryPolicy.setEnabled( settingsRepositoryPolicy.isEnabled() );
350            modelRepositoryPolicy.setUpdatePolicy( settingsRepositoryPolicy.getUpdatePolicy() );
351            modelRepositoryPolicy.setChecksumPolicy( settingsRepositoryPolicy.getChecksumPolicy() );
352        }
353        return modelRepositoryPolicy;
354    }
355
356    public static ArtifactRepository buildArtifactRepository( org.apache.maven.settings.Repository repo )
357        throws InvalidRepositoryException
358    {
359        return buildArtifactRepository( fromSettingsRepository( repo ) );
360    }
361
362    public static ArtifactRepository buildArtifactRepository( org.apache.maven.model.Repository repo )
363        throws InvalidRepositoryException
364    {
365        if ( repo != null )
366        {
367            String id = repo.getId();
368
369            if ( StringUtils.isEmpty( id ) )
370            {
371                throw new InvalidRepositoryException( "Repository identifier missing", "" );
372            }
373
374            String url = repo.getUrl();
375
376            if ( StringUtils.isEmpty( url ) )
377            {
378                throw new InvalidRepositoryException( "URL missing for repository " + id, id );
379            }
380
381            ArtifactRepositoryPolicy snapshots = buildArtifactRepositoryPolicy( repo.getSnapshots() );
382
383            ArtifactRepositoryPolicy releases = buildArtifactRepositoryPolicy( repo.getReleases() );
384
385            ArtifactRepositoryLayout layout = new DefaultRepositoryLayout();
386
387            return createArtifactRepository( id, url, layout, snapshots, releases );
388        }
389        else
390        {
391            return null;
392        }
393    }
394
395    public static ArtifactRepositoryPolicy buildArtifactRepositoryPolicy( org.apache.maven.model.RepositoryPolicy
396                                                                          policy )
397    {
398        boolean enabled = true;
399
400        String updatePolicy = null;
401
402        String checksumPolicy = null;
403
404        if ( policy != null )
405        {
406            enabled = policy.isEnabled();
407
408            if ( policy.getUpdatePolicy() != null )
409            {
410                updatePolicy = policy.getUpdatePolicy();
411            }
412            if ( policy.getChecksumPolicy() != null )
413            {
414                checksumPolicy = policy.getChecksumPolicy();
415            }
416        }
417
418        return new ArtifactRepositoryPolicy( enabled, updatePolicy, checksumPolicy );
419    }    
420    
421    public ArtifactRepository createArtifactRepository( String id, String url, String layoutId,
422                                                        ArtifactRepositoryPolicy snapshots,
423                                                        ArtifactRepositoryPolicy releases )
424        throws Exception
425    {
426        ArtifactRepositoryLayout layout = layouts.get( layoutId );
427
428        checkLayout( id, layoutId, layout );
429
430        return createArtifactRepository( id, url, layout, snapshots, releases );
431    }
432
433    private void checkLayout( String repositoryId, String layoutId, ArtifactRepositoryLayout layout )
434        throws Exception
435    {
436        if ( layout == null )
437        {
438            throw new Exception( String.format( "Cannot find ArtifactRepositoryLayout instance for: %s %s", layoutId,
439                                                repositoryId ) );
440        }
441    }
442    
443    public static ArtifactRepository createArtifactRepository( String id, String url,
444                                                        ArtifactRepositoryLayout repositoryLayout,
445                                                        ArtifactRepositoryPolicy snapshots,
446                                                        ArtifactRepositoryPolicy releases )
447    {
448        if ( snapshots == null )
449        {
450            snapshots = new ArtifactRepositoryPolicy();
451        }
452
453        if ( releases == null )
454        {
455            releases = new ArtifactRepositoryPolicy();
456        }
457
458        ArtifactRepository repository;
459        if ( repositoryLayout instanceof ArtifactRepositoryLayout2 )
460        {
461            repository =
462                ( (ArtifactRepositoryLayout2) repositoryLayout ).newMavenArtifactRepository( id, url, snapshots,
463                                                                                             releases );
464        }
465        else
466        {
467            repository = new MavenArtifactRepository( id, url, repositoryLayout, snapshots, releases );
468        }
469
470        return repository;
471    }
472
473    // ArtifactFactory
474    private Artifact XcreateArtifact( String groupId, String artifactId, String version, String scope, String type )
475    {
476        return XcreateArtifact( groupId, artifactId, version, scope, type, null, null );
477    }
478
479    private Artifact XcreateDependencyArtifact( String groupId, String artifactId, VersionRange versionRange,
480                                              String type, String classifier, String scope, boolean optional )
481    {
482        return XcreateArtifact( groupId, artifactId, versionRange, type, classifier, scope, null, optional );
483    }
484
485    private Artifact XcreateProjectArtifact( String groupId, String artifactId, String version )
486    {
487        return XcreateProjectArtifact( groupId, artifactId, version, null );
488    }
489
490    private Artifact XcreateParentArtifact( String groupId, String artifactId, String version )
491    {
492        return XcreateProjectArtifact( groupId, artifactId, version );
493    }
494
495    private Artifact XcreatePluginArtifact( String groupId, String artifactId, VersionRange versionRange )
496    {
497        return XcreateArtifact( groupId, artifactId, versionRange, "maven-plugin", null, Artifact.SCOPE_RUNTIME, null );
498    }
499
500    private Artifact XcreateProjectArtifact( String groupId, String artifactId, String version, String scope )
501    {
502        return XcreateArtifact( groupId, artifactId, version, scope, "pom" );
503    }
504
505    private Artifact XcreateExtensionArtifact( String groupId, String artifactId, VersionRange versionRange )
506    {
507        return XcreateArtifact( groupId, artifactId, versionRange, "jar", null, Artifact.SCOPE_RUNTIME, null );
508    }
509
510    private Artifact XcreateArtifact( String groupId, String artifactId, String version, String scope, String type,
511                                     String classifier, String inheritedScope )
512    {
513        VersionRange versionRange = null;
514        if ( version != null )
515        {
516            versionRange = VersionRange.createFromVersion( version );
517        }
518        return XcreateArtifact( groupId, artifactId, versionRange, type, classifier, scope, inheritedScope );
519    }
520
521    private Artifact XcreateArtifact( String groupId, String artifactId, VersionRange versionRange, String type,
522                                     String classifier, String scope, String inheritedScope )
523    {
524        return XcreateArtifact( groupId, artifactId, versionRange, type, classifier, scope, inheritedScope, false );
525    }
526
527    private Artifact XcreateArtifact( String groupId, String artifactId, VersionRange versionRange, String type,
528                                     String classifier, String scope, String inheritedScope, boolean optional )
529    {
530        String desiredScope = Artifact.SCOPE_RUNTIME;
531
532        if ( inheritedScope == null )
533        {
534            desiredScope = scope;
535        }
536        else if ( Artifact.SCOPE_TEST.equals( scope ) || Artifact.SCOPE_PROVIDED.equals( scope ) )
537        {
538            return null;
539        }
540        else if ( Artifact.SCOPE_COMPILE.equals( scope ) && Artifact.SCOPE_COMPILE.equals( inheritedScope ) )
541        {
542            // added to retain compile artifactScope. Remove if you want compile inherited as runtime
543            desiredScope = Artifact.SCOPE_COMPILE;
544        }
545
546        if ( Artifact.SCOPE_TEST.equals( inheritedScope ) )
547        {
548            desiredScope = Artifact.SCOPE_TEST;
549        }
550
551        if ( Artifact.SCOPE_PROVIDED.equals( inheritedScope ) )
552        {
553            desiredScope = Artifact.SCOPE_PROVIDED;
554        }
555
556        if ( Artifact.SCOPE_SYSTEM.equals( scope ) )
557        {
558            // system scopes come through unchanged...
559            desiredScope = Artifact.SCOPE_SYSTEM;
560        }
561
562        ArtifactHandler handler = artifactHandlerManager.getArtifactHandler( type );
563
564        return new DefaultArtifact( groupId, artifactId, versionRange, desiredScope, type, classifier, handler,
565                                    optional );
566    }
567    
568    //
569    // Code taken from LegacyRepositorySystem
570    //
571        
572    public ArtifactRepository createDefaultRemoteRepository( MavenExecutionRequest request )
573        throws Exception
574    {
575        return createRepository( RepositorySystem.DEFAULT_REMOTE_REPO_URL, RepositorySystem.DEFAULT_REMOTE_REPO_ID,
576                                 true, ArtifactRepositoryPolicy.UPDATE_POLICY_DAILY, false,
577                                 ArtifactRepositoryPolicy.UPDATE_POLICY_DAILY,
578                                 ArtifactRepositoryPolicy.CHECKSUM_POLICY_WARN );
579    }
580    
581    public ArtifactRepository createRepository( String url, String repositoryId, boolean releases,
582                                                 String releaseUpdates, boolean snapshots, String snapshotUpdates,
583                                                 String checksumPolicy ) throws Exception
584    {
585        ArtifactRepositoryPolicy snapshotsPolicy =
586            new ArtifactRepositoryPolicy( snapshots, snapshotUpdates, checksumPolicy );
587
588        ArtifactRepositoryPolicy releasesPolicy =
589            new ArtifactRepositoryPolicy( releases, releaseUpdates, checksumPolicy );
590
591        return createArtifactRepository( repositoryId, url, "default", snapshotsPolicy, releasesPolicy );
592    }
593        
594    public Set<String> getRepoIds( List<ArtifactRepository> repositories )
595    {
596        Set<String> repoIds = new HashSet<>();
597
598        if ( repositories != null )
599        {
600            for ( ArtifactRepository repository : repositories )
601            {
602                repoIds.add( repository.getId() );
603            }
604        }
605
606        return repoIds;
607    }
608    
609    
610    public ArtifactRepository createLocalRepository( MavenExecutionRequest request, File localRepository )
611        throws Exception
612    {
613        return createRepository( "file://" + localRepository.toURI().getRawPath(),
614                                 RepositorySystem.DEFAULT_LOCAL_REPO_ID, true,
615                                 ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS, true,
616                                 ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS,
617                                 ArtifactRepositoryPolicy.CHECKSUM_POLICY_IGNORE );
618    }    
619    
620    private static final String WILDCARD = "*";
621
622    private static final String EXTERNAL_WILDCARD = "external:*";
623
624    public static Mirror getMirror( ArtifactRepository repository, List<Mirror> mirrors )
625    {
626        String repoId = repository.getId();
627
628        if ( repoId != null && mirrors != null )
629        {
630            for ( Mirror mirror : mirrors )
631            {
632                if ( repoId.equals( mirror.getMirrorOf() ) && matchesLayout( repository, mirror ) )
633                {
634                    return mirror;
635                }
636            }
637
638            for ( Mirror mirror : mirrors )
639            {
640                if ( matchPattern( repository, mirror.getMirrorOf() ) && matchesLayout( repository, mirror ) )
641                {
642                    return mirror;
643                }
644            }
645        }
646
647        return null;
648    }
649
650    /**
651     * This method checks if the pattern matches the originalRepository. Valid patterns: * = everything external:* =
652     * everything not on the localhost and not file based. repo,repo1 = repo or repo1 *,!repo1 = everything except repo1
653     *
654     * @param originalRepository to compare for a match.
655     * @param pattern used for match. Currently only '*' is supported.
656     * @return true if the repository is a match to this pattern.
657     */
658    static boolean matchPattern( ArtifactRepository originalRepository, String pattern )
659    {
660        boolean result = false;
661        String originalId = originalRepository.getId();
662
663        // simple checks first to short circuit processing below.
664        if ( WILDCARD.equals( pattern ) || pattern.equals( originalId ) )
665        {
666            result = true;
667        }
668        else
669        {
670            // process the list
671            String[] repos = pattern.split( "," );
672            for ( String repo : repos )
673            {
674                // see if this is a negative match
675                if ( repo.length() > 1 && repo.startsWith( "!" ) )
676                {
677                    if ( repo.substring( 1 ).equals( originalId ) )
678                    {
679                        // explicitly exclude. Set result and stop processing.
680                        result = false;
681                        break;
682                    }
683                }
684                // check for exact match
685                else if ( repo.equals( originalId ) )
686                {
687                    result = true;
688                    break;
689                }
690                // check for external:*
691                else if ( EXTERNAL_WILDCARD.equals( repo ) && isExternalRepo( originalRepository ) )
692                {
693                    result = true;
694                    // don't stop processing in case a future segment explicitly excludes this repo
695                }
696                else if ( WILDCARD.equals( repo ) )
697                {
698                    result = true;
699                    // don't stop processing in case a future segment explicitly excludes this repo
700                }
701            }
702        }
703        return result;
704    }
705
706    /**
707     * Checks the URL to see if this repository refers to an external repository
708     *
709     * @param originalRepository
710     * @return true if external.
711     */
712    static boolean isExternalRepo( ArtifactRepository originalRepository )
713    {
714        try
715        {
716            URL url = new URL( originalRepository.getUrl() );
717            return !( url.getHost().equals( "localhost" ) || url.getHost().equals( "127.0.0.1" )
718                            || url.getProtocol().equals( "file" ) );
719        }
720        catch ( MalformedURLException e )
721        {
722            // bad url just skip it here. It should have been validated already, but the wagon lookup will deal with it
723            return false;
724        }
725    }
726
727    static boolean matchesLayout( ArtifactRepository repository, Mirror mirror )
728    {
729        return matchesLayout( RepositoryUtils.getLayout( repository ), mirror.getMirrorOfLayouts() );
730    }
731
732    /**
733     * Checks whether the layouts configured for a mirror match with the layout of the repository.
734     *
735     * @param repoLayout The layout of the repository, may be {@code null}.
736     * @param mirrorLayout The layouts supported by the mirror, may be {@code null}.
737     * @return {@code true} if the layouts associated with the mirror match the layout of the original repository,
738     *         {@code false} otherwise.
739     */
740    static boolean matchesLayout( String repoLayout, String mirrorLayout )
741    {
742        boolean result = false;
743
744        // simple checks first to short circuit processing below.
745        if ( StringUtils.isEmpty( mirrorLayout ) || WILDCARD.equals( mirrorLayout ) )
746        {
747            result = true;
748        }
749        else if ( mirrorLayout.equals( repoLayout ) )
750        {
751            result = true;
752        }
753        else
754        {
755            // process the list
756            String[] layouts = mirrorLayout.split( "," );
757            for ( String layout : layouts )
758            {
759                // see if this is a negative match
760                if ( layout.length() > 1 && layout.startsWith( "!" ) )
761                {
762                    if ( layout.substring( 1 ).equals( repoLayout ) )
763                    {
764                        // explicitly exclude. Set result and stop processing.
765                        result = false;
766                        break;
767                    }
768                }
769                // check for exact match
770                else if ( layout.equals( repoLayout ) )
771                {
772                    result = true;
773                    break;
774                }
775                else if ( WILDCARD.equals( layout ) )
776                {
777                    result = true;
778                    // don't stop processing in case a future segment explicitly excludes this repo
779                }
780            }
781        }
782
783        return result;
784    }    
785}