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