1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  package org.apache.maven.project.interpolation;
20  
21  import java.io.File;
22  import java.io.IOException;
23  import java.io.StringReader;
24  import java.io.StringWriter;
25  import java.util.ArrayList;
26  import java.util.Arrays;
27  import java.util.Collections;
28  import java.util.List;
29  import java.util.Map;
30  import java.util.Properties;
31  
32  import org.apache.maven.model.Model;
33  import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
34  import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
35  import org.apache.maven.project.DefaultProjectBuilderConfiguration;
36  import org.apache.maven.project.ProjectBuilderConfiguration;
37  import org.apache.maven.project.path.PathTranslator;
38  import org.codehaus.plexus.component.annotations.Requirement;
39  import org.codehaus.plexus.interpolation.AbstractValueSource;
40  import org.codehaus.plexus.interpolation.InterpolationException;
41  import org.codehaus.plexus.interpolation.InterpolationPostProcessor;
42  import org.codehaus.plexus.interpolation.Interpolator;
43  import org.codehaus.plexus.interpolation.MapBasedValueSource;
44  import org.codehaus.plexus.interpolation.ObjectBasedValueSource;
45  import org.codehaus.plexus.interpolation.PrefixAwareRecursionInterceptor;
46  import org.codehaus.plexus.interpolation.PrefixedObjectValueSource;
47  import org.codehaus.plexus.interpolation.PrefixedValueSourceWrapper;
48  import org.codehaus.plexus.interpolation.RecursionInterceptor;
49  import org.codehaus.plexus.interpolation.ValueSource;
50  import org.codehaus.plexus.logging.AbstractLogEnabled;
51  import org.codehaus.plexus.logging.Logger;
52  import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
53  import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
54  import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
55  
56  
57  
58  
59  
60  
61  
62  @Deprecated
63  public abstract class AbstractStringBasedModelInterpolator extends AbstractLogEnabled
64          implements ModelInterpolator, Initializable {
65  
66      private static final List<String> PROJECT_PREFIXES = Arrays.asList("pom.", "project.");
67  
68      private static final List<String> TRANSLATED_PATH_EXPRESSIONS;
69  
70      static {
71          List<String> translatedPrefixes = new ArrayList<>();
72  
73          
74          
75          
76          
77          
78          translatedPrefixes.add("build.directory");
79          translatedPrefixes.add("build.outputDirectory");
80          translatedPrefixes.add("build.testOutputDirectory");
81          translatedPrefixes.add("build.sourceDirectory");
82          translatedPrefixes.add("build.testSourceDirectory");
83          translatedPrefixes.add("build.scriptSourceDirectory");
84          translatedPrefixes.add("reporting.outputDirectory");
85  
86          TRANSLATED_PATH_EXPRESSIONS = translatedPrefixes;
87      }
88  
89      @Requirement
90      private PathTranslator pathTranslator;
91  
92      private Interpolator interpolator;
93  
94      private RecursionInterceptor recursionInterceptor;
95  
96      
97      protected AbstractStringBasedModelInterpolator(PathTranslator pathTranslator) {
98          this.pathTranslator = pathTranslator;
99      }
100 
101     protected AbstractStringBasedModelInterpolator() {}
102 
103     public Model interpolate(Model model, Map<String, ?> context) throws ModelInterpolationException {
104         return interpolate(model, context, true);
105     }
106 
107     
108 
109 
110 
111 
112 
113 
114 
115 
116 
117 
118 
119 
120     public Model interpolate(Model model, Map<String, ?> context, boolean strict) throws ModelInterpolationException {
121         Properties props = new Properties();
122         props.putAll(context);
123 
124         return interpolate(model, null, new DefaultProjectBuilderConfiguration().setExecutionProperties(props), true);
125     }
126 
127     public Model interpolate(Model model, File projectDir, ProjectBuilderConfiguration config, boolean debugEnabled)
128             throws ModelInterpolationException {
129         StringWriter sWriter = new StringWriter(1024);
130 
131         MavenXpp3Writer writer = new MavenXpp3Writer();
132         try {
133             writer.write(sWriter, model);
134         } catch (IOException e) {
135             throw new ModelInterpolationException("Cannot serialize project model for interpolation.", e);
136         }
137 
138         String serializedModel = sWriter.toString();
139         serializedModel = interpolate(serializedModel, model, projectDir, config, debugEnabled);
140 
141         StringReader sReader = new StringReader(serializedModel);
142 
143         MavenXpp3Reader modelReader = new MavenXpp3Reader();
144         try {
145             model = modelReader.read(sReader);
146         } catch (IOException | XmlPullParserException e) {
147             throw new ModelInterpolationException(
148                     "Cannot read project model from interpolating filter of serialized version.", e);
149         }
150 
151         return model;
152     }
153 
154     
155 
156 
157 
158 
159 
160 
161 
162 
163 
164 
165 
166     public String interpolate(
167             String src, Model model, final File projectDir, ProjectBuilderConfiguration config, boolean debug)
168             throws ModelInterpolationException {
169         try {
170             List<ValueSource> valueSources = createValueSources(model, projectDir, config);
171             List<InterpolationPostProcessor> postProcessors = createPostProcessors(model, projectDir, config);
172 
173             return interpolateInternal(src, valueSources, postProcessors, debug);
174         } finally {
175             interpolator.clearAnswers();
176         }
177     }
178 
179     protected List<ValueSource> createValueSources(
180             final Model model, final File projectDir, final ProjectBuilderConfiguration config) {
181         String timestampFormat = DEFAULT_BUILD_TIMESTAMP_FORMAT;
182 
183         Properties modelProperties = model.getProperties();
184         if (modelProperties != null) {
185             timestampFormat = modelProperties.getProperty(BUILD_TIMESTAMP_FORMAT_PROPERTY, timestampFormat);
186         }
187 
188         ValueSource modelValueSource1 = new PrefixedObjectValueSource(PROJECT_PREFIXES, model, false);
189         ValueSource modelValueSource2 = new ObjectBasedValueSource(model);
190 
191         ValueSource basedirValueSource = new PrefixedValueSourceWrapper(
192                 new AbstractValueSource(false) {
193 
194                     public Object getValue(String expression) {
195                         if (projectDir != null && "basedir".equals(expression)) {
196                             return projectDir.getAbsolutePath();
197                         }
198                         return null;
199                     }
200                 },
201                 PROJECT_PREFIXES,
202                 true);
203         ValueSource baseUriValueSource = new PrefixedValueSourceWrapper(
204                 new AbstractValueSource(false) {
205 
206                     public Object getValue(String expression) {
207                         if (projectDir != null && "baseUri".equals(expression)) {
208                             return projectDir.getAbsoluteFile().toPath().toUri().toASCIIString();
209                         }
210                         return null;
211                     }
212                 },
213                 PROJECT_PREFIXES,
214                 false);
215 
216         List<ValueSource> valueSources = new ArrayList<>(9);
217 
218         
219         valueSources.add(basedirValueSource);
220         valueSources.add(baseUriValueSource);
221         valueSources.add(new BuildTimestampValueSource(config.getBuildStartTime(), timestampFormat));
222         valueSources.add(modelValueSource1);
223         valueSources.add(new MapBasedValueSource(config.getUserProperties()));
224         valueSources.add(new MapBasedValueSource(modelProperties));
225         valueSources.add(new MapBasedValueSource(config.getExecutionProperties()));
226         valueSources.add(new AbstractValueSource(false) {
227 
228             public Object getValue(String expression) {
229                 return config.getExecutionProperties().getProperty("env." + expression);
230             }
231         });
232         valueSources.add(modelValueSource2);
233 
234         return valueSources;
235     }
236 
237     protected List<InterpolationPostProcessor> createPostProcessors(
238             final Model model, final File projectDir, final ProjectBuilderConfiguration config) {
239         return Collections.singletonList((InterpolationPostProcessor) new PathTranslatingPostProcessor(
240                 PROJECT_PREFIXES, TRANSLATED_PATH_EXPRESSIONS, projectDir, pathTranslator));
241     }
242 
243     @SuppressWarnings("unchecked")
244     protected String interpolateInternal(
245             String src, List<ValueSource> valueSources, List<InterpolationPostProcessor> postProcessors, boolean debug)
246             throws ModelInterpolationException {
247         if (!src.contains("${")) {
248             return src;
249         }
250 
251         Logger logger = getLogger();
252 
253         String result = src;
254         synchronized (this) {
255             for (ValueSource vs : valueSources) {
256                 interpolator.addValueSource(vs);
257             }
258 
259             for (InterpolationPostProcessor postProcessor : postProcessors) {
260                 interpolator.addPostProcessor(postProcessor);
261             }
262 
263             try {
264                 try {
265                     result = interpolator.interpolate(result, recursionInterceptor);
266                 } catch (InterpolationException e) {
267                     throw new ModelInterpolationException(e.getMessage(), e);
268                 }
269 
270                 if (debug) {
271                     List<Object> feedback = interpolator.getFeedback();
272                     if (feedback != null && !feedback.isEmpty()) {
273                         logger.debug("Maven encountered the following problems during initial POM interpolation:");
274 
275                         Object last = null;
276                         for (Object next : feedback) {
277                             if (next instanceof Throwable) {
278                                 if (last == null) {
279                                     logger.debug("", ((Throwable) next));
280                                 } else {
281                                     logger.debug(String.valueOf(last), ((Throwable) next));
282                                 }
283                             } else {
284                                 if (last != null) {
285                                     logger.debug(String.valueOf(last));
286                                 }
287 
288                                 last = next;
289                             }
290                         }
291 
292                         if (last != null) {
293                             logger.debug(String.valueOf(last));
294                         }
295                     }
296                 }
297 
298                 interpolator.clearFeedback();
299             } finally {
300                 for (ValueSource vs : valueSources) {
301                     interpolator.removeValuesSource(vs);
302                 }
303 
304                 for (InterpolationPostProcessor postProcessor : postProcessors) {
305                     interpolator.removePostProcessor(postProcessor);
306                 }
307             }
308         }
309 
310         return result;
311     }
312 
313     protected RecursionInterceptor getRecursionInterceptor() {
314         return recursionInterceptor;
315     }
316 
317     protected void setRecursionInterceptor(RecursionInterceptor recursionInterceptor) {
318         this.recursionInterceptor = recursionInterceptor;
319     }
320 
321     protected abstract Interpolator createInterpolator();
322 
323     public void initialize() throws InitializationException {
324         interpolator = createInterpolator();
325         recursionInterceptor = new PrefixAwareRecursionInterceptor(PROJECT_PREFIXES);
326     }
327 
328     protected final Interpolator getInterpolator() {
329         return interpolator;
330     }
331 }