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.codehaus.plexus.util.cli.CommandLineUtils; 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 048 /** 049 * @parameter default-value="${project}" 050 * @required 051 * @readonly 052 */ 053 private MavenProject project; 054 055 /** 056 * Locations where properties files can be found. Any url Spring resource loading can understand is valid. eg 057 * <code>classpath:myprops.properties</code>. Both, .properties and .xml style properties are supported. 058 * 059 * @parameter 060 * @required 061 */ 062 private String[] locations; 063 064 /** 065 * If true, the plugin will silently ignore any non-existent properties files, and the build will continue 066 * 067 * @parameter expression="${properties.quiet}" default-value="false" 068 */ 069 private boolean quiet; 070 071 /** 072 * If true, the plugin operate silently without emitting any log messages 073 * 074 * @parameter expression="${properties.silent}" default-value="false" 075 */ 076 private boolean silent; 077 078 /** 079 * If true, the plugin will emit more verbose logging messages. 080 * 081 * @parameter expression="${properties.verbose}" default-value="false" 082 */ 083 private boolean verbose; 084 085 /** 086 * Comma separated list of property values to ignore 087 * 088 * @parameter expression="${properties.ignore}" 089 */ 090 private String ignore; 091 092 @Override 093 public void execute() throws MojoExecutionException { 094 List<String> ignoreList = getListFromCSV(ignore); 095 Properties projectProperties = project.getProperties(); 096 if (!silent && verbose && !StringUtils.isBlank(ignore)) { 097 getLog().info("Ignoring " + ignore); 098 } 099 for (int i = 0; i < locations.length; i++) { 100 String location = locations[i]; 101 if (!validate(location)) { 102 continue; 103 } 104 if (!silent) { 105 getLog().info("Loading " + location); 106 } 107 Properties p = getProperties(location); 108 updateProperties(projectProperties, p, ignoreList); 109 } 110 111 Properties env = getEnvironment(); 112 for (String name : projectProperties.stringPropertyNames()) { 113 String value = getPropertyValue(name, projectProperties, env); 114 projectProperties.setProperty(name, value); 115 } 116 } 117 118 protected Properties getEnvironment() throws MojoExecutionException { 119 try { 120 return CommandLineUtils.getSystemEnvVars(); 121 } catch (IOException e) { 122 throw new MojoExecutionException("Error get environment variables", e); 123 } 124 } 125 126 protected void updateProperties(Properties p1, Properties p2, List<String> ignore) { 127 Set<String> names = p2.stringPropertyNames(); 128 for (String name : names) { 129 if (!ignore.contains(name)) { 130 String value = p2.getProperty(name); 131 p1.setProperty(name, value); 132 } 133 } 134 } 135 136 protected static final List<String> getListFromCSV(String csv) { 137 if (StringUtils.isBlank(csv)) { 138 return new ArrayList<String>(); 139 } 140 List<String> list = new ArrayList<String>(); 141 String[] tokens = StringUtils.split(csv, ","); 142 for (String token : tokens) { 143 list.add(token.trim()); 144 } 145 return list; 146 } 147 148 /** 149 * Retrieves a property value, replacing values like ${token} using the Properties to look them up. Shamelessly 150 * adapted from: 151 * http://maven.apache.org/plugins/maven-war-plugin/xref/org/apache/maven/plugin/war/PropertyUtils.html 152 * 153 * It will leave unresolved properties alone, trying for System properties, and environment variables and implements 154 * reparsing (in the case that the value of a property contains a key), and will not loop endlessly on a pair like 155 * test = ${test} 156 * 157 * @param k 158 * property key 159 * @param p 160 * project properties 161 * @param environment 162 * environment variables 163 * @return resolved property value 164 */ 165 protected String getPropertyValue(String k, Properties p, Properties environment) { 166 String v = p.getProperty(k); 167 String ret = ""; 168 int idx, idx2; 169 170 while ((idx = v.indexOf("${")) >= 0) { 171 // append prefix to result 172 ret += v.substring(0, idx); 173 174 // strip prefix from original 175 v = v.substring(idx + 2); 176 177 idx2 = v.indexOf("}"); 178 179 // if no matching } then bail 180 if (idx2 < 0) { 181 break; 182 } 183 184 // strip out the key and resolve it 185 // resolve the key/value for the ${statement} 186 String nk = v.substring(0, idx2); 187 v = v.substring(idx2 + 1); 188 String nv = p.getProperty(nk); 189 190 // try global environment 191 if (nv == null) { 192 nv = System.getProperty(nk); 193 } 194 195 // try environment variable 196 if (nv == null && nk.startsWith("env.") && environment != null) { 197 nv = environment.getProperty(nk.substring(4)); 198 } 199 200 // if the key cannot be resolved, 201 // leave it alone ( and don't parse again ) 202 // else prefix the original string with the 203 // resolved property ( so it can be parsed further ) 204 // taking recursion into account. 205 if (nv == null || nv.equals(nk)) { 206 ret += "${" + nk + "}"; 207 } else { 208 v = nv + v; 209 } 210 } 211 return ret + v; 212 } 213 214 protected String toEmpty(String s) { 215 if (StringUtils.isBlank(s)) { 216 return ""; 217 } else { 218 return s; 219 } 220 } 221 222 protected boolean exists(String location) { 223 if (StringUtils.isBlank(location)) { 224 return false; 225 } 226 File file = new File(location); 227 if (file.exists()) { 228 return true; 229 } 230 ResourceLoader loader = new DefaultResourceLoader(); 231 Resource resource = loader.getResource(location); 232 return resource.exists(); 233 } 234 235 protected boolean validate(String location) throws MojoExecutionException { 236 boolean exists = exists(location); 237 if (exists) { 238 return true; 239 } 240 if (quiet) { 241 if (verbose && !silent) { 242 getLog().info("Ignoring non-existent properties file '" + toEmpty(location) + "'"); 243 } 244 return false; 245 } else { 246 throw new MojoExecutionException("Non-existent properties file '" + location + "'"); 247 } 248 } 249 250 protected InputStream getInputStream(String location) throws IOException { 251 File file = new File(location); 252 if (file.exists()) { 253 return new FileInputStream(location); 254 } 255 ResourceLoader loader = new DefaultResourceLoader(); 256 Resource resource = loader.getResource(location); 257 return resource.getInputStream(); 258 } 259 260 protected Properties getProperties(String location) throws MojoExecutionException { 261 InputStream in = null; 262 try { 263 Properties properties = new Properties(); 264 in = getInputStream(location); 265 if (location.toLowerCase().endsWith(".xml")) { 266 properties.loadFromXML(in); 267 } else { 268 properties.load(in); 269 } 270 return properties; 271 } catch (IOException e) { 272 throw new MojoExecutionException("Error reading properties file " + location, e); 273 } finally { 274 IOUtils.closeQuietly(in); 275 } 276 } 277 278 public boolean isQuiet() { 279 return quiet; 280 } 281 282 public void setQuiet(boolean quiet) { 283 this.quiet = quiet; 284 } 285 286 public String getIgnore() { 287 return ignore; 288 } 289 290 public void setIgnore(String ignoreProperties) { 291 this.ignore = ignoreProperties; 292 } 293 294 public MavenProject getProject() { 295 return project; 296 } 297 298 public String[] getLocations() { 299 return locations; 300 } 301 302 public void setLocations(String[] locations) { 303 this.locations = locations; 304 } 305 306 public boolean isVerbose() { 307 return verbose; 308 } 309 310 public void setVerbose(boolean verbose) { 311 this.verbose = verbose; 312 } 313 314 public boolean isSilent() { 315 return silent; 316 } 317 318 public void setSilent(boolean silent) { 319 this.silent = silent; 320 } 321 322 }