View Javadoc
1   package org.apache.maven.repository;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.net.MalformedURLException;
23  import java.net.URL;
24  import java.util.List;
25  
26  import org.apache.maven.RepositoryUtils;
27  import org.apache.maven.artifact.repository.ArtifactRepository;
28  import org.apache.maven.settings.Mirror;
29  import org.codehaus.plexus.component.annotations.Component;
30  import org.codehaus.plexus.util.StringUtils;
31  
32  /**
33   * DefaultMirrorSelector
34   */
35  @Component( role = MirrorSelector.class )
36  public class DefaultMirrorSelector
37      implements MirrorSelector
38  {
39  
40      private static final String WILDCARD = "*";
41  
42      private static final String EXTERNAL_WILDCARD = "external:*";
43  
44      public Mirror getMirror( ArtifactRepository repository, List<Mirror> mirrors )
45      {
46          String repoId = repository.getId();
47  
48          if ( repoId != null && mirrors != null )
49          {
50              for ( Mirror mirror : mirrors )
51              {
52                  if ( repoId.equals( mirror.getMirrorOf() ) && matchesLayout( repository, mirror ) )
53                  {
54                      return mirror;
55                  }
56              }
57  
58              for ( Mirror mirror : mirrors )
59              {
60                  if ( matchPattern( repository, mirror.getMirrorOf() ) && matchesLayout( repository, mirror ) )
61                  {
62                      return mirror;
63                  }
64              }
65          }
66  
67          return null;
68      }
69  
70      /**
71       * This method checks if the pattern matches the originalRepository. Valid patterns: * =
72       * everything external:* = everything not on the localhost and not file based. repo,repo1 = repo
73       * or repo1 *,!repo1 = everything except repo1
74       *
75       * @param originalRepository to compare for a match.
76       * @param pattern used for match. Currently only '*' is supported.
77       * @return true if the repository is a match to this pattern.
78       */
79      static boolean matchPattern( ArtifactRepository originalRepository, String pattern )
80      {
81          boolean result = false;
82          String originalId = originalRepository.getId();
83  
84          // simple checks first to short circuit processing below.
85          if ( WILDCARD.equals( pattern ) || pattern.equals( originalId ) )
86          {
87              result = true;
88          }
89          else
90          {
91              // process the list
92              String[] repos = pattern.split( "," );
93              for ( String repo : repos )
94              {
95                  repo = repo.trim();
96                  // see if this is a negative match
97                  if ( repo.length() > 1 && repo.startsWith( "!" ) )
98                  {
99                      if ( repo.substring( 1 ).equals( originalId ) )
100                     {
101                         // explicitly exclude. Set result and stop processing.
102                         result = false;
103                         break;
104                     }
105                 }
106                 // check for exact match
107                 else if ( repo.equals( originalId ) )
108                 {
109                     result = true;
110                     break;
111                 }
112                 // check for external:*
113                 else if ( EXTERNAL_WILDCARD.equals( repo ) && isExternalRepo( originalRepository ) )
114                 {
115                     result = true;
116                     // don't stop processing in case a future segment explicitly excludes this repo
117                 }
118                 else if ( WILDCARD.equals( repo ) )
119                 {
120                     result = true;
121                     // don't stop processing in case a future segment explicitly excludes this repo
122                 }
123             }
124         }
125         return result;
126     }
127 
128     /**
129      * Checks the URL to see if this repository refers to an external repository
130      *
131      * @param originalRepository
132      * @return true if external.
133      */
134     static boolean isExternalRepo( ArtifactRepository originalRepository )
135     {
136         try
137         {
138             URL url = new URL( originalRepository.getUrl() );
139             return !( url.getHost().equals( "localhost" ) || url.getHost().equals( "127.0.0.1" )
140                             || url.getProtocol().equals( "file" ) );
141         }
142         catch ( MalformedURLException e )
143         {
144             // bad url just skip it here. It should have been validated already, but the wagon lookup will deal with it
145             return false;
146         }
147     }
148 
149     static boolean matchesLayout( ArtifactRepository repository, Mirror mirror )
150     {
151         return matchesLayout( RepositoryUtils.getLayout( repository ), mirror.getMirrorOfLayouts() );
152     }
153 
154     /**
155      * Checks whether the layouts configured for a mirror match with the layout of the repository.
156      *
157      * @param repoLayout The layout of the repository, may be {@code null}.
158      * @param mirrorLayout The layouts supported by the mirror, may be {@code null}.
159      * @return {@code true} if the layouts associated with the mirror match the layout of the original repository,
160      *         {@code false} otherwise.
161      */
162     static boolean matchesLayout( String repoLayout, String mirrorLayout )
163     {
164         boolean result = false;
165 
166         // simple checks first to short circuit processing below.
167         if ( StringUtils.isEmpty( mirrorLayout ) || WILDCARD.equals( mirrorLayout ) )
168         {
169             result = true;
170         }
171         else if ( mirrorLayout.equals( repoLayout ) )
172         {
173             result = true;
174         }
175         else
176         {
177             // process the list
178             String[] layouts = mirrorLayout.split( "," );
179             for ( String layout : layouts )
180             {
181                 // see if this is a negative match
182                 if ( layout.length() > 1 && layout.startsWith( "!" ) )
183                 {
184                     if ( layout.substring( 1 ).equals( repoLayout ) )
185                     {
186                         // explicitly exclude. Set result and stop processing.
187                         result = false;
188                         break;
189                     }
190                 }
191                 // check for exact match
192                 else if ( layout.equals( repoLayout ) )
193                 {
194                     result = true;
195                     break;
196                 }
197                 else if ( WILDCARD.equals( layout ) )
198                 {
199                     result = true;
200                     // don't stop processing in case a future segment explicitly excludes this repo
201                 }
202             }
203         }
204 
205         return result;
206     }
207 
208 }