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.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   * Use a regular expression search to find and resolve expressions within the POM.
50   *
51   * @author jdcasey Created on Feb 3, 2005
52   */
53  public abstract class AbstractStringBasedModelInterpolator implements ModelInterpolator {
54      private static final List<String> PROJECT_PREFIXES = Arrays.asList("pom.", "project.");
55  
56      private static final Collection<String> TRANSLATED_PATH_EXPRESSIONS;
57  
58      static {
59          Collection<String> translatedPrefixes = new HashSet<>();
60  
61          // MNG-1927, MNG-2124, MNG-3355:
62          // If the build section is present and the project directory is non-null, we should make
63          // sure interpolation of the directories below uses translated paths.
64          // Afterward, we'll double back and translate any paths that weren't covered during interpolation via the
65          // code below...
66          translatedPrefixes.add("build.directory");
67          translatedPrefixes.add("build.outputDirectory");
68          translatedPrefixes.add("build.testOutputDirectory");
69          translatedPrefixes.add("build.sourceDirectory");
70          translatedPrefixes.add("build.testSourceDirectory");
71          translatedPrefixes.add("build.scriptSourceDirectory");
72          translatedPrefixes.add("reporting.outputDirectory");
73  
74          TRANSLATED_PATH_EXPRESSIONS = translatedPrefixes;
75      }
76  
77      @Inject
78      private PathTranslator pathTranslator;
79  
80      @Inject
81      private UrlNormalizer urlNormalizer;
82  
83      @Inject
84      private ModelVersionProcessor versionProcessor;
85  
86      @Inject
87      private RootLocator rootLocator;
88  
89      public AbstractStringBasedModelInterpolator setPathTranslator(PathTranslator pathTranslator) {
90          this.pathTranslator = pathTranslator;
91          return this;
92      }
93  
94      public AbstractStringBasedModelInterpolator setUrlNormalizer(UrlNormalizer urlNormalizer) {
95          this.urlNormalizer = urlNormalizer;
96          return this;
97      }
98  
99      public AbstractStringBasedModelInterpolator setVersionPropertiesProcessor(ModelVersionProcessor processor) {
100         this.versionProcessor = processor;
101         return this;
102     }
103 
104     public AbstractStringBasedModelInterpolator setRootLocator(RootLocator rootLocator) {
105         this.rootLocator = rootLocator;
106         return this;
107     }
108 
109     protected List<ValueSource> createValueSources(
110             final Model model,
111             final File projectDir,
112             final ModelBuildingRequest config,
113             final ModelProblemCollector problems) {
114         Properties modelProperties = model.getProperties();
115 
116         ValueSource modelValueSource1 = new PrefixedObjectValueSource(PROJECT_PREFIXES, model, false);
117         if (config.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0) {
118             modelValueSource1 = new ProblemDetectingValueSource(modelValueSource1, "pom.", "project.", problems);
119         }
120 
121         ValueSource modelValueSource2 = new ObjectBasedValueSource(model);
122         if (config.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0) {
123             modelValueSource2 = new ProblemDetectingValueSource(modelValueSource2, "", "project.", problems);
124         }
125 
126         // NOTE: Order counts here!
127         List<ValueSource> valueSources = new ArrayList<>(11);
128 
129         if (projectDir != null) {
130             ValueSource basedirValueSource = new PrefixedValueSourceWrapper(
131                     new AbstractValueSource(false) {
132                         @Override
133                         public Object getValue(String expression) {
134                             if ("basedir".equals(expression)) {
135                                 return projectDir.getAbsolutePath();
136                             }
137                             return null;
138                         }
139                     },
140                     PROJECT_PREFIXES,
141                     true);
142             valueSources.add(basedirValueSource);
143 
144             ValueSource rootDirectoryValueSource = new PrefixedValueSourceWrapper(
145                     new AbstractValueSource(false) {
146                         @Override
147                         public Object getValue(String expression) {
148                             if ("rootDirectory".equals(expression)) {
149                                 return rootLocator
150                                         .findMandatoryRoot(projectDir.toPath())
151                                         .toAbsolutePath()
152                                         .toString();
153                             }
154                             return null;
155                         }
156                     },
157                     PROJECT_PREFIXES,
158                     true);
159             valueSources.add(rootDirectoryValueSource);
160 
161             ValueSource baseUriValueSource = new PrefixedValueSourceWrapper(
162                     new AbstractValueSource(false) {
163                         @Override
164                         public Object getValue(String expression) {
165                             if ("baseUri".equals(expression)) {
166                                 return projectDir
167                                         .getAbsoluteFile()
168                                         .toPath()
169                                         .toUri()
170                                         .toASCIIString();
171                             }
172                             return null;
173                         }
174                     },
175                     PROJECT_PREFIXES,
176                     false);
177             valueSources.add(baseUriValueSource);
178             valueSources.add(new BuildTimestampValueSource(config.getBuildStartTime(), modelProperties));
179         }
180 
181         valueSources.add(modelValueSource1);
182 
183         valueSources.add(new MapBasedValueSource(config.getUserProperties()));
184 
185         // Overwrite existing values in model properties. Otherwise it's not possible
186         // to define them via command line e.g.: mvn -Drevision=6.5.7 ...
187         versionProcessor.overwriteModelProperties(modelProperties, config);
188         valueSources.add(new MapBasedValueSource(modelProperties));
189 
190         valueSources.add(new MapBasedValueSource(config.getSystemProperties()));
191 
192         valueSources.add(new AbstractValueSource(false) {
193             @Override
194             public Object getValue(String expression) {
195                 return config.getSystemProperties().getProperty("env." + expression);
196             }
197         });
198 
199         valueSources.add(modelValueSource2);
200 
201         // last source: make sure Maven Repo Central is present (if is present anywhere else, it will prevail this one)
202         valueSources.add(new SingleResponseValueSource(MAVEN_REPO_CENTRAL_KEY, DEFAULT_MAVEN_REPO_CENTRAL_URL));
203 
204         return valueSources;
205     }
206 
207     protected List<? extends InterpolationPostProcessor> createPostProcessors(
208             final Model model, final File projectDir, final ModelBuildingRequest config) {
209         List<InterpolationPostProcessor> processors = new ArrayList<>(2);
210         if (projectDir != null) {
211             processors.add(new PathTranslatingPostProcessor(
212                     PROJECT_PREFIXES, TRANSLATED_PATH_EXPRESSIONS,
213                     projectDir, pathTranslator));
214         }
215         processors.add(new UrlNormalizingPostProcessor(urlNormalizer));
216         return processors;
217     }
218 
219     protected RecursionInterceptor createRecursionInterceptor() {
220         return new PrefixAwareRecursionInterceptor(PROJECT_PREFIXES);
221     }
222 }