View Javadoc
1   package org.apache.maven.settings.validation;
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.util.HashSet;
23  import java.util.List;
24  import java.util.Set;
25  import java.util.regex.Pattern;
26  
27  import javax.inject.Named;
28  import javax.inject.Singleton;
29  
30  import org.apache.maven.settings.Mirror;
31  import org.apache.maven.settings.Profile;
32  import org.apache.maven.settings.Repository;
33  import org.apache.maven.settings.Proxy;
34  import org.apache.maven.settings.Server;
35  import org.apache.maven.settings.Settings;
36  import org.apache.maven.settings.building.SettingsProblem.Severity;
37  import org.apache.maven.settings.building.SettingsProblemCollector;
38  import org.codehaus.plexus.util.StringUtils;
39  
40  /**
41   * @author Milos Kleint
42   */
43  @Named
44  @Singleton
45  public class DefaultSettingsValidator
46      implements SettingsValidator
47  {
48  
49      private static final String ID = "[\\w.-]+";
50      private static final Pattern ID_REGEX = Pattern.compile( ID );
51  
52      private static final String ILLEGAL_FS_CHARS = "\\/:\"<>|?*";
53  
54      private static final String ILLEGAL_REPO_ID_CHARS = ILLEGAL_FS_CHARS;
55  
56      @Override
57      public void validate( Settings settings, SettingsProblemCollector problems )
58      {
59          if ( settings.isUsePluginRegistry() )
60          {
61              addViolation( problems, Severity.WARNING, "usePluginRegistry", null, "is deprecated and has no effect." );
62          }
63  
64          List<String> pluginGroups = settings.getPluginGroups();
65  
66          if ( pluginGroups != null )
67          {
68              for ( int i = 0; i < pluginGroups.size(); i++ )
69              {
70                  String pluginGroup = pluginGroups.get( i ).trim();
71  
72                  if ( StringUtils.isBlank( pluginGroup ) )
73                  {
74                      addViolation( problems, Severity.ERROR, "pluginGroups.pluginGroup[" + i + "]", null,
75                                    "must not be empty" );
76                  }
77                   else if ( !ID_REGEX.matcher( pluginGroup ).matches() )
78                  {
79                      addViolation( problems, Severity.ERROR, "pluginGroups.pluginGroup[" + i + "]", null,
80                                    "must denote a valid group id and match the pattern " + ID );
81                  }
82              }
83          }
84  
85          List<Server> servers = settings.getServers();
86  
87          if ( servers != null )
88          {
89              Set<String> serverIds = new HashSet<>();
90  
91              for ( int i = 0; i < servers.size(); i++ )
92              {
93                  Server server = servers.get( i );
94  
95                  validateStringNotEmpty( problems, "servers.server[" + i + "].id", server.getId(), null );
96  
97                  if ( !serverIds.add( server.getId() ) )
98                  {
99                      addViolation( problems, Severity.WARNING, "servers.server.id", null,
100                                   "must be unique but found duplicate server with id " + server.getId() );
101                 }
102             }
103         }
104 
105         List<Mirror> mirrors = settings.getMirrors();
106 
107         if ( mirrors != null )
108         {
109             for ( Mirror mirror : mirrors )
110             {
111                 validateStringNotEmpty( problems, "mirrors.mirror.id", mirror.getId(), mirror.getUrl() );
112 
113                 validateBannedCharacters( problems, "mirrors.mirror.id", Severity.WARNING, mirror.getId(), null,
114                                           ILLEGAL_REPO_ID_CHARS );
115 
116                 if ( "local".equals( mirror.getId() ) )
117                 {
118                     addViolation( problems, Severity.WARNING, "mirrors.mirror.id", null, "must not be 'local'"
119                         + ", this identifier is reserved for the local repository"
120                         + ", using it for other repositories will corrupt your repository metadata." );
121                 }
122 
123                 validateStringNotEmpty( problems, "mirrors.mirror.url", mirror.getUrl(), mirror.getId() );
124 
125                 validateStringNotEmpty( problems, "mirrors.mirror.mirrorOf", mirror.getMirrorOf(), mirror.getId() );
126             }
127         }
128 
129         List<Profile> profiles = settings.getProfiles();
130 
131         if ( profiles != null )
132         {
133             Set<String> profileIds = new HashSet<>();
134 
135             for ( Profile profile : profiles )
136             {
137                 if ( !profileIds.add( profile.getId() ) )
138                 {
139                     addViolation( problems, Severity.WARNING, "profiles.profile.id", null,
140                                   "must be unique but found duplicate profile with id " + profile.getId() );
141                 }
142 
143                 String prefix = "profiles.profile[" + profile.getId() + "].";
144 
145                 validateRepositories( problems, profile.getRepositories(), prefix + "repositories.repository" );
146                 validateRepositories( problems, profile.getPluginRepositories(), prefix
147                     + "pluginRepositories.pluginRepository" );
148             }
149         }
150 
151         List<Proxy> proxies = settings.getProxies();
152 
153         if ( proxies != null )
154         {
155             Set<String> proxyIds = new HashSet<>();
156             
157             for ( Proxy proxy : proxies )
158             {
159                 if ( !proxyIds.add( proxy.getId() ) )
160                 {
161                     addViolation( problems, Severity.WARNING, "proxies.proxy.id", null,
162                                   "must be unique but found duplicate proxy with id " + proxy.getId() );
163                 }
164                 validateStringNotEmpty( problems, "proxies.proxy.host", proxy.getHost(), proxy.getId() );
165             }
166         }
167     }
168 
169     private void validateRepositories( SettingsProblemCollector problems, List<Repository> repositories, String prefix )
170     {
171         Set<String> repoIds = new HashSet<>();
172 
173         for ( Repository repository : repositories )
174         {
175             validateStringNotEmpty( problems, prefix + ".id", repository.getId(), repository.getUrl() );
176 
177             validateBannedCharacters( problems, prefix + ".id", Severity.WARNING, repository.getId(), null,
178                                       ILLEGAL_REPO_ID_CHARS );
179 
180             if ( "local".equals( repository.getId() ) )
181             {
182                 addViolation( problems, Severity.WARNING, prefix + ".id", null, "must not be 'local'"
183                     + ", this identifier is reserved for the local repository"
184                     + ", using it for other repositories will corrupt your repository metadata." );
185             }
186 
187             if ( !repoIds.add( repository.getId() ) )
188             {
189                 addViolation( problems, Severity.WARNING, prefix + ".id", null,
190                               "must be unique but found duplicate repository with id " + repository.getId() );
191             }
192 
193             validateStringNotEmpty( problems, prefix + ".url", repository.getUrl(), repository.getId() );
194 
195             if ( "legacy".equals( repository.getLayout() ) )
196             {
197                 addViolation( problems, Severity.WARNING, prefix + ".layout", repository.getId(),
198                               "uses the unsupported value 'legacy', artifact resolution might fail." );
199             }
200         }
201     }
202 
203     // ----------------------------------------------------------------------
204     // Field validation
205     // ----------------------------------------------------------------------
206 
207     /**
208      * Asserts:
209      * <p/>
210      * <ul>
211      * <li><code>string.length != null</code>
212      * <li><code>string.length > 0</code>
213      * </ul>
214      */
215     private static boolean validateStringNotEmpty( SettingsProblemCollector problems, String fieldName, String string,
216                                             String sourceHint )
217     {
218         if ( !validateNotNull( problems, fieldName, string, sourceHint ) )
219         {
220             return false;
221         }
222 
223         if ( string.length() > 0 )
224         {
225             return true;
226         }
227 
228         addViolation( problems, Severity.ERROR, fieldName, sourceHint, "is missing" );
229 
230         return false;
231     }
232 
233     /**
234      * Asserts:
235      * <p/>
236      * <ul>
237      * <li><code>string != null</code>
238      * </ul>
239      */
240     private static boolean validateNotNull( SettingsProblemCollector problems, String fieldName, Object object,
241                                             String sourceHint )
242     {
243         if ( object != null )
244         {
245             return true;
246         }
247 
248         addViolation( problems, Severity.ERROR, fieldName, sourceHint, "is missing" );
249 
250         return false;
251     }
252 
253     private static boolean validateBannedCharacters( SettingsProblemCollector problems, String fieldName,
254                                                      Severity severity, String string, String sourceHint,
255                                                      String banned )
256     {
257         if ( string != null )
258         {
259             for ( int i = string.length() - 1; i >= 0; i-- )
260             {
261                 if ( banned.indexOf( string.charAt( i ) ) >= 0 )
262                 {
263                     addViolation( problems, severity, fieldName, sourceHint,
264                                   "must not contain any of these characters " + banned + " but found "
265                                       + string.charAt( i ) );
266                     return false;
267                 }
268             }
269         }
270 
271         return true;
272     }
273 
274     private static void addViolation( SettingsProblemCollector problems, Severity severity, String fieldName,
275                                String sourceHint, String message )
276     {
277         StringBuilder buffer = new StringBuilder( 256 );
278         buffer.append( '\'' ).append( fieldName ).append( '\'' );
279 
280         if ( sourceHint != null )
281         {
282             buffer.append( " for " ).append( sourceHint );
283         }
284 
285         buffer.append( ' ' ).append( message );
286 
287         problems.add( severity, buffer.toString(), -1, -1, null );
288     }
289 
290 }