View Javadoc

1   package org.apache.maven.shared.filtering;
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 java.io.File;
23  import java.io.IOException;
24  import java.io.Reader;
25  import java.util.ArrayList;
26  import java.util.Collections;
27  import java.util.LinkedHashSet;
28  import java.util.List;
29  import java.util.Properties;
30  
31  import org.apache.maven.execution.MavenSession;
32  import org.apache.maven.project.MavenProject;
33  import org.apache.maven.settings.Settings;
34  import org.apache.maven.shared.utils.StringUtils;
35  import org.apache.maven.shared.utils.io.FileUtils;
36  import org.apache.maven.shared.utils.io.FileUtils.FilterWrapper;
37  import org.codehaus.plexus.interpolation.InterpolationPostProcessor;
38  import org.codehaus.plexus.interpolation.PrefixAwareRecursionInterceptor;
39  import org.codehaus.plexus.interpolation.PrefixedObjectValueSource;
40  import org.codehaus.plexus.interpolation.PropertiesBasedValueSource;
41  import org.codehaus.plexus.interpolation.RecursionInterceptor;
42  import org.codehaus.plexus.interpolation.SimpleRecursionInterceptor;
43  import org.codehaus.plexus.interpolation.SingleResponseValueSource;
44  import org.codehaus.plexus.interpolation.ValueSource;
45  import org.codehaus.plexus.interpolation.multi.MultiDelimiterStringSearchInterpolator;
46  import org.codehaus.plexus.logging.AbstractLogEnabled;
47  import org.sonatype.plexus.build.incremental.BuildContext;
48  
49  /**
50   * @author Olivier Lamy
51   *
52   * @plexus.component role="org.apache.maven.shared.filtering.MavenFileFilter"
53   * role-hint="default"
54   */
55  public class DefaultMavenFileFilter
56      extends AbstractLogEnabled
57      implements MavenFileFilter
58  {
59  
60      /**
61       * @plexus.requirement
62       */
63      private BuildContext buildContext;
64  
65      public void copyFile( File from, File to, boolean filtering, MavenProject mavenProject, List<String> filters,
66                            boolean escapedBackslashesInFilePath, String encoding, MavenSession mavenSession )
67          throws MavenFilteringException
68      {
69          MavenResourcesExecution mre = new MavenResourcesExecution();
70          mre.setMavenProject( mavenProject );
71          mre.setFileFilters( filters );
72          mre.setEscapeWindowsPaths( escapedBackslashesInFilePath );
73          mre.setMavenSession( mavenSession );
74          mre.setInjectProjectBuildFilters( true );
75  
76          List<FileUtils.FilterWrapper> filterWrappers = getDefaultFilterWrappers( mre );
77          copyFile( from, to, filtering, filterWrappers, encoding );
78      }
79  
80  
81      public void copyFile( MavenFileFilterRequest mavenFileFilterRequest )
82          throws MavenFilteringException
83      {
84          List<FilterWrapper> filterWrappers = getDefaultFilterWrappers( mavenFileFilterRequest );
85  
86          copyFile( mavenFileFilterRequest.getFrom(), mavenFileFilterRequest.getTo(),
87                    mavenFileFilterRequest.isFiltering(), filterWrappers, mavenFileFilterRequest.getEncoding() );
88      }
89  
90  
91      public void copyFile( File from, File to, boolean filtering, List<FileUtils.FilterWrapper> filterWrappers,
92                            String encoding )
93          throws MavenFilteringException
94      {
95          // overwrite forced to false to preserve backward comp
96          copyFile( from, to, filtering, filterWrappers, encoding, false );
97      }
98  
99  
100     public void copyFile( File from, File to, boolean filtering, List<FileUtils.FilterWrapper> filterWrappers,
101                           String encoding, boolean overwrite )
102         throws MavenFilteringException
103     {
104         try
105         {
106             if ( filtering )
107             {
108                 if ( getLogger().isDebugEnabled() )
109                 {
110                     getLogger().debug( "filtering " + from.getPath() + " to " + to.getPath() );
111                 }
112                 FileUtils.FilterWrapper[] wrappers = filterWrappers.toArray(
113                     new FileUtils.FilterWrapper[filterWrappers.size()] );
114                 FileUtils.copyFile( from, to, encoding, wrappers );
115             }
116             else
117             {
118                 if ( getLogger().isDebugEnabled() )
119                 {
120                     getLogger().debug( "copy " + from.getPath() + " to " + to.getPath() );
121                 }
122                 FileUtils.copyFile( from, to, encoding, new FileUtils.FilterWrapper[0], overwrite );
123             }
124 
125             buildContext.refresh( to );
126         }
127         catch ( IOException e )
128         {
129             throw new MavenFilteringException( e.getMessage(), e );
130         }
131 
132     }
133 
134     /**
135      * @see org.apache.maven.shared.filtering.MavenFileFilter#getDefaultFilterWrappers(org.apache.maven.project.MavenProject, java.util.List, boolean, org.apache.maven.execution.MavenSession)
136      * @deprecated
137      */
138     public List<FileUtils.FilterWrapper> getDefaultFilterWrappers( final MavenProject mavenProject,
139                                                                    List<String> filters,
140                                                                    final boolean escapedBackslashesInFilePath,
141                                                                    MavenSession mavenSession )
142         throws MavenFilteringException
143     {
144         return getDefaultFilterWrappers( mavenProject, filters, escapedBackslashesInFilePath, mavenSession, null );
145     }
146 
147 
148     public List<FileUtils.FilterWrapper> getDefaultFilterWrappers( final MavenProject mavenProject, List<String> filters,
149                                                                    final boolean escapedBackslashesInFilePath,
150                                                                    MavenSession mavenSession,
151                                                                    MavenResourcesExecution mavenResourcesExecution )
152         throws MavenFilteringException
153     {
154 
155         MavenResourcesExecution mre =
156             mavenResourcesExecution == null ? new MavenResourcesExecution() : mavenResourcesExecution.copyOf();
157 
158         mre.setMavenProject( mavenProject );
159         mre.setMavenSession( mavenSession );
160         mre.setFilters( filters );
161         mre.setEscapedBackslashesInFilePath( escapedBackslashesInFilePath );
162 
163         return getDefaultFilterWrappers( mre );
164 
165     }
166 
167     public List<FileUtils.FilterWrapper> getDefaultFilterWrappers( final AbstractMavenFilteringRequest req )
168         throws MavenFilteringException
169     {
170         // backup values
171         boolean supportMultiLineFiltering = req.isSupportMultiLineFiltering();
172 
173         // compensate for null parameter value.
174         final AbstractMavenFilteringRequest request = req == null ? new MavenFileFilterRequest() : req;
175 
176         request.setSupportMultiLineFiltering( supportMultiLineFiltering );
177 
178         // Here we build some properties which will be used to read some properties files
179         // to interpolate the expression ${ } in this properties file
180 
181         // Take a copy of filterProperties to ensure that evaluated filterTokens are not propagated
182         // to subsequent filter files. Note: this replicates current behaviour and seems to make sense.
183 
184         final Properties baseProps = new Properties();
185 
186         // Project properties
187         if ( request.getMavenProject() != null )
188         {
189             baseProps.putAll( request.getMavenProject().getProperties() == null
190                                   ? Collections.emptyMap()
191                                   : request.getMavenProject().getProperties() );
192         }
193         // TODO this is NPE free but do we consider this as normal
194         // or do we have to throw an MavenFilteringException with mavenSession cannot be null
195         if ( request.getMavenSession() != null )
196         {
197             // execution properties wins
198             baseProps.putAll( request.getMavenSession().getExecutionProperties() );
199         }
200 
201         // now we build properties to use for resources interpolation
202 
203         final Properties filterProperties = new Properties();
204 
205         File basedir = request.getMavenProject() != null ? request.getMavenProject().getBasedir() : new File( "." ); 
206 
207         loadProperties( filterProperties, basedir, request.getFileFilters(), baseProps );
208         if ( filterProperties.size() < 1 )
209         {
210             filterProperties.putAll( baseProps );
211         }
212 
213         if ( request.getMavenProject() != null )
214         {
215             if ( request.isInjectProjectBuildFilters() )
216             {
217                 @SuppressWarnings( "unchecked" )
218                 List<String> buildFilters = new ArrayList<String>( request.getMavenProject().getBuild().getFilters() );
219 
220                 // JDK-8015656: (coll) unexpected NPE from removeAll 
221                 if ( request.getFileFilters() != null )
222                 {
223                     buildFilters.removeAll( request.getFileFilters() );
224                 }
225 
226                 loadProperties( filterProperties, basedir, buildFilters, baseProps );
227             }
228 
229             // Project properties
230             filterProperties.putAll( request.getMavenProject().getProperties() == null
231                                          ? Collections.emptyMap()
232                                          : request.getMavenProject().getProperties() );
233         }
234         if ( request.getMavenSession() != null )
235         {
236             // execution properties wins
237             filterProperties.putAll( request.getMavenSession().getExecutionProperties() );
238         }
239 
240         if ( request.getAdditionalProperties() != null )
241         {
242             // additional properties wins
243             filterProperties.putAll( request.getAdditionalProperties() );
244         }
245 
246         List<FileUtils.FilterWrapper> defaultFilterWrappers = request == null
247             ? new ArrayList<FileUtils.FilterWrapper>( 1 )
248             : new ArrayList<FileUtils.FilterWrapper>( request.getDelimiters().size() + 1 );
249 
250         if ( getLogger().isDebugEnabled() )
251         {
252             getLogger().debug( "properties used " + filterProperties );
253         }
254 
255         final ValueSource propertiesValueSource = new PropertiesBasedValueSource( filterProperties );
256 
257         if ( request != null )
258         {
259             FileUtils.FilterWrapper wrapper =
260                 new Wrapper( request.getDelimiters(), request.getMavenProject(), request.getMavenSession(),
261                              propertiesValueSource, request.getProjectStartExpressions(), request.getEscapeString(),
262                              request.isEscapeWindowsPaths(), request.isSupportMultiLineFiltering() );
263 
264             defaultFilterWrappers.add( wrapper );
265         }
266 
267         return defaultFilterWrappers;
268     }
269 
270     /**
271      * default visibility only for testing reason !
272      */
273     void loadProperties( Properties filterProperties, File basedir, List<String> propertiesFilePaths, Properties baseProps )
274         throws MavenFilteringException
275     {
276         if ( propertiesFilePaths != null )
277         {
278             Properties workProperties = new Properties();
279             workProperties.putAll( baseProps );
280 
281             for ( String filterFile : propertiesFilePaths )
282             {
283                 if ( StringUtils.isEmpty( filterFile ) )
284                 {
285                     // skip empty file name
286                     continue;
287                 }
288                 try
289                 {
290                     File propFile = FileUtils.resolveFile( basedir, filterFile );
291                     Properties properties = PropertyUtils.loadPropertyFile( propFile, workProperties );
292                     filterProperties.putAll( properties );
293                     workProperties.putAll( properties );
294                 }
295                 catch ( IOException e )
296                 {
297                     throw new MavenFilteringException( "Error loading property file '" + filterFile + "'", e );
298                 }
299             }
300         }
301     }
302 
303     private static final class Wrapper
304         extends FileUtils.FilterWrapper
305     {
306 
307         private LinkedHashSet<String> delimiters;
308 
309         private MavenProject project;
310 
311         private ValueSource propertiesValueSource;
312 
313         private List<String> projectStartExpressions;
314 
315         private String escapeString;
316 
317         private boolean escapeWindowsPaths;
318 
319         private final MavenSession mavenSession;
320 
321         private boolean supportMultiLineFiltering;
322 
323         Wrapper( LinkedHashSet<String> delimiters, MavenProject project, MavenSession mavenSession,
324                  ValueSource propertiesValueSource, List<String> projectStartExpressions, String escapeString,
325                  boolean escapeWindowsPaths, boolean supportMultiLineFiltering )
326         {
327             super();
328             this.delimiters = delimiters;
329             this.project = project;
330             this.mavenSession = mavenSession;
331             this.propertiesValueSource = propertiesValueSource;
332             this.projectStartExpressions = projectStartExpressions;
333             this.escapeString = escapeString;
334             this.escapeWindowsPaths = escapeWindowsPaths;
335             this.supportMultiLineFiltering = supportMultiLineFiltering;
336         }
337 
338         public Reader getReader( Reader reader )
339         {
340             MultiDelimiterStringSearchInterpolator interpolator = new MultiDelimiterStringSearchInterpolator();
341             interpolator.setDelimiterSpecs( delimiters );
342 
343             RecursionInterceptor ri = null;
344             if ( projectStartExpressions != null && !projectStartExpressions.isEmpty() )
345             {
346                 ri = new PrefixAwareRecursionInterceptor( projectStartExpressions, true );
347             }
348             else
349             {
350                 ri = new SimpleRecursionInterceptor();
351             }
352 
353             interpolator.addValueSource( propertiesValueSource );
354 
355             if ( project != null )
356             {
357                 interpolator.addValueSource( new PrefixedObjectValueSource( projectStartExpressions, project, true ) );
358             }
359 
360             if ( mavenSession != null )
361             {
362                 interpolator.addValueSource( new PrefixedObjectValueSource( "session", mavenSession ) );
363 
364                 final Settings settings = mavenSession.getSettings();
365                 if ( settings != null )
366                 {
367                     interpolator.addValueSource( new PrefixedObjectValueSource( "settings", settings ) );
368                     interpolator.addValueSource(
369                         new SingleResponseValueSource( "localRepository", settings.getLocalRepository() ) );
370                 }
371             }
372 
373             interpolator.setEscapeString( escapeString );
374 
375             if ( escapeWindowsPaths )
376             {
377                 interpolator.addPostProcessor( new InterpolationPostProcessor()
378                 {
379                     public Object execute( String expression, Object value )
380                     {
381                         if ( value instanceof String )
382                         {
383                             return FilteringUtils.escapeWindowsPath( (String) value );
384                         }
385 
386                         return value;
387                     }
388                 } );
389             }
390 
391             MultiDelimiterInterpolatorFilterReaderLineEnding filterReader =
392                 new MultiDelimiterInterpolatorFilterReaderLineEnding( reader, interpolator, supportMultiLineFiltering );
393             filterReader.setRecursionInterceptor( ri );
394             filterReader.setDelimiterSpecs( delimiters );
395 
396             filterReader.setInterpolateWithPrefixPattern( false );
397             filterReader.setEscapeString( escapeString );
398 
399             return filterReader;
400         }
401 
402     }
403 
404 }