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     protected AbstractStringBasedModelInterpolator()
107     {
108     }
109 
110     public Model interpolate( Model model, Map<String, ?> context )
111         throws ModelInterpolationException
112     {
113         return interpolate( model, context, true );
114     }
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 | XmlPullParserException e )
170         {
171             throw new ModelInterpolationException(
172                 "Cannot read project model from interpolating filter of serialized version.", e );
173         }
174 
175         return model;
176     }
177 
178     
179 
180 
181 
182 
183 
184 
185 
186 
187 
188 
189 
190     public String interpolate( String src,
191                                Model model,
192                                final File projectDir,
193                                ProjectBuilderConfiguration config,
194                                boolean debug )
195         throws ModelInterpolationException
196     {
197         try
198         {
199             List<ValueSource> valueSources = createValueSources( model, projectDir, config );
200             List<InterpolationPostProcessor> postProcessors = createPostProcessors( model, projectDir, config );
201 
202             return interpolateInternal( src, valueSources, postProcessors, debug );
203         }
204         finally
205         {
206             interpolator.clearAnswers();
207         }
208     }
209 
210     protected List<ValueSource> createValueSources( final Model model, final File projectDir,
211                                                     final ProjectBuilderConfiguration config )
212     {
213         String timestampFormat = DEFAULT_BUILD_TIMESTAMP_FORMAT;
214 
215         Properties modelProperties = model.getProperties();
216         if ( modelProperties != null )
217         {
218             timestampFormat = modelProperties.getProperty( BUILD_TIMESTAMP_FORMAT_PROPERTY, timestampFormat );
219         }
220 
221         ValueSource modelValueSource1 = new PrefixedObjectValueSource( PROJECT_PREFIXES, model, false );
222         ValueSource modelValueSource2 = new ObjectBasedValueSource( model );
223 
224         ValueSource basedirValueSource = new PrefixedValueSourceWrapper( new AbstractValueSource( false )
225         {
226 
227             public Object getValue( String expression )
228             {
229                 if ( projectDir != null && "basedir".equals( expression ) )
230                 {
231                     return projectDir.getAbsolutePath();
232                 }
233                 return null;
234             }
235 
236         }, PROJECT_PREFIXES, true );
237         ValueSource baseUriValueSource = new PrefixedValueSourceWrapper( new AbstractValueSource( false )
238         {
239 
240             public Object getValue( String expression )
241             {
242                 if ( projectDir != null && "baseUri".equals( expression ) )
243                 {
244                     return projectDir.getAbsoluteFile().toPath().toUri().toASCIIString();
245                 }
246                 return null;
247             }
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 
264             public Object getValue( String expression )
265             {
266                 return config.getExecutionProperties().getProperty( "env." + expression );
267             }
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(
279             (InterpolationPostProcessor) new PathTranslatingPostProcessor(
280                 PROJECT_PREFIXES,
281                 TRANSLATED_PATH_EXPRESSIONS,
282                 projectDir,
283                 pathTranslator ) );
284 
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.contains( "${" ) )
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 }