1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.model.interpolation;
20
21 import javax.inject.Inject;
22
23 import java.io.File;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.Collection;
27 import java.util.HashSet;
28 import java.util.List;
29 import java.util.Properties;
30
31 import org.apache.maven.model.Model;
32 import org.apache.maven.model.building.ModelBuildingRequest;
33 import org.apache.maven.model.building.ModelProblemCollector;
34 import org.apache.maven.model.path.PathTranslator;
35 import org.apache.maven.model.path.UrlNormalizer;
36 import org.apache.maven.model.root.RootLocator;
37 import org.codehaus.plexus.interpolation.AbstractValueSource;
38 import org.codehaus.plexus.interpolation.InterpolationPostProcessor;
39 import org.codehaus.plexus.interpolation.MapBasedValueSource;
40 import org.codehaus.plexus.interpolation.ObjectBasedValueSource;
41 import org.codehaus.plexus.interpolation.PrefixAwareRecursionInterceptor;
42 import org.codehaus.plexus.interpolation.PrefixedObjectValueSource;
43 import org.codehaus.plexus.interpolation.PrefixedValueSourceWrapper;
44 import org.codehaus.plexus.interpolation.RecursionInterceptor;
45 import org.codehaus.plexus.interpolation.SingleResponseValueSource;
46 import org.codehaus.plexus.interpolation.ValueSource;
47
48
49
50
51
52
53 public abstract class AbstractStringBasedModelInterpolator implements ModelInterpolator {
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68 public static final String FULL_EXTERNAL_INTERPOLATION_PROPERTY = "maven.model.dependencyInterpolation.full";
69
70 private static final List<String> PROJECT_PREFIXES = Arrays.asList("pom.", "project.");
71
72 private static final Collection<String> TRANSLATED_PATH_EXPRESSIONS;
73
74 static {
75 Collection<String> translatedPrefixes = new HashSet<>();
76
77
78
79
80
81
82 translatedPrefixes.add("build.directory");
83 translatedPrefixes.add("build.outputDirectory");
84 translatedPrefixes.add("build.testOutputDirectory");
85 translatedPrefixes.add("build.sourceDirectory");
86 translatedPrefixes.add("build.testSourceDirectory");
87 translatedPrefixes.add("build.scriptSourceDirectory");
88 translatedPrefixes.add("reporting.outputDirectory");
89
90 TRANSLATED_PATH_EXPRESSIONS = translatedPrefixes;
91 }
92
93 @Inject
94 private PathTranslator pathTranslator;
95
96 @Inject
97 private UrlNormalizer urlNormalizer;
98
99 @Inject
100 private ModelVersionProcessor versionProcessor;
101
102 @Inject
103 private RootLocator rootLocator;
104
105 public AbstractStringBasedModelInterpolator setPathTranslator(PathTranslator pathTranslator) {
106 this.pathTranslator = pathTranslator;
107 return this;
108 }
109
110 public AbstractStringBasedModelInterpolator setUrlNormalizer(UrlNormalizer urlNormalizer) {
111 this.urlNormalizer = urlNormalizer;
112 return this;
113 }
114
115 public AbstractStringBasedModelInterpolator setVersionPropertiesProcessor(ModelVersionProcessor processor) {
116 this.versionProcessor = processor;
117 return this;
118 }
119
120 public AbstractStringBasedModelInterpolator setRootLocator(RootLocator rootLocator) {
121 this.rootLocator = rootLocator;
122 return this;
123 }
124
125 protected List<ValueSource> createValueSources(
126 final Model model,
127 final File projectDir,
128 final ModelBuildingRequest config,
129 final ModelProblemCollector problems) {
130 Properties modelProperties = model.getProperties();
131
132 ValueSource modelValueSource1 = new PrefixedObjectValueSource(PROJECT_PREFIXES, model, false);
133 if (config.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0) {
134 modelValueSource1 = new ProblemDetectingValueSource(modelValueSource1, "pom.", "project.", problems);
135 }
136
137 ValueSource modelValueSource2 = new ObjectBasedValueSource(model);
138 if (config.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0) {
139 modelValueSource2 = new ProblemDetectingValueSource(modelValueSource2, "", "project.", problems);
140 }
141
142
143 List<ValueSource> valueSources = new ArrayList<>(11);
144
145 if (projectDir != null) {
146 ValueSource basedirValueSource = new PrefixedValueSourceWrapper(
147 new AbstractValueSource(false) {
148 @Override
149 public Object getValue(String expression) {
150 if ("basedir".equals(expression)) {
151 return projectDir.getAbsolutePath();
152 }
153 return null;
154 }
155 },
156 PROJECT_PREFIXES,
157 true);
158 valueSources.add(basedirValueSource);
159
160 ValueSource rootDirectoryValueSource = new PrefixedValueSourceWrapper(
161 new AbstractValueSource(false) {
162 @Override
163 public Object getValue(String expression) {
164 if ("rootDirectory".equals(expression)) {
165 return rootLocator
166 .findMandatoryRoot(projectDir.toPath())
167 .toAbsolutePath()
168 .toString();
169 }
170 return null;
171 }
172 },
173 PROJECT_PREFIXES,
174 true);
175 valueSources.add(rootDirectoryValueSource);
176
177 ValueSource baseUriValueSource = new PrefixedValueSourceWrapper(
178 new AbstractValueSource(false) {
179 @Override
180 public Object getValue(String expression) {
181 if ("baseUri".equals(expression)) {
182 return projectDir
183 .getAbsoluteFile()
184 .toPath()
185 .toUri()
186 .toASCIIString();
187 }
188 return null;
189 }
190 },
191 PROJECT_PREFIXES,
192 false);
193 valueSources.add(baseUriValueSource);
194 valueSources.add(new BuildTimestampValueSource(config.getBuildStartTime(), modelProperties));
195 }
196
197 valueSources.add(modelValueSource1);
198
199
200
201
202
203
204
205 boolean restricted = restrictExternalModelInterpolation(config);
206
207 ValueSource userPropertiesValueSource = new MapBasedValueSource(config.getUserProperties());
208 valueSources.add(restricted ? restrictToSafeExpressions(userPropertiesValueSource) : userPropertiesValueSource);
209
210
211
212 versionProcessor.overwriteModelProperties(modelProperties, config);
213 valueSources.add(new MapBasedValueSource(modelProperties));
214
215 ValueSource systemPropertiesValueSource = new MapBasedValueSource(config.getSystemProperties());
216 valueSources.add(
217 restricted ? restrictToSafeExpressions(systemPropertiesValueSource) : systemPropertiesValueSource);
218
219 if (!restricted) {
220 valueSources.add(new AbstractValueSource(false) {
221 @Override
222 public Object getValue(String expression) {
223 return config.getSystemProperties().getProperty("env." + expression);
224 }
225 });
226 }
227
228 valueSources.add(modelValueSource2);
229
230
231 valueSources.add(new SingleResponseValueSource(MAVEN_REPO_CENTRAL_KEY, DEFAULT_MAVEN_REPO_CENTRAL_URL));
232
233 return valueSources;
234 }
235
236 private static boolean restrictExternalModelInterpolation(ModelBuildingRequest config) {
237 return config.getValidationLevel() < ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0
238 && !Boolean.parseBoolean(config.getSystemProperties().getProperty(FULL_EXTERNAL_INTERPOLATION_PROPERTY))
239 && !Boolean.parseBoolean(config.getUserProperties().getProperty(FULL_EXTERNAL_INTERPOLATION_PROPERTY));
240 }
241
242 private static ValueSource restrictToSafeExpressions(ValueSource source) {
243 return new AbstractValueSource(false) {
244 @Override
245 public Object getValue(String expression) {
246 return isSafeExternalExpression(expression) ? source.getValue(expression) : null;
247 }
248 };
249 }
250
251
252
253
254
255
256 private static boolean isSafeExternalExpression(String expression) {
257 return expression.startsWith("java.")
258 || expression.startsWith("os.")
259 || expression.startsWith("maven.")
260 || "file.separator".equals(expression)
261 || "path.separator".equals(expression)
262 || "line.separator".equals(expression)
263 || "revision".equals(expression)
264 || "changelist".equals(expression)
265 || "sha1".equals(expression);
266 }
267
268 protected List<? extends InterpolationPostProcessor> createPostProcessors(
269 final Model model, final File projectDir, final ModelBuildingRequest config) {
270 List<InterpolationPostProcessor> processors = new ArrayList<>(2);
271 if (projectDir != null) {
272 processors.add(new PathTranslatingPostProcessor(
273 PROJECT_PREFIXES, TRANSLATED_PATH_EXPRESSIONS,
274 projectDir, pathTranslator));
275 }
276 processors.add(new UrlNormalizingPostProcessor(urlNormalizer));
277 return processors;
278 }
279
280 protected RecursionInterceptor createRecursionInterceptor() {
281 return new PrefixAwareRecursionInterceptor(PROJECT_PREFIXES);
282 }
283 }