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.Collection;
26  import java.util.Collections;
27  import java.util.HashSet;
28  import java.util.List;
29  import java.util.Map;
30  
31  import org.apache.maven.api.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.codehaus.plexus.interpolation.AbstractValueSource;
37  import org.codehaus.plexus.interpolation.InterpolationPostProcessor;
38  import org.codehaus.plexus.interpolation.MapBasedValueSource;
39  import org.codehaus.plexus.interpolation.PrefixAwareRecursionInterceptor;
40  import org.codehaus.plexus.interpolation.PrefixedObjectValueSource;
41  import org.codehaus.plexus.interpolation.PrefixedValueSourceWrapper;
42  import org.codehaus.plexus.interpolation.RecursionInterceptor;
43  import org.codehaus.plexus.interpolation.ValueSource;
44  
45  /**
46   * Use a regular expression search to find and resolve expressions within the POM.
47   *
48   * @author jdcasey Created on Feb 3, 2005
49   */
50  public abstract class AbstractStringBasedModelInterpolator implements ModelInterpolator {
51      private static final List<String> PROJECT_PREFIXES = Collections.singletonList("project.");
52  
53      private static final Collection<String> TRANSLATED_PATH_EXPRESSIONS;
54  
55      static {
56          Collection<String> translatedPrefixes = new HashSet<>();
57  
58          // MNG-1927, MNG-2124, MNG-3355:
59          // If the build section is present and the project directory is non-null, we should make
60          // sure interpolation of the directories below uses translated paths.
61          // Afterward, we'll double back and translate any paths that weren't covered during interpolation via the
62          // code below...
63          translatedPrefixes.add("build.directory");
64          translatedPrefixes.add("build.outputDirectory");
65          translatedPrefixes.add("build.testOutputDirectory");
66          translatedPrefixes.add("build.sourceDirectory");
67          translatedPrefixes.add("build.testSourceDirectory");
68          translatedPrefixes.add("build.scriptSourceDirectory");
69          translatedPrefixes.add("reporting.outputDirectory");
70  
71          TRANSLATED_PATH_EXPRESSIONS = translatedPrefixes;
72      }
73  
74      private final PathTranslator pathTranslator;
75      private final UrlNormalizer urlNormalizer;
76  
77      @Inject
78      public AbstractStringBasedModelInterpolator(PathTranslator pathTranslator, UrlNormalizer urlNormalizer) {
79          this.pathTranslator = pathTranslator;
80          this.urlNormalizer = urlNormalizer;
81      }
82  
83      @Override
84      public org.apache.maven.model.Model interpolateModel(
85              org.apache.maven.model.Model model,
86              File projectDir,
87              ModelBuildingRequest request,
88              ModelProblemCollector problems) {
89          return new org.apache.maven.model.Model(interpolateModel(model.getDelegate(), projectDir, request, problems));
90      }
91  
92      protected List<ValueSource> createValueSources(
93              final Model model, final File projectDir, final ModelBuildingRequest config) {
94          Map<String, String> modelProperties = model.getProperties();
95  
96          ValueSource projectPrefixValueSource = new PrefixedObjectValueSource(PROJECT_PREFIXES, model, false);
97  
98          // NOTE: Order counts here!
99          List<ValueSource> valueSources = new ArrayList<>(8);
100 
101         if (projectDir != null) {
102             ValueSource basedirValueSource = new PrefixedValueSourceWrapper(
103                     new AbstractValueSource(false) {
104                         @Override
105                         public Object getValue(String expression) {
106                             if ("basedir".equals(expression)) {
107                                 return projectDir.getAbsolutePath();
108                             }
109                             return null;
110                         }
111                     },
112                     PROJECT_PREFIXES,
113                     true);
114             valueSources.add(basedirValueSource);
115 
116             ValueSource baseUriValueSource = new PrefixedValueSourceWrapper(
117                     new AbstractValueSource(false) {
118                         @Override
119                         public Object getValue(String expression) {
120                             if ("baseUri".equals(expression)) {
121                                 return projectDir
122                                         .getAbsoluteFile()
123                                         .toPath()
124                                         .toUri()
125                                         .toASCIIString();
126                             }
127                             return null;
128                         }
129                     },
130                     PROJECT_PREFIXES,
131                     false);
132             valueSources.add(baseUriValueSource);
133             valueSources.add(new BuildTimestampValueSource(config.getBuildStartTime(), modelProperties));
134         }
135 
136         valueSources.add(projectPrefixValueSource);
137 
138         valueSources.add(new MapBasedValueSource(config.getUserProperties()));
139 
140         valueSources.add(new MapBasedValueSource(modelProperties));
141 
142         valueSources.add(new MapBasedValueSource(config.getSystemProperties()));
143 
144         valueSources.add(new AbstractValueSource(false) {
145             @Override
146             public Object getValue(String expression) {
147                 return config.getSystemProperties().getProperty("env." + expression);
148             }
149         });
150 
151         return valueSources;
152     }
153 
154     protected List<? extends InterpolationPostProcessor> createPostProcessors(
155             final Model model, final File projectDir, final ModelBuildingRequest config) {
156         List<InterpolationPostProcessor> processors = new ArrayList<>(2);
157         if (projectDir != null) {
158             processors.add(new PathTranslatingPostProcessor(
159                     PROJECT_PREFIXES, TRANSLATED_PATH_EXPRESSIONS,
160                     projectDir, pathTranslator));
161         }
162         processors.add(new UrlNormalizingPostProcessor(urlNormalizer));
163         return processors;
164     }
165 
166     protected RecursionInterceptor createRecursionInterceptor() {
167         return new PrefixAwareRecursionInterceptor(PROJECT_PREFIXES);
168     }
169 }