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.kuali.maven.common.PropertiesUtils;
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      PropertiesUtils utils = new PropertiesUtils();
48  
49      /**
50       * @parameter default-value="${project}"
51       * @required
52       * @readonly
53       */
54      private MavenProject project;
55  
56      /**
57       * Locations where properties files can be found. Any url Spring resource loading can understand is valid. eg
58       * <code>classpath:myprops.properties</code>. Both, .properties and .xml style properties are supported.
59       *
60       * @parameter
61       * @required
62       */
63      private String[] locations;
64  
65      /**
66       * If true, the plugin will silently ignore any non-existent properties files, and the build will continue
67       *
68       * @parameter expression="${properties.quiet}" default-value="false"
69       */
70      private boolean quiet;
71  
72      /**
73       * If true, the plugin will operate silently without emitting any log messages
74       *
75       * @parameter expression="${properties.silent}" default-value="false"
76       */
77      private boolean silent;
78  
79      /**
80       * If true, the plugin will emit more verbose logging messages.
81       *
82       * @parameter expression="${properties.verbose}" default-value="false"
83       */
84      private boolean verbose;
85  
86      /**
87       * Comma separated list of property values to ignore
88       *
89       * @parameter expression="${properties.ignore}"
90       */
91      private String ignore;
92  
93      /**
94       * If true, property values are resolved
95       *
96       * @parameter expression="${properties.resolveValues}" default-value="true"
97       */
98      boolean resolveValues;
99  
100     /**
101      * If supplied, only the comma separated list of property keys are resolved.
102      *
103      * @parameter expression="${properties.propertyKeysToResolve}"
104      */
105     String propertyKeysToResolve;
106 
107     @Override
108     public void execute() throws MojoExecutionException {
109         // Figure out if there are properties we need to ignore
110         List<String> ignoreList = getIgnoreList();
111 
112         // Update project properties by loading in properties from the locations they've specified
113         updateProjectProperties(ignoreList);
114 
115         if (resolveValues) {
116             // Project + system + env properties
117             Properties allProperties = utils.getMavenProperties(project);
118             resolveValues(project.getProperties(), allProperties, getListFromCSV(propertyKeysToResolve));
119         }
120 
121     }
122 
123     protected void resolveValues(Properties p1, Properties p2, List<String> keys) {
124         for (String name : p1.stringPropertyNames()) {
125             if (resolve(name, keys)) {
126                 String originalValue = p1.getProperty(name);
127                 String resolvedValue = utils.getResolvedValue(originalValue, p2);
128                 p1.setProperty(name, resolvedValue);
129             }
130         }
131     }
132 
133     protected boolean resolve(String key, List<String> keys) {
134         if (keys == null || keys.size() == 0) {
135             return true;
136         } else {
137             return keys.contains(key);
138         }
139     }
140 
141     /**
142      * Copy properties from p2 into p1, overwriting p1 values as we go.
143      *
144      * Ignore any properties with a key that appears in the ignore list
145      *
146      * @param p1
147      * @param p2
148      * @param ignore
149      */
150     protected void updateProperties(Properties p1, Properties p2, List<String> ignore) {
151         Set<String> names = p2.stringPropertyNames();
152         for (String name : names) {
153             if (!ignore.contains(name)) {
154                 String value = p2.getProperty(name);
155                 p1.setProperty(name, value);
156             }
157         }
158     }
159 
160     protected static final List<String> getListFromCSV(String csv) {
161         if (StringUtils.isBlank(csv)) {
162             return new ArrayList<String>();
163         }
164         List<String> list = new ArrayList<String>();
165         String[] tokens = StringUtils.split(csv, ",");
166         for (String token : tokens) {
167             list.add(token.trim());
168         }
169         return list;
170     }
171 
172     protected String toEmpty(String s) {
173         if (StringUtils.isBlank(s)) {
174             return "";
175         } else {
176             return s;
177         }
178     }
179 
180     protected boolean exists(String location) {
181         if (StringUtils.isBlank(location)) {
182             return false;
183         }
184         File file = new File(location);
185         if (file.exists()) {
186             return true;
187         }
188         ResourceLoader loader = new DefaultResourceLoader();
189         Resource resource = loader.getResource(location);
190         return resource.exists();
191     }
192 
193     protected boolean validate(String location) throws MojoExecutionException {
194         boolean exists = exists(location);
195         if (exists) {
196             return true;
197         }
198         if (quiet) {
199             if (verbose && !silent) {
200                 getLog().info("Ignoring non-existent properties file '" + toEmpty(location) + "'");
201             }
202             return false;
203         } else {
204             throw new MojoExecutionException("Non-existent properties file '" + location + "'");
205         }
206     }
207 
208     protected InputStream getInputStream(String location) throws IOException {
209         File file = new File(location);
210         if (file.exists()) {
211             return new FileInputStream(location);
212         }
213         ResourceLoader loader = new DefaultResourceLoader();
214         Resource resource = loader.getResource(location);
215         return resource.getInputStream();
216     }
217 
218     protected Properties getProperties(String location) throws MojoExecutionException {
219         InputStream in = null;
220         try {
221             Properties properties = new Properties();
222             in = getInputStream(location);
223             if (location.toLowerCase().endsWith(".xml")) {
224                 properties.loadFromXML(in);
225             } else {
226                 properties.load(in);
227             }
228             return properties;
229         } catch (IOException e) {
230             throw new MojoExecutionException("Error reading properties file " + location, e);
231         } finally {
232             IOUtils.closeQuietly(in);
233         }
234     }
235 
236     public boolean isQuiet() {
237         return quiet;
238     }
239 
240     public void setQuiet(boolean quiet) {
241         this.quiet = quiet;
242     }
243 
244     public String getIgnore() {
245         return ignore;
246     }
247 
248     public void setIgnore(String ignoreProperties) {
249         this.ignore = ignoreProperties;
250     }
251 
252     public MavenProject getProject() {
253         return project;
254     }
255 
256     public String[] getLocations() {
257         return locations;
258     }
259 
260     public void setLocations(String[] locations) {
261         this.locations = locations;
262     }
263 
264     public boolean isVerbose() {
265         return verbose;
266     }
267 
268     public void setVerbose(boolean verbose) {
269         this.verbose = verbose;
270     }
271 
272     public boolean isSilent() {
273         return silent;
274     }
275 
276     public void setSilent(boolean silent) {
277         this.silent = silent;
278     }
279 
280     protected List<String> getIgnoreList() {
281         List<String> ignoreList = getListFromCSV(ignore);
282         if (!silent && verbose && !StringUtils.isBlank(ignore)) {
283             getLog().info("Ignoring " + ignore);
284         }
285         return ignoreList;
286     }
287 
288     protected void updateProjectProperties(List<String> ignoreList) throws MojoExecutionException {
289         Properties projectProperties = project.getProperties();
290         for (int i = 0; i < locations.length; i++) {
291             Properties allProperties = utils.getMavenProperties(project);
292             String originalLocation = locations[i];
293             String resolvedLocation = utils.getResolvedValue(originalLocation, allProperties);
294             getLog().debug("o=" + originalLocation + " r=" + resolvedLocation);
295             if (!validate(resolvedLocation)) {
296                 continue;
297             }
298             if (!silent) {
299                 getLog().info("Loading " + resolvedLocation);
300             }
301 
302             // Load properties from this location
303             Properties p = getProperties(resolvedLocation);
304 
305             // Update project properties from the properties we just loaded
306             updateProperties(projectProperties, p, ignoreList);
307         }
308     }
309 
310     public boolean isResolveValues() {
311         return resolveValues;
312     }
313 
314     public void setResolveValues(boolean resolveValues) {
315         this.resolveValues = resolveValues;
316     }
317 
318     public String getPropertyKeysToResolve() {
319         return propertyKeysToResolve;
320     }
321 
322     public void setPropertyKeysToResolve(String propertyKeysToResolve) {
323         this.propertyKeysToResolve = propertyKeysToResolve;
324     }
325 
326 }