View Javadoc
1   package org.apache.maven.bridge;
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.util.StringUtils;
30  
31  public class MirrorSelector
32  {
33      private static final String WILDCARD = "*";
34  
35      private static final String EXTERNAL_WILDCARD = "external:*";
36  
37      public static Mirror getMirror( ArtifactRepository repository, List<Mirror> mirrors )
38      {
39          String repoId = repository.getId();
40  
41          if ( repoId != null && mirrors != null )
42          {
43              for ( Mirror mirror : mirrors )
44              {
45                  if ( repoId.equals( mirror.getMirrorOf() ) && matchesLayout( repository, mirror ) )
46                  {
47                      return mirror;
48                  }
49              }
50  
51              for ( Mirror mirror : mirrors )
52              {
53                  if ( matchPattern( repository, mirror.getMirrorOf() ) && matchesLayout( repository, mirror ) )
54                  {
55                      return mirror;
56                  }
57              }
58          }
59  
60          return null;
61      }
62  
63      /**
64       * This method checks if the pattern matches the originalRepository. Valid patterns: * = everything external:* =
65       * everything not on the localhost and not file based. repo,repo1 = repo or repo1 *,!repo1 = everything except repo1
66       *
67       * @param originalRepository to compare for a match.
68       * @param pattern used for match. Currently only '*' is supported.
69       * @return true if the repository is a match to this pattern.
70       */
71      static boolean matchPattern( ArtifactRepository originalRepository, String pattern )
72      {
73          boolean result = false;
74          String originalId = originalRepository.getId();
75  
76          // simple checks first to short circuit processing below.
77          if ( WILDCARD.equals( pattern ) || pattern.equals( originalId ) )
78          {
79              result = true;
80          }
81          else
82          {
83              // process the list
84              String[] repos = pattern.split( "," );
85              for ( String repo : repos )
86              {
87                  // see if this is a negative match
88                  if ( repo.length() > 1 && repo.startsWith( "!" ) )
89                  {
90                      if ( repo.substring( 1 ).equals( originalId ) )
91                      {
92                          // explicitly exclude. Set result and stop processing.
93                          result = false;
94                          break;
95                      }
96                  }
97                  // check for exact match
98                  else if ( repo.equals( originalId ) )
99                  {
100                     result = true;
101                     break;
102                 }
103                 // check for external:*
104                 else if ( EXTERNAL_WILDCARD.equals( repo ) && isExternalRepo( originalRepository ) )
105                 {
106                     result = true;
107                     // don't stop processing in case a future segment explicitly excludes this repo
108                 }
109                 else if ( WILDCARD.equals( repo ) )
110                 {
111                     result = true;
112                     // don't stop processing in case a future segment explicitly excludes this repo
113                 }
114             }
115         }
116         return result;
117     }
118 
119     /**
120      * Checks the URL to see if this repository refers to an external repository
121      *
122      * @param originalRepository
123      * @return true if external.
124      */
125     static boolean isExternalRepo( ArtifactRepository originalRepository )
126     {
127         try
128         {
129             URL url = new URL( originalRepository.getUrl() );
130             return !( url.getHost().equals( "localhost" ) || url.getHost().equals( "127.0.0.1" ) || url.getProtocol().equals( "file" ) );
131         }
132         catch ( MalformedURLException e )
133         {
134             // bad url just skip it here. It should have been validated already, but the wagon lookup will deal with it
135             return false;
136         }
137     }
138 
139     static boolean matchesLayout( ArtifactRepository repository, Mirror mirror )
140     {
141         return matchesLayout( RepositoryUtils.getLayout( repository ), mirror.getMirrorOfLayouts() );
142     }
143 
144     /**
145      * Checks whether the layouts configured for a mirror match with the layout of the repository.
146      *
147      * @param repoLayout The layout of the repository, may be {@code null}.
148      * @param mirrorLayout The layouts supported by the mirror, may be {@code null}.
149      * @return {@code true} if the layouts associated with the mirror match the layout of the original repository,
150      *         {@code false} otherwise.
151      */
152     static boolean matchesLayout( String repoLayout, String mirrorLayout )
153     {
154         boolean result = false;
155 
156         // simple checks first to short circuit processing below.
157         if ( StringUtils.isEmpty( mirrorLayout ) || WILDCARD.equals( mirrorLayout ) )
158         {
159             result = true;
160         }
161         else if ( mirrorLayout.equals( repoLayout ) )
162         {
163             result = true;
164         }
165         else
166         {
167             // process the list
168             String[] layouts = mirrorLayout.split( "," );
169             for ( String layout : layouts )
170             {
171                 // see if this is a negative match
172                 if ( layout.length() > 1 && layout.startsWith( "!" ) )
173                 {
174                     if ( layout.substring( 1 ).equals( repoLayout ) )
175                     {
176                         // explicitly exclude. Set result and stop processing.
177                         result = false;
178                         break;
179                     }
180                 }
181                 // check for exact match
182                 else if ( layout.equals( repoLayout ) )
183                 {
184                     result = true;
185                     break;
186                 }
187                 else if ( WILDCARD.equals( layout ) )
188                 {
189                     result = true;
190                     // don't stop processing in case a future segment explicitly excludes this repo
191                 }
192             }
193         }
194 
195         return result;
196     }
197 }