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