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 }