001 /** 002 * Copyright 2009-2012 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 package org.codehaus.mojo.properties; 017 018 import java.io.File; 019 import java.io.FileInputStream; 020 import java.io.IOException; 021 import java.io.InputStream; 022 import java.util.ArrayList; 023 import java.util.List; 024 import java.util.Properties; 025 import java.util.Set; 026 027 import org.apache.commons.io.IOUtils; 028 import org.apache.commons.lang.StringUtils; 029 import org.apache.maven.plugin.AbstractMojo; 030 import org.apache.maven.plugin.MojoExecutionException; 031 import org.apache.maven.project.MavenProject; 032 import org.kuali.maven.common.PropertiesUtils; 033 import org.springframework.core.io.DefaultResourceLoader; 034 import org.springframework.core.io.Resource; 035 import org.springframework.core.io.ResourceLoader; 036 037 /** 038 * The read-project-properties goal reads property files and stores the properties as project properties. It serves as 039 * an alternate to specifying properties in pom.xml. 040 * 041 * @author <a href="mailto:zarars@gmail.com">Zarar Siddiqi</a> 042 * @author <a href="mailto:Krystian.Nowak@gmail.com">Krystian Nowak</a> 043 * @version $Id: ReadPropertiesMojo.java 8861 2009-01-21 15:35:38Z pgier $ 044 * @goal read-project-properties 045 */ 046 public class ReadPropertiesMojo extends AbstractMojo { 047 PropertiesUtils utils = new PropertiesUtils(); 048 049 /** 050 * @parameter default-value="${project}" 051 * @required 052 * @readonly 053 */ 054 private MavenProject project; 055 056 /** 057 * Locations where properties files can be found. Any url Spring resource loading can understand is valid. eg 058 * <code>classpath:myprops.properties</code>. Both, .properties and .xml style properties are supported. 059 * 060 * @parameter 061 * @required 062 */ 063 private String[] locations; 064 065 /** 066 * If true, the plugin will silently ignore any non-existent properties files, and the build will continue 067 * 068 * @parameter expression="${properties.quiet}" default-value="false" 069 */ 070 private boolean quiet; 071 072 /** 073 * If true, the plugin will operate silently without emitting any log messages 074 * 075 * @parameter expression="${properties.silent}" default-value="false" 076 */ 077 private boolean silent; 078 079 /** 080 * If true, the plugin will emit more verbose logging messages. 081 * 082 * @parameter expression="${properties.verbose}" default-value="false" 083 */ 084 private boolean verbose; 085 086 /** 087 * Comma separated list of property values to ignore 088 * 089 * @parameter expression="${properties.ignore}" 090 */ 091 private String ignore; 092 093 /** 094 * If true, property values are resolved 095 * 096 * @parameter expression="${properties.resolveValues}" default-value="true" 097 */ 098 boolean resolveValues; 099 100 /** 101 * If supplied, only the comma separated list of property keys are resolved. 102 * 103 * @parameter expression="${properties.propertyKeysToResolve}" 104 */ 105 String propertyKeysToResolve; 106 107 @Override 108 public void execute() throws MojoExecutionException { 109 // Figure out if there are properties we need to ignore 110 List<String> ignoreList = getIgnoreList(); 111 112 // Update project properties by loading in properties from the locations they've specified 113 updateProjectProperties(ignoreList); 114 115 if (resolveValues) { 116 // Project + system + env properties 117 Properties allProperties = utils.getMavenProperties(project); 118 resolveValues(project.getProperties(), allProperties, getListFromCSV(propertyKeysToResolve)); 119 } 120 121 } 122 123 protected void resolveValues(Properties p1, Properties p2, List<String> keys) { 124 for (String name : p1.stringPropertyNames()) { 125 if (resolve(name, keys)) { 126 String originalValue = p1.getProperty(name); 127 String resolvedValue = utils.getResolvedValue(originalValue, p2); 128 p1.setProperty(name, resolvedValue); 129 } 130 } 131 } 132 133 protected boolean resolve(String key, List<String> keys) { 134 if (keys == null || keys.size() == 0) { 135 return true; 136 } else { 137 return keys.contains(key); 138 } 139 } 140 141 /** 142 * Copy properties from p2 into p1, overwriting p1 values as we go. 143 * 144 * Ignore any properties with a key that appears in the ignore list 145 * 146 * @param p1 147 * @param p2 148 * @param ignore 149 */ 150 protected void updateProperties(Properties p1, Properties p2, List<String> ignore) { 151 Set<String> names = p2.stringPropertyNames(); 152 for (String name : names) { 153 if (!ignore.contains(name)) { 154 String value = p2.getProperty(name); 155 p1.setProperty(name, value); 156 } 157 } 158 } 159 160 protected static final List<String> getListFromCSV(String csv) { 161 if (StringUtils.isBlank(csv)) { 162 return new ArrayList<String>(); 163 } 164 List<String> list = new ArrayList<String>(); 165 String[] tokens = StringUtils.split(csv, ","); 166 for (String token : tokens) { 167 list.add(token.trim()); 168 } 169 return list; 170 } 171 172 protected String toEmpty(String s) { 173 if (StringUtils.isBlank(s)) { 174 return ""; 175 } else { 176 return s; 177 } 178 } 179 180 protected boolean exists(String location) { 181 if (StringUtils.isBlank(location)) { 182 return false; 183 } 184 File file = new File(location); 185 if (file.exists()) { 186 return true; 187 } 188 ResourceLoader loader = new DefaultResourceLoader(); 189 Resource resource = loader.getResource(location); 190 return resource.exists(); 191 } 192 193 protected boolean validate(String location) throws MojoExecutionException { 194 boolean exists = exists(location); 195 if (exists) { 196 return true; 197 } 198 if (quiet) { 199 if (verbose && !silent) { 200 getLog().info("Ignoring non-existent properties file '" + toEmpty(location) + "'"); 201 } 202 return false; 203 } else { 204 throw new MojoExecutionException("Non-existent properties file '" + location + "'"); 205 } 206 } 207 208 protected InputStream getInputStream(String location) throws IOException { 209 File file = new File(location); 210 if (file.exists()) { 211 return new FileInputStream(location); 212 } 213 ResourceLoader loader = new DefaultResourceLoader(); 214 Resource resource = loader.getResource(location); 215 return resource.getInputStream(); 216 } 217 218 protected Properties getProperties(String location) throws MojoExecutionException { 219 InputStream in = null; 220 try { 221 Properties properties = new Properties(); 222 in = getInputStream(location); 223 if (location.toLowerCase().endsWith(".xml")) { 224 properties.loadFromXML(in); 225 } else { 226 properties.load(in); 227 } 228 return properties; 229 } catch (IOException e) { 230 throw new MojoExecutionException("Error reading properties file " + location, e); 231 } finally { 232 IOUtils.closeQuietly(in); 233 } 234 } 235 236 public boolean isQuiet() { 237 return quiet; 238 } 239 240 public void setQuiet(boolean quiet) { 241 this.quiet = quiet; 242 } 243 244 public String getIgnore() { 245 return ignore; 246 } 247 248 public void setIgnore(String ignoreProperties) { 249 this.ignore = ignoreProperties; 250 } 251 252 public MavenProject getProject() { 253 return project; 254 } 255 256 public String[] getLocations() { 257 return locations; 258 } 259 260 public void setLocations(String[] locations) { 261 this.locations = locations; 262 } 263 264 public boolean isVerbose() { 265 return verbose; 266 } 267 268 public void setVerbose(boolean verbose) { 269 this.verbose = verbose; 270 } 271 272 public boolean isSilent() { 273 return silent; 274 } 275 276 public void setSilent(boolean silent) { 277 this.silent = silent; 278 } 279 280 protected List<String> getIgnoreList() { 281 List<String> ignoreList = getListFromCSV(ignore); 282 if (!silent && verbose && !StringUtils.isBlank(ignore)) { 283 getLog().info("Ignoring " + ignore); 284 } 285 return ignoreList; 286 } 287 288 protected void updateProjectProperties(List<String> ignoreList) throws MojoExecutionException { 289 Properties projectProperties = project.getProperties(); 290 for (int i = 0; i < locations.length; i++) { 291 Properties allProperties = utils.getMavenProperties(project); 292 String originalLocation = locations[i]; 293 String resolvedLocation = utils.getResolvedValue(originalLocation, allProperties); 294 getLog().debug("o=" + originalLocation + " r=" + resolvedLocation); 295 if (!validate(resolvedLocation)) { 296 continue; 297 } 298 if (!silent) { 299 getLog().info("Loading " + resolvedLocation); 300 } 301 302 // Load properties from this location 303 Properties p = getProperties(resolvedLocation); 304 305 // Update project properties from the properties we just loaded 306 updateProperties(projectProperties, p, ignoreList); 307 } 308 } 309 310 public boolean isResolveValues() { 311 return resolveValues; 312 } 313 314 public void setResolveValues(boolean resolveValues) { 315 this.resolveValues = resolveValues; 316 } 317 318 public String getPropertyKeysToResolve() { 319 return propertyKeysToResolve; 320 } 321 322 public void setPropertyKeysToResolve(String propertyKeysToResolve) { 323 this.propertyKeysToResolve = propertyKeysToResolve; 324 } 325 326 }