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.<br>
040 *
041 * Properties files handled by this plugin, have their property values resolved using Spring's expression parser. This
042 * means anything you can do with Spring property values you can do with property values handled by this plugin. For
043 * example, nested properties are supported: eg foo=${a.${b}.c}
044 *
045 * @author <a href="mailto:zarars@gmail.com">Zarar Siddiqi</a>
046 * @author <a href="mailto:Krystian.Nowak@gmail.com">Krystian Nowak</a>
047 * @auther Jeff Caddel
048 * @version $Id: ReadPropertiesMojo.java 8861 2009-01-21 15:35:38Z pgier $
049 * @goal read-project-properties
050 */
051 public class ReadPropertiesMojo extends AbstractMojo {
052 PropertiesUtils utils = new PropertiesUtils();
053
054 /**
055 * @parameter default-value="${project}"
056 * @required
057 * @readonly
058 */
059 private MavenProject project;
060
061 /**
062 * Locations where properties files can be found. Any url Spring resource loading can understand is valid. eg
063 * <code>classpath:myprops.properties</code>. Both, .properties and .xml style properties are supported.
064 *
065 * @parameter
066 * @required
067 */
068 private String[] locations;
069
070 /**
071 * If true, the plugin will silently ignore any non-existent properties files, and the build will continue
072 *
073 * @parameter expression="${properties.quiet}" default-value="false"
074 */
075 private boolean quiet;
076
077 /**
078 * If true, the plugin will operate silently without emitting any log messages
079 *
080 * @parameter expression="${properties.silent}" default-value="false"
081 */
082 private boolean silent;
083
084 /**
085 * If true, the plugin will emit more verbose logging messages.
086 *
087 * @parameter expression="${properties.verbose}" default-value="false"
088 */
089 private boolean verbose;
090
091 /**
092 * Comma separated list of property values to ignore
093 *
094 * @parameter expression="${properties.ignore}"
095 */
096 private String ignore;
097
098 @Override
099 public void execute() throws MojoExecutionException {
100 // Figure out if there are properties we need to ignore
101 List<String> ignoreList = getIgnoreList();
102
103 // Update project properties by loading in properties from the locations they've specified
104 updateProjectProperties(ignoreList);
105
106 // Project + system + env properties
107 Properties allProperties = utils.getMavenProperties(project);
108 resolveValues(project.getProperties(), allProperties);
109
110 }
111
112 protected void resolveValues(Properties p1, Properties p2) {
113 for (String name : p1.stringPropertyNames()) {
114 String originalValue = p1.getProperty(name);
115 String resolvedValue = utils.getResolvedValue(originalValue, p2);
116 p1.setProperty(name, resolvedValue);
117 }
118 }
119
120 /**
121 * Copy properties from p2 into p1, overwriting p1 values as we go.
122 *
123 * Ignore any properties with a key that appears in the ignore list
124 *
125 * @param p1
126 * @param p2
127 * @param ignore
128 */
129 protected void updateProperties(Properties p1, Properties p2, List<String> ignore) {
130 Set<String> names = p2.stringPropertyNames();
131 for (String name : names) {
132 if (!ignore.contains(name)) {
133 String value = p2.getProperty(name);
134 p1.setProperty(name, value);
135 }
136 }
137 }
138
139 protected static final List<String> getListFromCSV(String csv) {
140 if (StringUtils.isBlank(csv)) {
141 return new ArrayList<String>();
142 }
143 List<String> list = new ArrayList<String>();
144 String[] tokens = StringUtils.split(csv, ",");
145 for (String token : tokens) {
146 list.add(token.trim());
147 }
148 return list;
149 }
150
151 protected String toEmpty(String s) {
152 if (StringUtils.isBlank(s)) {
153 return "";
154 } else {
155 return s;
156 }
157 }
158
159 protected boolean exists(String location) {
160 if (StringUtils.isBlank(location)) {
161 return false;
162 }
163 File file = new File(location);
164 if (file.exists()) {
165 return true;
166 }
167 ResourceLoader loader = new DefaultResourceLoader();
168 Resource resource = loader.getResource(location);
169 return resource.exists();
170 }
171
172 protected boolean validate(String location) throws MojoExecutionException {
173 boolean exists = exists(location);
174 if (exists) {
175 return true;
176 }
177 if (quiet) {
178 if (verbose && !silent) {
179 getLog().info("Ignoring non-existent properties file '" + toEmpty(location) + "'");
180 }
181 return false;
182 } else {
183 throw new MojoExecutionException("Non-existent properties file '" + location + "'");
184 }
185 }
186
187 protected InputStream getInputStream(String location) throws IOException {
188 File file = new File(location);
189 if (file.exists()) {
190 return new FileInputStream(location);
191 }
192 ResourceLoader loader = new DefaultResourceLoader();
193 Resource resource = loader.getResource(location);
194 return resource.getInputStream();
195 }
196
197 protected Properties getProperties(String location) throws MojoExecutionException {
198 InputStream in = null;
199 try {
200 Properties properties = new Properties();
201 in = getInputStream(location);
202 if (location.toLowerCase().endsWith(".xml")) {
203 properties.loadFromXML(in);
204 } else {
205 properties.load(in);
206 }
207 return properties;
208 } catch (IOException e) {
209 throw new MojoExecutionException("Error reading properties file " + location, e);
210 } finally {
211 IOUtils.closeQuietly(in);
212 }
213 }
214
215 public boolean isQuiet() {
216 return quiet;
217 }
218
219 public void setQuiet(boolean quiet) {
220 this.quiet = quiet;
221 }
222
223 public String getIgnore() {
224 return ignore;
225 }
226
227 public void setIgnore(String ignoreProperties) {
228 this.ignore = ignoreProperties;
229 }
230
231 public MavenProject getProject() {
232 return project;
233 }
234
235 public String[] getLocations() {
236 return locations;
237 }
238
239 public void setLocations(String[] locations) {
240 this.locations = locations;
241 }
242
243 public boolean isVerbose() {
244 return verbose;
245 }
246
247 public void setVerbose(boolean verbose) {
248 this.verbose = verbose;
249 }
250
251 public boolean isSilent() {
252 return silent;
253 }
254
255 public void setSilent(boolean silent) {
256 this.silent = silent;
257 }
258
259 protected List<String> getIgnoreList() {
260 List<String> ignoreList = getListFromCSV(ignore);
261 if (!silent && verbose && !StringUtils.isBlank(ignore)) {
262 getLog().info("Ignoring " + ignore);
263 }
264 return ignoreList;
265 }
266
267 protected void updateProjectProperties(List<String> ignoreList) throws MojoExecutionException {
268 Properties projectProperties = project.getProperties();
269 for (int i = 0; i < locations.length; i++) {
270 Properties allProperties = utils.getMavenProperties(project);
271 String originalLocation = locations[i];
272 String resolvedLocation = utils.getResolvedValue(originalLocation, allProperties);
273 getLog().debug("o=" + originalLocation + " r=" + resolvedLocation);
274 if (!validate(resolvedLocation)) {
275 continue;
276 }
277 if (!silent) {
278 getLog().info("Loading " + resolvedLocation);
279 }
280
281 // Load properties from this location
282 Properties p = getProperties(resolvedLocation);
283
284 // Update project properties from the properties we just loaded
285 updateProperties(projectProperties, p, ignoreList);
286 }
287 }
288
289 }