1 package org.apache.maven.plugin.resources; 2 3 /* 4 * Licensed to the Apache Software Foundation (ASF) under one 5 * or more contributor license agreements. See the NOTICE file 6 * distributed with this work for additional information 7 * regarding copyright ownership. The ASF licenses this file 8 * to you under the Apache License, Version 2.0 (the 9 * "License"); you may not use this file except in compliance 10 * with the License. You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, 15 * software distributed under the License is distributed on an 16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 * KIND, either express or implied. See the License for the 18 * specific language governing permissions and limitations 19 * under the License. 20 */ 21 22 import org.codehaus.plexus.util.IOUtil; 23 24 import java.io.File; 25 import java.io.FileInputStream; 26 import java.io.FileNotFoundException; 27 import java.io.IOException; 28 import java.util.Iterator; 29 import java.util.Properties; 30 31 /** 32 * @deprecated use classes in the component maven-filtering 33 * TODO remove the class ? 34 * @author <a href="mailto:kenney@neonics.com">Kenney Westerhof</a> 35 * @author William Ferguson 36 * @version $Id: PropertyUtils.java 728546 2008-12-21 22:56:51Z bentmann $ 37 */ 38 public final class PropertyUtils 39 { 40 private PropertyUtils() 41 { 42 // prevent instantiation 43 } 44 45 /** 46 * Reads a property file, resolving all internal variables, using the supplied base properties. 47 * <p> 48 * The properties are resolved iteratively, so if the value of property A refers to property B, then after 49 * resolution the value of property B will contain the value of property B. 50 * </p> 51 * 52 * @param propFile The property file to load. 53 * @param baseProps Properties containing the initial values to subsitute into the properties file. 54 * @return Properties object containing the properties in the file with their values fully resolved. 55 * @throws IOException if profile does not exist, or cannot be read. 56 */ 57 public static Properties loadPropertyFile( File propFile, Properties baseProps ) 58 throws IOException 59 { 60 if ( !propFile.exists() ) 61 { 62 throw new FileNotFoundException( propFile.toString() ); 63 } 64 65 final Properties fileProps = new Properties(); 66 final FileInputStream inStream = new FileInputStream( propFile ); 67 try 68 { 69 fileProps.load( inStream ); 70 } 71 finally 72 { 73 IOUtil.close( inStream ); 74 } 75 76 final Properties combinedProps = new Properties(); 77 combinedProps.putAll( baseProps ); 78 combinedProps.putAll( fileProps ); 79 80 // The algorithm iterates only over the fileProps which is all that is required to resolve 81 // the properties defined within the file. This is slighlty different to current, however 82 // I suspect that this was the actual original intent. 83 // 84 // The difference is that #loadPropertyFile(File, boolean, boolean) also resolves System properties 85 // whose values contain expressions. I believe this is unexpected and is not validated by the test cases, 86 // as can be verified by replacing the implementation of #loadPropertyFile(File, boolean, boolean) 87 // with the commented variant I have provided that reuses this method. 88 89 for ( Iterator iter = fileProps.keySet().iterator(); iter.hasNext(); ) 90 { 91 final String k = (String) iter.next(); 92 final String propValue = getPropertyValue( k, combinedProps ); 93 fileProps.setProperty( k, propValue ); 94 } 95 96 return fileProps; 97 } 98 99 /** 100 * Reads a property file, resolving all internal variables. 101 * 102 * @param propfile The property file to load 103 * @param fail wheter to throw an exception when the file cannot be loaded or to return null 104 * @param useSystemProps wheter to incorporate System.getProperties settings into the returned Properties object. 105 * @return the loaded and fully resolved Properties object 106 */ 107 public static Properties loadPropertyFile( File propfile, boolean fail, boolean useSystemProps ) 108 throws IOException 109 { 110 111 final Properties baseProps = new Properties(); 112 113 if ( useSystemProps ) 114 { 115 baseProps.putAll( System.getProperties() ); 116 } 117 118 final Properties resolvedProps = new Properties(); 119 try 120 { 121 resolvedProps.putAll( loadPropertyFile( propfile, baseProps ) ); 122 } 123 catch ( FileNotFoundException e ) 124 { 125 if ( fail ) 126 { 127 throw new FileNotFoundException( propfile.toString() ); 128 } 129 } 130 131 if ( useSystemProps ) 132 { 133 resolvedProps.putAll( baseProps ); 134 } 135 136 return resolvedProps; 137 } 138 139 /** 140 * Retrieves a property value, replacing values like ${token} 141 * using the Properties to look them up. 142 * 143 * It will leave unresolved properties alone, trying for System 144 * properties, and implements reparsing (in the case that 145 * the value of a property contains a key), and will 146 * not loop endlessly on a pair like 147 * test = ${test}. 148 */ 149 private static String getPropertyValue( String k, Properties p ) 150 { 151 // This can also be done using InterpolationFilterReader, 152 // but it requires reparsing the file over and over until 153 // it doesn't change. 154 155 String v = p.getProperty( k ); 156 String ret = ""; 157 int idx, idx2; 158 159 while ( ( idx = v.indexOf( "${" ) ) >= 0 ) 160 { 161 // append prefix to result 162 ret += v.substring( 0, idx ); 163 164 // strip prefix from original 165 v = v.substring( idx + 2 ); 166 167 // if no matching } then bail 168 idx2 = v.indexOf( '}' ); 169 if ( idx2 < 0 ) 170 { 171 break; 172 } 173 174 // strip out the key and resolve it 175 // resolve the key/value for the ${statement} 176 String nk = v.substring( 0, idx2 ); 177 v = v.substring( idx2 + 1 ); 178 String nv = p.getProperty( nk ); 179 180 // try global environment.. 181 if ( nv == null ) 182 { 183 nv = System.getProperty( nk ); 184 } 185 186 // if the key cannot be resolved, 187 // leave it alone ( and don't parse again ) 188 // else prefix the original string with the 189 // resolved property ( so it can be parsed further ) 190 // taking recursion into account. 191 if ( nv == null || nv.equals( k ) ) 192 { 193 ret += "${" + nk + "}"; 194 } 195 else 196 { 197 v = nv + v; 198 } 199 } 200 return ret + v; 201 } 202 }