View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.model.interpolation;
20  
21  import javax.inject.Inject;
22  
23  import java.net.URI;
24  import java.nio.file.Path;
25  import java.util.ArrayList;
26  import java.util.Arrays;
27  import java.util.Collection;
28  import java.util.Collections;
29  import java.util.HashSet;
30  import java.util.List;
31  import java.util.Map;
32  
33  import org.apache.maven.api.model.Model;
34  import org.apache.maven.model.building.ModelBuildingRequest;
35  import org.apache.maven.model.building.ModelProblemCollector;
36  import org.apache.maven.model.path.PathTranslator;
37  import org.apache.maven.model.path.UrlNormalizer;
38  import org.apache.maven.model.root.RootLocator;
39  import org.codehaus.plexus.interpolation.AbstractValueSource;
40  import org.codehaus.plexus.interpolation.InterpolationPostProcessor;
41  import org.codehaus.plexus.interpolation.MapBasedValueSource;
42  import org.codehaus.plexus.interpolation.PrefixAwareRecursionInterceptor;
43  import org.codehaus.plexus.interpolation.PrefixedValueSourceWrapper;
44  import org.codehaus.plexus.interpolation.RecursionInterceptor;
45  import org.codehaus.plexus.interpolation.ValueSource;
46  
47  /**
48   * Use a regular expression search to find and resolve expressions within the POM.
49   *
50   * @deprecated use {@link org.apache.maven.api.services.ModelBuilder} instead
51   */
52  @Deprecated(since = "4.0.0")
53  public abstract class AbstractStringBasedModelInterpolator implements ModelInterpolator {
54      private static final String PREFIX_PROJECT = "project.";
55      private static final String PREFIX_POM = "pom.";
56      private static final List<String> PROJECT_PREFIXES_3_1 = Arrays.asList(PREFIX_POM, PREFIX_PROJECT);
57      private static final List<String> PROJECT_PREFIXES_4_0 = Collections.singletonList(PREFIX_PROJECT);
58  
59      private static final Collection<String> TRANSLATED_PATH_EXPRESSIONS;
60  
61      static {
62          Collection<String> translatedPrefixes = new HashSet<>();
63  
64          // MNG-1927, MNG-2124, MNG-3355:
65          // If the build section is present and the project directory is non-null, we should make
66          // sure interpolation of the directories below uses translated paths.
67          // Afterward, we'll double back and translate any paths that weren't covered during interpolation via the
68          // code below...
69          translatedPrefixes.add("build.directory");
70          translatedPrefixes.add("build.outputDirectory");
71          translatedPrefixes.add("build.testOutputDirectory");
72          translatedPrefixes.add("build.sourceDirectory");
73          translatedPrefixes.add("build.testSourceDirectory");
74          translatedPrefixes.add("build.scriptSourceDirectory");
75          translatedPrefixes.add("reporting.outputDirectory");
76  
77          TRANSLATED_PATH_EXPRESSIONS = translatedPrefixes;
78      }
79  
80      private final PathTranslator pathTranslator;
81      private final UrlNormalizer urlNormalizer;
82  
83      private final RootLocator rootLocator;
84  
85      @Inject
86      public AbstractStringBasedModelInterpolator(
87              PathTranslator pathTranslator, UrlNormalizer urlNormalizer, RootLocator rootLocator) {
88          this.pathTranslator = pathTranslator;
89          this.urlNormalizer = urlNormalizer;
90          this.rootLocator = rootLocator;
91      }
92  
93      @Override
94      public org.apache.maven.model.Model interpolateModel(
95              org.apache.maven.model.Model model,
96              java.io.File projectDir,
97              ModelBuildingRequest request,
98              ModelProblemCollector problems) {
99          return new org.apache.maven.model.Model(interpolateModel(
100                 model.getDelegate(), projectDir != null ? projectDir.toPath() : null, request, problems));
101     }
102 
103     @Override
104     public org.apache.maven.model.Model interpolateModel(
105             org.apache.maven.model.Model model,
106             Path projectDir,
107             ModelBuildingRequest request,
108             ModelProblemCollector problems) {
109         return new org.apache.maven.model.Model(interpolateModel(model.getDelegate(), projectDir, request, problems));
110     }
111 
112     protected List<String> getProjectPrefixes(ModelBuildingRequest config) {
113         return config.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_4_0
114                 ? PROJECT_PREFIXES_4_0
115                 : PROJECT_PREFIXES_3_1;
116     }
117 
118     protected List<ValueSource> createValueSources(
119             final Model model,
120             final Path projectDir,
121             final ModelBuildingRequest config,
122             ModelProblemCollector problems) {
123         Map<String, String> modelProperties = model.getProperties();
124 
125         ValueSource projectPrefixValueSource;
126         ValueSource prefixlessObjectBasedValueSource;
127         if (config.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_4_0) {
128             projectPrefixValueSource = new PrefixedObjectValueSource(PROJECT_PREFIXES_4_0, model, false);
129             prefixlessObjectBasedValueSource = new ObjectBasedValueSource(model);
130         } else {
131             projectPrefixValueSource = new PrefixedObjectValueSource(PROJECT_PREFIXES_3_1, model, false);
132             if (config.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0) {
133                 projectPrefixValueSource =
134                         new ProblemDetectingValueSource(projectPrefixValueSource, PREFIX_POM, PREFIX_PROJECT, problems);
135             }
136 
137             prefixlessObjectBasedValueSource = new ObjectBasedValueSource(model);
138             if (config.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0) {
139                 prefixlessObjectBasedValueSource =
140                         new ProblemDetectingValueSource(prefixlessObjectBasedValueSource, "", PREFIX_PROJECT, problems);
141             }
142         }
143 
144         // NOTE: Order counts here!
145         List<ValueSource> valueSources = new ArrayList<>(9);
146 
147         if (projectDir != null) {
148             ValueSource basedirValueSource = new PrefixedValueSourceWrapper(
149                     new AbstractValueSource(false) {
150                         @Override
151                         public Object getValue(String expression) {
152                             if ("basedir".equals(expression)) {
153                                 return projectDir.toAbsolutePath().toString();
154                             } else if (expression.startsWith("basedir.")) {
155                                 Path basedir = projectDir.toAbsolutePath();
156                                 return new ObjectBasedValueSource(basedir)
157                                         .getValue(expression.substring("basedir.".length()));
158                             }
159                             return null;
160                         }
161                     },
162                     getProjectPrefixes(config),
163                     true);
164             valueSources.add(basedirValueSource);
165 
166             ValueSource baseUriValueSource = new PrefixedValueSourceWrapper(
167                     new AbstractValueSource(false) {
168                         @Override
169                         public Object getValue(String expression) {
170                             if ("baseUri".equals(expression)) {
171                                 return projectDir.toAbsolutePath().toUri().toASCIIString();
172                             } else if (expression.startsWith("baseUri.")) {
173                                 URI baseUri = projectDir.toAbsolutePath().toUri();
174                                 return new ObjectBasedValueSource(baseUri)
175                                         .getValue(expression.substring("baseUri.".length()));
176                             }
177                             return null;
178                         }
179                     },
180                     getProjectPrefixes(config),
181                     false);
182             valueSources.add(baseUriValueSource);
183             valueSources.add(new BuildTimestampValueSource(config.getBuildStartTime(), modelProperties));
184         }
185 
186         valueSources.add(new PrefixedValueSourceWrapper(
187                 new AbstractValueSource(false) {
188                     @Override
189                     public Object getValue(String expression) {
190                         if ("rootDirectory".equals(expression)) {
191                             Path root = rootLocator.findMandatoryRoot(projectDir);
192                             return root.toFile().getPath();
193                         } else if (expression.startsWith("rootDirectory.")) {
194                             Path root = rootLocator.findMandatoryRoot(projectDir);
195                             return new ObjectBasedValueSource(root)
196                                     .getValue(expression.substring("rootDirectory.".length()));
197                         }
198                         return null;
199                     }
200                 },
201                 getProjectPrefixes(config)));
202 
203         valueSources.add(projectPrefixValueSource);
204 
205         valueSources.add(new MapBasedValueSource(config.getUserProperties()));
206 
207         valueSources.add(new MapBasedValueSource(modelProperties));
208 
209         valueSources.add(new MapBasedValueSource(config.getSystemProperties()));
210 
211         valueSources.add(new AbstractValueSource(false) {
212             @Override
213             public Object getValue(String expression) {
214                 return config.getSystemProperties().getProperty("env." + expression);
215             }
216         });
217 
218         valueSources.add(prefixlessObjectBasedValueSource);
219 
220         return valueSources;
221     }
222 
223     protected List<? extends InterpolationPostProcessor> createPostProcessors(
224             final Model model, final Path projectDir, final ModelBuildingRequest config) {
225         List<InterpolationPostProcessor> processors = new ArrayList<>(2);
226         if (projectDir != null) {
227             processors.add(new PathTranslatingPostProcessor(
228                     getProjectPrefixes(config), TRANSLATED_PATH_EXPRESSIONS, projectDir, pathTranslator));
229         }
230         processors.add(new UrlNormalizingPostProcessor(urlNormalizer));
231         return processors;
232     }
233 
234     protected RecursionInterceptor createRecursionInterceptor(ModelBuildingRequest config) {
235         return new PrefixAwareRecursionInterceptor(getProjectPrefixes(config));
236     }
237 }