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.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 }