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.*;
26  
27  import org.apache.maven.execution.MavenSession;
28  import org.apache.maven.project.MavenProject;
29  import org.apache.maven.settings.Settings;
30  import org.apache.maven.shared.utils.StringUtils;
31  import org.apache.maven.shared.utils.io.FileUtils;
32  import org.codehaus.plexus.interpolation.*;
33  import org.codehaus.plexus.interpolation.multi.MultiDelimiterStringSearchInterpolator;
34  import org.codehaus.plexus.logging.AbstractLogEnabled;
35  
36  import javax.annotation.Nonnull;
37  
38  class BaseFilter extends AbstractLogEnabled implements DefaultFilterInfo {
39  
40  
41  	/**
42  	 * @see org.apache.maven.shared.filtering.MavenFileFilter#getDefaultFilterWrappers(org.apache.maven.project.MavenProject, java.util.List, boolean, org.apache.maven.execution.MavenSession)
43  	 * @deprecated
44  	 */
45  	public List<FileUtils.FilterWrapper> getDefaultFilterWrappers( final MavenProject mavenProject,
46  			List<String> filters,
47  			final boolean escapedBackslashesInFilePath,
48  			MavenSession mavenSession )
49  			throws MavenFilteringException
50  	{
51  		return getDefaultFilterWrappers( mavenProject, filters, escapedBackslashesInFilePath, mavenSession, null );
52  	}
53  
54  
55  	@Nonnull public List<FileUtils.FilterWrapper> getDefaultFilterWrappers( final MavenProject mavenProject, List<String> filters,
56  			final boolean escapedBackslashesInFilePath,
57  			MavenSession mavenSession,
58  			MavenResourcesExecution mavenResourcesExecution )
59  			throws MavenFilteringException
60  	{
61  
62  		MavenResourcesExecution mre =
63  				mavenResourcesExecution == null ? new MavenResourcesExecution() : mavenResourcesExecution.copyOf();
64  
65  		mre.setMavenProject( mavenProject );
66  		mre.setMavenSession( mavenSession );
67  		mre.setFilters( filters );
68  		mre.setEscapedBackslashesInFilePath( escapedBackslashesInFilePath );
69  
70  		return getDefaultFilterWrappers( mre );
71  
72  	}
73  
74  	@Nonnull public List<FileUtils.FilterWrapper> getDefaultFilterWrappers( final AbstractMavenFilteringRequest req )
75  			throws MavenFilteringException
76  	{
77  		// backup values
78  		boolean supportMultiLineFiltering = req.isSupportMultiLineFiltering();
79  
80  		// compensate for null parameter value.
81  		final AbstractMavenFilteringRequest request = req == null ? new MavenFileFilterRequest() : req;
82  
83  		request.setSupportMultiLineFiltering( supportMultiLineFiltering );
84  
85  		// Here we build some properties which will be used to read some properties files
86  		// to interpolate the expression ${ } in this properties file
87  
88  		// Take a copy of filterProperties to ensure that evaluated filterTokens are not propagated
89  		// to subsequent filter files. Note: this replicates current behaviour and seems to make sense.
90  
91  		final Properties baseProps = new Properties();
92  
93  		// Project properties
94  		if ( request.getMavenProject() != null )
95  		{
96  			baseProps.putAll( request.getMavenProject().getProperties() == null
97  					? Collections.emptyMap()
98  					: request.getMavenProject().getProperties() );
99  		}
100 		// TODO this is NPE free but do we consider this as normal
101 		// or do we have to throw an MavenFilteringException with mavenSession cannot be null
102 		if ( request.getMavenSession() != null )
103 		{
104 			// execution properties wins
105 			baseProps.putAll( request.getMavenSession().getExecutionProperties() );
106 		}
107 
108 		// now we build properties to use for resources interpolation
109 
110 		final Properties filterProperties = new Properties();
111 
112 		File basedir = request.getMavenProject() != null ? request.getMavenProject().getBasedir() : new File( "." );
113 
114 		loadProperties( filterProperties, basedir, request.getFileFilters(), baseProps );
115 		if ( filterProperties.size() < 1 )
116 		{
117 			filterProperties.putAll( baseProps );
118 		}
119 
120 		if ( request.getMavenProject() != null )
121 		{
122 			if ( request.isInjectProjectBuildFilters() )
123 			{
124 				@SuppressWarnings( "unchecked" )
125 				List<String> buildFilters = new ArrayList<String>( request.getMavenProject().getBuild().getFilters() );
126 
127 				// JDK-8015656: (coll) unexpected NPE from removeAll
128 				if ( request.getFileFilters() != null )
129 				{
130 					buildFilters.removeAll( request.getFileFilters() );
131 				}
132 
133 				loadProperties( filterProperties, basedir, buildFilters, baseProps );
134 			}
135 
136 			// Project properties
137 			filterProperties.putAll( request.getMavenProject().getProperties() == null
138 					? Collections.emptyMap()
139 					: request.getMavenProject().getProperties() );
140 		}
141 		if ( request.getMavenSession() != null )
142 		{
143 			// execution properties wins
144 			filterProperties.putAll( request.getMavenSession().getExecutionProperties() );
145 		}
146 
147 		if ( request.getAdditionalProperties() != null )
148 		{
149 			// additional properties wins
150 			filterProperties.putAll( request.getAdditionalProperties() );
151 		}
152 
153 		List<FileUtils.FilterWrapper> defaultFilterWrappers = request == null
154 				? new ArrayList<FileUtils.FilterWrapper>( 1 )
155 				: new ArrayList<FileUtils.FilterWrapper>( request.getDelimiters().size() + 1 );
156 
157 		if ( getLogger().isDebugEnabled() )
158 		{
159 			getLogger().debug( "properties used " + filterProperties );
160 		}
161 
162 		final ValueSource propertiesValueSource = new PropertiesBasedValueSource( filterProperties );
163 
164 		if ( request != null )
165 		{
166 			FileUtils.FilterWrapper wrapper =
167 					new Wrapper( request.getDelimiters(), request.getMavenProject(), request.getMavenSession(),
168 							propertiesValueSource, request.getProjectStartExpressions(), request.getEscapeString(),
169 							request.isEscapeWindowsPaths(), request.isSupportMultiLineFiltering() );
170 
171 			defaultFilterWrappers.add( wrapper );
172 		}
173 
174 		return defaultFilterWrappers;
175 	}
176 
177 	/**
178 	 * default visibility only for testing reason !
179 	 */
180 	void loadProperties( Properties filterProperties, File basedir, List<String> propertiesFilePaths, Properties baseProps )
181 			throws MavenFilteringException
182 	{
183 		if ( propertiesFilePaths != null )
184 		{
185 			Properties workProperties = new Properties();
186 			workProperties.putAll( baseProps );
187 
188 			for ( String filterFile : propertiesFilePaths )
189 			{
190 				if ( StringUtils.isEmpty(filterFile) )
191 				{
192 					// skip empty file name
193 					continue;
194 				}
195 				try
196 				{
197 					File propFile = FileUtils.resolveFile( basedir, filterFile );
198 					Properties properties = PropertyUtils.loadPropertyFile( propFile, workProperties );
199 					filterProperties.putAll( properties );
200 					workProperties.putAll( properties );
201 				}
202 				catch ( IOException e )
203 				{
204 					throw new MavenFilteringException( "Error loading property file '" + filterFile + "'", e );
205 				}
206 			}
207 		}
208 	}
209 
210 	private static final class Wrapper
211 			extends FileUtils.FilterWrapper
212 	{
213 
214 		private LinkedHashSet<String> delimiters;
215 
216 		private MavenProject project;
217 
218 		private ValueSource propertiesValueSource;
219 
220 		private List<String> projectStartExpressions;
221 
222 		private String escapeString;
223 
224 		private boolean escapeWindowsPaths;
225 
226 		private final MavenSession mavenSession;
227 
228 		private boolean supportMultiLineFiltering;
229 
230 		Wrapper( LinkedHashSet<String> delimiters, MavenProject project, MavenSession mavenSession,
231 				ValueSource propertiesValueSource, List<String> projectStartExpressions, String escapeString,
232 				boolean escapeWindowsPaths, boolean supportMultiLineFiltering )
233 		{
234 			super();
235 			this.delimiters = delimiters;
236 			this.project = project;
237 			this.mavenSession = mavenSession;
238 			this.propertiesValueSource = propertiesValueSource;
239 			this.projectStartExpressions = projectStartExpressions;
240 			this.escapeString = escapeString;
241 			this.escapeWindowsPaths = escapeWindowsPaths;
242 			this.supportMultiLineFiltering = supportMultiLineFiltering;
243 		}
244 
245 		public Reader getReader( Reader reader )
246 		{
247 			MultiDelimiterStringSearchInterpolator interpolator = new MultiDelimiterStringSearchInterpolator();
248 			interpolator.setDelimiterSpecs( delimiters );
249 
250 			RecursionInterceptor ri = null;
251 			if ( projectStartExpressions != null && !projectStartExpressions.isEmpty() )
252 			{
253 				ri = new PrefixAwareRecursionInterceptor( projectStartExpressions, true );
254 			}
255 			else
256 			{
257 				ri = new SimpleRecursionInterceptor();
258 			}
259 
260 			interpolator.addValueSource( propertiesValueSource );
261 
262 			if ( project != null )
263 			{
264 				interpolator.addValueSource( new PrefixedObjectValueSource( projectStartExpressions, project, true ) );
265 			}
266 
267 			if ( mavenSession != null )
268 			{
269 				interpolator.addValueSource( new PrefixedObjectValueSource( "session", mavenSession ) );
270 
271 				final Settings settings = mavenSession.getSettings();
272 				if ( settings != null )
273 				{
274 					interpolator.addValueSource( new PrefixedObjectValueSource( "settings", settings ) );
275 					interpolator.addValueSource(
276 							new SingleResponseValueSource( "localRepository", settings.getLocalRepository() ) );
277 				}
278 			}
279 
280 			interpolator.setEscapeString( escapeString );
281 
282 			if ( escapeWindowsPaths )
283 			{
284 				interpolator.addPostProcessor( new InterpolationPostProcessor()
285 				{
286 					public Object execute( String expression, Object value )
287 					{
288 						if ( value instanceof String )
289 						{
290 							return FilteringUtils.escapeWindowsPath( (String) value );
291 						}
292 
293 						return value;
294 					}
295 				} );
296 			}
297 
298 			MultiDelimiterInterpolatorFilterReaderLineEnding filterReader =
299 					new MultiDelimiterInterpolatorFilterReaderLineEnding( reader, interpolator, supportMultiLineFiltering );
300 			filterReader.setRecursionInterceptor( ri );
301 			filterReader.setDelimiterSpecs( delimiters );
302 
303 			filterReader.setInterpolateWithPrefixPattern( false );
304 			filterReader.setEscapeString( escapeString );
305 
306 			return filterReader;
307 		}
308 
309 	}
310 }