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 public Model interpolate( Model model, Map<String, ?> context, boolean strict )
130 throws ModelInterpolationException
131 {
132 Properties props = new Properties();
133 props.putAll( context );
134
135 return interpolate( model,
136 null,
137 new DefaultProjectBuilderConfiguration().setExecutionProperties( props ),
138 true );
139 }
140
141 public Model interpolate( Model model,
142 File projectDir,
143 ProjectBuilderConfiguration config,
144 boolean debugEnabled )
145 throws ModelInterpolationException
146 {
147 StringWriter sWriter = new StringWriter( 1024 );
148
149 MavenXpp3Writer writer = new MavenXpp3Writer();
150 try
151 {
152 writer.write( sWriter, model );
153 }
154 catch ( IOException e )
155 {
156 throw new ModelInterpolationException( "Cannot serialize project model for interpolation.", e );
157 }
158
159 String serializedModel = sWriter.toString();
160 serializedModel = interpolate( serializedModel, model, projectDir, config, debugEnabled );
161
162 StringReader sReader = new StringReader( serializedModel );
163
164 MavenXpp3Reader modelReader = new MavenXpp3Reader();
165 try
166 {
167 model = modelReader.read( sReader );
168 }
169 catch ( IOException | XmlPullParserException e )
170 {
171 throw new ModelInterpolationException(
172 "Cannot read project model from interpolating filter of serialized version.", e );
173 }
174
175 return model;
176 }
177
178
179
180
181
182
183
184
185
186
187
188
189
190 public String interpolate( String src,
191 Model model,
192 final File projectDir,
193 ProjectBuilderConfiguration config,
194 boolean debug )
195 throws ModelInterpolationException
196 {
197 try
198 {
199 List<ValueSource> valueSources = createValueSources( model, projectDir, config );
200 List<InterpolationPostProcessor> postProcessors = createPostProcessors( model, projectDir, config );
201
202 return interpolateInternal( src, valueSources, postProcessors, debug );
203 }
204 finally
205 {
206 interpolator.clearAnswers();
207 }
208 }
209
210 protected List<ValueSource> createValueSources( final Model model, final File projectDir,
211 final ProjectBuilderConfiguration config )
212 {
213 String timestampFormat = DEFAULT_BUILD_TIMESTAMP_FORMAT;
214
215 Properties modelProperties = model.getProperties();
216 if ( modelProperties != null )
217 {
218 timestampFormat = modelProperties.getProperty( BUILD_TIMESTAMP_FORMAT_PROPERTY, timestampFormat );
219 }
220
221 ValueSource modelValueSource1 = new PrefixedObjectValueSource( PROJECT_PREFIXES, model, false );
222 ValueSource modelValueSource2 = new ObjectBasedValueSource( model );
223
224 ValueSource basedirValueSource = new PrefixedValueSourceWrapper( new AbstractValueSource( false )
225 {
226
227 public Object getValue( String expression )
228 {
229 if ( projectDir != null && "basedir".equals( expression ) )
230 {
231 return projectDir.getAbsolutePath();
232 }
233 return null;
234 }
235
236 }, PROJECT_PREFIXES, true );
237 ValueSource baseUriValueSource = new PrefixedValueSourceWrapper( new AbstractValueSource( false )
238 {
239
240 public Object getValue( String expression )
241 {
242 if ( projectDir != null && "baseUri".equals( expression ) )
243 {
244 return projectDir.getAbsoluteFile().toPath().toUri().toASCIIString();
245 }
246 return null;
247 }
248
249 }, PROJECT_PREFIXES, false );
250
251 List<ValueSource> valueSources = new ArrayList<>( 9 );
252
253
254 valueSources.add( basedirValueSource );
255 valueSources.add( baseUriValueSource );
256 valueSources.add( new BuildTimestampValueSource( config.getBuildStartTime(), timestampFormat ) );
257 valueSources.add( modelValueSource1 );
258 valueSources.add( new MapBasedValueSource( config.getUserProperties() ) );
259 valueSources.add( new MapBasedValueSource( modelProperties ) );
260 valueSources.add( new MapBasedValueSource( config.getExecutionProperties() ) );
261 valueSources.add( new AbstractValueSource( false )
262 {
263
264 public Object getValue( String expression )
265 {
266 return config.getExecutionProperties().getProperty( "env." + expression );
267 }
268
269 } );
270 valueSources.add( modelValueSource2 );
271
272 return valueSources;
273 }
274
275 protected List<InterpolationPostProcessor> createPostProcessors( final Model model, final File projectDir,
276 final ProjectBuilderConfiguration config )
277 {
278 return Collections.singletonList(
279 (InterpolationPostProcessor) new PathTranslatingPostProcessor(
280 PROJECT_PREFIXES,
281 TRANSLATED_PATH_EXPRESSIONS,
282 projectDir,
283 pathTranslator ) );
284
285 }
286
287 @SuppressWarnings( "unchecked" )
288 protected String interpolateInternal( String src, List<ValueSource> valueSources,
289 List<InterpolationPostProcessor> postProcessors, boolean debug )
290 throws ModelInterpolationException
291 {
292 if ( !src.contains( "${" ) )
293 {
294 return src;
295 }
296
297 Logger logger = getLogger();
298
299 String result = src;
300 synchronized ( this )
301 {
302
303 for ( ValueSource vs : valueSources )
304 {
305 interpolator.addValueSource( vs );
306 }
307
308 for ( InterpolationPostProcessor postProcessor : postProcessors )
309 {
310 interpolator.addPostProcessor( postProcessor );
311 }
312
313 try
314 {
315 try
316 {
317 result = interpolator.interpolate( result, recursionInterceptor );
318 }
319 catch ( InterpolationException e )
320 {
321 throw new ModelInterpolationException( e.getMessage(), e );
322 }
323
324 if ( debug )
325 {
326 List<Object> feedback = interpolator.getFeedback();
327 if ( feedback != null && !feedback.isEmpty() )
328 {
329 logger.debug( "Maven encountered the following problems during initial POM interpolation:" );
330
331 Object last = null;
332 for ( Object next : feedback )
333 {
334 if ( next instanceof Throwable )
335 {
336 if ( last == null )
337 {
338 logger.debug( "", ( (Throwable) next ) );
339 }
340 else
341 {
342 logger.debug( String.valueOf( last ), ( (Throwable) next ) );
343 }
344 }
345 else
346 {
347 if ( last != null )
348 {
349 logger.debug( String.valueOf( last ) );
350 }
351
352 last = next;
353 }
354 }
355
356 if ( last != null )
357 {
358 logger.debug( String.valueOf( last ) );
359 }
360 }
361 }
362
363 interpolator.clearFeedback();
364 }
365 finally
366 {
367 for ( ValueSource vs : valueSources )
368 {
369 interpolator.removeValuesSource( vs );
370 }
371
372 for ( InterpolationPostProcessor postProcessor : postProcessors )
373 {
374 interpolator.removePostProcessor( postProcessor );
375 }
376 }
377 }
378
379 return result;
380 }
381
382 protected RecursionInterceptor getRecursionInterceptor()
383 {
384 return recursionInterceptor;
385 }
386
387 protected void setRecursionInterceptor( RecursionInterceptor recursionInterceptor )
388 {
389 this.recursionInterceptor = recursionInterceptor;
390 }
391
392 protected abstract Interpolator createInterpolator();
393
394 public void initialize()
395 throws InitializationException
396 {
397 interpolator = createInterpolator();
398 recursionInterceptor = new PrefixAwareRecursionInterceptor( PROJECT_PREFIXES );
399 }
400
401 protected final Interpolator getInterpolator()
402 {
403 return interpolator;
404 }
405
406 }