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  @Deprecated
64  public abstract class AbstractStringBasedModelInterpolator
65      extends AbstractLogEnabled
66      implements ModelInterpolator, Initializable
67  {
68      private static final List<String> PROJECT_PREFIXES = Arrays.asList( new String[]{ "pom.", "project." } );
69  
70      private static final List<String> TRANSLATED_PATH_EXPRESSIONS;
71  
72      static
73      {
74          List<String> translatedPrefixes = new ArrayList<String>();
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<String, ?> 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<String, ?> 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<ValueSource> valueSources = createValueSources( model, projectDir, config );
208             List<InterpolationPostProcessor> 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<ValueSource> createValueSources( final Model model, final File projectDir,
219                                                     final ProjectBuilderConfiguration config )
220     {
221         String timestampFormat = DEFAULT_BUILD_TIMESTAMP_FORMAT;
222 
223         Properties modelProperties = model.getProperties();
224         if ( modelProperties != null )
225         {
226             timestampFormat = modelProperties.getProperty( BUILD_TIMESTAMP_FORMAT_PROPERTY, timestampFormat );
227         }
228 
229         ValueSource modelValueSource1 = new PrefixedObjectValueSource( PROJECT_PREFIXES, model, false );
230         ValueSource modelValueSource2 = new ObjectBasedValueSource( model );
231 
232         ValueSource basedirValueSource = new PrefixedValueSourceWrapper( new AbstractValueSource( false )
233         {
234             public Object getValue( String expression )
235             {
236                 if ( projectDir != null && "basedir".equals( expression ) )
237                 {
238                     return projectDir.getAbsolutePath();
239                 }
240                 return null;
241             }
242         }, PROJECT_PREFIXES, true );
243         ValueSource baseUriValueSource = new PrefixedValueSourceWrapper( new AbstractValueSource( false )
244         {
245             public Object getValue( String expression )
246             {
247                 if ( projectDir != null && "baseUri".equals( expression ) )
248                 {
249                     return projectDir.getAbsoluteFile().toURI().toString();
250                 }
251                 return null;
252             }
253         }, PROJECT_PREFIXES, false );
254 
255         List<ValueSource> valueSources = new ArrayList<ValueSource>( 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             public Object getValue( String expression )
268             {
269                 return config.getExecutionProperties().getProperty( "env." + expression );
270             }
271         } );
272         valueSources.add( modelValueSource2 );
273 
274         return valueSources;
275     }
276 
277     protected List<InterpolationPostProcessor> createPostProcessors( final Model model, final File projectDir,
278                                                                      final ProjectBuilderConfiguration config )
279     {
280         return Collections.singletonList( (InterpolationPostProcessor) new PathTranslatingPostProcessor(
281                                                                                                          PROJECT_PREFIXES,
282                                                                                                          TRANSLATED_PATH_EXPRESSIONS,
283                                                                                                          projectDir,
284                                                                                                          pathTranslator ) );
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.indexOf( "${" ) < 0 )
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 }