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 }