001 package org.apache.maven.settings.validation;
002
003 /*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements. See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership. The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License. You may obtain a copy of the License at
011 *
012 * http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied. See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022 import java.util.HashSet;
023 import java.util.List;
024 import java.util.Set;
025
026 import org.apache.maven.settings.Mirror;
027 import org.apache.maven.settings.Profile;
028 import org.apache.maven.settings.Repository;
029 import org.apache.maven.settings.Server;
030 import org.apache.maven.settings.Settings;
031 import org.apache.maven.settings.building.SettingsProblem.Severity;
032 import org.apache.maven.settings.building.SettingsProblemCollector;
033 import org.codehaus.plexus.component.annotations.Component;
034 import org.codehaus.plexus.util.StringUtils;
035
036 /**
037 * @author Milos Kleint
038 */
039 @Component( role = SettingsValidator.class )
040 public class DefaultSettingsValidator
041 implements SettingsValidator
042 {
043
044 private static final String ID_REGEX = "[A-Za-z0-9_\\-.]+";
045
046 private static final String ILLEGAL_FS_CHARS = "\\/:\"<>|?*";
047
048 private static final String ILLEGAL_REPO_ID_CHARS = ILLEGAL_FS_CHARS;
049
050 public void validate( Settings settings, SettingsProblemCollector problems )
051 {
052 if ( settings.isUsePluginRegistry() )
053 {
054 addViolation( problems, Severity.WARNING, "usePluginRegistry", null, "is deprecated and has no effect." );
055 }
056
057 List<String> pluginGroups = settings.getPluginGroups();
058
059 if ( pluginGroups != null )
060 {
061 for ( int i = 0; i < pluginGroups.size(); i++ )
062 {
063 String pluginGroup = pluginGroups.get( i ).trim();
064
065 if ( StringUtils.isBlank( pluginGroup ) )
066 {
067 addViolation( problems, Severity.ERROR, "pluginGroups.pluginGroup[" + i + "]", null,
068 "must not be empty" );
069 }
070 else if ( !pluginGroup.matches( ID_REGEX ) )
071 {
072 addViolation( problems, Severity.ERROR, "pluginGroups.pluginGroup[" + i + "]", null,
073 "must denote a valid group id and match the pattern " + ID_REGEX );
074 }
075 }
076 }
077
078 List<Server> servers = settings.getServers();
079
080 if ( servers != null )
081 {
082 Set<String> serverIds = new HashSet<String>();
083
084 for ( int i = 0; i < servers.size(); i++ )
085 {
086 Server server = servers.get( i );
087
088 validateStringNotEmpty( problems, "servers.server[" + i + "].id", server.getId(), null );
089
090 if ( !serverIds.add( server.getId() ) )
091 {
092 addViolation( problems, Severity.WARNING, "servers.server.id", null,
093 "must be unique but found duplicate server with id " + server.getId() );
094 }
095 }
096 }
097
098 List<Mirror> mirrors = settings.getMirrors();
099
100 if ( mirrors != null )
101 {
102 for ( Mirror mirror : mirrors )
103 {
104 validateStringNotEmpty( problems, "mirrors.mirror.id", mirror.getId(), mirror.getUrl() );
105
106 validateBannedCharacters( problems, "mirrors.mirror.id", Severity.WARNING, mirror.getId(), null,
107 ILLEGAL_REPO_ID_CHARS );
108
109 if ( "local".equals( mirror.getId() ) )
110 {
111 addViolation( problems, Severity.WARNING, "mirrors.mirror.id", null, "must not be 'local'"
112 + ", this identifier is reserved for the local repository"
113 + ", using it for other repositories will corrupt your repository metadata." );
114 }
115
116 validateStringNotEmpty( problems, "mirrors.mirror.url", mirror.getUrl(), mirror.getId() );
117
118 validateStringNotEmpty( problems, "mirrors.mirror.mirrorOf", mirror.getMirrorOf(), mirror.getId() );
119 }
120 }
121
122 List<Profile> profiles = settings.getProfiles();
123
124 if ( profiles != null )
125 {
126 Set<String> profileIds = new HashSet<String>();
127
128 for ( Profile profile : profiles )
129 {
130 if ( !profileIds.add( profile.getId() ) )
131 {
132 addViolation( problems, Severity.WARNING, "profiles.profile.id", null,
133 "must be unique but found duplicate profile with id " + profile.getId() );
134 }
135
136 String prefix = "profiles.profile[" + profile.getId() + "].";
137
138 validateRepositories( problems, profile.getRepositories(), prefix + "repositories.repository" );
139 validateRepositories( problems, profile.getPluginRepositories(), prefix
140 + "pluginRepositories.pluginRepository" );
141 }
142 }
143 }
144
145 private void validateRepositories( SettingsProblemCollector problems, List<Repository> repositories, String prefix )
146 {
147 Set<String> repoIds = new HashSet<String>();
148
149 for ( Repository repository : repositories )
150 {
151 validateStringNotEmpty( problems, prefix + ".id", repository.getId(), repository.getUrl() );
152
153 validateBannedCharacters( problems, prefix + ".id", Severity.WARNING, repository.getId(), null,
154 ILLEGAL_REPO_ID_CHARS );
155
156 if ( "local".equals( repository.getId() ) )
157 {
158 addViolation( problems, Severity.WARNING, prefix + ".id", null, "must not be 'local'"
159 + ", this identifier is reserved for the local repository"
160 + ", using it for other repositories will corrupt your repository metadata." );
161 }
162
163 if ( !repoIds.add( repository.getId() ) )
164 {
165 addViolation( problems, Severity.WARNING, prefix + ".id", null,
166 "must be unique but found duplicate repository with id " + repository.getId() );
167 }
168
169 validateStringNotEmpty( problems, prefix + ".url", repository.getUrl(), repository.getId() );
170
171 if ( "legacy".equals( repository.getLayout() ) )
172 {
173 addViolation( problems, Severity.WARNING, prefix + ".layout", repository.getId(),
174 "uses the unsupported value 'legacy', artifact resolution might fail." );
175 }
176 }
177 }
178
179 // ----------------------------------------------------------------------
180 // Field validation
181 // ----------------------------------------------------------------------
182
183 /**
184 * Asserts:
185 * <p/>
186 * <ul>
187 * <li><code>string.length != null</code>
188 * <li><code>string.length > 0</code>
189 * </ul>
190 */
191 private boolean validateStringNotEmpty( SettingsProblemCollector problems, String fieldName, String string,
192 String sourceHint )
193 {
194 if ( !validateNotNull( problems, fieldName, string, sourceHint ) )
195 {
196 return false;
197 }
198
199 if ( string.length() > 0 )
200 {
201 return true;
202 }
203
204 addViolation( problems, Severity.ERROR, fieldName, sourceHint, "is missing" );
205
206 return false;
207 }
208
209 /**
210 * Asserts:
211 * <p/>
212 * <ul>
213 * <li><code>string != null</code>
214 * </ul>
215 */
216 private boolean validateNotNull( SettingsProblemCollector problems, String fieldName, Object object,
217 String sourceHint )
218 {
219 if ( object != null )
220 {
221 return true;
222 }
223
224 addViolation( problems, Severity.ERROR, fieldName, sourceHint, "is missing" );
225
226 return false;
227 }
228
229 private boolean validateBannedCharacters( SettingsProblemCollector problems, String fieldName, Severity severity,
230 String string, String sourceHint, String banned )
231 {
232 if ( string != null )
233 {
234 for ( int i = string.length() - 1; i >= 0; i-- )
235 {
236 if ( banned.indexOf( string.charAt( i ) ) >= 0 )
237 {
238 addViolation( problems, severity, fieldName, sourceHint,
239 "must not contain any of these characters " + banned + " but found "
240 + string.charAt( i ) );
241 return false;
242 }
243 }
244 }
245
246 return true;
247 }
248
249 private void addViolation( SettingsProblemCollector problems, Severity severity, String fieldName,
250 String sourceHint, String message )
251 {
252 StringBuilder buffer = new StringBuilder( 256 );
253 buffer.append( '\'' ).append( fieldName ).append( '\'' );
254
255 if ( sourceHint != null )
256 {
257 buffer.append( " for " ).append( sourceHint );
258 }
259
260 buffer.append( ' ' ).append( message );
261
262 problems.add( severity, buffer.toString(), -1, -1, null );
263 }
264
265 }