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