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