001package 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 022import java.util.HashSet; 023import java.util.List; 024import java.util.Set; 025 026import org.apache.maven.settings.Mirror; 027import org.apache.maven.settings.Profile; 028import org.apache.maven.settings.Repository; 029import org.apache.maven.settings.Proxy; 030import org.apache.maven.settings.Server; 031import org.apache.maven.settings.Settings; 032import org.apache.maven.settings.building.SettingsProblem.Severity; 033import org.apache.maven.settings.building.SettingsProblemCollector; 034import org.codehaus.plexus.component.annotations.Component; 035import org.codehaus.plexus.util.StringUtils; 036 037/** 038 * @author Milos Kleint 039 */ 040@Component( role = SettingsValidator.class ) 041public class DefaultSettingsValidator 042 implements SettingsValidator 043{ 044 045 private static final String ID_REGEX = "[A-Za-z0-9_\\-.]+"; 046 047 private static final String ILLEGAL_FS_CHARS = "\\/:\"<>|?*"; 048 049 private static final String ILLEGAL_REPO_ID_CHARS = ILLEGAL_FS_CHARS; 050 051 @Override 052 public void validate( Settings settings, SettingsProblemCollector problems ) 053 { 054 if ( settings.isUsePluginRegistry() ) 055 { 056 addViolation( problems, Severity.WARNING, "usePluginRegistry", null, "is deprecated and has no effect." ); 057 } 058 059 List<String> pluginGroups = settings.getPluginGroups(); 060 061 if ( pluginGroups != null ) 062 { 063 for ( int i = 0; i < pluginGroups.size(); i++ ) 064 { 065 String pluginGroup = pluginGroups.get( i ).trim(); 066 067 if ( StringUtils.isBlank( pluginGroup ) ) 068 { 069 addViolation( problems, Severity.ERROR, "pluginGroups.pluginGroup[" + i + "]", null, 070 "must not be empty" ); 071 } 072 else if ( !pluginGroup.matches( ID_REGEX ) ) 073 { 074 addViolation( problems, Severity.ERROR, "pluginGroups.pluginGroup[" + i + "]", null, 075 "must denote a valid group id and match the pattern " + ID_REGEX ); 076 } 077 } 078 } 079 080 List<Server> servers = settings.getServers(); 081 082 if ( servers != null ) 083 { 084 Set<String> serverIds = new HashSet<>(); 085 086 for ( int i = 0; i < servers.size(); i++ ) 087 { 088 Server server = servers.get( i ); 089 090 validateStringNotEmpty( problems, "servers.server[" + i + "].id", server.getId(), null ); 091 092 if ( !serverIds.add( server.getId() ) ) 093 { 094 addViolation( problems, Severity.WARNING, "servers.server.id", null, 095 "must be unique but found duplicate server with id " + server.getId() ); 096 } 097 } 098 } 099 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}