1 package org.apache.maven.project.interpolation;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.maven.model.Model;
23 import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
24 import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
25 import org.apache.maven.project.DefaultProjectBuilderConfiguration;
26 import org.apache.maven.project.ProjectBuilderConfiguration;
27 import org.apache.maven.project.path.PathTranslator;
28 import org.codehaus.plexus.component.annotations.Requirement;
29 import org.codehaus.plexus.interpolation.AbstractValueSource;
30 import org.codehaus.plexus.interpolation.InterpolationException;
31 import org.codehaus.plexus.interpolation.InterpolationPostProcessor;
32 import org.codehaus.plexus.interpolation.Interpolator;
33 import org.codehaus.plexus.interpolation.MapBasedValueSource;
34 import org.codehaus.plexus.interpolation.ObjectBasedValueSource;
35 import org.codehaus.plexus.interpolation.PrefixAwareRecursionInterceptor;
36 import org.codehaus.plexus.interpolation.PrefixedObjectValueSource;
37 import org.codehaus.plexus.interpolation.PrefixedValueSourceWrapper;
38 import org.codehaus.plexus.interpolation.RecursionInterceptor;
39 import org.codehaus.plexus.interpolation.ValueSource;
40 import org.codehaus.plexus.logging.AbstractLogEnabled;
41 import org.codehaus.plexus.logging.Logger;
42 import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
43 import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
44 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
45
46 import java.io.File;
47 import java.io.IOException;
48 import java.io.StringReader;
49 import java.io.StringWriter;
50 import java.util.ArrayList;
51 import java.util.Arrays;
52 import java.util.Collections;
53 import java.util.List;
54 import java.util.Map;
55 import java.util.Properties;
56
57
58
59
60
61
62
63 @Deprecated
64 public abstract class AbstractStringBasedModelInterpolator
65 extends AbstractLogEnabled
66 implements ModelInterpolator, Initializable
67 {
68
69 private static final List<String> PROJECT_PREFIXES = Arrays.asList( "pom.", "project." );
70
71 private static final List<String> TRANSLATED_PATH_EXPRESSIONS;
72
73 static
74 {
75 List<String> translatedPrefixes = new ArrayList<>();
76
77
78
79
80
81
82 translatedPrefixes.add( "build.directory" );
83 translatedPrefixes.add( "build.outputDirectory" );
84 translatedPrefixes.add( "build.testOutputDirectory" );
85 translatedPrefixes.add( "build.sourceDirectory" );
86 translatedPrefixes.add( "build.testSourceDirectory" );
87 translatedPrefixes.add( "build.scriptSourceDirectory" );
88 translatedPrefixes.add( "reporting.outputDirectory" );
89
90 TRANSLATED_PATH_EXPRESSIONS = translatedPrefixes;
91 }
92
93 @Requirement
94 private PathTranslator pathTranslator;
95
96 private Interpolator interpolator;
97
98 private RecursionInterceptor recursionInterceptor;
99
100
101 protected AbstractStringBasedModelInterpolator( PathTranslator pathTranslator )
102 {
103 this.pathTranslator = pathTranslator;
104 }
105
106 protected AbstractStringBasedModelInterpolator()
107 {
108 }
109
110 public Model interpolate( Model model, Map<String, ?> context )
111 throws ModelInterpolationException
112 {
113 return interpolate( model, context, true );
114 }
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129 @Deprecated
130 public Model interpolate( Model model, Map<String, ?> context, boolean strict )
131 throws ModelInterpolationException
132 {
133 Properties props = new Properties();
134 props.putAll( context );
135
136 return interpolate( model,
137 null,
138 new DefaultProjectBuilderConfiguration().setExecutionProperties( props ),
139 true );
140 }
141
142 public Model interpolate( Model model,
143 File projectDir,
144 ProjectBuilderConfiguration config,
145 boolean debugEnabled )
146 throws ModelInterpolationException
147 {
148 StringWriter sWriter = new StringWriter( 1024 );
149
150 MavenXpp3Writer writer = new MavenXpp3Writer();
151 try
152 {
153 writer.write( sWriter, model );
154 }
155 catch ( IOException e )
156 {
157 throw new ModelInterpolationException( "Cannot serialize project model for interpolation.", e );
158 }
159
160 String serializedModel = sWriter.toString();
161 serializedModel = interpolate( serializedModel, model, projectDir, config, debugEnabled );
162
163 StringReader sReader = new StringReader( serializedModel );
164
165 MavenXpp3Reader modelReader = new MavenXpp3Reader();
166 try
167 {
168 model = modelReader.read( sReader );
169 }
170 catch ( IOException | XmlPullParserException e )
171 {
172 throw new ModelInterpolationException(
173 "Cannot read project model from interpolating filter of serialized version.", e );
174 }
175
176 return model;
177 }
178
179
180
181
182
183
184
185
186
187
188
189
190
191 public String interpolate( String src,
192 Model model,
193 final File projectDir,
194 ProjectBuilderConfiguration config,
195 boolean debug )
196 throws ModelInterpolationException
197 {
198 try
199 {
200 List<ValueSource> valueSources = createValueSources( model, projectDir, config );
201 List<InterpolationPostProcessor> postProcessors = createPostProcessors( model, projectDir, config );
202
203 return interpolateInternal( src, valueSources, postProcessors, debug );
204 }
205 finally
206 {
207 interpolator.clearAnswers();
208 }
209 }
210
211 protected List<ValueSource> createValueSources( final Model model, final File projectDir,
212 final ProjectBuilderConfiguration config )
213 {
214 String timestampFormat = DEFAULT_BUILD_TIMESTAMP_FORMAT;
215
216 Properties modelProperties = model.getProperties();
217 if ( modelProperties != null )
218 {
219 timestampFormat = modelProperties.getProperty( BUILD_TIMESTAMP_FORMAT_PROPERTY, timestampFormat );
220 }
221
222 ValueSource modelValueSource1 = new PrefixedObjectValueSource( PROJECT_PREFIXES, model, false );
223 ValueSource modelValueSource2 = new ObjectBasedValueSource( model );
224
225 ValueSource basedirValueSource = new PrefixedValueSourceWrapper( new AbstractValueSource( false )
226 {
227
228 public Object getValue( String expression )
229 {
230 if ( projectDir != null && "basedir".equals( expression ) )
231 {
232 return projectDir.getAbsolutePath();
233 }
234 return null;
235 }
236
237 }, PROJECT_PREFIXES, true );
238 ValueSource baseUriValueSource = new PrefixedValueSourceWrapper( new AbstractValueSource( false )
239 {
240
241 public Object getValue( String expression )
242 {
243 if ( projectDir != null && "baseUri".equals( expression ) )
244 {
245 return projectDir.getAbsoluteFile().toPath().toUri().toASCIIString();
246 }
247 return null;
248 }
249
250 }, PROJECT_PREFIXES, false );
251
252 List<ValueSource> valueSources = new ArrayList<>( 9 );
253
254
255 valueSources.add( basedirValueSource );
256 valueSources.add( baseUriValueSource );
257 valueSources.add( new BuildTimestampValueSource( config.getBuildStartTime(), timestampFormat ) );
258 valueSources.add( modelValueSource1 );
259 valueSources.add( new MapBasedValueSource( config.getUserProperties() ) );
260 valueSources.add( new MapBasedValueSource( modelProperties ) );
261 valueSources.add( new MapBasedValueSource( config.getExecutionProperties() ) );
262 valueSources.add( new AbstractValueSource( false )
263 {
264
265 public Object getValue( String expression )
266 {
267 return config.getExecutionProperties().getProperty( "env." + expression );
268 }
269
270 } );
271 valueSources.add( modelValueSource2 );
272
273 return valueSources;
274 }
275
276 protected List<InterpolationPostProcessor> createPostProcessors( final Model model, final File projectDir,
277 final ProjectBuilderConfiguration config )
278 {
279 return Collections.singletonList(
280 (InterpolationPostProcessor) new PathTranslatingPostProcessor(
281 PROJECT_PREFIXES,
282 TRANSLATED_PATH_EXPRESSIONS,
283 projectDir,
284 pathTranslator ) );
285
286 }
287
288 @SuppressWarnings( "unchecked" )
289 protected String interpolateInternal( String src, List<ValueSource> valueSources,
290 List<InterpolationPostProcessor> postProcessors, boolean debug )
291 throws ModelInterpolationException
292 {
293 if ( !src.contains( "${" ) )
294 {
295 return src;
296 }
297
298 Logger logger = getLogger();
299
300 String result = src;
301 synchronized ( this )
302 {
303
304 for ( ValueSource vs : valueSources )
305 {
306 interpolator.addValueSource( vs );
307 }
308
309 for ( InterpolationPostProcessor postProcessor : postProcessors )
310 {
311 interpolator.addPostProcessor( postProcessor );
312 }
313
314 try
315 {
316 try
317 {
318 result = interpolator.interpolate( result, recursionInterceptor );
319 }
320 catch ( InterpolationException e )
321 {
322 throw new ModelInterpolationException( e.getMessage(), e );
323 }
324
325 if ( debug )
326 {
327 List<Object> feedback = interpolator.getFeedback();
328 if ( feedback != null && !feedback.isEmpty() )
329 {
330 logger.debug( "Maven encountered the following problems during initial POM interpolation:" );
331
332 Object last = null;
333 for ( Object next : feedback )
334 {
335 if ( next instanceof Throwable )
336 {
337 if ( last == null )
338 {
339 logger.debug( "", ( (Throwable) next ) );
340 }
341 else
342 {
343 logger.debug( String.valueOf( last ), ( (Throwable) next ) );
344 }
345 }
346 else
347 {
348 if ( last != null )
349 {
350 logger.debug( String.valueOf( last ) );
351 }
352
353 last = next;
354 }
355 }
356
357 if ( last != null )
358 {
359 logger.debug( String.valueOf( last ) );
360 }
361 }
362 }
363
364 interpolator.clearFeedback();
365 }
366 finally
367 {
368 for ( ValueSource vs : valueSources )
369 {
370 interpolator.removeValuesSource( vs );
371 }
372
373 for ( InterpolationPostProcessor postProcessor : postProcessors )
374 {
375 interpolator.removePostProcessor( postProcessor );
376 }
377 }
378 }
379
380 return result;
381 }
382
383 protected RecursionInterceptor getRecursionInterceptor()
384 {
385 return recursionInterceptor;
386 }
387
388 protected void setRecursionInterceptor( RecursionInterceptor recursionInterceptor )
389 {
390 this.recursionInterceptor = recursionInterceptor;
391 }
392
393 protected abstract Interpolator createInterpolator();
394
395 public void initialize()
396 throws InitializationException
397 {
398 interpolator = createInterpolator();
399 recursionInterceptor = new PrefixAwareRecursionInterceptor( PROJECT_PREFIXES );
400 }
401
402 protected final Interpolator getInterpolator()
403 {
404 return interpolator;
405 }
406
407 }