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.interpolation.AbstractValueSource;
29 import org.codehaus.plexus.interpolation.InterpolationException;
30 import org.codehaus.plexus.interpolation.InterpolationPostProcessor;
31 import org.codehaus.plexus.interpolation.Interpolator;
32 import org.codehaus.plexus.interpolation.MapBasedValueSource;
33 import org.codehaus.plexus.interpolation.ObjectBasedValueSource;
34 import org.codehaus.plexus.interpolation.PrefixAwareRecursionInterceptor;
35 import org.codehaus.plexus.interpolation.PrefixedObjectValueSource;
36 import org.codehaus.plexus.interpolation.PrefixedValueSourceWrapper;
37 import org.codehaus.plexus.interpolation.RecursionInterceptor;
38 import org.codehaus.plexus.interpolation.ValueSource;
39 import org.codehaus.plexus.logging.AbstractLogEnabled;
40 import org.codehaus.plexus.logging.Logger;
41 import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
42 import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
43 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
44
45 import java.io.File;
46 import java.io.IOException;
47 import java.io.StringReader;
48 import java.io.StringWriter;
49 import java.util.ArrayList;
50 import java.util.Arrays;
51 import java.util.Collections;
52 import java.util.List;
53 import java.util.Map;
54 import java.util.Properties;
55
56
57
58
59
60
61
62
63 public abstract class AbstractStringBasedModelInterpolator
64 extends AbstractLogEnabled
65 implements ModelInterpolator, Initializable
66 {
67 private static final List<String> PROJECT_PREFIXES = Arrays.asList( new String[]{ "pom.", "project." } );
68
69 private static final List<String> TRANSLATED_PATH_EXPRESSIONS;
70
71 static
72 {
73 List<String> translatedPrefixes = new ArrayList<String>();
74
75
76
77
78
79
80 translatedPrefixes.add( "build.directory" );
81 translatedPrefixes.add( "build.outputDirectory" );
82 translatedPrefixes.add( "build.testOutputDirectory" );
83 translatedPrefixes.add( "build.sourceDirectory" );
84 translatedPrefixes.add( "build.testSourceDirectory" );
85 translatedPrefixes.add( "build.scriptSourceDirectory" );
86 translatedPrefixes.add( "reporting.outputDirectory" );
87
88 TRANSLATED_PATH_EXPRESSIONS = translatedPrefixes;
89 }
90
91 private PathTranslator pathTranslator;
92
93 private Interpolator interpolator;
94
95 private RecursionInterceptor recursionInterceptor;
96
97
98 protected AbstractStringBasedModelInterpolator( PathTranslator pathTranslator )
99 {
100 this.pathTranslator = pathTranslator;
101 }
102
103
104
105
106
107 protected AbstractStringBasedModelInterpolator()
108 {
109 }
110
111 public Model interpolate( Model model, Map<String, ?> context )
112 throws ModelInterpolationException
113 {
114 return interpolate( model, context, true );
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 e )
170 {
171 throw new ModelInterpolationException(
172 "Cannot read project model from interpolating filter of serialized version.", e );
173 }
174 catch ( XmlPullParserException e )
175 {
176 throw new ModelInterpolationException(
177 "Cannot read project model from interpolating filter of serialized version.", e );
178 }
179
180 return model;
181 }
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197 public String interpolate( String src,
198 Model model,
199 final File projectDir,
200 ProjectBuilderConfiguration config,
201 boolean debug )
202 throws ModelInterpolationException
203 {
204 try
205 {
206 List<ValueSource> valueSources = createValueSources( model, projectDir, config );
207 List<InterpolationPostProcessor> postProcessors = createPostProcessors( model, projectDir, config );
208
209 return interpolateInternal( src, valueSources, postProcessors, debug );
210 }
211 finally
212 {
213 interpolator.clearAnswers();
214 }
215 }
216
217 protected List<ValueSource> createValueSources( final Model model, final File projectDir, final ProjectBuilderConfiguration config )
218 {
219 String timestampFormat = DEFAULT_BUILD_TIMESTAMP_FORMAT;
220
221 Properties modelProperties = model.getProperties();
222 if ( modelProperties != null )
223 {
224 timestampFormat = modelProperties.getProperty( BUILD_TIMESTAMP_FORMAT_PROPERTY, timestampFormat );
225 }
226
227 ValueSource modelValueSource1 = new PrefixedObjectValueSource( PROJECT_PREFIXES, model, false );
228 ValueSource modelValueSource2 = new ObjectBasedValueSource( model );
229
230 ValueSource basedirValueSource = new PrefixedValueSourceWrapper( new AbstractValueSource( false ){
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 public Object getValue( String expression )
243 {
244 if ( projectDir != null && "baseUri".equals( expression ) )
245 {
246 return projectDir.getAbsoluteFile().toURI().toString();
247 }
248 return null;
249 }
250 },
251 PROJECT_PREFIXES, false );
252
253 List<ValueSource> valueSources = new ArrayList<ValueSource>( 9 );
254
255
256 valueSources.add( basedirValueSource );
257 valueSources.add( baseUriValueSource );
258 valueSources.add( new BuildTimestampValueSource( config.getBuildStartTime(), timestampFormat ) );
259 valueSources.add( modelValueSource1 );
260 valueSources.add( new MapBasedValueSource( config.getUserProperties() ) );
261 valueSources.add( new MapBasedValueSource( modelProperties ) );
262 valueSources.add( new MapBasedValueSource( config.getExecutionProperties() ) );
263 valueSources.add( new AbstractValueSource( false )
264 {
265 public Object getValue( String expression )
266 {
267 return config.getExecutionProperties().getProperty( "env." + expression );
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( (InterpolationPostProcessor) new PathTranslatingPostProcessor(
279 PROJECT_PREFIXES,
280 TRANSLATED_PATH_EXPRESSIONS,
281 projectDir,
282 pathTranslator ) );
283 }
284
285 @SuppressWarnings("unchecked")
286 protected String interpolateInternal( String src, List<ValueSource> valueSources,
287 List<InterpolationPostProcessor> postProcessors, boolean debug )
288 throws ModelInterpolationException
289 {
290 if ( src.indexOf( "${" ) < 0 )
291 {
292 return src;
293 }
294
295 Logger logger = getLogger();
296
297 String result = src;
298 synchronized( this )
299 {
300
301 for ( ValueSource vs : valueSources )
302 {
303 interpolator.addValueSource( vs );
304 }
305
306 for ( InterpolationPostProcessor postProcessor : postProcessors )
307 {
308 interpolator.addPostProcessor( postProcessor );
309 }
310
311 try
312 {
313 try
314 {
315 result = interpolator.interpolate( result, recursionInterceptor );
316 }
317 catch( InterpolationException e )
318 {
319 throw new ModelInterpolationException( e.getMessage(), e );
320 }
321
322 if ( debug )
323 {
324 List<Object> feedback = (List<Object>) interpolator.getFeedback();
325 if ( feedback != null && !feedback.isEmpty() )
326 {
327 logger.debug( "Maven encountered the following problems during initial POM interpolation:" );
328
329 Object last = null;
330 for ( Object next : feedback )
331 {
332 if ( next instanceof Throwable )
333 {
334 if ( last == null )
335 {
336 logger.debug( "", ( (Throwable) next ) );
337 }
338 else
339 {
340 logger.debug( String.valueOf( last ), ( (Throwable) next ) );
341 }
342 }
343 else
344 {
345 if ( last != null )
346 {
347 logger.debug( String.valueOf( last ) );
348 }
349
350 last = next;
351 }
352 }
353
354 if ( last != null )
355 {
356 logger.debug( String.valueOf( last ) );
357 }
358 }
359 }
360
361 interpolator.clearFeedback();
362 }
363 finally
364 {
365 for ( ValueSource vs : valueSources )
366 {
367 interpolator.removeValuesSource( vs );
368 }
369
370 for ( InterpolationPostProcessor postProcessor : postProcessors )
371 {
372 interpolator.removePostProcessor( postProcessor );
373 }
374 }
375 }
376
377 return result;
378 }
379
380 protected RecursionInterceptor getRecursionInterceptor()
381 {
382 return recursionInterceptor;
383 }
384
385 protected void setRecursionInterceptor( RecursionInterceptor recursionInterceptor )
386 {
387 this.recursionInterceptor = recursionInterceptor;
388 }
389
390 protected abstract Interpolator createInterpolator();
391
392 public void initialize()
393 throws InitializationException
394 {
395 interpolator = createInterpolator();
396 recursionInterceptor = new PrefixAwareRecursionInterceptor( PROJECT_PREFIXES );
397 }
398
399 protected final Interpolator getInterpolator()
400 {
401 return interpolator;
402 }
403
404 }