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