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.Server; 030import org.apache.maven.settings.Settings; 031import org.apache.maven.settings.building.SettingsProblem.Severity; 032import org.apache.maven.settings.building.SettingsProblemCollector; 033import org.codehaus.plexus.component.annotations.Component; 034import org.codehaus.plexus.util.StringUtils; 035 036/** 037 * @author Milos Kleint 038 */ 039@Component( role = SettingsValidator.class ) 040public 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 @Override 051 public void validate( Settings settings, SettingsProblemCollector problems ) 052 { 053 if ( settings.isUsePluginRegistry() ) 054 { 055 addViolation( problems, Severity.WARNING, "usePluginRegistry", null, "is deprecated and has no effect." ); 056 } 057 058 List<String> pluginGroups = settings.getPluginGroups(); 059 060 if ( pluginGroups != null ) 061 { 062 for ( int i = 0; i < pluginGroups.size(); i++ ) 063 { 064 String pluginGroup = pluginGroups.get( i ).trim(); 065 066 if ( StringUtils.isBlank( pluginGroup ) ) 067 { 068 addViolation( problems, Severity.ERROR, "pluginGroups.pluginGroup[" + i + "]", null, 069 "must not be empty" ); 070 } 071 else if ( !pluginGroup.matches( ID_REGEX ) ) 072 { 073 addViolation( problems, Severity.ERROR, "pluginGroups.pluginGroup[" + i + "]", null, 074 "must denote a valid group id and match the pattern " + ID_REGEX ); 075 } 076 } 077 } 078 079 List<Server> servers = settings.getServers(); 080 081 if ( servers != null ) 082 { 083 Set<String> serverIds = new HashSet<String>(); 084 085 for ( int i = 0; i < servers.size(); i++ ) 086 { 087 Server server = servers.get( i ); 088 089 validateStringNotEmpty( problems, "servers.server[" + i + "].id", server.getId(), null ); 090 091 if ( !serverIds.add( server.getId() ) ) 092 { 093 addViolation( problems, Severity.WARNING, "servers.server.id", null, 094 "must be unique but found duplicate server with id " + server.getId() ); 095 } 096 } 097 } 098 099 List<Mirror> mirrors = settings.getMirrors(); 100 101 if ( mirrors != null ) 102 { 103 for ( Mirror mirror : mirrors ) 104 { 105 validateStringNotEmpty( problems, "mirrors.mirror.id", mirror.getId(), mirror.getUrl() ); 106 107 validateBannedCharacters( problems, "mirrors.mirror.id", Severity.WARNING, mirror.getId(), null, 108 ILLEGAL_REPO_ID_CHARS ); 109 110 if ( "local".equals( mirror.getId() ) ) 111 { 112 addViolation( problems, Severity.WARNING, "mirrors.mirror.id", null, "must not be 'local'" 113 + ", this identifier is reserved for the local repository" 114 + ", using it for other repositories will corrupt your repository metadata." ); 115 } 116 117 validateStringNotEmpty( problems, "mirrors.mirror.url", mirror.getUrl(), mirror.getId() ); 118 119 validateStringNotEmpty( problems, "mirrors.mirror.mirrorOf", mirror.getMirrorOf(), mirror.getId() ); 120 } 121 } 122 123 List<Profile> profiles = settings.getProfiles(); 124 125 if ( profiles != null ) 126 { 127 Set<String> profileIds = new HashSet<String>(); 128 129 for ( Profile profile : profiles ) 130 { 131 if ( !profileIds.add( profile.getId() ) ) 132 { 133 addViolation( problems, Severity.WARNING, "profiles.profile.id", null, 134 "must be unique but found duplicate profile with id " + profile.getId() ); 135 } 136 137 String prefix = "profiles.profile[" + profile.getId() + "]."; 138 139 validateRepositories( problems, profile.getRepositories(), prefix + "repositories.repository" ); 140 validateRepositories( problems, profile.getPluginRepositories(), prefix 141 + "pluginRepositories.pluginRepository" ); 142 } 143 } 144 } 145 146 private void validateRepositories( SettingsProblemCollector problems, List<Repository> repositories, String prefix ) 147 { 148 Set<String> repoIds = new HashSet<String>(); 149 150 for ( Repository repository : repositories ) 151 { 152 validateStringNotEmpty( problems, prefix + ".id", repository.getId(), repository.getUrl() ); 153 154 validateBannedCharacters( problems, prefix + ".id", Severity.WARNING, repository.getId(), null, 155 ILLEGAL_REPO_ID_CHARS ); 156 157 if ( "local".equals( repository.getId() ) ) 158 { 159 addViolation( problems, Severity.WARNING, prefix + ".id", null, "must not be 'local'" 160 + ", this identifier is reserved for the local repository" 161 + ", using it for other repositories will corrupt your repository metadata." ); 162 } 163 164 if ( !repoIds.add( repository.getId() ) ) 165 { 166 addViolation( problems, Severity.WARNING, prefix + ".id", null, 167 "must be unique but found duplicate repository with id " + repository.getId() ); 168 } 169 170 validateStringNotEmpty( problems, prefix + ".url", repository.getUrl(), repository.getId() ); 171 172 if ( "legacy".equals( repository.getLayout() ) ) 173 { 174 addViolation( problems, Severity.WARNING, prefix + ".layout", repository.getId(), 175 "uses the unsupported value 'legacy', artifact resolution might fail." ); 176 } 177 } 178 } 179 180 // ---------------------------------------------------------------------- 181 // Field validation 182 // ---------------------------------------------------------------------- 183 184 /** 185 * Asserts: 186 * <p/> 187 * <ul> 188 * <li><code>string.length != null</code> 189 * <li><code>string.length > 0</code> 190 * </ul> 191 */ 192 private boolean validateStringNotEmpty( SettingsProblemCollector problems, String fieldName, String string, 193 String sourceHint ) 194 { 195 if ( !validateNotNull( problems, fieldName, string, sourceHint ) ) 196 { 197 return false; 198 } 199 200 if ( string.length() > 0 ) 201 { 202 return true; 203 } 204 205 addViolation( problems, Severity.ERROR, fieldName, sourceHint, "is missing" ); 206 207 return false; 208 } 209 210 /** 211 * Asserts: 212 * <p/> 213 * <ul> 214 * <li><code>string != null</code> 215 * </ul> 216 */ 217 private boolean validateNotNull( SettingsProblemCollector problems, String fieldName, Object object, 218 String sourceHint ) 219 { 220 if ( object != null ) 221 { 222 return true; 223 } 224 225 addViolation( problems, Severity.ERROR, fieldName, sourceHint, "is missing" ); 226 227 return false; 228 } 229 230 private boolean validateBannedCharacters( SettingsProblemCollector problems, String fieldName, Severity severity, 231 String string, String sourceHint, String banned ) 232 { 233 if ( string != null ) 234 { 235 for ( int i = string.length() - 1; i >= 0; i-- ) 236 { 237 if ( banned.indexOf( string.charAt( i ) ) >= 0 ) 238 { 239 addViolation( problems, severity, fieldName, sourceHint, 240 "must not contain any of these characters " + banned + " but found " 241 + string.charAt( i ) ); 242 return false; 243 } 244 } 245 } 246 247 return true; 248 } 249 250 private void addViolation( SettingsProblemCollector problems, Severity severity, String fieldName, 251 String sourceHint, String message ) 252 { 253 StringBuilder buffer = new StringBuilder( 256 ); 254 buffer.append( '\'' ).append( fieldName ).append( '\'' ); 255 256 if ( sourceHint != null ) 257 { 258 buffer.append( " for " ).append( sourceHint ); 259 } 260 261 buffer.append( ' ' ).append( message ); 262 263 problems.add( severity, buffer.toString(), -1, -1, null ); 264 } 265 266}