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 will emit more verbose logging messages.
73       *
74       * @parameter expression="${properties.verbose}" default-value="false"
75       */
76      private boolean verbose;
77  
78      /**
79       * Comma separated list of property values to ignore
80       *
81       * @parameter expression="${properties.ignore}"
82       */
83      private String ignore;
84  
85      @Override
86      public void execute() throws MojoExecutionException {
87          List<String> ignoreList = getListFromCSV(ignore);
88          Properties projectProperties = project.getProperties();
89          if (verbose && !StringUtils.isBlank(ignore)) {
90              getLog().info("Ignoring " + ignore);
91          }
92          for (int i = 0; i < locations.length; i++) {
93              String location = locations[i];
94              if (!validate(location)) {
95                  continue;
96              }
97              getLog().info("Loading " + location);
98              Properties p = getProperties(location);
99              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 }