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