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