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 private static final List<String> PROJECT_PREFIXES = Arrays.asList( "pom.", "project." );
69
70 private static final List<String> TRANSLATED_PATH_EXPRESSIONS;
71
72 static
73 {
74 List<String> translatedPrefixes = new ArrayList<>();
75
76
77
78
79
80
81 translatedPrefixes.add( "build.directory" );
82 translatedPrefixes.add( "build.outputDirectory" );
83 translatedPrefixes.add( "build.testOutputDirectory" );
84 translatedPrefixes.add( "build.sourceDirectory" );
85 translatedPrefixes.add( "build.testSourceDirectory" );
86 translatedPrefixes.add( "build.scriptSourceDirectory" );
87 translatedPrefixes.add( "reporting.outputDirectory" );
88
89 TRANSLATED_PATH_EXPRESSIONS = translatedPrefixes;
90 }
91
92 @Requirement
93 private PathTranslator pathTranslator;
94
95 private Interpolator interpolator;
96
97 private RecursionInterceptor recursionInterceptor;
98
99
100 protected AbstractStringBasedModelInterpolator( PathTranslator pathTranslator )
101 {
102 this.pathTranslator = pathTranslator;
103 }
104
105
106
107
108
109 protected AbstractStringBasedModelInterpolator()
110 {
111 }
112
113 public Model interpolate( Model model, Map<String, ?> context )
114 throws ModelInterpolationException
115 {
116 return interpolate( model, context, true );
117 }
118
119
120
121
122
123
124
125
126
127
128
129
130
131 public Model interpolate( Model model, Map<String, ?> context, boolean strict )
132 throws ModelInterpolationException
133 {
134 Properties props = new Properties();
135 props.putAll( context );
136
137 return interpolate( model,
138 null,
139 new DefaultProjectBuilderConfiguration().setExecutionProperties( props ),
140 true );
141 }
142
143 public Model interpolate( Model model,
144 File projectDir,
145 ProjectBuilderConfiguration config,
146 boolean debugEnabled )
147 throws ModelInterpolationException
148 {
149 StringWriter sWriter = new StringWriter( 1024 );
150
151 MavenXpp3Writer writer = new MavenXpp3Writer();
152 try
153 {
154 writer.write( sWriter, model );
155 }
156 catch ( IOException e )
157 {
158 throw new ModelInterpolationException( "Cannot serialize project model for interpolation.", e );
159 }
160
161 String serializedModel = sWriter.toString();
162 serializedModel = interpolate( serializedModel, model, projectDir, config, debugEnabled );
163
164 StringReader sReader = new StringReader( serializedModel );
165
166 MavenXpp3Reader modelReader = new MavenXpp3Reader();
167 try
168 {
169 model = modelReader.read( sReader );
170 }
171 catch ( IOException | XmlPullParserException e )
172 {
173 throw new ModelInterpolationException(
174 "Cannot read project model from interpolating filter of serialized version.", e );
175 }
176
177 return model;
178 }
179
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 public Object getValue( String expression )
231 {
232 if ( projectDir != null && "basedir".equals( expression ) )
233 {
234 return projectDir.getAbsolutePath();
235 }
236 return null;
237 }
238 }, PROJECT_PREFIXES, true );
239 ValueSource baseUriValueSource = new PrefixedValueSourceWrapper( new AbstractValueSource( false )
240 {
241 public Object getValue( String expression )
242 {
243 if ( projectDir != null && "baseUri".equals( expression ) )
244 {
245 return projectDir.getAbsoluteFile().toURI().toString();
246 }
247 return null;
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 public Object getValue( String expression )
264 {
265 return config.getExecutionProperties().getProperty( "env." + expression );
266 }
267 } );
268 valueSources.add( modelValueSource2 );
269
270 return valueSources;
271 }
272
273 protected List<InterpolationPostProcessor> createPostProcessors( final Model model, final File projectDir,
274 final ProjectBuilderConfiguration config )
275 {
276 return Collections.singletonList( (InterpolationPostProcessor) new PathTranslatingPostProcessor(
277 PROJECT_PREFIXES,
278 TRANSLATED_PATH_EXPRESSIONS,
279 projectDir,
280 pathTranslator ) );
281 }
282
283 @SuppressWarnings( "unchecked" )
284 protected String interpolateInternal( String src, List<ValueSource> valueSources,
285 List<InterpolationPostProcessor> postProcessors, boolean debug )
286 throws ModelInterpolationException
287 {
288 if ( !src.contains( "${" ) )
289 {
290 return src;
291 }
292
293 Logger logger = getLogger();
294
295 String result = src;
296 synchronized ( this )
297 {
298
299 for ( ValueSource vs : valueSources )
300 {
301 interpolator.addValueSource( vs );
302 }
303
304 for ( InterpolationPostProcessor postProcessor : postProcessors )
305 {
306 interpolator.addPostProcessor( postProcessor );
307 }
308
309 try
310 {
311 try
312 {
313 result = interpolator.interpolate( result, recursionInterceptor );
314 }
315 catch ( InterpolationException e )
316 {
317 throw new ModelInterpolationException( e.getMessage(), e );
318 }
319
320 if ( debug )
321 {
322 List<Object> feedback = interpolator.getFeedback();
323 if ( feedback != null && !feedback.isEmpty() )
324 {
325 logger.debug( "Maven encountered the following problems during initial POM interpolation:" );
326
327 Object last = null;
328 for ( Object next : feedback )
329 {
330 if ( next instanceof Throwable )
331 {
332 if ( last == null )
333 {
334 logger.debug( "", ( (Throwable) next ) );
335 }
336 else
337 {
338 logger.debug( String.valueOf( last ), ( (Throwable) next ) );
339 }
340 }
341 else
342 {
343 if ( last != null )
344 {
345 logger.debug( String.valueOf( last ) );
346 }
347
348 last = next;
349 }
350 }
351
352 if ( last != null )
353 {
354 logger.debug( String.valueOf( last ) );
355 }
356 }
357 }
358
359 interpolator.clearFeedback();
360 }
361 finally
362 {
363 for ( ValueSource vs : valueSources )
364 {
365 interpolator.removeValuesSource( vs );
366 }
367
368 for ( InterpolationPostProcessor postProcessor : postProcessors )
369 {
370 interpolator.removePostProcessor( postProcessor );
371 }
372 }
373 }
374
375 return result;
376 }
377
378 protected RecursionInterceptor getRecursionInterceptor()
379 {
380 return recursionInterceptor;
381 }
382
383 protected void setRecursionInterceptor( RecursionInterceptor recursionInterceptor )
384 {
385 this.recursionInterceptor = recursionInterceptor;
386 }
387
388 protected abstract Interpolator createInterpolator();
389
390 public void initialize()
391 throws InitializationException
392 {
393 interpolator = createInterpolator();
394 recursionInterceptor = new PrefixAwareRecursionInterceptor( PROJECT_PREFIXES );
395 }
396
397 protected final Interpolator getInterpolator()
398 {
399 return interpolator;
400 }
401
402 }