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