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