View Javadoc

1   package org.apache.maven.project.interpolation;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
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                                                 // add the null back in...not sure what else to do...
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 //            if ( fieldType.isPrimitive() )
366 //            {
367 //                return false;
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 }