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