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 }