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