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 }