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