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.kuali.maven.common.PropertiesUtils;
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 PropertiesUtils utils = new PropertiesUtils();
048
049 /**
050 * @parameter default-value="${project}"
051 * @required
052 * @readonly
053 */
054 private MavenProject project;
055
056 /**
057 * Locations where properties files can be found. Any url Spring resource loading can understand is valid. eg
058 * <code>classpath:myprops.properties</code>. Both, .properties and .xml style properties are supported.
059 *
060 * @parameter
061 * @required
062 */
063 private String[] locations;
064
065 /**
066 * If true, the plugin will silently ignore any non-existent properties files, and the build will continue
067 *
068 * @parameter expression="${properties.quiet}" default-value="false"
069 */
070 private boolean quiet;
071
072 /**
073 * If true, the plugin will operate silently without emitting any log messages
074 *
075 * @parameter expression="${properties.silent}" default-value="false"
076 */
077 private boolean silent;
078
079 /**
080 * If true, the plugin will emit more verbose logging messages.
081 *
082 * @parameter expression="${properties.verbose}" default-value="false"
083 */
084 private boolean verbose;
085
086 /**
087 * Comma separated list of property values to ignore
088 *
089 * @parameter expression="${properties.ignore}"
090 */
091 private String ignore;
092
093 /**
094 * If true, property values are resolved
095 *
096 * @parameter expression="${properties.resolveValues}" default-value="true"
097 */
098 boolean resolveValues;
099
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 }