View Javadoc

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