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    /*
019     * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE
020     * file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file
021     * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
022     * License. You may obtain a copy of the License at
023     *
024     * http://www.apache.org/licenses/LICENSE-2.0
025     *
026     * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
027     * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
028     * specific language governing permissions and limitations under the License.
029     */
030    
031    import java.io.File;
032    import java.io.FileInputStream;
033    import java.io.IOException;
034    import java.io.InputStream;
035    import java.util.Enumeration;
036    import java.util.Properties;
037    
038    import org.apache.commons.io.IOUtils;
039    import org.apache.maven.plugin.AbstractMojo;
040    import org.apache.maven.plugin.MojoExecutionException;
041    import org.apache.maven.project.MavenProject;
042    import org.codehaus.plexus.util.cli.CommandLineUtils;
043    
044    /**
045     * The read-project-properties goal reads property files and stores the properties as project properties. It serves as
046     * an alternate to specifying properties in pom.xml.
047     *
048     * @author <a href="mailto:zarars@gmail.com">Zarar Siddiqi</a>
049     * @author <a href="mailto:Krystian.Nowak@gmail.com">Krystian Nowak</a>
050     * @version $Id: ReadPropertiesMojo.java 8861 2009-01-21 15:35:38Z pgier $
051     * @goal read-project-properties
052     */
053    public class ReadPropertiesMojo extends AbstractMojo {
054    
055        /**
056         * @parameter default-value="${project}"
057         * @required
058         * @readonly
059         */
060        private MavenProject project;
061    
062        /**
063         * The properties files that will be used when reading properties. Can use both .properties and .xml files
064         *
065         * @parameter
066         * @required
067         */
068        private File[] files;
069    
070        /**
071         * If true, the plugin will ignore any non-existent properties files
072         *
073         * @parameter default-value="false"
074         */
075        private boolean quiet;
076    
077        public void execute() throws MojoExecutionException {
078            Properties projectProperties = project.getProperties();
079            for (int i = 0; i < files.length; i++) {
080                File file = files[i];
081                if (validate(file)) {
082                    load(file, projectProperties);
083                }
084            }
085    
086            boolean useEnvVariables = false;
087            for (Enumeration n = projectProperties.propertyNames(); n.hasMoreElements();) {
088                String k = (String) n.nextElement();
089                String p = (String) projectProperties.get(k);
090                if (p.indexOf("${env.") != -1) {
091                    useEnvVariables = true;
092                    break;
093                }
094            }
095            Properties environment = null;
096            if (useEnvVariables) {
097                try {
098                    environment = CommandLineUtils.getSystemEnvVars();
099                } catch (IOException e) {
100                    throw new MojoExecutionException("Error getting system envorinment variables: ", e);
101                }
102            }
103            for (Enumeration n = projectProperties.propertyNames(); n.hasMoreElements();) {
104                String k = (String) n.nextElement();
105                projectProperties.setProperty(k, getPropertyValue(k, projectProperties, environment));
106            }
107        }
108    
109        /**
110         * Retrieves a property value, replacing values like ${token} using the Properties to look them up. Shamelessly
111         * adapted from:
112         * http://maven.apache.org/plugins/maven-war-plugin/xref/org/apache/maven/plugin/war/PropertyUtils.html
113         *
114         * It will leave unresolved properties alone, trying for System properties, and environment variables and implements
115         * reparsing (in the case that the value of a property contains a key), and will not loop endlessly on a pair like
116         * test = ${test}
117         *
118         * @param k
119         *            property key
120         * @param p
121         *            project properties
122         * @param environment
123         *            environment variables
124         * @return resolved property value
125         */
126        protected String getPropertyValue(String k, Properties p, Properties environment) {
127            String v = p.getProperty(k);
128            String ret = "";
129            int idx, idx2;
130    
131            while ((idx = v.indexOf("${")) >= 0) {
132                // append prefix to result
133                ret += v.substring(0, idx);
134    
135                // strip prefix from original
136                v = v.substring(idx + 2);
137    
138                idx2 = v.indexOf("}");
139    
140                // if no matching } then bail
141                if (idx2 < 0) {
142                    break;
143                }
144    
145                // strip out the key and resolve it
146                // resolve the key/value for the ${statement}
147                String nk = v.substring(0, idx2);
148                v = v.substring(idx2 + 1);
149                String nv = p.getProperty(nk);
150    
151                // try global environment
152                if (nv == null) {
153                    nv = System.getProperty(nk);
154                }
155    
156                // try environment variable
157                if (nv == null && nk.startsWith("env.") && environment != null) {
158                    nv = environment.getProperty(nk.substring(4));
159                }
160    
161                // if the key cannot be resolved,
162                // leave it alone ( and don't parse again )
163                // else prefix the original string with the
164                // resolved property ( so it can be parsed further )
165                // taking recursion into account.
166                if (nv == null || nv.equals(nk)) {
167                    ret += "${" + nk + "}";
168                } else {
169                    v = nv + v;
170                }
171            }
172            return ret + v;
173        }
174    
175        protected boolean validate(File file) throws MojoExecutionException {
176            boolean exists = file != null && file.exists();
177            if (exists) {
178                return true;
179            }
180            if (quiet) {
181                getLog().info("Ignoring non-existent properties file '" + file + "'");
182                return false;
183            } else {
184                throw new MojoExecutionException("Non-existent properties file '" + file + "'");
185            }
186        }
187    
188        protected void load(File file, Properties properties) throws MojoExecutionException {
189            InputStream in = null;
190            try {
191                getLog().info("Loading " + file);
192                in = new FileInputStream(file);
193                String filename = file.getName().toLowerCase();
194                if (filename.endsWith(".xml")) {
195                    properties.loadFromXML(in);
196                } else {
197                    properties.load(in);
198                }
199            } catch (IOException e) {
200                throw new MojoExecutionException("Error reading properties file " + file.getAbsolutePath(), e);
201            } finally {
202                IOUtils.closeQuietly(in);
203            }
204        }
205    
206    }