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 /* 019 * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE 020 * file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file 021 * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the 022 * License. You may obtain a copy of the License at 023 * 024 * http://www.apache.org/licenses/LICENSE-2.0 025 * 026 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 027 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 028 * specific language governing permissions and limitations under the License. 029 */ 030 031 import java.io.File; 032 import java.io.FileInputStream; 033 import java.io.IOException; 034 import java.io.InputStream; 035 import java.util.ArrayList; 036 import java.util.Enumeration; 037 import java.util.List; 038 import java.util.Properties; 039 import java.util.Set; 040 041 import org.apache.commons.io.IOUtils; 042 import org.apache.maven.plugin.AbstractMojo; 043 import org.apache.maven.plugin.MojoExecutionException; 044 import org.apache.maven.project.MavenProject; 045 import org.codehaus.plexus.util.StringUtils; 046 import org.codehaus.plexus.util.cli.CommandLineUtils; 047 048 /** 049 * The read-project-properties goal reads property files and stores the properties as project properties. It serves as 050 * an alternate to specifying properties in pom.xml. 051 * 052 * @author <a href="mailto:zarars@gmail.com">Zarar Siddiqi</a> 053 * @author <a href="mailto:Krystian.Nowak@gmail.com">Krystian Nowak</a> 054 * @version $Id: ReadPropertiesMojo.java 8861 2009-01-21 15:35:38Z pgier $ 055 * @goal read-project-properties 056 */ 057 public class ReadPropertiesMojo extends AbstractMojo { 058 059 /** 060 * @parameter default-value="${project}" 061 * @required 062 * @readonly 063 */ 064 private MavenProject project; 065 066 /** 067 * The properties files that will be used when reading properties. Can use both .properties and .xml files 068 * 069 * @parameter 070 * @required 071 */ 072 private File[] files; 073 074 /** 075 * If true, the plugin will silently ignore any non-existent properties files, and the build will continue 076 * 077 * @parameter expression="${properties.quiet}" default-value="false" 078 */ 079 private boolean quiet; 080 081 /** 082 * Comma separated list of property values to ignore 083 * 084 * @parameter expression="${properties.ignore}" 085 */ 086 private String ignore; 087 088 @Override 089 public void execute() throws MojoExecutionException { 090 List<String> ignoreList = getListFromCSV(ignore); 091 Properties projectProperties = project.getProperties(); 092 for (int i = 0; i < files.length; i++) { 093 File file = files[i]; 094 if (validate(file)) { 095 Properties p = getProperties(file); 096 updateProperties(projectProperties, p, ignoreList); 097 } 098 } 099 100 boolean useEnvVariables = false; 101 for (Enumeration<?> n = projectProperties.propertyNames(); n.hasMoreElements();) { 102 String k = (String) n.nextElement(); 103 String p = (String) projectProperties.get(k); 104 if (p.indexOf("${env.") != -1) { 105 useEnvVariables = true; 106 break; 107 } 108 } 109 Properties environment = null; 110 if (useEnvVariables) { 111 try { 112 environment = CommandLineUtils.getSystemEnvVars(); 113 } catch (IOException e) { 114 throw new MojoExecutionException("Error getting system envorinment variables: ", e); 115 } 116 } 117 for (Enumeration<?> n = projectProperties.propertyNames(); n.hasMoreElements();) { 118 String k = (String) n.nextElement(); 119 projectProperties.setProperty(k, getPropertyValue(k, projectProperties, environment)); 120 } 121 } 122 123 protected void updateProperties(Properties p1, Properties p2, List<String> ignore) { 124 Set<String> names = p2.stringPropertyNames(); 125 for (String name : names) { 126 if (!ignore.contains(name)) { 127 String value = p2.getProperty(name); 128 p1.setProperty(name, value); 129 } 130 } 131 } 132 133 protected List<String> getListFromCSV(String csv) { 134 if (StringUtils.isBlank(csv)) { 135 return new ArrayList<String>(); 136 } 137 List<String> list = new ArrayList<String>(); 138 String[] tokens = StringUtils.split(csv, ","); 139 for (String token : tokens) { 140 list.add(token.trim()); 141 } 142 return list; 143 } 144 145 /** 146 * Retrieves a property value, replacing values like ${token} using the Properties to look them up. Shamelessly 147 * adapted from: 148 * http://maven.apache.org/plugins/maven-war-plugin/xref/org/apache/maven/plugin/war/PropertyUtils.html 149 * 150 * It will leave unresolved properties alone, trying for System properties, and environment variables and implements 151 * reparsing (in the case that the value of a property contains a key), and will not loop endlessly on a pair like 152 * test = ${test} 153 * 154 * @param k 155 * property key 156 * @param p 157 * project properties 158 * @param environment 159 * environment variables 160 * @return resolved property value 161 */ 162 protected String getPropertyValue(String k, Properties p, Properties environment) { 163 String v = p.getProperty(k); 164 String ret = ""; 165 int idx, idx2; 166 167 while ((idx = v.indexOf("${")) >= 0) { 168 // append prefix to result 169 ret += v.substring(0, idx); 170 171 // strip prefix from original 172 v = v.substring(idx + 2); 173 174 idx2 = v.indexOf("}"); 175 176 // if no matching } then bail 177 if (idx2 < 0) { 178 break; 179 } 180 181 // strip out the key and resolve it 182 // resolve the key/value for the ${statement} 183 String nk = v.substring(0, idx2); 184 v = v.substring(idx2 + 1); 185 String nv = p.getProperty(nk); 186 187 // try global environment 188 if (nv == null) { 189 nv = System.getProperty(nk); 190 } 191 192 // try environment variable 193 if (nv == null && nk.startsWith("env.") && environment != null) { 194 nv = environment.getProperty(nk.substring(4)); 195 } 196 197 // if the key cannot be resolved, 198 // leave it alone ( and don't parse again ) 199 // else prefix the original string with the 200 // resolved property ( so it can be parsed further ) 201 // taking recursion into account. 202 if (nv == null || nv.equals(nk)) { 203 ret += "${" + nk + "}"; 204 } else { 205 v = nv + v; 206 } 207 } 208 return ret + v; 209 } 210 211 protected boolean validate(File file) throws MojoExecutionException { 212 boolean exists = file != null && file.exists(); 213 if (exists) { 214 return true; 215 } 216 if (quiet) { 217 getLog().info("Ignoring non-existent properties file '" + file + "'"); 218 return false; 219 } else { 220 throw new MojoExecutionException("Non-existent properties file '" + file + "'"); 221 } 222 } 223 224 protected Properties getProperties(File file) throws MojoExecutionException { 225 InputStream in = null; 226 try { 227 getLog().info("Loading " + file); 228 Properties properties = new Properties(); 229 in = new FileInputStream(file); 230 String filename = file.getName().toLowerCase(); 231 if (filename.endsWith(".xml")) { 232 properties.loadFromXML(in); 233 } else { 234 properties.load(in); 235 } 236 return properties; 237 } catch (IOException e) { 238 throw new MojoExecutionException("Error reading properties file " + file.getAbsolutePath(), e); 239 } finally { 240 IOUtils.closeQuietly(in); 241 } 242 } 243 244 public File[] getFiles() { 245 return files; 246 } 247 248 public void setFiles(File[] files) { 249 this.files = files; 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 }