Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
PropertyUtils |
|
| 4.0;4 |
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 | 0 | { |
42 | // prevent instantiation | |
43 | 0 | } |
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 | 11 | if ( !propFile.exists() ) |
61 | { | |
62 | 2 | throw new FileNotFoundException( propFile.toString() ); |
63 | } | |
64 | ||
65 | 9 | final Properties fileProps = new Properties(); |
66 | 9 | final FileInputStream inStream = new FileInputStream( propFile ); |
67 | try | |
68 | { | |
69 | 9 | fileProps.load( inStream ); |
70 | } | |
71 | finally | |
72 | { | |
73 | 9 | IOUtil.close( inStream ); |
74 | 9 | } |
75 | ||
76 | 9 | final Properties combinedProps = new Properties(); |
77 | 9 | combinedProps.putAll( baseProps ); |
78 | 9 | 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 | 9 | for ( Iterator iter = fileProps.keySet().iterator(); iter.hasNext(); ) |
90 | { | |
91 | 54 | final String k = (String) iter.next(); |
92 | 54 | final String propValue = getPropertyValue( k, combinedProps ); |
93 | 54 | fileProps.setProperty( k, propValue ); |
94 | 54 | } |
95 | ||
96 | 9 | 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 | 8 | final Properties baseProps = new Properties(); |
112 | ||
113 | 8 | if ( useSystemProps ) |
114 | { | |
115 | 4 | baseProps.putAll( System.getProperties() ); |
116 | } | |
117 | ||
118 | 8 | final Properties resolvedProps = new Properties(); |
119 | try | |
120 | { | |
121 | 8 | resolvedProps.putAll( loadPropertyFile( propfile, baseProps ) ); |
122 | } | |
123 | 1 | catch ( FileNotFoundException e ) |
124 | { | |
125 | 1 | if ( fail ) |
126 | { | |
127 | 1 | throw new FileNotFoundException( propfile.toString() ); |
128 | } | |
129 | 7 | } |
130 | ||
131 | 7 | if ( useSystemProps ) |
132 | { | |
133 | 3 | resolvedProps.putAll( baseProps ); |
134 | } | |
135 | ||
136 | 7 | 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 | 54 | String v = p.getProperty( k ); |
156 | 54 | String ret = ""; |
157 | int idx, idx2; | |
158 | ||
159 | 90 | while ( ( idx = v.indexOf( "${" ) ) >= 0 ) |
160 | { | |
161 | // append prefix to result | |
162 | 36 | ret += v.substring( 0, idx ); |
163 | ||
164 | // strip prefix from original | |
165 | 36 | v = v.substring( idx + 2 ); |
166 | ||
167 | // if no matching } then bail | |
168 | 36 | idx2 = v.indexOf( '}' ); |
169 | 36 | if ( idx2 < 0 ) |
170 | { | |
171 | 0 | break; |
172 | } | |
173 | ||
174 | // strip out the key and resolve it | |
175 | // resolve the key/value for the ${statement} | |
176 | 36 | String nk = v.substring( 0, idx2 ); |
177 | 36 | v = v.substring( idx2 + 1 ); |
178 | 36 | String nv = p.getProperty( nk ); |
179 | ||
180 | // try global environment.. | |
181 | 36 | if ( nv == null ) |
182 | { | |
183 | 0 | 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 | 36 | if ( nv == null || nv.equals( k ) ) |
192 | { | |
193 | 0 | ret += "${" + nk + "}"; |
194 | } | |
195 | else | |
196 | { | |
197 | 36 | v = nv + v; |
198 | } | |
199 | 36 | } |
200 | 54 | return ret + v; |
201 | } | |
202 | } |