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.apache.maven.bridge;
20  
21  import javax.inject.Inject;
22  import javax.inject.Named;
23  import javax.inject.Singleton;
24  
25  import java.io.File;
26  import java.net.MalformedURLException;
27  import java.net.URL;
28  import java.util.ArrayList;
29  import java.util.Collection;
30  import java.util.Collections;
31  import java.util.HashSet;
32  import java.util.LinkedHashMap;
33  import java.util.List;
34  import java.util.Map;
35  import java.util.Properties;
36  import java.util.Set;
37  
38  import org.apache.maven.RepositoryUtils;
39  import org.apache.maven.artifact.Artifact;
40  import org.apache.maven.artifact.DefaultArtifact;
41  import org.apache.maven.artifact.InvalidRepositoryException;
42  import org.apache.maven.artifact.handler.ArtifactHandler;
43  import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
44  import org.apache.maven.artifact.metadata.ArtifactMetadata;
45  import org.apache.maven.artifact.repository.ArtifactRepository;
46  import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
47  import org.apache.maven.artifact.repository.Authentication;
48  import org.apache.maven.artifact.repository.MavenArtifactRepository;
49  import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
50  import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout2;
51  import org.apache.maven.artifact.resolver.filter.ExclusionArtifactFilter;
52  import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
53  import org.apache.maven.artifact.versioning.VersionRange;
54  import org.apache.maven.execution.MavenExecutionRequest;
55  import org.apache.maven.model.Dependency;
56  import org.apache.maven.model.Plugin;
57  import org.apache.maven.model.Repository;
58  import org.apache.maven.model.interpolation.ModelInterpolator;
59  import org.apache.maven.repository.Proxy;
60  import org.apache.maven.repository.RepositorySystem;
61  import org.apache.maven.settings.Mirror;
62  import org.codehaus.plexus.util.StringUtils;
63  import org.eclipse.aether.RepositorySystemSession;
64  import org.eclipse.aether.repository.AuthenticationContext;
65  import org.eclipse.aether.repository.AuthenticationSelector;
66  import org.eclipse.aether.repository.ProxySelector;
67  import org.eclipse.aether.repository.RemoteRepository;
68  import org.slf4j.Logger;
69  import org.slf4j.LoggerFactory;
70  
71  /**
72   * @author Jason van Zyl
73   * @since 3.2.3
74   */
75  @Singleton
76  @Named("default")
77  public class MavenRepositorySystem {
78  
79      // Singleton instance for static deprecated methods
80      private static MavenRepositorySystem instance;
81  
82      private static final Logger LOGGER = LoggerFactory.getLogger(MavenRepositorySystem.class);
83  
84      @Inject
85      private ArtifactHandlerManager artifactHandlerManager;
86  
87      @Inject
88      private Map<String, ArtifactRepositoryLayout> layouts;
89  
90      MavenRepositorySystem() {
91          instance = this;
92      }
93  
94      // DefaultProjectBuilder
95      public Artifact createArtifact(String groupId, String artifactId, String version, String scope, String type) {
96          return createArtifactX(groupId, artifactId, version, scope, type);
97      }
98  
99      // DefaultProjectBuilder
100     public Artifact createProjectArtifact(String groupId, String artifactId, String metaVersionId) {
101         return createProjectArtifactX(groupId, artifactId, metaVersionId);
102     }
103 
104     // DefaultProjectBuilder
105     public Artifact createDependencyArtifact(Dependency d) {
106         if (d.getVersion() == null) {
107             return null;
108         }
109 
110         VersionRange versionRange;
111         try {
112             versionRange = VersionRange.createFromVersionSpec(d.getVersion());
113         } catch (InvalidVersionSpecificationException e) {
114             return null;
115         }
116 
117         Artifact artifact = createDependencyArtifactX(
118                 d.getGroupId(),
119                 d.getArtifactId(),
120                 versionRange,
121                 d.getType(),
122                 d.getClassifier(),
123                 d.getScope(),
124                 d.isOptional());
125 
126         if (Artifact.SCOPE_SYSTEM.equals(d.getScope()) && d.getSystemPath() != null) {
127             artifact.setFile(new File(d.getSystemPath()));
128         }
129 
130         if (!d.getExclusions().isEmpty()) {
131             artifact.setDependencyFilter(new ExclusionArtifactFilter(d.getExclusions()));
132         }
133 
134         return artifact;
135     }
136 
137     // DefaultProjectBuilder
138     public Artifact createExtensionArtifact(String groupId, String artifactId, String version) {
139         VersionRange versionRange;
140         try {
141             versionRange = VersionRange.createFromVersionSpec(version);
142         } catch (InvalidVersionSpecificationException e) {
143             return null;
144         }
145 
146         return createExtensionArtifactX(groupId, artifactId, versionRange);
147     }
148 
149     // DefaultProjectBuilder
150     public Artifact createParentArtifact(String groupId, String artifactId, String version) {
151         return createParentArtifactX(groupId, artifactId, version);
152     }
153 
154     // DefaultProjectBuilder
155     public Artifact createPluginArtifact(Plugin plugin) {
156         VersionRange versionRange;
157         try {
158             String version = plugin.getVersion();
159             if (StringUtils.isEmpty(version)) {
160                 version = "RELEASE";
161             }
162             versionRange = VersionRange.createFromVersionSpec(version);
163         } catch (InvalidVersionSpecificationException e) {
164             return null;
165         }
166 
167         return createPluginArtifactX(plugin.getGroupId(), plugin.getArtifactId(), versionRange);
168     }
169 
170     public void injectMirror(List<ArtifactRepository> repositories, List<Mirror> mirrors) {
171         if (repositories != null && mirrors != null) {
172             for (ArtifactRepository repository : repositories) {
173                 Mirror mirror = getMirror(repository, mirrors);
174                 injectMirror(repository, mirror);
175             }
176         }
177     }
178 
179     private Mirror getMirror(RepositorySystemSession session, ArtifactRepository repository) {
180         if (session != null) {
181             org.eclipse.aether.repository.MirrorSelector selector = session.getMirrorSelector();
182             if (selector != null) {
183                 RemoteRepository repo = selector.getMirror(RepositoryUtils.toRepo(repository));
184                 if (repo != null) {
185                     Mirror mirror = new Mirror();
186                     mirror.setId(repo.getId());
187                     mirror.setUrl(repo.getUrl());
188                     mirror.setLayout(repo.getContentType());
189                     mirror.setBlocked(repo.isBlocked());
190                     return mirror;
191                 }
192             }
193         }
194         return null;
195     }
196 
197     public void injectMirror(RepositorySystemSession session, List<ArtifactRepository> repositories) {
198         if (repositories != null && session != null) {
199             for (ArtifactRepository repository : repositories) {
200                 Mirror mirror = getMirror(session, repository);
201                 injectMirror(repository, mirror);
202             }
203         }
204     }
205 
206     private void injectMirror(ArtifactRepository repository, Mirror mirror) {
207         if (mirror != null) {
208             ArtifactRepository original = createArtifactRepository(
209                     repository.getId(),
210                     repository.getUrl(),
211                     repository.getLayout(),
212                     repository.getSnapshots(),
213                     repository.getReleases());
214 
215             repository.setMirroredRepositories(Collections.singletonList(original));
216 
217             repository.setId(mirror.getId());
218             repository.setUrl(mirror.getUrl());
219 
220             if (StringUtils.isNotEmpty(mirror.getLayout())) {
221                 repository.setLayout(getLayout(mirror.getId(), mirror.getLayout()));
222             }
223 
224             repository.setBlocked(mirror.isBlocked());
225         }
226     }
227 
228     private Authentication getAuthentication(RepositorySystemSession session, ArtifactRepository repository) {
229         if (session != null) {
230             AuthenticationSelector selector = session.getAuthenticationSelector();
231             if (selector != null) {
232                 RemoteRepository repo = RepositoryUtils.toRepo(repository);
233                 org.eclipse.aether.repository.Authentication auth = selector.getAuthentication(repo);
234                 if (auth != null) {
235                     repo = new RemoteRepository.Builder(repo)
236                             .setAuthentication(auth)
237                             .build();
238                     AuthenticationContext authCtx = AuthenticationContext.forRepository(session, repo);
239                     Authentication result = new Authentication(
240                             authCtx.get(AuthenticationContext.USERNAME), authCtx.get(AuthenticationContext.PASSWORD));
241                     result.setPrivateKey(authCtx.get(AuthenticationContext.PRIVATE_KEY_PATH));
242                     result.setPassphrase(authCtx.get(AuthenticationContext.PRIVATE_KEY_PASSPHRASE));
243                     authCtx.close();
244                     return result;
245                 }
246             }
247         }
248         return null;
249     }
250 
251     public void injectAuthentication(RepositorySystemSession session, List<ArtifactRepository> repositories) {
252         if (repositories != null && session != null) {
253             for (ArtifactRepository repository : repositories) {
254                 repository.setAuthentication(getAuthentication(session, repository));
255             }
256         }
257     }
258 
259     private Proxy getProxy(RepositorySystemSession session, ArtifactRepository repository) {
260         if (session != null) {
261             ProxySelector selector = session.getProxySelector();
262             if (selector != null) {
263                 RemoteRepository repo = RepositoryUtils.toRepo(repository);
264                 org.eclipse.aether.repository.Proxy proxy = selector.getProxy(repo);
265                 if (proxy != null) {
266                     Proxy p = new Proxy();
267                     p.setHost(proxy.getHost());
268                     p.setProtocol(proxy.getType());
269                     p.setPort(proxy.getPort());
270                     if (proxy.getAuthentication() != null) {
271                         repo = new RemoteRepository.Builder(repo)
272                                 .setProxy(proxy)
273                                 .build();
274                         AuthenticationContext authCtx = AuthenticationContext.forProxy(session, repo);
275                         p.setUserName(authCtx.get(AuthenticationContext.USERNAME));
276                         p.setPassword(authCtx.get(AuthenticationContext.PASSWORD));
277                         p.setNtlmDomain(authCtx.get(AuthenticationContext.NTLM_DOMAIN));
278                         p.setNtlmHost(authCtx.get(AuthenticationContext.NTLM_WORKSTATION));
279                         authCtx.close();
280                     }
281                     return p;
282                 }
283             }
284         }
285         return null;
286     }
287 
288     public void injectProxy(RepositorySystemSession session, List<ArtifactRepository> repositories) {
289         if (repositories != null && session != null) {
290             for (ArtifactRepository repository : repositories) {
291                 repository.setProxy(getProxy(session, repository));
292             }
293         }
294     }
295 
296     private ArtifactRepositoryLayout getLayout(String repoId, String layoutId) {
297         ArtifactRepositoryLayout layout = layouts.get(layoutId);
298 
299         if (layout == null) {
300             LOGGER.debug("No layout '{}' found for repository id '{}'", layoutId, repoId);
301             layout = new UnknownRepositoryLayout(layoutId, layouts.get("default"));
302         }
303 
304         return layout;
305     }
306 
307     //
308     // Taken from LegacyRepositorySystem
309     //
310 
311     public static org.apache.maven.model.Repository fromSettingsRepository(
312             org.apache.maven.settings.Repository settingsRepository) {
313         org.apache.maven.model.Repository modelRepository = new org.apache.maven.model.Repository();
314         modelRepository.setId(settingsRepository.getId());
315         modelRepository.setLayout(settingsRepository.getLayout());
316         modelRepository.setName(settingsRepository.getName());
317         modelRepository.setUrl(settingsRepository.getUrl());
318         modelRepository.setReleases(fromSettingsRepositoryPolicy(settingsRepository.getReleases()));
319         modelRepository.setSnapshots(fromSettingsRepositoryPolicy(settingsRepository.getSnapshots()));
320         return modelRepository;
321     }
322 
323     public static org.apache.maven.model.RepositoryPolicy fromSettingsRepositoryPolicy(
324             org.apache.maven.settings.RepositoryPolicy settingsRepositoryPolicy) {
325         org.apache.maven.model.RepositoryPolicy modelRepositoryPolicy = new org.apache.maven.model.RepositoryPolicy();
326         if (settingsRepositoryPolicy != null) {
327             modelRepositoryPolicy.setEnabled(settingsRepositoryPolicy.isEnabled());
328             modelRepositoryPolicy.setUpdatePolicy(settingsRepositoryPolicy.getUpdatePolicy());
329             modelRepositoryPolicy.setChecksumPolicy(settingsRepositoryPolicy.getChecksumPolicy());
330         }
331         return modelRepositoryPolicy;
332     }
333 
334     /**
335      * @deprecated use a service method {@link #buildArtifactRepositoryFromRepo(org.apache.maven.settings.Repository)} instead
336      */
337     @Deprecated
338     public static ArtifactRepository buildArtifactRepository(org.apache.maven.settings.Repository repo)
339             throws InvalidRepositoryException {
340         return instance.buildArtifactRepositoryFromRepo(repo);
341     }
342 
343     /**
344      * @since 3.9.12
345      */
346     public ArtifactRepository buildArtifactRepositoryFromRepo(org.apache.maven.settings.Repository repo)
347             throws InvalidRepositoryException {
348         return buildArtifactRepositoryFromRepo(fromSettingsRepository(repo));
349     }
350 
351     /**
352      * @deprecated use a service method {@link #buildArtifactRepositoryFromRepo(Repository)} instead
353      */
354     @Deprecated
355     public static ArtifactRepository buildArtifactRepository(org.apache.maven.model.Repository repo)
356             throws InvalidRepositoryException {
357         return instance.buildArtifactRepositoryFromRepo(repo);
358     }
359 
360     /**
361      * @since 3.9.12
362      */
363     public ArtifactRepository buildArtifactRepositoryFromRepo(org.apache.maven.model.Repository repo)
364             throws InvalidRepositoryException {
365         if (repo != null) {
366             String id = repo.getId();
367 
368             if (StringUtils.isEmpty(id)) {
369                 throw new InvalidRepositoryException("Repository identifier missing", "");
370             }
371 
372             String url = repo.getUrl();
373 
374             if (StringUtils.isEmpty(url)) {
375                 throw new InvalidRepositoryException("URL missing for repository " + id, id);
376             }
377 
378             ArtifactRepositoryPolicy snapshots = buildArtifactRepositoryPolicy(repo.getSnapshots());
379 
380             ArtifactRepositoryPolicy releases = buildArtifactRepositoryPolicy(repo.getReleases());
381 
382             ArtifactRepositoryLayout layout = getLayout(repo.getId(), repo.getLayout());
383 
384             return createArtifactRepository(id, url, layout, snapshots, releases);
385         } else {
386             return null;
387         }
388     }
389 
390     public static ArtifactRepositoryPolicy buildArtifactRepositoryPolicy(
391             org.apache.maven.model.RepositoryPolicy policy) {
392         boolean enabled = true;
393 
394         String updatePolicy = null;
395 
396         String checksumPolicy = null;
397 
398         if (policy != null) {
399             enabled = policy.isEnabled();
400 
401             if (policy.getUpdatePolicy() != null) {
402                 updatePolicy = policy.getUpdatePolicy();
403             }
404             if (policy.getChecksumPolicy() != null) {
405                 checksumPolicy = policy.getChecksumPolicy();
406             }
407         }
408 
409         return new ArtifactRepositoryPolicy(enabled, updatePolicy, checksumPolicy);
410     }
411 
412     public ArtifactRepository createArtifactRepository(
413             String id,
414             String url,
415             String layoutId,
416             ArtifactRepositoryPolicy snapshots,
417             ArtifactRepositoryPolicy releases)
418             throws Exception {
419         ArtifactRepositoryLayout layout = layouts.get(layoutId);
420 
421         checkLayout(id, layoutId, layout);
422 
423         return createArtifactRepository(id, url, layout, snapshots, releases);
424     }
425 
426     private void checkLayout(String repositoryId, String layoutId, ArtifactRepositoryLayout layout) throws Exception {
427         if (layout == null) {
428             throw new Exception(
429                     String.format("Cannot find ArtifactRepositoryLayout instance for: %s %s", layoutId, repositoryId));
430         }
431     }
432 
433     public static ArtifactRepository createArtifactRepository(
434             String id,
435             String url,
436             ArtifactRepositoryLayout repositoryLayout,
437             ArtifactRepositoryPolicy snapshots,
438             ArtifactRepositoryPolicy releases) {
439         if (snapshots == null) {
440             snapshots = new ArtifactRepositoryPolicy();
441         }
442 
443         if (releases == null) {
444             releases = new ArtifactRepositoryPolicy();
445         }
446 
447         ArtifactRepository repository;
448         if (repositoryLayout instanceof ArtifactRepositoryLayout2) {
449             repository = ((ArtifactRepositoryLayout2) repositoryLayout)
450                     .newMavenArtifactRepository(id, url, snapshots, releases);
451         } else {
452             repository = new MavenArtifactRepository(id, url, repositoryLayout, snapshots, releases);
453         }
454 
455         return repository;
456     }
457 
458     // ArtifactFactory
459     private Artifact createArtifactX(String groupId, String artifactId, String version, String scope, String type) {
460         return createArtifactX(groupId, artifactId, version, scope, type, null, null);
461     }
462 
463     private Artifact createDependencyArtifactX(
464             String groupId,
465             String artifactId,
466             VersionRange versionRange,
467             String type,
468             String classifier,
469             String scope,
470             boolean optional) {
471         return createArtifactX(groupId, artifactId, versionRange, type, classifier, scope, null, optional);
472     }
473 
474     private Artifact createProjectArtifactX(String groupId, String artifactId, String version) {
475         return createProjectArtifactX(groupId, artifactId, version, null);
476     }
477 
478     private Artifact createParentArtifactX(String groupId, String artifactId, String version) {
479         return createProjectArtifactX(groupId, artifactId, version);
480     }
481 
482     private Artifact createPluginArtifactX(String groupId, String artifactId, VersionRange versionRange) {
483         return createArtifactX(groupId, artifactId, versionRange, "maven-plugin", null, Artifact.SCOPE_RUNTIME, null);
484     }
485 
486     private Artifact createProjectArtifactX(String groupId, String artifactId, String version, String scope) {
487         return createArtifactX(groupId, artifactId, version, scope, "pom");
488     }
489 
490     private Artifact createExtensionArtifactX(String groupId, String artifactId, VersionRange versionRange) {
491         return createArtifactX(groupId, artifactId, versionRange, "jar", null, Artifact.SCOPE_RUNTIME, null);
492     }
493 
494     private Artifact createArtifactX(
495             String groupId,
496             String artifactId,
497             String version,
498             String scope,
499             String type,
500             String classifier,
501             String inheritedScope) {
502         VersionRange versionRange = null;
503         if (version != null) {
504             versionRange = VersionRange.createFromVersion(version);
505         }
506         return createArtifactX(groupId, artifactId, versionRange, type, classifier, scope, inheritedScope);
507     }
508 
509     private Artifact createArtifactX(
510             String groupId,
511             String artifactId,
512             VersionRange versionRange,
513             String type,
514             String classifier,
515             String scope,
516             String inheritedScope) {
517         return createArtifactX(groupId, artifactId, versionRange, type, classifier, scope, inheritedScope, false);
518     }
519 
520     @SuppressWarnings("checkstyle:parameternumber")
521     private Artifact createArtifactX(
522             String groupId,
523             String artifactId,
524             VersionRange versionRange,
525             String type,
526             String classifier,
527             String scope,
528             String inheritedScope,
529             boolean optional) {
530         String desiredScope = Artifact.SCOPE_RUNTIME;
531 
532         if (inheritedScope == null) {
533             desiredScope = scope;
534         } else if (Artifact.SCOPE_TEST.equals(scope) || Artifact.SCOPE_PROVIDED.equals(scope)) {
535             return null;
536         } else if (Artifact.SCOPE_COMPILE.equals(scope) && Artifact.SCOPE_COMPILE.equals(inheritedScope)) {
537             // added to retain compile artifactScope. Remove if you want compile inherited as runtime
538             desiredScope = Artifact.SCOPE_COMPILE;
539         }
540 
541         if (Artifact.SCOPE_TEST.equals(inheritedScope)) {
542             desiredScope = Artifact.SCOPE_TEST;
543         }
544 
545         if (Artifact.SCOPE_PROVIDED.equals(inheritedScope)) {
546             desiredScope = Artifact.SCOPE_PROVIDED;
547         }
548 
549         if (Artifact.SCOPE_SYSTEM.equals(scope)) {
550             // system scopes come through unchanged...
551             desiredScope = Artifact.SCOPE_SYSTEM;
552         }
553 
554         ArtifactHandler handler = artifactHandlerManager.getArtifactHandler(type);
555 
556         return new DefaultArtifact(
557                 groupId, artifactId, versionRange, desiredScope, type, classifier, handler, optional);
558     }
559 
560     //
561     // Code taken from LegacyRepositorySystem
562     //
563 
564     public ArtifactRepository createDefaultRemoteRepository(MavenExecutionRequest request) throws Exception {
565         return createRepository(
566                 determineDefaultRemoteRepositoryUrl(request),
567                 RepositorySystem.DEFAULT_REMOTE_REPO_ID,
568                 true,
569                 ArtifactRepositoryPolicy.UPDATE_POLICY_DAILY,
570                 false,
571                 ArtifactRepositoryPolicy.UPDATE_POLICY_DAILY,
572                 ArtifactRepositoryPolicy.CHECKSUM_POLICY_WARN);
573     }
574 
575     private String determineDefaultRemoteRepositoryUrl(MavenExecutionRequest request) {
576         Properties effective = new Properties();
577         effective.putAll(request.getSystemProperties());
578         effective.putAll(request.getUserProperties());
579         return effective.getProperty(
580                 ModelInterpolator.MAVEN_REPO_CENTRAL_KEY, ModelInterpolator.DEFAULT_MAVEN_REPO_CENTRAL_URL);
581     }
582 
583     public ArtifactRepository createRepository(
584             String url,
585             String repositoryId,
586             boolean releases,
587             String releaseUpdates,
588             boolean snapshots,
589             String snapshotUpdates,
590             String checksumPolicy)
591             throws Exception {
592         ArtifactRepositoryPolicy snapshotsPolicy =
593                 new ArtifactRepositoryPolicy(snapshots, snapshotUpdates, checksumPolicy);
594 
595         ArtifactRepositoryPolicy releasesPolicy =
596                 new ArtifactRepositoryPolicy(releases, releaseUpdates, checksumPolicy);
597 
598         return createArtifactRepository(repositoryId, url, "default", snapshotsPolicy, releasesPolicy);
599     }
600 
601     public Set<String> getRepoIds(List<ArtifactRepository> repositories) {
602         Set<String> repoIds = new HashSet<>();
603 
604         if (repositories != null) {
605             for (ArtifactRepository repository : repositories) {
606                 repoIds.add(repository.getId());
607             }
608         }
609 
610         return repoIds;
611     }
612 
613     /**
614      * Source from org.apache.maven.repository.legacy.LegacyRepositorySystem#getEffectiveRepositories
615      *
616      * @param repositories
617      * @return
618      * @since 3.6.1
619      */
620     public List<ArtifactRepository> getEffectiveRepositories(List<ArtifactRepository> repositories) {
621         if (repositories == null) {
622             return null;
623         }
624 
625         Map<String, List<ArtifactRepository>> reposByKey = new LinkedHashMap<>();
626 
627         for (ArtifactRepository repository : repositories) {
628             String key = repository.getId();
629 
630             List<ArtifactRepository> aliasedRepos = reposByKey.get(key);
631 
632             if (aliasedRepos == null) {
633                 aliasedRepos = new ArrayList<>();
634                 reposByKey.put(key, aliasedRepos);
635             }
636 
637             aliasedRepos.add(repository);
638         }
639 
640         List<ArtifactRepository> effectiveRepositories = new ArrayList<>();
641 
642         for (List<ArtifactRepository> aliasedRepos : reposByKey.values()) {
643             List<ArtifactRepository> mirroredRepos = new ArrayList<>();
644 
645             List<ArtifactRepositoryPolicy> releasePolicies = new ArrayList<>(aliasedRepos.size());
646 
647             for (ArtifactRepository aliasedRepo : aliasedRepos) {
648                 releasePolicies.add(aliasedRepo.getReleases());
649                 mirroredRepos.addAll(aliasedRepo.getMirroredRepositories());
650             }
651 
652             ArtifactRepositoryPolicy releasePolicy = getEffectivePolicy(releasePolicies);
653 
654             List<ArtifactRepositoryPolicy> snapshotPolicies = new ArrayList<>(aliasedRepos.size());
655 
656             for (ArtifactRepository aliasedRepo : aliasedRepos) {
657                 snapshotPolicies.add(aliasedRepo.getSnapshots());
658             }
659 
660             ArtifactRepositoryPolicy snapshotPolicy = getEffectivePolicy(snapshotPolicies);
661 
662             ArtifactRepository aliasedRepo = aliasedRepos.get(0);
663 
664             ArtifactRepository effectiveRepository = createArtifactRepository(
665                     aliasedRepo.getId(), aliasedRepo.getUrl(), aliasedRepo.getLayout(), snapshotPolicy, releasePolicy);
666 
667             effectiveRepository.setAuthentication(aliasedRepo.getAuthentication());
668 
669             effectiveRepository.setProxy(aliasedRepo.getProxy());
670 
671             effectiveRepository.setMirroredRepositories(mirroredRepos);
672 
673             effectiveRepository.setBlocked(aliasedRepo.isBlocked());
674 
675             effectiveRepositories.add(effectiveRepository);
676         }
677 
678         return effectiveRepositories;
679     }
680 
681     private ArtifactRepositoryPolicy getEffectivePolicy(Collection<ArtifactRepositoryPolicy> policies) {
682         ArtifactRepositoryPolicy effectivePolicy = null;
683 
684         for (ArtifactRepositoryPolicy policy : policies) {
685             if (effectivePolicy == null) {
686                 effectivePolicy = new ArtifactRepositoryPolicy(policy);
687             } else {
688                 effectivePolicy.merge(policy);
689             }
690         }
691 
692         return effectivePolicy;
693     }
694 
695     public ArtifactRepository createLocalRepository(MavenExecutionRequest request, File localRepository)
696             throws Exception {
697         return createRepository(
698                 "file://" + localRepository.toURI().getRawPath(),
699                 RepositorySystem.DEFAULT_LOCAL_REPO_ID,
700                 true,
701                 ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS,
702                 true,
703                 ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS,
704                 ArtifactRepositoryPolicy.CHECKSUM_POLICY_IGNORE);
705     }
706 
707     private static final String WILDCARD = "*";
708 
709     private static final String EXTERNAL_WILDCARD = "external:*";
710 
711     private static final String EXTERNAL_HTTP_WILDCARD = "external:http:*";
712 
713     public static Mirror getMirror(ArtifactRepository repository, List<Mirror> mirrors) {
714         String repoId = repository.getId();
715 
716         if (repoId != null && mirrors != null) {
717             for (Mirror mirror : mirrors) {
718                 if (repoId.equals(mirror.getMirrorOf()) && matchesLayout(repository, mirror)) {
719                     return mirror;
720                 }
721             }
722 
723             for (Mirror mirror : mirrors) {
724                 if (matchPattern(repository, mirror.getMirrorOf()) && matchesLayout(repository, mirror)) {
725                     return mirror;
726                 }
727             }
728         }
729 
730         return null;
731     }
732 
733     /**
734      * This method checks if the pattern matches the originalRepository. Valid patterns:
735      * <ul>
736      * <li>{@code *} (since 2.0.5)= everything,</li>
737      * <li>{@code external:*}  (since 2.0.9)= everything not on the localhost and not file based,</li>
738      * <li>{@code external:http:*} (since 3.8.0)= any repository not on the localhost using HTTP,</li>
739      * <li>{@code repo,repo1}  (since 2.0.9)= {@code repo} or {@code repo1},</li>
740      * <li>{@code *,!repo1} (since 2.0.9)= everything except {@code repo1}.</li>
741      * </ul>
742      *
743      * @param originalRepository to compare for a match.
744      * @param pattern used for match.
745      * @return true if the repository is a match to this pattern.
746      */
747     static boolean matchPattern(ArtifactRepository originalRepository, String pattern) {
748         boolean result = false;
749         String originalId = originalRepository.getId();
750 
751         // simple checks first to short circuit processing below.
752         if (WILDCARD.equals(pattern) || pattern.equals(originalId)) {
753             result = true;
754         } else {
755             // process the list
756             String[] repos = pattern.split(",");
757             for (String repo : repos) {
758                 // see if this is a negative match
759                 if (repo.length() > 1 && repo.startsWith("!")) {
760                     if (repo.substring(1).equals(originalId)) {
761                         // explicitly exclude. Set result and stop processing.
762                         result = false;
763                         break;
764                     }
765                 }
766                 // check for exact match
767                 else if (repo.equals(originalId)) {
768                     result = true;
769                     break;
770                 }
771                 // check for external:*
772                 else if (EXTERNAL_WILDCARD.equals(repo) && isExternalRepo(originalRepository)) {
773                     result = true;
774                     // don't stop processing in case a future segment explicitly excludes this repo
775                 }
776                 // check for external:http:*
777                 else if (EXTERNAL_HTTP_WILDCARD.equals(repo) && isExternalHttpRepo(originalRepository)) {
778                     result = true;
779                     // don't stop processing in case a future segment explicitly excludes this repo
780                 } else if (WILDCARD.equals(repo)) {
781                     result = true;
782                     // don't stop processing in case a future segment explicitly excludes this repo
783                 }
784             }
785         }
786         return result;
787     }
788 
789     /**
790      * Checks the URL to see if this repository refers to an external repository
791      *
792      * @param originalRepository
793      * @return true if external.
794      */
795     static boolean isExternalRepo(ArtifactRepository originalRepository) {
796         try {
797             URL url = new URL(originalRepository.getUrl());
798             return !(isLocal(url.getHost()) || url.getProtocol().equals("file"));
799         } catch (MalformedURLException e) {
800             // bad url just skip it here. It should have been validated already, but the wagon lookup will deal with it
801             return false;
802         }
803     }
804 
805     private static boolean isLocal(String host) {
806         return "localhost".equals(host) || "127.0.0.1".equals(host);
807     }
808 
809     /**
810      * Checks the URL to see if this repository refers to a non-localhost repository using HTTP.
811      *
812      * @param originalRepository
813      * @return true if external.
814      */
815     static boolean isExternalHttpRepo(ArtifactRepository originalRepository) {
816         try {
817             URL url = new URL(originalRepository.getUrl());
818             return ("http".equalsIgnoreCase(url.getProtocol())
819                             || "dav".equalsIgnoreCase(url.getProtocol())
820                             || "dav:http".equalsIgnoreCase(url.getProtocol())
821                             || "dav+http".equalsIgnoreCase(url.getProtocol()))
822                     && !isLocal(url.getHost());
823         } catch (MalformedURLException e) {
824             // bad url just skip it here. It should have been validated already, but the wagon lookup will deal with it
825             return false;
826         }
827     }
828 
829     static boolean matchesLayout(ArtifactRepository repository, Mirror mirror) {
830         return matchesLayout(RepositoryUtils.getLayout(repository), mirror.getMirrorOfLayouts());
831     }
832 
833     /**
834      * Checks whether the layouts configured for a mirror match with the layout of the repository.
835      *
836      * @param repoLayout The layout of the repository, may be {@code null}.
837      * @param mirrorLayout The layouts supported by the mirror, may be {@code null}.
838      * @return {@code true} if the layouts associated with the mirror match the layout of the original repository,
839      *         {@code false} otherwise.
840      */
841     static boolean matchesLayout(String repoLayout, String mirrorLayout) {
842         boolean result = false;
843 
844         // simple checks first to short circuit processing below.
845         if (StringUtils.isEmpty(mirrorLayout) || WILDCARD.equals(mirrorLayout)) {
846             result = true;
847         } else if (mirrorLayout.equals(repoLayout)) {
848             result = true;
849         } else {
850             // process the list
851             String[] layouts = mirrorLayout.split(",");
852             for (String layout : layouts) {
853                 // see if this is a negative match
854                 if (layout.length() > 1 && layout.startsWith("!")) {
855                     if (layout.substring(1).equals(repoLayout)) {
856                         // explicitly exclude. Set result and stop processing.
857                         result = false;
858                         break;
859                     }
860                 }
861                 // check for exact match
862                 else if (layout.equals(repoLayout)) {
863                     result = true;
864                     break;
865                 } else if (WILDCARD.equals(layout)) {
866                     result = true;
867                     // don't stop processing in case a future segment explicitly excludes this repo
868                 }
869             }
870         }
871 
872         return result;
873     }
874 
875     /**
876      * In the future, the legacy system might encounter repository types for which no layout components exists because
877      * the actual communication with the repository happens via a repository connector. As a minimum, the legacy system
878      * needs to retain the id of this layout so that the content type of the remote repository can still be accurately
879      * described.
880      */
881     static class UnknownRepositoryLayout implements ArtifactRepositoryLayout {
882 
883         private final String id;
884 
885         private final ArtifactRepositoryLayout fallback;
886 
887         UnknownRepositoryLayout(String id, ArtifactRepositoryLayout fallback) {
888             this.id = id;
889             this.fallback = fallback;
890         }
891 
892         public String getId() {
893             return id;
894         }
895 
896         public String pathOf(Artifact artifact) {
897             return fallback.pathOf(artifact);
898         }
899 
900         public String pathOfLocalRepositoryMetadata(ArtifactMetadata metadata, ArtifactRepository repository) {
901             return fallback.pathOfLocalRepositoryMetadata(metadata, repository);
902         }
903 
904         public String pathOfRemoteRepositoryMetadata(ArtifactMetadata metadata) {
905             return fallback.pathOfRemoteRepositoryMetadata(metadata);
906         }
907 
908         @Override
909         public String toString() {
910             return getId();
911         }
912     }
913 }