View Javadoc
1   package org.apache.maven.model.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.InputLocation;
23  import org.apache.maven.model.InputSource;
24  import org.apache.maven.model.Model;
25  import org.apache.maven.model.building.DefaultModelBuildingRequest;
26  import org.apache.maven.model.building.ModelBuildingRequest;
27  import org.apache.maven.model.building.SimpleProblemCollector;
28  
29  import java.io.File;
30  import java.util.*;
31  import java.util.concurrent.Callable;
32  import java.util.concurrent.CountDownLatch;
33  import java.util.concurrent.Future;
34  import java.util.concurrent.FutureTask;
35  
36  import static org.hamcrest.CoreMatchers.anyOf;
37  import static org.hamcrest.CoreMatchers.is;
38  import static org.junit.Assert.assertThat;
39  import static org.powermock.reflect.Whitebox.getField;
40  import static org.powermock.reflect.Whitebox.getInternalState;
41  
42  /**
43   * @author jdcasey
44   * @author Benjamin Bentmann
45   */
46  public class StringSearchModelInterpolatorTest
47      extends AbstractModelInterpolatorTest
48  {
49  
50      protected ModelInterpolator interpolator;
51  
52      @Override
53      protected void setUp()
54          throws Exception
55      {
56          super.setUp();
57          interpolator = new StringSearchModelInterpolator();
58      }
59  
60  
61      protected ModelInterpolator createInterpolator( org.apache.maven.model.path.PathTranslator translator )
62          throws Exception
63      {
64          return this.interpolator;
65      }
66  
67      protected ModelInterpolator createInterpolator()
68          throws Exception
69      {
70          return this.interpolator;
71      }
72  
73      public void testInterpolateStringArray()
74          throws Exception
75      {
76          Model model = new Model();
77  
78          Properties p = new Properties();
79          p.setProperty( "key", "value" );
80          p.setProperty( "key2", "value2" );
81  
82          String[] values = { "${key}", "${key2}" };
83  
84          StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
85  
86          ModelBuildingRequest config = createModelBuildingRequest(p);
87  
88          final SimpleProblemCollector collector = new SimpleProblemCollector();
89          interpolator.interpolateObject( values, model, new File( "." ), config, collector );
90          assertProblemFree( collector );
91  
92          assertEquals( "value", values[0] );
93          assertEquals( "value2", values[1] );
94      }
95  
96      private ModelBuildingRequest createModelBuildingRequest( Properties p )
97      {
98          ModelBuildingRequest config = new DefaultModelBuildingRequest();
99          config.setSystemProperties( p );
100         return config;
101     }
102 
103     public void testInterpolateObjectWithStringArrayField()
104         throws Exception
105     {
106         Model model = new Model();
107 
108         Properties p = new Properties();
109         p.setProperty( "key", "value" );
110         p.setProperty( "key2", "value2" );
111 
112         String[] values = { "${key}", "${key2}" };
113 
114         ObjectWithStringArrayField obj = new ObjectWithStringArrayField( values );
115 
116         StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
117 
118         ModelBuildingRequest config = createModelBuildingRequest( p );
119 
120         final SimpleProblemCollector collector = new SimpleProblemCollector();
121         interpolator.interpolateObject( obj, model, new File( "." ), config, collector );
122         assertProblemFree( collector );
123 
124         assertEquals( "value", obj.values[0] );
125         assertEquals( "value2", obj.values[1] );
126     }
127 
128     public void testInterpolateObjectWithStringListField()
129         throws Exception
130     {
131         Model model = new Model();
132 
133         Properties p = new Properties();
134         p.setProperty( "key", "value" );
135         p.setProperty( "key2", "value2" );
136 
137         List<String> values = new ArrayList<>();
138         values.add( "${key}" );
139         values.add( "${key2}" );
140 
141         ObjectWithListField obj = new ObjectWithListField( values );
142 
143         StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
144 
145         ModelBuildingRequest config = createModelBuildingRequest( p );
146 
147         final SimpleProblemCollector collector = new SimpleProblemCollector();
148         interpolator.interpolateObject( obj, model, new File( "." ), config, collector );
149         assertProblemFree( collector );
150 
151         assertEquals( "value", obj.values.get( 0 ) );
152         assertEquals( "value2", obj.values.get( 1 ) );
153     }
154 
155     public void testInterpolateObjectWithStringListFieldAndOneLiteralValue()
156         throws Exception
157     {
158         Model model = new Model();
159 
160         Properties p = new Properties();
161         p.setProperty( "key", "value" );
162         p.setProperty( "key2", "value2" );
163 
164         List<String> values = new ArrayList<>();
165         values.add( "key" );
166         values.add( "${key2}" );
167 
168         ObjectWithListField obj = new ObjectWithListField( values );
169 
170         StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
171 
172         ModelBuildingRequest config = createModelBuildingRequest( p );
173 
174         final SimpleProblemCollector collector = new SimpleProblemCollector();
175         interpolator.interpolateObject( obj, model, new File( "." ), config, collector );
176         assertProblemFree( collector );
177 
178         assertEquals( "key", obj.values.get( 0 ) );
179         assertEquals( "value2", obj.values.get( 1 ) );
180     }
181 
182     public void testInterpolateObjectWithUnmodifiableStringListField()
183         throws Exception
184     {
185         Model model = new Model();
186 
187         Properties p = new Properties();
188         p.setProperty( "key", "value" );
189         p.setProperty( "key2", "value2" );
190 
191         List<String> values = Collections.unmodifiableList( Collections.singletonList( "${key}" ) );
192 
193         ObjectWithListField obj = new ObjectWithListField( values );
194 
195         StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
196 
197         ModelBuildingRequest config = createModelBuildingRequest( p );
198 
199         final SimpleProblemCollector collector = new SimpleProblemCollector();
200         interpolator.interpolateObject( obj, model, new File( "." ), config, collector );
201         assertProblemFree( collector );
202 
203         assertEquals( "${key}", obj.values.get( 0 ) );
204     }
205 
206     public void testInterpolateObjectWithStringArrayListField()
207         throws Exception
208     {
209         Model model = new Model();
210 
211         Properties p = new Properties();
212         p.setProperty( "key", "value" );
213         p.setProperty( "key2", "value2" );
214         p.setProperty( "key3", "value3" );
215         p.setProperty( "key4", "value4" );
216 
217         List<String[]> values = new ArrayList<>();
218         values.add( new String[] { "${key}", "${key2}" } );
219         values.add( new String[] { "${key3}", "${key4}" } );
220 
221         ObjectWithListField obj = new ObjectWithListField( values );
222 
223         StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
224 
225         ModelBuildingRequest config = createModelBuildingRequest( p );
226 
227         final SimpleProblemCollector collector = new SimpleProblemCollector();
228         interpolator.interpolateObject( obj, model, new File( "." ), config, collector );
229         assertProblemFree( collector );
230 
231         assertEquals( "value", ( (String[]) obj.values.get( 0 ) )[0] );
232         assertEquals( "value2", ( (String[]) obj.values.get( 0 ) )[1] );
233         assertEquals( "value3", ( (String[]) obj.values.get( 1 ) )[0] );
234         assertEquals( "value4", ( (String[]) obj.values.get( 1 ) )[1] );
235     }
236 
237     public void testInterpolateObjectWithStringToStringMapField()
238         throws Exception
239     {
240         Model model = new Model();
241 
242         Properties p = new Properties();
243         p.setProperty( "key", "value" );
244         p.setProperty( "key2", "value2" );
245 
246         Map<String, String> values = new HashMap<>();
247         values.put( "key", "${key}" );
248         values.put( "key2", "${key2}" );
249 
250         ObjectWithMapField obj = new ObjectWithMapField( values );
251 
252         StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
253 
254         ModelBuildingRequest config = createModelBuildingRequest( p );
255 
256         final SimpleProblemCollector collector = new SimpleProblemCollector();
257         interpolator.interpolateObject( obj, model, new File( "." ), config, collector );
258         assertProblemFree( collector );
259 
260         assertEquals( "value", obj.values.get( "key" ) );
261         assertEquals( "value2", obj.values.get( "key2" ) );
262     }
263 
264     public void testInterpolateObjectWithStringToStringMapFieldAndOneLiteralValue()
265         throws Exception
266     {
267         Model model = new Model();
268 
269         Properties p = new Properties();
270         p.setProperty( "key", "value" );
271         p.setProperty( "key2", "value2" );
272 
273         Map<String, String> values = new HashMap<>();
274         values.put( "key", "val" );
275         values.put( "key2", "${key2}" );
276 
277         ObjectWithMapField obj = new ObjectWithMapField( values );
278 
279         StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
280 
281         ModelBuildingRequest config = createModelBuildingRequest( p );
282 
283         final SimpleProblemCollector collector = new SimpleProblemCollector();
284         interpolator.interpolateObject( obj, model, new File( "." ), config, collector );
285         assertProblemFree( collector );
286 
287         assertEquals( "val", obj.values.get( "key" ) );
288         assertEquals( "value2", obj.values.get( "key2" ) );
289     }
290 
291     public void testInterpolateObjectWithUnmodifiableStringToStringMapField()
292         throws Exception
293     {
294         Model model = new Model();
295 
296         Properties p = new Properties();
297         p.setProperty( "key", "value" );
298         p.setProperty( "key2", "value2" );
299 
300         Map<String, String> values = Collections.unmodifiableMap( Collections.singletonMap( "key", "${key}" ) );
301 
302         ObjectWithMapField obj = new ObjectWithMapField( values );
303 
304         StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
305 
306         ModelBuildingRequest config = createModelBuildingRequest( p );
307 
308         final SimpleProblemCollector collector = new SimpleProblemCollector();
309         interpolator.interpolateObject( obj, model, new File( "." ), config, collector );
310         assertProblemFree( collector );
311 
312         assertEquals( "${key}", obj.values.get( "key" ) );
313     }
314 
315     public void testInterpolateObjectWithStringToStringArrayMapField()
316         throws Exception
317     {
318         Model model = new Model();
319 
320         Properties p = new Properties();
321         p.setProperty( "key", "value" );
322         p.setProperty( "key2", "value2" );
323         p.setProperty( "key3", "value3" );
324         p.setProperty( "key4", "value4" );
325 
326         Map<String, String[]> values = new HashMap<>();
327         values.put( "key", new String[] { "${key}", "${key2}" } );
328         values.put( "key2", new String[] { "${key3}", "${key4}" } );
329 
330         ObjectWithMapField obj = new ObjectWithMapField( values );
331 
332         StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
333 
334         ModelBuildingRequest config = createModelBuildingRequest( p );
335 
336         final SimpleProblemCollector collector = new SimpleProblemCollector();
337         interpolator.interpolateObject( obj, model, new File( "." ), config, collector );
338         assertProblemFree( collector );
339 
340         assertEquals( "value", ( (String[]) obj.values.get( "key" ) )[0] );
341         assertEquals( "value2", ( (String[]) obj.values.get( "key" ) )[1] );
342         assertEquals( "value3", ( (String[]) obj.values.get( "key2" ) )[0] );
343         assertEquals( "value4", ( (String[]) obj.values.get( "key2" ) )[1] );
344     }
345 
346     public void testInterpolateObjectWithPomFile()
347             throws Exception
348     {
349         Model model = new Model();
350         model.setPomFile( new File( System.getProperty( "user.dir" ), "pom.xml" ) );
351         File baseDir = model.getProjectDirectory();
352 
353         Properties p = new Properties();
354 
355         Map<String, String> values = new HashMap<>();
356         values.put( "key", "${project.basedir}" + File.separator + "target" );
357 
358         ObjectWithMapField obj = new ObjectWithMapField( values );
359 
360         StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
361 
362         ModelBuildingRequest config = createModelBuildingRequest( p );
363 
364         SimpleProblemCollector collector = new SimpleProblemCollector();
365         interpolator.interpolateObject( obj, model, new File( "." ), config, collector );
366         assertProblemFree( collector );
367 
368         assertThat( baseDir.getCanonicalPath(), is( System.getProperty( "user.dir" ) ) );
369         assertThat( obj.values.size(), is( 1 ) );
370         assertThat( (String) obj.values.get( "key" ), is( anyOf(
371                 is( System.getProperty( "user.dir" ) + File.separator + "target" ),
372                 // TODO why MVN adds dot /./ in paths???
373                 is( System.getProperty( "user.dir" ) + File.separator + '.' + File.separator + "target" )
374         ) ) );
375     }
376 
377     public void testNotInterpolateObjectWithFile()
378             throws Exception
379     {
380         Model model = new Model();
381 
382         File baseDir = new File( System.getProperty( "user.dir" ) );
383 
384         Properties p = new Properties();
385 
386         ObjectWithNotInterpolatedFile obj = new ObjectWithNotInterpolatedFile( baseDir );
387 
388         StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
389 
390         ModelBuildingRequest config = createModelBuildingRequest( p );
391 
392         SimpleProblemCollector collector = new SimpleProblemCollector();
393         interpolator.interpolateObject( obj, model, new File( "." ), config, collector );
394         assertProblemFree( collector );
395 
396         //noinspection unchecked
397         Map<Class<?>, ?> cache =
398                 (Map<Class<?>, ?>) getField( StringSearchModelInterpolator.class, "CACHED_ENTRIES" )
399                         .get( null );
400 
401         Object objCacheItem = cache.get( Object.class );
402         Object fileCacheItem = cache.get( File.class );
403 
404         assertNotNull( objCacheItem );
405         assertNotNull( fileCacheItem );
406 
407         assertThat( ( (Object[]) getInternalState( objCacheItem, "fields" ) ).length, is( 0 ) );
408         assertThat( ( (Object[]) getInternalState( fileCacheItem, "fields" ) ).length, is( 0 ) );
409     }
410 
411     public void testNotInterpolateFile()
412             throws Exception
413     {
414         Model model = new Model();
415 
416         File baseDir = new File( System.getProperty( "user.dir" ) );
417 
418         Properties p = new Properties();
419 
420         StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
421 
422         ModelBuildingRequest config = createModelBuildingRequest( p );
423 
424         SimpleProblemCollector collector = new SimpleProblemCollector();
425         interpolator.interpolateObject( baseDir, model, new File( "." ), config, collector );
426         assertProblemFree( collector );
427 
428         //noinspection unchecked
429         Map<Class<?>, ?> cache =
430                 (Map<Class<?>, ?>) getField( StringSearchModelInterpolator.class, "CACHED_ENTRIES" )
431                         .get( null );
432 
433         Object fileCacheItem = cache.get( File.class );
434 
435         assertNotNull( fileCacheItem );
436 
437         assertThat( ( (Object[]) getInternalState( fileCacheItem, "fields" ) ).length, is( 0 ) );
438     }
439 
440 
441     public void testConcurrentInterpolation()
442         throws Exception
443     {
444         final Model model = new Model();
445 
446         final Properties p = new Properties();
447         p.setProperty( "key", "value" );
448         p.setProperty( "key2", "value2" );
449         p.setProperty( "key3", "value3" );
450         p.setProperty( "key4", "value4" );
451         p.setProperty( "key5", "value5" );
452 
453         final StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
454 
455 
456         int numItems = 100;
457         final CountDownLatch countDownLatch = new CountDownLatch(1);
458 
459         List<Future<SimpleProblemCollector>>  futures = new ArrayList<>();
460         for ( int i = 0; i < numItems; i++ )
461         {
462             Callable<SimpleProblemCollector> future = new Callable<SimpleProblemCollector>()
463             {
464                 public SimpleProblemCollector call()
465                     throws Exception
466                 {
467                     final ObjectWithMixedProtection obj = getValueList();
468                     final ModelBuildingRequest config = createModelBuildingRequest( p );
469 
470                     countDownLatch.await();
471                     final SimpleProblemCollector collector = new SimpleProblemCollector();
472                     interpolator.interpolateObject( obj, model, new File( "." ), config, collector );
473                     return collector;
474                 }
475             };
476             FutureTask<SimpleProblemCollector> task = new FutureTask<>( future );
477             futures.add( task );
478             new Thread( task ).start();
479         }
480         countDownLatch.countDown(); // Start all the threads
481         for ( Future<SimpleProblemCollector> result : futures )
482         {
483             SimpleProblemCollector problemCollector = result.get(); // ArrayIndexOutOfBoundsException are typical indication of threading issues
484             assertProblemFree( problemCollector );
485         }
486     }
487 
488     private ObjectWithMixedProtection getValueList()
489     {
490         List<String[]> values = new ArrayList<>();
491 
492         values.add( new String[] { "${key}", "${key2}" } );
493         values.add( new String[] { "${key3}", "${key4}" } );
494         List<String> values2 = new ArrayList<>();
495         values.add( new String[] { "${key}", "${key2}" } );
496         values.add( new String[] { "${key3}", "${key4}" } );
497         List<String> values3 = new ArrayList<>();
498         values.add( new String[] { "${key}", "${key2}" } );
499         values.add( new String[] { "${key3}", "${key4}" } );
500 
501         return new ObjectWithMixedProtection( values, values2, values3, "${key5}" );
502     }
503 
504 
505     private static final class ObjectWithStringArrayField
506     {
507         private final String[] values;
508 
509         public ObjectWithStringArrayField( String[] values )
510         {
511             this.values = values;
512         }
513     }
514 
515     private static final class ObjectWithListField
516     {
517         private final List<?> values;
518 
519         public ObjectWithListField( List<?> values )
520         {
521             this.values = values;
522         }
523     }
524 
525     private static final class ObjectWithMapField
526     {
527         private final Map<?, ?> values;
528 
529         public ObjectWithMapField( Map<?, ?> values )
530         {
531             this.values = values;
532         }
533     }
534 
535     private static final class ObjectWithNotInterpolatedFile
536     {
537         private final File f;
538 
539         ObjectWithNotInterpolatedFile( File f )
540         {
541             this.f = f;
542         }
543     }
544 
545     @SuppressWarnings( "unused" )
546     private static final class ObjectWithMixedProtection
547     {
548         private List<?> values1;
549         protected List<?> values2;
550         List<?> values3;
551         private String fooBar;
552 
553         private ObjectWithMixedProtection( List<?> values1, List<?> values2, List<?> values3 )
554         {
555             this.values1 = values1;
556             this.values2 = values2;
557             this.values3 = values3;
558         }
559 
560         private ObjectWithMixedProtection( List<?> values1, List<?> values2, List<?> values3, String fooBar )
561         {
562             this.values1 = values1;
563             this.values2 = values2;
564             this.values3 = values3;
565             this.fooBar = fooBar;
566         }
567 
568         public String getFooBar()
569         {
570             return fooBar;
571         }
572     }
573 
574     public void testFinalFieldsExcludedFromInterpolation()
575     {
576         Properties props = new Properties();
577         props.setProperty( "expression", "value" );
578         DefaultModelBuildingRequest request = new DefaultModelBuildingRequest();
579         request.setUserProperties( props );
580 
581         SimpleProblemCollector problems = new SimpleProblemCollector();
582         StringSearchModelInterpolator interpolator = new StringSearchModelInterpolator();
583         interpolator.interpolateObject( new ClassWithFinalField(), new Model(), null, request, problems );
584 
585         assertProblemFree(  problems );
586     }
587 
588     static class ClassWithFinalField
589     {
590         public static final String CONSTANT = "${expression}";
591     }
592 
593     public void testLocationTrackerShouldBeExcludedFromInterpolation()
594     {
595         Properties props = new Properties();
596         props.setProperty( "expression", "value" );
597         DefaultModelBuildingRequest request = new DefaultModelBuildingRequest();
598         request.setUserProperties( props );
599 
600         InputSource source = new InputSource();
601         source.setLocation( "${expression}" );
602         source.setModelId( "${expression}" );
603         Model model = new Model();
604         model.setLocation( "", new InputLocation( 1, 1, source ) );
605 
606         SimpleProblemCollector problems = new SimpleProblemCollector();
607         StringSearchModelInterpolator interpolator = new StringSearchModelInterpolator();
608         interpolator.interpolateObject( model, model, null, request, problems );
609 
610         assertProblemFree( problems );
611         assertEquals( "${expression}", source.getLocation() );
612         assertEquals( "${expression}", source.getModelId() );
613     }
614 
615 }