1 package org.apache.maven.project.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.project.ProjectBuilderConfiguration;
24 import org.apache.maven.project.path.PathTranslator;
25 import org.codehaus.plexus.component.annotations.Component;
26 import org.codehaus.plexus.interpolation.InterpolationPostProcessor;
27 import org.codehaus.plexus.interpolation.Interpolator;
28 import org.codehaus.plexus.interpolation.StringSearchInterpolator;
29 import org.codehaus.plexus.interpolation.ValueSource;
30 import org.codehaus.plexus.logging.Logger;
31
32 import java.io.File;
33 import java.lang.reflect.Array;
34 import java.lang.reflect.Field;
35 import java.security.AccessController;
36 import java.security.PrivilegedAction;
37 import java.util.ArrayList;
38 import java.util.Collection;
39 import java.util.LinkedList;
40 import java.util.List;
41 import java.util.Map;
42 import java.util.WeakHashMap;
43
44 @Deprecated
45 @Component( role = ModelInterpolator.class )
46 public class StringSearchModelInterpolator
47 extends AbstractStringBasedModelInterpolator
48 {
49
50 private static final Map<Class<?>, Field[]> fieldsByClass = new WeakHashMap<Class<?>, Field[]>();
51 private static final Map<Class<?>, Boolean> fieldIsPrimitiveByClass = new WeakHashMap<Class<?>, Boolean>();
52
53 public StringSearchModelInterpolator()
54 {
55 }
56
57 public StringSearchModelInterpolator( PathTranslator pathTranslator )
58 {
59 super( pathTranslator );
60 }
61
62 public Model interpolate( Model model, File projectDir, ProjectBuilderConfiguration config, boolean debugEnabled )
63 throws ModelInterpolationException
64 {
65 interpolateObject( model, model, projectDir, config, debugEnabled );
66
67 return model;
68 }
69
70 protected void interpolateObject( Object obj, Model model, File projectDir, ProjectBuilderConfiguration config,
71 boolean debugEnabled )
72 throws ModelInterpolationException
73 {
74 try
75 {
76 List<ValueSource> valueSources = createValueSources( model, projectDir, config );
77 List<InterpolationPostProcessor> postProcessors = createPostProcessors( model, projectDir, config );
78
79 InterpolateObjectAction action =
80 new InterpolateObjectAction( obj, valueSources, postProcessors, debugEnabled,
81 this, getLogger() );
82
83 ModelInterpolationException error = AccessController.doPrivileged( action );
84
85 if ( error != null )
86 {
87 throw error;
88 }
89 }
90 finally
91 {
92 getInterpolator().clearAnswers();
93 }
94 }
95
96 protected Interpolator createInterpolator()
97 {
98 StringSearchInterpolator interpolator = new StringSearchInterpolator();
99 interpolator.setCacheAnswers( true );
100
101 return interpolator;
102 }
103
104 private static final class InterpolateObjectAction implements PrivilegedAction<ModelInterpolationException>
105 {
106
107 private final boolean debugEnabled;
108 private final LinkedList<Object> interpolationTargets;
109 private final StringSearchModelInterpolator modelInterpolator;
110 private final Logger logger;
111 private final List<ValueSource> valueSources;
112 private final List<InterpolationPostProcessor> postProcessors;
113
114 public InterpolateObjectAction( Object target, List<ValueSource> valueSources,
115 List<InterpolationPostProcessor> postProcessors, boolean debugEnabled,
116 StringSearchModelInterpolator modelInterpolator, Logger logger )
117 {
118 this.valueSources = valueSources;
119 this.postProcessors = postProcessors;
120 this.debugEnabled = debugEnabled;
121
122 this.interpolationTargets = new LinkedList<Object>();
123 interpolationTargets.add( target );
124
125 this.modelInterpolator = modelInterpolator;
126 this.logger = logger;
127 }
128
129 public ModelInterpolationException run()
130 {
131 while ( !interpolationTargets.isEmpty() )
132 {
133 Object obj = interpolationTargets.removeFirst();
134
135 try
136 {
137 traverseObjectWithParents( obj.getClass(), obj );
138 }
139 catch ( ModelInterpolationException e )
140 {
141 return e;
142 }
143 }
144
145 return null;
146 }
147
148 @SuppressWarnings( "unchecked" )
149 private void traverseObjectWithParents( Class<?> cls, Object target )
150 throws ModelInterpolationException
151 {
152 if ( cls == null )
153 {
154 return;
155 }
156
157
158 if ( cls.isArray() )
159 {
160 evaluateArray( target );
161 }
162 else if ( isQualifiedForInterpolation( cls ) )
163 {
164 Field[] fields = fieldsByClass.get( cls );
165 if ( fields == null )
166 {
167 fields = cls.getDeclaredFields();
168 fieldsByClass.put( cls, fields );
169 }
170
171 for ( int i = 0; i < fields.length; i++ )
172 {
173 Class<?> type = fields[i].getType();
174 if ( isQualifiedForInterpolation( fields[i], type ) )
175 {
176 boolean isAccessible = fields[i].isAccessible();
177 fields[i].setAccessible( true );
178 try
179 {
180 try
181 {
182 if ( String.class == type )
183 {
184 String value = (String) fields[i].get( target );
185 if ( value != null )
186 {
187 String interpolated = modelInterpolator.interpolateInternal( value, valueSources, postProcessors, debugEnabled );
188
189 if ( !interpolated.equals( value ) )
190 {
191 fields[i].set( target, interpolated );
192 }
193 }
194 }
195 else if ( Collection.class.isAssignableFrom( type ) )
196 {
197 Collection<Object> c = (Collection<Object>) fields[i].get( target );
198 if ( c != null && !c.isEmpty() )
199 {
200 List<Object> originalValues = new ArrayList<Object>( c );
201 try
202 {
203 c.clear();
204 }
205 catch ( UnsupportedOperationException e )
206 {
207 if ( debugEnabled && logger != null )
208 {
209 logger.debug( "Skipping interpolation of field: " + fields[i] + " in: "
210 + cls.getName() + "; it is an unmodifiable collection." );
211 }
212 continue;
213 }
214
215 for ( Object value : originalValues )
216 {
217 if ( value != null )
218 {
219 if ( String.class == value.getClass() )
220 {
221 String interpolated =
222 modelInterpolator.interpolateInternal( (String) value,
223 valueSources,
224 postProcessors,
225 debugEnabled );
226
227 if ( !interpolated.equals( value ) )
228 {
229 c.add( interpolated );
230 }
231 else
232 {
233 c.add( value );
234 }
235 }
236 else
237 {
238 c.add( value );
239 if ( value.getClass().isArray() )
240 {
241 evaluateArray( value );
242 }
243 else
244 {
245 interpolationTargets.add( value );
246 }
247 }
248 }
249 else
250 {
251
252 c.add( value );
253 }
254 }
255 }
256 }
257 else if ( Map.class.isAssignableFrom( type ) )
258 {
259 Map<Object, Object> m = (Map<Object, Object>) fields[i].get( target );
260 if ( m != null && !m.isEmpty() )
261 {
262 for ( Map.Entry<Object, Object> entry : m.entrySet() )
263 {
264 Object value = entry.getValue();
265
266 if ( value != null )
267 {
268 if ( String.class == value.getClass() )
269 {
270 String interpolated =
271 modelInterpolator.interpolateInternal( (String) value,
272 valueSources,
273 postProcessors,
274 debugEnabled );
275
276 if ( !interpolated.equals( value ) )
277 {
278 try
279 {
280 entry.setValue( interpolated );
281 }
282 catch ( UnsupportedOperationException e )
283 {
284 if ( debugEnabled && logger != null )
285 {
286 logger.debug( "Skipping interpolation of field: "
287 + fields[i] + " (key: " + entry.getKey() + ") in: "
288 + cls.getName()
289 + "; it is an unmodifiable collection." );
290 }
291 continue;
292 }
293 }
294 }
295 else
296 {
297 if ( value.getClass().isArray() )
298 {
299 evaluateArray( value );
300 }
301 else
302 {
303 interpolationTargets.add( value );
304 }
305 }
306 }
307 }
308 }
309 }
310 else
311 {
312 Object value = fields[i].get( target );
313 if ( value != null )
314 {
315 if ( fields[i].getType().isArray() )
316 {
317 evaluateArray( value );
318 }
319 else
320 {
321 interpolationTargets.add( value );
322 }
323 }
324 }
325 }
326 catch ( IllegalArgumentException e )
327 {
328 throw new ModelInterpolationException( "Failed to interpolate field: " + fields[i]
329 + " on class: " + cls.getName(), e );
330 }
331 catch ( IllegalAccessException e )
332 {
333 throw new ModelInterpolationException( "Failed to interpolate field: " + fields[i]
334 + " on class: " + cls.getName(), e );
335 }
336 }
337 finally
338 {
339 fields[i].setAccessible( isAccessible );
340 }
341 }
342 }
343
344 traverseObjectWithParents( cls.getSuperclass(), target );
345 }
346 }
347
348 private boolean isQualifiedForInterpolation( Class<?> cls )
349 {
350 return !cls.getPackage().getName().startsWith( "java" );
351 }
352
353 private boolean isQualifiedForInterpolation( Field field, Class<?> fieldType )
354 {
355 if ( !fieldIsPrimitiveByClass.containsKey( fieldType ) )
356 {
357 fieldIsPrimitiveByClass.put( fieldType, Boolean.valueOf( fieldType.isPrimitive() ) );
358 }
359
360 if ( fieldIsPrimitiveByClass.get( fieldType ).booleanValue() )
361 {
362 return false;
363 }
364
365
366
367
368
369
370 if ( "parent".equals( field.getName() ) )
371 {
372 return false;
373 }
374
375 return true;
376 }
377
378 private void evaluateArray( Object target )
379 throws ModelInterpolationException
380 {
381 int len = Array.getLength( target );
382 for ( int i = 0; i < len; i++ )
383 {
384 Object value = Array.get( target, i );
385 if ( value != null )
386 {
387 if ( String.class == value.getClass() )
388 {
389 String interpolated =
390 modelInterpolator.interpolateInternal( (String) value, valueSources, postProcessors,
391 debugEnabled );
392
393 if ( !interpolated.equals( value ) )
394 {
395 Array.set( target, i, interpolated );
396 }
397 }
398 else
399 {
400 interpolationTargets.add( value );
401 }
402 }
403 }
404 }
405 }
406
407 }