001    package 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    
022    import org.apache.maven.model.InputLocation;
023    import org.apache.maven.model.InputSource;
024    import org.apache.maven.model.Model;
025    import org.apache.maven.model.building.DefaultModelBuildingRequest;
026    import org.apache.maven.model.building.ModelBuildingRequest;
027    import org.apache.maven.model.building.SimpleProblemCollector;
028    
029    import java.io.File;
030    import java.util.*;
031    import java.util.concurrent.Callable;
032    import java.util.concurrent.CountDownLatch;
033    import java.util.concurrent.Future;
034    import java.util.concurrent.FutureTask;
035    
036    /**
037     * @author jdcasey
038     * @author Benjamin Bentmann
039     */
040    public 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    }