View Javadoc
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 }