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 }