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 javax.inject.Inject;
22  import javax.xml.stream.XMLStreamException;
23  
24  import java.io.File;
25  import java.io.IOException;
26  import java.io.StringReader;
27  import java.io.StringWriter;
28  import java.util.ArrayList;
29  import java.util.Arrays;
30  import java.util.Collections;
31  import java.util.List;
32  import java.util.Map;
33  import java.util.Properties;
34  
35  import org.apache.maven.model.Model;
36  import org.apache.maven.model.v4.MavenStaxReader;
37  import org.apache.maven.model.v4.MavenStaxWriter;
38  import org.apache.maven.project.DefaultProjectBuilderConfiguration;
39  import org.apache.maven.project.ProjectBuilderConfiguration;
40  import org.apache.maven.project.path.PathTranslator;
41  import org.codehaus.plexus.interpolation.AbstractValueSource;
42  import org.codehaus.plexus.interpolation.InterpolationException;
43  import org.codehaus.plexus.interpolation.InterpolationPostProcessor;
44  import org.codehaus.plexus.interpolation.Interpolator;
45  import org.codehaus.plexus.interpolation.MapBasedValueSource;
46  import org.codehaus.plexus.interpolation.ObjectBasedValueSource;
47  import org.codehaus.plexus.interpolation.PrefixAwareRecursionInterceptor;
48  import org.codehaus.plexus.interpolation.PrefixedObjectValueSource;
49  import org.codehaus.plexus.interpolation.PrefixedValueSourceWrapper;
50  import org.codehaus.plexus.interpolation.RecursionInterceptor;
51  import org.codehaus.plexus.interpolation.ValueSource;
52  import org.codehaus.plexus.logging.AbstractLogEnabled;
53  import org.codehaus.plexus.logging.Logger;
54  import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
55  import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
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      @Inject
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     @Deprecated
121     public Model interpolate(Model model, Map<String, ?> context, boolean strict) throws ModelInterpolationException {
122         Properties props = new Properties();
123         props.putAll(context);
124 
125         return interpolate(model, null, new DefaultProjectBuilderConfiguration().setExecutionProperties(props), true);
126     }
127 
128     public Model interpolate(Model model, File projectDir, ProjectBuilderConfiguration config, boolean debugEnabled)
129             throws ModelInterpolationException {
130         StringWriter sWriter = new StringWriter(1024);
131 
132         MavenStaxWriter writer = new MavenStaxWriter();
133         try {
134             writer.write(sWriter, model.getDelegate());
135         } catch (IOException | XMLStreamException e) {
136             throw new ModelInterpolationException("Cannot serialize project model for interpolation.", e);
137         }
138 
139         String serializedModel = sWriter.toString();
140         serializedModel = interpolate(serializedModel, model, projectDir, config, debugEnabled);
141 
142         StringReader sReader = new StringReader(serializedModel);
143 
144         MavenStaxReader modelReader = new MavenStaxReader();
145         try {
146             model = new Model(modelReader.read(sReader));
147         } catch (XMLStreamException e) {
148             throw new ModelInterpolationException(
149                     "Cannot read project model from interpolating filter of serialized version.", e);
150         }
151 
152         return model;
153     }
154 
155     
156 
157 
158 
159 
160 
161 
162 
163 
164 
165 
166 
167     public String interpolate(
168             String src, Model model, final File projectDir, ProjectBuilderConfiguration config, boolean debug)
169             throws ModelInterpolationException {
170         try {
171             List<ValueSource> valueSources = createValueSources(model, projectDir, config);
172             List<InterpolationPostProcessor> postProcessors = createPostProcessors(model, projectDir, config);
173 
174             return interpolateInternal(src, valueSources, postProcessors, debug);
175         } finally {
176             interpolator.clearAnswers();
177         }
178     }
179 
180     protected List<ValueSource> createValueSources(
181             final Model model, final File projectDir, final ProjectBuilderConfiguration config) {
182         String timestampFormat = DEFAULT_BUILD_TIMESTAMP_FORMAT;
183 
184         Properties modelProperties = model.getProperties();
185         if (modelProperties != null) {
186             timestampFormat = modelProperties.getProperty(BUILD_TIMESTAMP_FORMAT_PROPERTY, timestampFormat);
187         }
188 
189         ValueSource modelValueSource1 = new PrefixedObjectValueSource(PROJECT_PREFIXES, model, false);
190         ValueSource modelValueSource2 = new ObjectBasedValueSource(model);
191 
192         ValueSource basedirValueSource = new PrefixedValueSourceWrapper(
193                 new AbstractValueSource(false) {
194 
195                     public Object getValue(String expression) {
196                         if (projectDir != null && "basedir".equals(expression)) {
197                             return projectDir.getAbsolutePath();
198                         }
199                         return null;
200                     }
201                 },
202                 PROJECT_PREFIXES,
203                 true);
204         ValueSource baseUriValueSource = new PrefixedValueSourceWrapper(
205                 new AbstractValueSource(false) {
206 
207                     public Object getValue(String expression) {
208                         if (projectDir != null && "baseUri".equals(expression)) {
209                             return projectDir.getAbsoluteFile().toPath().toUri().toASCIIString();
210                         }
211                         return null;
212                     }
213                 },
214                 PROJECT_PREFIXES,
215                 false);
216 
217         List<ValueSource> valueSources = new ArrayList<>(9);
218 
219         
220         valueSources.add(basedirValueSource);
221         valueSources.add(baseUriValueSource);
222         valueSources.add(new BuildTimestampValueSource(config.getBuildStartTime(), timestampFormat));
223         valueSources.add(modelValueSource1);
224         valueSources.add(new MapBasedValueSource(config.getUserProperties()));
225         valueSources.add(new MapBasedValueSource(modelProperties));
226         valueSources.add(new MapBasedValueSource(config.getExecutionProperties()));
227         valueSources.add(new AbstractValueSource(false) {
228 
229             public Object getValue(String expression) {
230                 return config.getExecutionProperties().getProperty("env." + expression);
231             }
232         });
233         valueSources.add(modelValueSource2);
234 
235         return valueSources;
236     }
237 
238     protected List<InterpolationPostProcessor> createPostProcessors(
239             final Model model, final File projectDir, final ProjectBuilderConfiguration config) {
240         return Collections.singletonList((InterpolationPostProcessor) new PathTranslatingPostProcessor(
241                 PROJECT_PREFIXES, TRANSLATED_PATH_EXPRESSIONS, projectDir, pathTranslator));
242     }
243 
244     @SuppressWarnings("unchecked")
245     protected String interpolateInternal(
246             String src, List<ValueSource> valueSources, List<InterpolationPostProcessor> postProcessors, boolean debug)
247             throws ModelInterpolationException {
248         if (!src.contains("${")) {
249             return src;
250         }
251 
252         Logger logger = getLogger();
253 
254         String result = src;
255         synchronized (this) {
256             for (ValueSource vs : valueSources) {
257                 interpolator.addValueSource(vs);
258             }
259 
260             for (InterpolationPostProcessor postProcessor : postProcessors) {
261                 interpolator.addPostProcessor(postProcessor);
262             }
263 
264             try {
265                 try {
266                     result = interpolator.interpolate(result, recursionInterceptor);
267                 } catch (InterpolationException e) {
268                     throw new ModelInterpolationException(e.getMessage(), e);
269                 }
270 
271                 if (debug) {
272                     List<Object> feedback = interpolator.getFeedback();
273                     if (feedback != null && !feedback.isEmpty()) {
274                         logger.debug("Maven encountered the following problems during initial POM interpolation:");
275 
276                         Object last = null;
277                         for (Object next : feedback) {
278                             if (next instanceof Throwable) {
279                                 if (last == null) {
280                                     logger.debug("", ((Throwable) next));
281                                 } else {
282                                     logger.debug(String.valueOf(last), ((Throwable) next));
283                                 }
284                             } else {
285                                 if (last != null) {
286                                     logger.debug(String.valueOf(last));
287                                 }
288 
289                                 last = next;
290                             }
291                         }
292 
293                         if (last != null) {
294                             logger.debug(String.valueOf(last));
295                         }
296                     }
297                 }
298 
299                 interpolator.clearFeedback();
300             } finally {
301                 for (ValueSource vs : valueSources) {
302                     interpolator.removeValuesSource(vs);
303                 }
304 
305                 for (InterpolationPostProcessor postProcessor : postProcessors) {
306                     interpolator.removePostProcessor(postProcessor);
307                 }
308             }
309         }
310 
311         return result;
312     }
313 
314     protected RecursionInterceptor getRecursionInterceptor() {
315         return recursionInterceptor;
316     }
317 
318     protected void setRecursionInterceptor(RecursionInterceptor recursionInterceptor) {
319         this.recursionInterceptor = recursionInterceptor;
320     }
321 
322     protected abstract Interpolator createInterpolator();
323 
324     public void initialize() throws InitializationException {
325         interpolator = createInterpolator();
326         recursionInterceptor = new PrefixAwareRecursionInterceptor(PROJECT_PREFIXES);
327     }
328 
329     protected final Interpolator getInterpolator() {
330         return interpolator;
331     }
332 }