001    /**
002     * Copyright 2009-2011 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.util.Enumeration;
035    import java.util.Properties;
036    
037    import org.apache.maven.plugin.AbstractMojo;
038    import org.apache.maven.plugin.MojoExecutionException;
039    import org.apache.maven.project.MavenProject;
040    import org.codehaus.plexus.util.cli.CommandLineUtils;
041    
042    /**
043     * The read-project-properties goal reads property files and stores the properties as project properties. It serves as
044     * an alternate to specifying properties in pom.xml.
045     *
046     * @author <a href="mailto:zarars@gmail.com">Zarar Siddiqi</a>
047     * @author <a href="mailto:Krystian.Nowak@gmail.com">Krystian Nowak</a>
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        /**
053         * @parameter default-value="${project}"
054         * @required
055         * @readonly
056         */
057        private MavenProject project;
058    
059        /**
060         * The properties files that will be used when reading properties. Can use both .properties and .xml files
061         *
062         * @parameter
063         * @required
064         */
065        private File[] files;
066    
067        /**
068         * If the plugin should be quiet if any of the files was not found
069         *
070         * @parameter default-value="false"
071         */
072        private boolean quiet;
073    
074        public void execute() throws MojoExecutionException {
075            Properties projectProperties = new Properties();
076            for (int i = 0; i < files.length; i++) {
077                File file = files[i];
078    
079                if (file.exists()) {
080                    try {
081                        getLog().debug("Loading property file: " + file);
082    
083                        FileInputStream stream = new FileInputStream(file);
084                        projectProperties = project.getProperties();
085    
086                        try {
087                            String filename = file.getName().toLowerCase();
088                            if (filename.endsWith(".xml")) {
089                                projectProperties.loadFromXML(stream);
090                            } else {
091                                projectProperties.load(stream);
092                            }
093                        } finally {
094                            if (stream != null) {
095                                stream.close();
096                            }
097                        }
098                    } catch (IOException e) {
099                        throw new MojoExecutionException("Error reading properties file " + file.getAbsolutePath(), e);
100                    }
101                } else {
102                    if (quiet) {
103                        getLog().warn("Ignoring missing properties file: " + file.getAbsolutePath());
104                    } else {
105                        throw new MojoExecutionException("Properties file not found: " + file.getAbsolutePath());
106                    }
107                }
108            }
109    
110            boolean useEnvVariables = false;
111            for (Enumeration n = projectProperties.propertyNames(); n.hasMoreElements();) {
112                String k = (String) n.nextElement();
113                String p = (String) projectProperties.get(k);
114                if (p.indexOf("${env.") != -1) {
115                    useEnvVariables = true;
116                    break;
117                }
118            }
119            Properties environment = null;
120            if (useEnvVariables) {
121                try {
122                    environment = CommandLineUtils.getSystemEnvVars();
123                } catch (IOException e) {
124                    throw new MojoExecutionException("Error getting system envorinment variables: ", e);
125                }
126            }
127            for (Enumeration n = projectProperties.propertyNames(); n.hasMoreElements();) {
128                String k = (String) n.nextElement();
129                projectProperties.setProperty(k, getPropertyValue(k, projectProperties, environment));
130            }
131        }
132    
133        /**
134         * Retrieves a property value, replacing values like ${token} using the Properties to look them up. Shamelessly
135         * adapted from:
136         * http://maven.apache.org/plugins/maven-war-plugin/xref/org/apache/maven/plugin/war/PropertyUtils.html
137         *
138         * It will leave unresolved properties alone, trying for System properties, and environment variables and implements
139         * reparsing (in the case that the value of a property contains a key), and will not loop endlessly on a pair like
140         * test = ${test}
141         *
142         * @param k
143         *            property key
144         * @param p
145         *            project properties
146         * @param environment
147         *            environment variables
148         * @return resolved property value
149         */
150        private String getPropertyValue(String k, Properties p, Properties environment) {
151            String v = p.getProperty(k);
152            String ret = "";
153            int idx, idx2;
154    
155            while ((idx = v.indexOf("${")) >= 0) {
156                // append prefix to result
157                ret += v.substring(0, idx);
158    
159                // strip prefix from original
160                v = v.substring(idx + 2);
161    
162                idx2 = v.indexOf("}");
163    
164                // if no matching } then bail
165                if (idx2 < 0) {
166                    break;
167                }
168    
169                // strip out the key and resolve it
170                // resolve the key/value for the ${statement}
171                String nk = v.substring(0, idx2);
172                v = v.substring(idx2 + 1);
173                String nv = p.getProperty(nk);
174    
175                // try global environment
176                if (nv == null) {
177                    nv = System.getProperty(nk);
178                }
179    
180                // try environment variable
181                if (nv == null && nk.startsWith("env.") && environment != null) {
182                    nv = environment.getProperty(nk.substring(4));
183                }
184    
185                // if the key cannot be resolved,
186                // leave it alone ( and don't parse again )
187                // else prefix the original string with the
188                // resolved property ( so it can be parsed further )
189                // taking recursion into account.
190                if (nv == null || nv.equals(nk)) {
191                    ret += "${" + nk + "}";
192                } else {
193                    v = nv + v;
194                }
195            }
196            return ret + v;
197        }
198    }