View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.internal.impl;
20  
21  import java.util.HashSet;
22  import java.util.List;
23  import java.util.Set;
24  import java.util.regex.Pattern;
25  
26  import org.apache.maven.api.services.BuilderProblem;
27  import org.apache.maven.api.settings.Mirror;
28  import org.apache.maven.api.settings.Profile;
29  import org.apache.maven.api.settings.Proxy;
30  import org.apache.maven.api.settings.Repository;
31  import org.apache.maven.api.settings.Server;
32  import org.apache.maven.api.settings.Settings;
33  
34  /**
35   */
36  public class DefaultSettingsValidator {
37  
38      private static final String ID = "[\\w.-]+";
39      private static final Pattern ID_REGEX = Pattern.compile(ID);
40  
41      private static final String ILLEGAL_REPO_ID_CHARS = "\\/:\"<>|?*"; // ILLEGAL_FS_CHARS
42  
43      @SuppressWarnings("checkstyle:MethodLength")
44      public void validate(Settings settings, boolean isProjectSettings, List<BuilderProblem> problems) {
45          if (isProjectSettings) {
46              String msgS = "is not supported on project settings.";
47              String msgP = "are not supported on project settings.";
48              if (settings.getLocalRepository() != null
49                      && !settings.getLocalRepository().isEmpty()) {
50                  addViolation(problems, BuilderProblem.Severity.WARNING, "localRepository", null, msgS);
51              }
52              if (!settings.isInteractiveMode()) {
53                  addViolation(problems, BuilderProblem.Severity.WARNING, "interactiveMode", null, msgS);
54              }
55              if (settings.isOffline()) {
56                  addViolation(problems, BuilderProblem.Severity.WARNING, "offline", null, msgS);
57              }
58              if (!settings.getProxies().isEmpty()) {
59                  addViolation(problems, BuilderProblem.Severity.WARNING, "proxies", null, msgP);
60              }
61              if (settings.isUsePluginRegistry()) {
62                  addViolation(problems, BuilderProblem.Severity.WARNING, "usePluginRegistry", null, msgS);
63              }
64              List<Server> servers = settings.getServers();
65              for (int i = 0; i < servers.size(); i++) {
66                  Server server = servers.get(i);
67                  String serverField = "servers.server[" + i + "]";
68                  validateStringEmpty(problems, serverField + ".username", server.getUsername(), msgS);
69                  validateStringEmpty(problems, serverField + ".password", server.getPassword(), msgS);
70                  validateStringEmpty(problems, serverField + ".privateKey", server.getPrivateKey(), msgS);
71                  validateStringEmpty(problems, serverField + ".passphrase", server.getPassphrase(), msgS);
72                  validateStringEmpty(problems, serverField + ".filePermissions", server.getFilePermissions(), msgS);
73                  validateStringEmpty(
74                          problems, serverField + ".directoryPermissions", server.getDirectoryPermissions(), msgS);
75              }
76          }
77  
78          if (settings.isUsePluginRegistry()) {
79              addViolation(
80                      problems,
81                      BuilderProblem.Severity.WARNING,
82                      "usePluginRegistry",
83                      null,
84                      "is deprecated and has no effect.");
85          }
86  
87          List<String> pluginGroups = settings.getPluginGroups();
88  
89          if (pluginGroups != null) {
90              for (int i = 0; i < pluginGroups.size(); i++) {
91                  String pluginGroup = pluginGroups.get(i);
92  
93                  validateStringNotEmpty(problems, "pluginGroups.pluginGroup[" + i + "]", pluginGroup, null);
94  
95                  if (!ID_REGEX.matcher(pluginGroup).matches()) {
96                      addViolation(
97                              problems,
98                              BuilderProblem.Severity.ERROR,
99                              "pluginGroups.pluginGroup[" + i + "]",
100                             null,
101                             "must denote a valid group id and match the pattern " + ID);
102                 }
103             }
104         }
105 
106         List<Server> servers = settings.getServers();
107 
108         if (servers != null) {
109             Set<String> serverIds = new HashSet<>();
110 
111             for (int i = 0; i < servers.size(); i++) {
112                 Server server = servers.get(i);
113 
114                 validateStringNotEmpty(problems, "servers.server[" + i + "].id", server.getId(), null);
115 
116                 if (!serverIds.add(server.getId())) {
117                     addViolation(
118                             problems,
119                             BuilderProblem.Severity.WARNING,
120                             "servers.server.id",
121                             null,
122                             "must be unique but found duplicate server with id " + server.getId());
123                 }
124             }
125         }
126 
127         List<Mirror> mirrors = settings.getMirrors();
128 
129         if (mirrors != null) {
130             for (Mirror mirror : mirrors) {
131                 validateStringNotEmpty(problems, "mirrors.mirror.id", mirror.getId(), mirror.getUrl());
132 
133                 validateBannedCharacters(
134                         problems,
135                         "mirrors.mirror.id",
136                         BuilderProblem.Severity.WARNING,
137                         mirror.getId(),
138                         null,
139                         ILLEGAL_REPO_ID_CHARS);
140 
141                 if ("local".equals(mirror.getId())) {
142                     addViolation(
143                             problems,
144                             BuilderProblem.Severity.WARNING,
145                             "mirrors.mirror.id",
146                             null,
147                             "must not be 'local'"
148                                     + ", this identifier is reserved for the local repository"
149                                     + ", using it for other repositories will corrupt your repository metadata.");
150                 }
151 
152                 validateStringNotEmpty(problems, "mirrors.mirror.url", mirror.getUrl(), mirror.getId());
153 
154                 validateStringNotEmpty(problems, "mirrors.mirror.mirrorOf", mirror.getMirrorOf(), mirror.getId());
155             }
156         }
157 
158         List<Profile> profiles = settings.getProfiles();
159 
160         if (profiles != null) {
161             Set<String> profileIds = new HashSet<>();
162 
163             for (Profile profile : profiles) {
164                 if (!profileIds.add(profile.getId())) {
165                     addViolation(
166                             problems,
167                             BuilderProblem.Severity.WARNING,
168                             "profiles.profile.id",
169                             null,
170                             "must be unique but found duplicate profile with id " + profile.getId());
171                 }
172 
173                 String prefix = "profiles.profile[" + profile.getId() + "].";
174 
175                 validateRepositories(problems, profile.getRepositories(), prefix + "repositories.repository");
176                 validateRepositories(
177                         problems, profile.getPluginRepositories(), prefix + "pluginRepositories.pluginRepository");
178             }
179         }
180 
181         List<Proxy> proxies = settings.getProxies();
182 
183         if (proxies != null) {
184             Set<String> proxyIds = new HashSet<>();
185 
186             for (Proxy proxy : proxies) {
187                 if (!proxyIds.add(proxy.getId())) {
188                     addViolation(
189                             problems,
190                             BuilderProblem.Severity.WARNING,
191                             "proxies.proxy.id",
192                             null,
193                             "must be unique but found duplicate proxy with id " + proxy.getId());
194                 }
195                 validateStringNotEmpty(problems, "proxies.proxy.host", proxy.getHost(), proxy.getId());
196 
197                 try {
198                     Integer.parseInt(proxy.getPortString());
199                 } catch (NumberFormatException e) {
200                     addViolation(
201                             problems,
202                             BuilderProblem.Severity.ERROR,
203                             "proxies.proxy[" + proxy.getId() + "].port",
204                             null,
205                             "must be a valid integer but found '" + proxy.getPortString() + "'");
206                 }
207             }
208         }
209     }
210 
211     private void validateRepositories(List<BuilderProblem> problems, List<Repository> repositories, String prefix) {
212         Set<String> repoIds = new HashSet<>();
213 
214         for (Repository repository : repositories) {
215             validateStringNotEmpty(problems, prefix + ".id", repository.getId(), repository.getUrl());
216 
217             validateBannedCharacters(
218                     problems,
219                     prefix + ".id",
220                     BuilderProblem.Severity.WARNING,
221                     repository.getId(),
222                     null,
223                     ILLEGAL_REPO_ID_CHARS);
224 
225             if ("local".equals(repository.getId())) {
226                 addViolation(
227                         problems,
228                         BuilderProblem.Severity.WARNING,
229                         prefix + ".id",
230                         null,
231                         "must not be 'local'"
232                                 + ", this identifier is reserved for the local repository"
233                                 + ", using it for other repositories will corrupt your repository metadata.");
234             }
235 
236             if (!repoIds.add(repository.getId())) {
237                 addViolation(
238                         problems,
239                         BuilderProblem.Severity.WARNING,
240                         prefix + ".id",
241                         null,
242                         "must be unique but found duplicate repository with id " + repository.getId());
243             }
244 
245             validateStringNotEmpty(problems, prefix + ".url", repository.getUrl(), repository.getId());
246 
247             if ("legacy".equals(repository.getLayout())) {
248                 addViolation(
249                         problems,
250                         BuilderProblem.Severity.WARNING,
251                         prefix + ".layout",
252                         repository.getId(),
253                         "uses the unsupported value 'legacy', artifact resolution might fail.");
254             }
255         }
256     }
257 
258     // ----------------------------------------------------------------------
259     // Field validation
260     // ----------------------------------------------------------------------
261 
262     /**
263      * Asserts:
264      * <p/>
265      * <ul>
266      * <li><code>string.length == null</code>
267      * <li><code>string.length == 0</code>
268      * </ul>
269      */
270     private static boolean validateStringEmpty(
271             List<BuilderProblem> problems, String fieldName, String string, String message) {
272         if (string == null || string.length() == 0) {
273             return true;
274         }
275 
276         addViolation(problems, BuilderProblem.Severity.WARNING, fieldName, null, message);
277 
278         return false;
279     }
280 
281     /**
282      * Asserts:
283      * <p/>
284      * <ul>
285      * <li><code>string.length != null</code>
286      * <li><code>string.length > 0</code>
287      * </ul>
288      */
289     private static boolean validateStringNotEmpty(
290             List<BuilderProblem> problems, String fieldName, String string, String sourceHint) {
291         if (!validateNotNull(problems, fieldName, string, sourceHint)) {
292             return false;
293         }
294 
295         if (!string.isEmpty()) {
296             return true;
297         }
298 
299         addViolation(problems, BuilderProblem.Severity.ERROR, fieldName, sourceHint, "is missing");
300 
301         return false;
302     }
303 
304     /**
305      * Asserts:
306      * <p/>
307      * <ul>
308      * <li><code>string != null</code>
309      * </ul>
310      */
311     private static boolean validateNotNull(
312             List<BuilderProblem> problems, String fieldName, Object object, String sourceHint) {
313         if (object != null) {
314             return true;
315         }
316 
317         addViolation(problems, BuilderProblem.Severity.ERROR, fieldName, sourceHint, "is missing");
318 
319         return false;
320     }
321 
322     private static boolean validateBannedCharacters(
323             List<BuilderProblem> problems,
324             String fieldName,
325             BuilderProblem.Severity severity,
326             String string,
327             String sourceHint,
328             String banned) {
329         if (string != null) {
330             for (int i = string.length() - 1; i >= 0; i--) {
331                 if (banned.indexOf(string.charAt(i)) >= 0) {
332                     addViolation(
333                             problems,
334                             severity,
335                             fieldName,
336                             sourceHint,
337                             "must not contain any of these characters " + banned + " but found " + string.charAt(i));
338                     return false;
339                 }
340             }
341         }
342 
343         return true;
344     }
345 
346     private static void addViolation(
347             List<BuilderProblem> problems,
348             BuilderProblem.Severity severity,
349             String fieldName,
350             String sourceHint,
351             String message) {
352         StringBuilder buffer = new StringBuilder(256);
353         buffer.append('\'').append(fieldName).append('\'');
354 
355         if (sourceHint != null) {
356             buffer.append(" for ").append(sourceHint);
357         }
358 
359         buffer.append(' ').append(message);
360 
361         problems.add(new DefaultBuilderProblem(null, -1, -1, null, buffer.toString(), severity));
362     }
363 }