View Javadoc

1   /**
2    * Copyright 2009-2012 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.codehaus.mojo.properties;
17  
18  import java.io.File;
19  import java.io.FileInputStream;
20  import java.io.IOException;
21  import java.io.InputStream;
22  import java.util.ArrayList;
23  import java.util.List;
24  import java.util.Properties;
25  import java.util.Set;
26  
27  import org.apache.commons.io.IOUtils;
28  import org.apache.commons.lang.StringUtils;
29  import org.apache.maven.plugin.AbstractMojo;
30  import org.apache.maven.plugin.MojoExecutionException;
31  import org.apache.maven.project.MavenProject;
32  import org.codehaus.plexus.util.cli.CommandLineUtils;
33  import org.springframework.core.io.DefaultResourceLoader;
34  import org.springframework.core.io.Resource;
35  import org.springframework.core.io.ResourceLoader;
36  
37  /**
38   * The read-project-properties goal reads property files and stores the properties as project properties. It serves as
39   * an alternate to specifying properties in pom.xml.
40   *
41   * @author <a href="mailto:zarars@gmail.com">Zarar Siddiqi</a>
42   * @author <a href="mailto:Krystian.Nowak@gmail.com">Krystian Nowak</a>
43   * @version $Id: ReadPropertiesMojo.java 8861 2009-01-21 15:35:38Z pgier $
44   * @goal read-project-properties
45   */
46  public class ReadPropertiesMojo extends AbstractMojo {
47  
48      /**
49       * @parameter default-value="${project}"
50       * @required
51       * @readonly
52       */
53      private MavenProject project;
54  
55      /**
56       * Locations where properties files can be found. Any url Spring resource loading can understand is valid. eg
57       * <code>classpath:myprops.properties</code>. Both, .properties and .xml style properties are supported.
58       *
59       * @parameter
60       * @required
61       */
62      private String[] locations;
63  
64      /**
65       * If true, the plugin will silently ignore any non-existent properties files, and the build will continue
66       *
67       * @parameter expression="${properties.quiet}" default-value="false"
68       */
69      private boolean quiet;
70  
71      /**
72       * If true, the plugin operate silently without emitting any log messages
73       *
74       * @parameter expression="${properties.silent}" default-value="false"
75       */
76      private boolean silent;
77  
78      /**
79       * If true, the plugin will emit more verbose logging messages.
80       *
81       * @parameter expression="${properties.verbose}" default-value="false"
82       */
83      private boolean verbose;
84  
85      /**
86       * Comma separated list of property values to ignore
87       *
88       * @parameter expression="${properties.ignore}"
89       */
90      private String ignore;
91  
92      @Override
93      public void execute() throws MojoExecutionException {
94          List<String> ignoreList = getListFromCSV(ignore);
95          Properties projectProperties = project.getProperties();
96          if (!silent && verbose && !StringUtils.isBlank(ignore)) {
97              getLog().info("Ignoring " + ignore);
98          }
99          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 }