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