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.Properties;
29
30 /**
31 * @deprecated use classes in the component maven-filtering
32 * TODO remove the class ?
33 * @author <a href="mailto:kenney@neonics.com">Kenney Westerhof</a>
34 * @author William Ferguson
35 *
36 */
37 public final class PropertyUtils
38 {
39 private PropertyUtils()
40 {
41 // prevent instantiation
42 }
43
44 /**
45 * Reads a property file, resolving all internal variables, using the supplied base properties.
46 * <p>
47 * The properties are resolved iteratively, so if the value of property A refers to property B, then after
48 * resolution the value of property B will contain the value of property B.
49 * </p>
50 *
51 * @param propFile The property file to load.
52 * @param baseProps Properties containing the initial values to subsitute into the properties file.
53 * @return Properties object containing the properties in the file with their values fully resolved.
54 * @throws IOException if profile does not exist, or cannot be read.
55 */
56 public static Properties loadPropertyFile( File propFile, Properties baseProps )
57 throws IOException
58 {
59 if ( !propFile.exists() )
60 {
61 throw new FileNotFoundException( propFile.toString() );
62 }
63
64 final Properties fileProps = new Properties();
65 final FileInputStream inStream = new FileInputStream( propFile );
66 try
67 {
68 fileProps.load( inStream );
69 }
70 finally
71 {
72 IOUtil.close( inStream );
73 }
74
75 final Properties combinedProps = new Properties();
76 combinedProps.putAll( baseProps );
77 combinedProps.putAll( fileProps );
78
79 // The algorithm iterates only over the fileProps which is all that is required to resolve
80 // the properties defined within the file. This is slighlty different to current, however
81 // I suspect that this was the actual original intent.
82 //
83 // The difference is that #loadPropertyFile(File, boolean, boolean) also resolves System properties
84 // whose values contain expressions. I believe this is unexpected and is not validated by the test cases,
85 // as can be verified by replacing the implementation of #loadPropertyFile(File, boolean, boolean)
86 // with the commented variant I have provided that reuses this method.
87
88 for (Object o : fileProps.keySet()) {
89 final String k = (String) o;
90 final String propValue = getPropertyValue(k, combinedProps);
91 fileProps.setProperty(k, propValue);
92 }
93
94 return fileProps;
95 }
96
97 /**
98 * Reads a property file, resolving all internal variables.
99 *
100 * @param propfile The property file to load
101 * @param fail wheter to throw an exception when the file cannot be loaded or to return null
102 * @param useSystemProps wheter to incorporate System.getProperties settings into the returned Properties object.
103 * @return the loaded and fully resolved Properties object
104 */
105 public static Properties loadPropertyFile( File propfile, boolean fail, boolean useSystemProps )
106 throws IOException
107 {
108
109 final Properties baseProps = new Properties();
110
111 if ( useSystemProps )
112 {
113 baseProps.putAll( System.getProperties() );
114 }
115
116 final Properties resolvedProps = new Properties();
117 try
118 {
119 resolvedProps.putAll( loadPropertyFile( propfile, baseProps ) );
120 }
121 catch ( FileNotFoundException e )
122 {
123 if ( fail )
124 {
125 throw new FileNotFoundException( propfile.toString() );
126 }
127 }
128
129 if ( useSystemProps )
130 {
131 resolvedProps.putAll( baseProps );
132 }
133
134 return resolvedProps;
135 }
136
137 /**
138 * Retrieves a property value, replacing values like ${token}
139 * using the Properties to look them up.
140 *
141 * It will leave unresolved properties alone, trying for System
142 * properties, and implements reparsing (in the case that
143 * the value of a property contains a key), and will
144 * not loop endlessly on a pair like
145 * test = ${test}.
146 */
147 private static String getPropertyValue( String k, Properties p )
148 {
149 // This can also be done using InterpolationFilterReader,
150 // but it requires reparsing the file over and over until
151 // it doesn't change.
152
153 String v = p.getProperty( k );
154 String ret = "";
155 int idx, idx2;
156
157 while ( ( idx = v.indexOf( "${" ) ) >= 0 )
158 {
159 // append prefix to result
160 ret += v.substring( 0, idx );
161
162 // strip prefix from original
163 v = v.substring( idx + 2 );
164
165 // if no matching } then bail
166 idx2 = v.indexOf( '}' );
167 if ( idx2 < 0 )
168 {
169 break;
170 }
171
172 // strip out the key and resolve it
173 // resolve the key/value for the ${statement}
174 String nk = v.substring( 0, idx2 );
175 v = v.substring( idx2 + 1 );
176 String nv = p.getProperty( nk );
177
178 // try global environment..
179 if ( nv == null )
180 {
181 nv = System.getProperty( nk );
182 }
183
184 // if the key cannot be resolved,
185 // leave it alone ( and don't parse again )
186 // else prefix the original string with the
187 // resolved property ( so it can be parsed further )
188 // taking recursion into account.
189 if ( nv == null || nv.equals( k ) )
190 {
191 ret += "${" + nk + "}";
192 }
193 else
194 {
195 v = nv + v;
196 }
197 }
198 return ret + v;
199 }
200 }