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