001package org.apache.maven.model.interpolation;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *   http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import org.apache.maven.model.InputLocation;
023import org.apache.maven.model.InputSource;
024import org.apache.maven.model.Model;
025import org.apache.maven.model.building.DefaultModelBuildingRequest;
026import org.apache.maven.model.building.ModelBuildingRequest;
027import org.apache.maven.model.building.SimpleProblemCollector;
028
029import java.io.File;
030import java.util.*;
031import java.util.concurrent.Callable;
032import java.util.concurrent.CountDownLatch;
033import java.util.concurrent.Future;
034import java.util.concurrent.FutureTask;
035
036/**
037 * @author jdcasey
038 * @author Benjamin Bentmann
039 */
040public class StringSearchModelInterpolatorTest
041    extends AbstractModelInterpolatorTest 
042{
043
044    protected ModelInterpolator interpolator;
045
046    @Override
047    protected void setUp()
048        throws Exception
049    {
050        super.setUp();
051        interpolator = lookup( ModelInterpolator.class );
052    }
053
054
055    protected ModelInterpolator createInterpolator( org.apache.maven.model.path.PathTranslator translator )
056        throws Exception
057    {
058        return this.interpolator;
059    }
060
061    protected ModelInterpolator createInterpolator()
062        throws Exception
063    {
064        return this.interpolator;
065    }
066
067    public void testInterpolateStringArray()
068        throws Exception
069    {
070        Model model = new Model();
071
072        Properties p = new Properties();
073        p.setProperty( "key", "value" );
074        p.setProperty( "key2", "value2" );
075
076        String[] values = { "${key}", "${key2}" };
077
078        StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
079
080        ModelBuildingRequest config = createModelBuildingRequest(p);
081
082        final SimpleProblemCollector collector = new SimpleProblemCollector();
083        interpolator.interpolateObject( values, model, new File( "." ), config, collector );
084        assertProblemFree( collector );        
085
086        assertEquals( "value", values[0] );
087        assertEquals( "value2", values[1] );
088    }
089
090    private ModelBuildingRequest createModelBuildingRequest( Properties p )
091    {
092        ModelBuildingRequest config = new DefaultModelBuildingRequest();
093        config.setSystemProperties( p );
094        return config;
095    }
096
097    public void testInterpolateObjectWithStringArrayField()
098        throws Exception
099    {
100        Model model = new Model();
101
102        Properties p = new Properties();
103        p.setProperty( "key", "value" );
104        p.setProperty( "key2", "value2" );
105
106        String[] values = { "${key}", "${key2}" };
107
108        ObjectWithStringArrayField obj = new ObjectWithStringArrayField( values );
109
110        StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
111
112        ModelBuildingRequest config = createModelBuildingRequest( p );
113
114        final SimpleProblemCollector collector = new SimpleProblemCollector();
115        interpolator.interpolateObject( obj, model, new File( "." ), config, collector );
116        assertProblemFree( collector );        
117
118        assertEquals( "value", obj.values[0] );
119        assertEquals( "value2", obj.values[1] );
120    }
121
122    public void testInterpolateObjectWithStringListField()
123        throws Exception
124    {
125        Model model = new Model();
126
127        Properties p = new Properties();
128        p.setProperty( "key", "value" );
129        p.setProperty( "key2", "value2" );
130
131        List<String> values = new ArrayList<String>();
132        values.add( "${key}" );
133        values.add( "${key2}" );
134
135        ObjectWithListField obj = new ObjectWithListField( values );
136
137        StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
138
139        ModelBuildingRequest config = createModelBuildingRequest( p );
140
141        final SimpleProblemCollector collector = new SimpleProblemCollector();
142        interpolator.interpolateObject( obj, model, new File( "." ), config, collector );
143        assertProblemFree( collector );
144
145        assertEquals( "value", obj.values.get( 0 ) );
146        assertEquals( "value2", obj.values.get( 1 ) );
147    }
148
149    public void testInterpolateObjectWithStringListFieldAndOneLiteralValue()
150        throws Exception
151    {
152        Model model = new Model();
153
154        Properties p = new Properties();
155        p.setProperty( "key", "value" );
156        p.setProperty( "key2", "value2" );
157
158        List<String> values = new ArrayList<String>();
159        values.add( "key" );
160        values.add( "${key2}" );
161
162        ObjectWithListField obj = new ObjectWithListField( values );
163
164        StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
165
166        ModelBuildingRequest config = createModelBuildingRequest( p );
167
168        final SimpleProblemCollector collector = new SimpleProblemCollector();
169        interpolator.interpolateObject( obj, model, new File( "." ), config, collector );
170        assertProblemFree( collector );        
171
172        assertEquals( "key", obj.values.get( 0 ) );
173        assertEquals( "value2", obj.values.get( 1 ) );
174    }
175
176    public void testInterpolateObjectWithUnmodifiableStringListField()
177        throws Exception
178    {
179        Model model = new Model();
180
181        Properties p = new Properties();
182        p.setProperty( "key", "value" );
183        p.setProperty( "key2", "value2" );
184
185        List<String> values = Collections.unmodifiableList( Collections.singletonList( "${key}" ) );
186
187        ObjectWithListField obj = new ObjectWithListField( values );
188
189        StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
190
191        ModelBuildingRequest config = createModelBuildingRequest( p );
192
193        final SimpleProblemCollector collector = new SimpleProblemCollector();
194        interpolator.interpolateObject( obj, model, new File( "." ), config, collector );
195        assertProblemFree( collector );        
196
197        assertEquals( "${key}", obj.values.get( 0 ) );
198    }
199
200    public void testInterpolateObjectWithStringArrayListField()
201        throws Exception
202    {
203        Model model = new Model();
204
205        Properties p = new Properties();
206        p.setProperty( "key", "value" );
207        p.setProperty( "key2", "value2" );
208        p.setProperty( "key3", "value3" );
209        p.setProperty( "key4", "value4" );
210
211        List<String[]> values = new ArrayList<String[]>();
212        values.add( new String[] { "${key}", "${key2}" } );
213        values.add( new String[] { "${key3}", "${key4}" } );
214
215        ObjectWithListField obj = new ObjectWithListField( values );
216
217        StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
218
219        ModelBuildingRequest config = createModelBuildingRequest( p );
220
221        final SimpleProblemCollector collector = new SimpleProblemCollector();
222        interpolator.interpolateObject( obj, model, new File( "." ), config, collector );
223        assertProblemFree( collector );
224
225        assertEquals( "value", ( (String[]) obj.values.get( 0 ) )[0] );
226        assertEquals( "value2", ( (String[]) obj.values.get( 0 ) )[1] );
227        assertEquals( "value3", ( (String[]) obj.values.get( 1 ) )[0] );
228        assertEquals( "value4", ( (String[]) obj.values.get( 1 ) )[1] );
229    }
230
231    public void testInterpolateObjectWithStringToStringMapField()
232        throws Exception
233    {
234        Model model = new Model();
235
236        Properties p = new Properties();
237        p.setProperty( "key", "value" );
238        p.setProperty( "key2", "value2" );
239
240        Map<String, String> values = new HashMap<String, String>();
241        values.put( "key", "${key}" );
242        values.put( "key2", "${key2}" );
243
244        ObjectWithMapField obj = new ObjectWithMapField( values );
245
246        StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
247
248        ModelBuildingRequest config = createModelBuildingRequest( p );
249
250        final SimpleProblemCollector collector = new SimpleProblemCollector();
251        interpolator.interpolateObject( obj, model, new File( "." ), config, collector );
252        assertProblemFree( collector );
253
254        assertEquals( "value", obj.values.get( "key" ) );
255        assertEquals( "value2", obj.values.get( "key2" ) );
256    }
257
258    public void testInterpolateObjectWithStringToStringMapFieldAndOneLiteralValue()
259        throws Exception
260    {
261        Model model = new Model();
262
263        Properties p = new Properties();
264        p.setProperty( "key", "value" );
265        p.setProperty( "key2", "value2" );
266
267        Map<String, String> values = new HashMap<String, String>();
268        values.put( "key", "val" );
269        values.put( "key2", "${key2}" );
270
271        ObjectWithMapField obj = new ObjectWithMapField( values );
272
273        StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
274
275        ModelBuildingRequest config = createModelBuildingRequest( p );
276
277        final SimpleProblemCollector collector = new SimpleProblemCollector();
278        interpolator.interpolateObject( obj, model, new File( "." ), config, collector );
279        assertProblemFree( collector );        
280
281        assertEquals( "val", obj.values.get( "key" ) );
282        assertEquals( "value2", obj.values.get( "key2" ) );
283    }
284
285    public void testInterpolateObjectWithUnmodifiableStringToStringMapField()
286        throws Exception
287    {
288        Model model = new Model();
289
290        Properties p = new Properties();
291        p.setProperty( "key", "value" );
292        p.setProperty( "key2", "value2" );
293
294        Map<String, String> values = Collections.unmodifiableMap( Collections.singletonMap( "key", "${key}" ) );
295
296        ObjectWithMapField obj = new ObjectWithMapField( values );
297
298        StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
299
300        ModelBuildingRequest config = createModelBuildingRequest( p );
301
302        final SimpleProblemCollector collector = new SimpleProblemCollector();
303        interpolator.interpolateObject( obj, model, new File( "." ), config, collector );
304        assertProblemFree( collector );
305
306        assertEquals( "${key}", obj.values.get( "key" ) );
307    }
308
309    public void testInterpolateObjectWithStringToStringArrayMapField()
310        throws Exception
311    {
312        Model model = new Model();
313
314        Properties p = new Properties();
315        p.setProperty( "key", "value" );
316        p.setProperty( "key2", "value2" );
317        p.setProperty( "key3", "value3" );
318        p.setProperty( "key4", "value4" );
319
320        Map<String, String[]> values = new HashMap<String, String[]>();
321        values.put( "key", new String[] { "${key}", "${key2}" } );
322        values.put( "key2", new String[] { "${key3}", "${key4}" } );
323
324        ObjectWithMapField obj = new ObjectWithMapField( values );
325
326        StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
327
328        ModelBuildingRequest config = createModelBuildingRequest( p );
329
330        final SimpleProblemCollector collector = new SimpleProblemCollector();
331        interpolator.interpolateObject( obj, model, new File( "." ), config, collector );
332        assertProblemFree( collector );        
333
334        assertEquals( "value", ( (String[]) obj.values.get( "key" ) )[0] );
335        assertEquals( "value2", ( (String[]) obj.values.get( "key" ) )[1] );
336        assertEquals( "value3", ( (String[]) obj.values.get( "key2" ) )[0] );
337        assertEquals( "value4", ( (String[]) obj.values.get( "key2" ) )[1] );
338    }
339
340
341    public void testConcurrentInterpolation()
342        throws Exception
343    {
344        final Model model = new Model();
345
346        final Properties p = new Properties();
347        p.setProperty( "key", "value" );
348        p.setProperty( "key2", "value2" );
349        p.setProperty( "key3", "value3" );
350        p.setProperty( "key4", "value4" );
351        p.setProperty( "key5", "value5" );
352
353        final StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
354
355
356        int numItems = 100;
357        final CountDownLatch countDownLatch = new CountDownLatch(1);
358
359        List<Future<SimpleProblemCollector>>  futures = new ArrayList<Future<SimpleProblemCollector>>();
360        for ( int i = 0; i < numItems; i++ )
361        {
362            Callable<SimpleProblemCollector> future = new Callable<SimpleProblemCollector>()
363            {
364                public SimpleProblemCollector call()
365                    throws Exception
366                {
367                    final ObjectWithMixedProtection obj = getValueList();
368                    final ModelBuildingRequest config = createModelBuildingRequest( p );
369
370                    countDownLatch.await();
371                    final SimpleProblemCollector collector = new SimpleProblemCollector();
372                    interpolator.interpolateObject( obj, model, new File( "." ), config, collector );
373                    return collector;
374                }
375            };
376            FutureTask<SimpleProblemCollector> task = new FutureTask<SimpleProblemCollector>( future );
377            futures.add( task );
378            new Thread( task ).start();
379        }
380        countDownLatch.countDown(); // Start all the threads
381        for ( Future<SimpleProblemCollector> result : futures )
382        {
383            SimpleProblemCollector problemCollector = result.get(); // ArrayIndexOutOfBoundsException are typical indication of threading issues
384            assertProblemFree( problemCollector );
385        }
386    }
387
388    private ObjectWithMixedProtection getValueList()
389    {
390        List<String[]> values = new ArrayList<String[]>();
391
392        values.add( new String[] { "${key}", "${key2}" } );
393        values.add( new String[] { "${key3}", "${key4}" } );
394        List<String> values2 = new ArrayList<String>();
395        values.add( new String[] { "${key}", "${key2}" } );
396        values.add( new String[] { "${key3}", "${key4}" } );
397        List<String> values3 = new ArrayList<String>();
398        values.add( new String[] { "${key}", "${key2}" } );
399        values.add( new String[] { "${key3}", "${key4}" } );
400
401        return new ObjectWithMixedProtection( values, values2, values3, "${key5}" );
402    }
403
404
405    private static final class ObjectWithStringArrayField
406    {
407        private final String[] values;
408
409        public ObjectWithStringArrayField( String[] values )
410        {
411            this.values = values;
412        }
413    }
414
415    private static final class ObjectWithListField
416    {
417        private final List<?> values;
418
419        public ObjectWithListField( List<?> values )
420        {
421            this.values = values;
422        }
423    }
424
425    private static final class ObjectWithMapField
426    {
427        private final Map<?, ?> values;
428
429        public ObjectWithMapField( Map<?, ?> values )
430        {
431            this.values = values;
432        }
433    }
434
435    @SuppressWarnings( "unused" )
436    private static final class ObjectWithMixedProtection
437    {
438        private List<?> values1;
439        protected List<?> values2;
440        List<?> values3;
441        private String fooBar;
442
443        private ObjectWithMixedProtection( List<?> values1, List<?> values2, List<?> values3 )
444        {
445            this.values1 = values1;
446            this.values2 = values2;
447            this.values3 = values3;
448        }
449
450        private ObjectWithMixedProtection( List<?> values1, List<?> values2, List<?> values3, String fooBar )
451        {
452            this.values1 = values1;
453            this.values2 = values2;
454            this.values3 = values3;
455            this.fooBar = fooBar;
456        }
457
458        public String getFooBar()
459        {
460            return fooBar;
461        }
462    }
463    
464    public void testFinalFieldsExcludedFromInterpolation()
465    {
466        Properties props = new Properties();
467        props.setProperty( "expression", "value" );
468        DefaultModelBuildingRequest request = new DefaultModelBuildingRequest();
469        request.setUserProperties( props );
470
471        SimpleProblemCollector problems = new SimpleProblemCollector();
472        StringSearchModelInterpolator interpolator = new StringSearchModelInterpolator();
473        interpolator.interpolateObject( new ClassWithFinalField(), new Model(), null, request, problems );
474
475        assertProblemFree(  problems );
476    }
477
478    static class ClassWithFinalField
479    {
480        public static final String CONSTANT = "${expression}";
481    }
482
483    public void testLocationTrackerShouldBeExcludedFromInterpolation()
484    {
485        Properties props = new Properties();
486        props.setProperty( "expression", "value" );
487        DefaultModelBuildingRequest request = new DefaultModelBuildingRequest();
488        request.setUserProperties( props );
489
490        InputSource source = new InputSource();
491        source.setLocation( "${expression}" );
492        source.setModelId( "${expression}" );
493        Model model = new Model();
494        model.setLocation( "", new InputLocation( 1, 1, source ) );
495
496        SimpleProblemCollector problems = new SimpleProblemCollector();
497        StringSearchModelInterpolator interpolator = new StringSearchModelInterpolator();
498        interpolator.interpolateObject( model, model, null, request, problems );
499
500        assertProblemFree( problems );
501        assertEquals( "${expression}", source.getLocation() );
502        assertEquals( "${expression}", source.getModelId() );
503    }
504
505}