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