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