[MNG-4542] StringSearchModelInterpolator concurrency problem

Revived test from 2.2.X code base, fixed concurrency issue and added concurrency test

git-svn-id: https://svn.apache.org/repos/asf/maven/maven-3/trunk@902080 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Kristian Rosenvold 2010-01-22 13:35:34 +00:00
parent 664537e3f8
commit 0bfae6deed
4 changed files with 945 additions and 55 deletions

View File

@ -60,7 +60,7 @@ public abstract class AbstractStringBasedModelInterpolator
/**
* The default format used for build timestamps.
*/
private static final String DEFAULT_BUILD_TIMESTAMP_FORMAT = "yyyyMMdd-HHmm";
static final String DEFAULT_BUILD_TIMESTAMP_FORMAT = "yyyyMMdd-HHmm";
/**
* The name of a property that if present in the model's {@code <properties>} section specifies a custom format for

View File

@ -58,12 +58,14 @@ public Model interpolateModel( Model model, File projectDir, ModelBuildingReques
return model;
}
protected void interpolateObject( Object obj, Model model, File projectDir, ModelBuildingRequest config, ModelProblemCollector problems )
protected void interpolateObject( Object obj, Model model, File projectDir, ModelBuildingRequest config,
ModelProblemCollector problems )
{
try
{
List<? extends ValueSource> valueSources = createValueSources( model, projectDir, config, problems );
List<? extends InterpolationPostProcessor> postProcessors = createPostProcessors( model, projectDir, config );
List<? extends InterpolationPostProcessor> postProcessors = createPostProcessors( model, projectDir,
config );
InterpolateObjectAction action =
new InterpolateObjectAction( obj, valueSources, postProcessors, this, problems );
@ -95,7 +97,7 @@ private static final class InterpolateObjectAction implements PrivilegedAction<O
public InterpolateObjectAction( Object target, List<? extends ValueSource> valueSources,
List<? extends InterpolationPostProcessor> postProcessors,
StringSearchModelInterpolator modelInterpolator, ModelProblemCollector problems )
StringSearchModelInterpolator modelInterpolator, ModelProblemCollector problems)
{
this.valueSources = valueSources;
this.postProcessors = postProcessors;
@ -135,28 +137,21 @@ private void traverseObjectWithParents( Class<?> cls, Object target )
}
else if ( isQualifiedForInterpolation( cls ) )
{
Field[] fields = fieldsByClass.get( cls );
if ( fields == null )
Field[] fields = getFields(cls);
for (Field currentField : fields)
{
fields = cls.getDeclaredFields();
fieldsByClass.put( cls, fields );
}
for ( int i = 0; i < fields.length; i++ )
{
Class<?> type = fields[i].getType();
if ( isQualifiedForInterpolation( fields[i], type ) )
Class<?> type = currentField.getType();
if ( isQualifiedForInterpolation( currentField, type ) )
{
boolean isAccessible = fields[i].isAccessible();
fields[i].setAccessible( true );
try
{
synchronized ( currentField){
boolean isAccessible = currentField.isAccessible();
currentField.setAccessible( true );
try
{
if ( String.class == type )
{
String value = (String) fields[i].get( target );
if ( value != null && !Modifier.isFinal( fields[i].getModifiers() ) )
String value = (String) currentField.get( target );
if ( value != null && !Modifier.isFinal( currentField.getModifiers() ) )
{
String interpolated =
modelInterpolator.interpolateInternal( value, valueSources, postProcessors,
@ -164,13 +159,13 @@ else if ( isQualifiedForInterpolation( cls ) )
if ( !interpolated.equals( value ) )
{
fields[i].set( target, interpolated );
currentField.set( target, interpolated );
}
}
}
else if ( Collection.class.isAssignableFrom( type ) )
{
Collection<Object> c = (Collection<Object>) fields[i].get( target );
Collection<Object> c = (Collection<Object>) currentField.get( target );
if ( c != null && !c.isEmpty() )
{
List<Object> originalValues = new ArrayList<Object>( c );
@ -192,7 +187,8 @@ else if ( Collection.class.isAssignableFrom( type ) )
String interpolated =
modelInterpolator.interpolateInternal( (String) value,
valueSources,
postProcessors, problems );
postProcessors,
problems );
if ( !interpolated.equals( value ) )
{
@ -226,7 +222,7 @@ else if ( Collection.class.isAssignableFrom( type ) )
}
else if ( Map.class.isAssignableFrom( type ) )
{
Map<Object, Object> m = (Map<Object, Object>) fields[i].get( target );
Map<Object, Object> m = (Map<Object, Object>) currentField.get( target );
if ( m != null && !m.isEmpty() )
{
for ( Map.Entry<Object, Object> entry : m.entrySet() )
@ -240,7 +236,8 @@ else if ( Map.class.isAssignableFrom( type ) )
String interpolated =
modelInterpolator.interpolateInternal( (String) value,
valueSources,
postProcessors, problems );
postProcessors,
problems );
if ( !interpolated.equals( value ) )
{
@ -271,10 +268,10 @@ else if ( Map.class.isAssignableFrom( type ) )
}
else
{
Object value = fields[i].get( target );
Object value = currentField.get( target );
if ( value != null )
{
if ( fields[i].getType().isArray() )
if ( currentField.getType().isArray() )
{
evaluateArray( value );
}
@ -287,18 +284,21 @@ else if ( Map.class.isAssignableFrom( type ) )
}
catch ( IllegalArgumentException e )
{
problems.add( Severity.ERROR, "Failed to interpolate field: " + fields[i]
+ " on class: " + cls.getName(), e );
e.printStackTrace(System.err);
problems.add( Severity.ERROR, "Failed to interpolate field3: " + currentField +
" on class: " + cls.getName(), e );
}
catch ( IllegalAccessException e )
{
problems.add( Severity.ERROR, "Failed to interpolate field: " + fields[i]
+ " on class: " + cls.getName(), e );
e.printStackTrace(System.err);
problems.add( Severity.ERROR, "Failed to interpolate field4: " + currentField +
" on class: " + cls.getName(), e );
}
finally
{
currentField.setAccessible( isAccessible );
}
}
finally
{
fields[i].setAccessible( isAccessible );
}
}
}
@ -307,6 +307,20 @@ else if ( Map.class.isAssignableFrom( type ) )
}
}
private Field[] getFields(Class<?> cls) {
Field[] fields;
synchronized(fieldsByClass)
{
fields = fieldsByClass.get( cls );
if ( fields == null )
{
fields = cls.getDeclaredFields();
fieldsByClass.put( cls, fields );
}
}
return fields;
}
private boolean isQualifiedForInterpolation( Class<?> cls )
{
return !cls.getName().startsWith( "java" );
@ -314,23 +328,23 @@ private boolean isQualifiedForInterpolation( Class<?> cls )
private boolean isQualifiedForInterpolation( Field field, Class<?> fieldType )
{
Boolean primitive = fieldIsPrimitiveByClass.get( fieldType );
if ( primitive == null )
Boolean primitive;
synchronized ( fieldIsPrimitiveByClass)
{
primitive = Boolean.valueOf( fieldType.isPrimitive() );
fieldIsPrimitiveByClass.put( fieldType, primitive );
primitive = fieldIsPrimitiveByClass.get( fieldType );
if ( primitive == null )
{
primitive = fieldType.isPrimitive();
fieldIsPrimitiveByClass.put( fieldType, primitive );
}
}
if ( primitive.booleanValue() )
if ( primitive )
{
return false;
}
if ( "parent".equals( field.getName() ) )
{
return false;
}
return !"parent".equals(field.getName());
return true;
}
private void evaluateArray( Object target )

View File

@ -0,0 +1,466 @@
package org.apache.maven.model.interpolation;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import org.apache.maven.model.Build;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.Model;
import org.apache.maven.model.Organization;
import org.apache.maven.model.Repository;
import org.apache.maven.model.Resource;
import org.apache.maven.model.Scm;
import org.apache.maven.model.building.DefaultModelBuildingRequest;
import org.apache.maven.model.building.ModelBuildingRequest;
import org.apache.maven.model.building.SimpleProblemCollector;
import org.apache.maven.model.path.PathTranslator;
import org.codehaus.plexus.PlexusTestCase;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
/**
* @author jdcasey
* @version $Id: AbstractModelInterpolatorTest.java 813569 2009-09-10 20:04:14Z jdcasey $
*/
public abstract class AbstractModelInterpolatorTest
extends PlexusTestCase
{
private Properties context;
protected void setUp()
throws Exception
{
super.setUp();
context = new Properties();
context.put( "basedir", "myBasedir" );
context.put( "project.baseUri", "myBaseUri" );
}
protected void assertProblemFree(SimpleProblemCollector collector){
assertEquals( "Expected no errors", 0, collector.getErrors().size() );
assertEquals( "Expected no warnings", 0, collector.getWarnings().size() );
assertEquals( "Expected no fatals", 0, collector.getFatals().size() );
}
protected void assertColllectorState(int numFatals, int numErrors, int numWarnings, SimpleProblemCollector collector){
assertEquals( "Errors", numErrors, collector.getErrors().size() );
assertEquals( "Warnings", numWarnings, collector.getWarnings().size() );
assertEquals( "Fatals", numFatals, collector.getFatals().size() );
}
private ModelBuildingRequest createModelBuildingRequest(Properties p) {
ModelBuildingRequest config = new DefaultModelBuildingRequest();
if (p!= null) config.setSystemProperties( p);
return config;
}
public void testDefaultBuildTimestampFormatShouldParseTimeIn24HourFormat()
{
Calendar cal = Calendar.getInstance();
cal.set( Calendar.HOUR, 12 );
cal.set( Calendar.AM_PM, Calendar.AM );
// just to make sure all the bases are covered...
cal.set( Calendar.HOUR_OF_DAY, 0 );
cal.set( Calendar.MINUTE, 16 );
cal.set( Calendar.YEAR, 1976 );
cal.set( Calendar.MONTH, Calendar.NOVEMBER );
cal.set( Calendar.DATE, 11 );
Date firstTestDate = cal.getTime();
cal.set( Calendar.HOUR, 11 );
cal.set( Calendar.AM_PM, Calendar.PM );
// just to make sure all the bases are covered...
cal.set( Calendar.HOUR_OF_DAY, 23 );
Date secondTestDate = cal.getTime();
SimpleDateFormat format = new SimpleDateFormat( AbstractStringBasedModelInterpolator.DEFAULT_BUILD_TIMESTAMP_FORMAT );
assertEquals( "19761111-0016", format.format( firstTestDate ) );
assertEquals( "19761111-2316", format.format( secondTestDate ) );
}
public void testShouldNotThrowExceptionOnReferenceToNonExistentValue()
throws Exception
{
Model model = new Model();
Scm scm = new Scm();
scm.setConnection( "${test}/somepath" );
model.setScm( scm );
ModelInterpolator interpolator = createInterpolator();
final SimpleProblemCollector collector = new SimpleProblemCollector();
Model out = interpolator.interpolateModel( model, new File("."), createModelBuildingRequest(context),
collector );
assertProblemFree( collector );
assertEquals( "${test}/somepath", out.getScm().getConnection() );
}
public void testShouldThrowExceptionOnRecursiveScmConnectionReference()
throws Exception
{
Model model = new Model();
Scm scm = new Scm();
scm.setConnection( "${project.scm.connection}/somepath" );
model.setScm( scm );
try
{
ModelInterpolator interpolator = createInterpolator();
final SimpleProblemCollector collector = new SimpleProblemCollector();
interpolator.interpolateModel( model, null, createModelBuildingRequest(context), collector );
assertColllectorState( 0, 1, 0, collector );
}
catch ( Exception e )
{
}
}
public void testShouldNotThrowExceptionOnReferenceToValueContainingNakedExpression()
throws Exception
{
Model model = new Model();
Scm scm = new Scm();
scm.setConnection( "${test}/somepath" );
model.setScm( scm );
model.addProperty( "test", "test" );
ModelInterpolator interpolator = createInterpolator();
final SimpleProblemCollector collector = new SimpleProblemCollector();
Model out = interpolator.interpolateModel( model, new File("."), createModelBuildingRequest(context),
collector );
assertProblemFree( collector );
assertEquals( "test/somepath", out.getScm().getConnection() );
}
public void testShouldInterpolateOrganizationNameCorrectly()
throws Exception
{
String orgName = "MyCo";
Model model = new Model();
model.setName( "${pom.organization.name} Tools" );
Organization org = new Organization();
org.setName( orgName );
model.setOrganization( org );
ModelInterpolator interpolator = createInterpolator();
Model out = interpolator.interpolateModel( model, new File("."), createModelBuildingRequest(context), new SimpleProblemCollector() );
assertEquals( orgName + " Tools", out.getName() );
}
public void testShouldInterpolateDependencyVersionToSetSameAsProjectVersion()
throws Exception
{
Model model = new Model();
model.setVersion( "3.8.1" );
Dependency dep = new Dependency();
dep.setVersion( "${version}" );
model.addDependency( dep );
ModelInterpolator interpolator = createInterpolator();
final SimpleProblemCollector collector = new SimpleProblemCollector();
Model out = interpolator.interpolateModel( model, new File("."), createModelBuildingRequest(context),
collector );
assertColllectorState(0, 0, 1, collector );
assertEquals( "3.8.1", ( out.getDependencies().get( 0 ) ).getVersion() );
}
public void testShouldNotInterpolateDependencyVersionWithInvalidReference()
throws Exception
{
Model model = new Model();
model.setVersion( "3.8.1" );
Dependency dep = new Dependency();
dep.setVersion( "${something}" );
model.addDependency( dep );
/*
// This is the desired behaviour, however there are too many crappy poms in the repo and an issue with the
// timing of executing the interpolation
try
{
new RegexBasedModelInterpolator().interpolate( model, context );
fail( "Should have failed to interpolate with invalid reference" );
}
catch ( ModelInterpolationException expected )
{
assertTrue( true );
}
*/
ModelInterpolator interpolator = createInterpolator();
final SimpleProblemCollector collector = new SimpleProblemCollector();
Model out = interpolator.interpolateModel( model, new File("."), createModelBuildingRequest(context),
collector );
assertProblemFree( collector );
assertEquals( "${something}", ( out.getDependencies().get( 0 ) ).getVersion() );
}
public void testTwoReferences()
throws Exception
{
Model model = new Model();
model.setVersion( "3.8.1" );
model.setArtifactId( "foo" );
Dependency dep = new Dependency();
dep.setVersion( "${artifactId}-${version}" );
model.addDependency( dep );
ModelInterpolator interpolator = createInterpolator();
final SimpleProblemCollector collector = new SimpleProblemCollector();
Model out = interpolator.interpolateModel( model, new File("."), createModelBuildingRequest(context),
collector );
assertColllectorState( 0, 0, 2, collector );
assertEquals( "foo-3.8.1", ( out.getDependencies().get( 0 ) ).getVersion() );
}
public void testBasedir()
throws Exception
{
Model model = new Model();
model.setVersion( "3.8.1" );
model.setArtifactId( "foo" );
Repository repository = new Repository();
repository.setUrl( "file://localhost/${basedir}/temp-repo" );
model.addRepository( repository );
ModelInterpolator interpolator = createInterpolator();
final SimpleProblemCollector collector = new SimpleProblemCollector();
Model out = interpolator.interpolateModel( model, null, createModelBuildingRequest(context), collector );
assertProblemFree( collector );
assertEquals( "file://localhost/myBasedir/temp-repo", ( out.getRepositories().get( 0 ) ).getUrl() );
}
public void testBaseUri()
throws Exception
{
Model model = new Model();
model.setVersion( "3.8.1" );
model.setArtifactId( "foo" );
Repository repository = new Repository();
repository.setUrl( "${project.baseUri}/temp-repo" );
model.addRepository( repository );
ModelInterpolator interpolator = createInterpolator();
final SimpleProblemCollector collector = new SimpleProblemCollector();
Model out = interpolator.interpolateModel( model, null, createModelBuildingRequest(context), collector );
assertProblemFree( collector );
assertEquals( "myBaseUri/temp-repo", ( out.getRepositories().get( 0 ) ).getUrl() );
}
public void testEnvars()
throws Exception
{
Properties context = new Properties();
context.put( "env.HOME", "/path/to/home" );
Model model = new Model();
Properties modelProperties = new Properties();
modelProperties.setProperty( "outputDirectory", "${env.HOME}" );
model.setProperties( modelProperties );
ModelInterpolator interpolator = createInterpolator();
final SimpleProblemCollector collector = new SimpleProblemCollector();
Model out = interpolator.interpolateModel( model, new File("."), createModelBuildingRequest(context),
collector );
assertProblemFree( collector );
assertEquals( "/path/to/home", out.getProperties().getProperty( "outputDirectory" ) );
}
public void testEnvarExpressionThatEvaluatesToNullReturnsTheLiteralString()
throws Exception
{
Model model = new Model();
Properties modelProperties = new Properties();
modelProperties.setProperty( "outputDirectory", "${env.DOES_NOT_EXIST}" );
model.setProperties( modelProperties );
ModelInterpolator interpolator = createInterpolator();
final SimpleProblemCollector collector = new SimpleProblemCollector();
Model out = interpolator.interpolateModel( model, new File("."), createModelBuildingRequest(context),
collector );
assertProblemFree( collector );
assertEquals( out.getProperties().getProperty( "outputDirectory" ), "${env.DOES_NOT_EXIST}" );
}
public void testExpressionThatEvaluatesToNullReturnsTheLiteralString()
throws Exception
{
Model model = new Model();
Properties modelProperties = new Properties();
modelProperties.setProperty( "outputDirectory", "${DOES_NOT_EXIST}" );
model.setProperties( modelProperties );
ModelInterpolator interpolator = createInterpolator();
final SimpleProblemCollector collector = new SimpleProblemCollector();
Model out = interpolator.interpolateModel( model, new File("."), createModelBuildingRequest(context),
collector );
assertProblemFree( collector );
assertEquals( out.getProperties().getProperty( "outputDirectory" ), "${DOES_NOT_EXIST}" );
}
public void testShouldInterpolateSourceDirectoryReferencedFromResourceDirectoryCorrectly()
throws Exception
{
Model model = new Model();
Build build = new Build();
build.setSourceDirectory( "correct" );
Resource res = new Resource();
res.setDirectory( "${project.build.sourceDirectory}" );
build.addResource( res );
Resource res2 = new Resource();
res2.setDirectory( "${pom.build.sourceDirectory}" );
build.addResource( res2 );
Resource res3 = new Resource();
res3.setDirectory( "${build.sourceDirectory}" );
build.addResource( res3 );
model.setBuild( build );
ModelInterpolator interpolator = createInterpolator();
final SimpleProblemCollector collector = new SimpleProblemCollector();
Model out = interpolator.interpolateModel( model, null, createModelBuildingRequest(context), collector );
assertColllectorState( 0, 0, 2, collector );
List outResources = out.getBuild().getResources();
Iterator resIt = outResources.iterator();
assertEquals( build.getSourceDirectory(), ( (Resource) resIt.next() ).getDirectory() );
assertEquals( build.getSourceDirectory(), ( (Resource) resIt.next() ).getDirectory() );
assertEquals( build.getSourceDirectory(), ( (Resource) resIt.next() ).getDirectory() );
}
public void testShouldInterpolateUnprefixedBasedirExpression()
throws Exception
{
File basedir = new File( "/test/path" );
Model model = new Model();
Dependency dep = new Dependency();
dep.setSystemPath( "${basedir}/artifact.jar" );
model.addDependency( dep );
ModelInterpolator interpolator = createInterpolator();
final SimpleProblemCollector collector = new SimpleProblemCollector();
Model result = interpolator.interpolateModel( model, basedir, createModelBuildingRequest(context), collector );
assertProblemFree( collector );
List rDeps = result.getDependencies();
assertNotNull( rDeps );
assertEquals( 1, rDeps.size() );
assertEquals( new File( basedir, "artifact.jar" ).getAbsolutePath(), new File( ( (Dependency) rDeps.get( 0 ) )
.getSystemPath() ).getAbsolutePath() );
}
protected abstract ModelInterpolator createInterpolator( PathTranslator translator )
throws Exception;
protected abstract ModelInterpolator createInterpolator()
throws Exception;
}

View File

@ -19,21 +19,435 @@
* under the License.
*/
import java.util.Properties;
import org.apache.maven.model.Model;
import org.apache.maven.model.building.DefaultModelBuildingRequest;
import org.apache.maven.model.building.ModelBuildingRequest;
import org.apache.maven.model.building.SimpleProblemCollector;
import junit.framework.TestCase;
import java.io.File;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
/**
* @author jdcasey
* @author Benjamin Bentmann
* @version $Id$
*/
public class StringSearchModelInterpolatorTest
extends TestCase
extends AbstractModelInterpolatorTest
{
protected ModelInterpolator interpolator;
@Override
protected void setUp()
throws Exception
{
super.setUp();
interpolator = lookup(ModelInterpolator.class);
}
protected ModelInterpolator createInterpolator( org.apache.maven.model.path.PathTranslator translator )
throws Exception
{
return this.interpolator;
}
protected ModelInterpolator createInterpolator()
throws Exception
{
return this.interpolator;
}
public void testInterpolateStringArray()
throws Exception
{
Model model = new Model();
Properties p = new Properties();
p.setProperty( "key", "value" );
p.setProperty( "key2", "value2" );
String[] values = { "${key}", "${key2}" };
StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
ModelBuildingRequest config = createModelBuildingRequest(p);
final SimpleProblemCollector collector = new SimpleProblemCollector();
interpolator.interpolateObject( values, model, new File( "." ), config, collector );
assertProblemFree( collector );
assertEquals( "value", values[0] );
assertEquals( "value2", values[1] );
}
private ModelBuildingRequest createModelBuildingRequest(Properties p) {
ModelBuildingRequest config = new DefaultModelBuildingRequest();
config.setSystemProperties( p);
return config;
}
public void testInterpolateObjectWithStringArrayField()
throws Exception
{
Model model = new Model();
Properties p = new Properties();
p.setProperty( "key", "value" );
p.setProperty( "key2", "value2" );
String[] values = { "${key}", "${key2}" };
ObjectWithStringArrayField obj = new ObjectWithStringArrayField( values );
StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
ModelBuildingRequest config = createModelBuildingRequest(p);
final SimpleProblemCollector collector = new SimpleProblemCollector();
interpolator.interpolateObject( obj, model, new File( "." ), config, collector );
assertProblemFree( collector );
assertEquals( "value", obj.values[0] );
assertEquals( "value2", obj.values[1] );
}
public void testInterpolateObjectWithStringListField()
throws Exception
{
Model model = new Model();
Properties p = new Properties();
p.setProperty( "key", "value" );
p.setProperty( "key2", "value2" );
List<String> values = new ArrayList<String>();
values.add( "${key}" );
values.add( "${key2}" );
ObjectWithListField obj = new ObjectWithListField( values );
StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
ModelBuildingRequest config = createModelBuildingRequest(p);
final SimpleProblemCollector collector = new SimpleProblemCollector();
interpolator.interpolateObject( obj, model, new File( "." ), config, collector );
assertProblemFree( collector );
assertEquals( "value", obj.values.get( 0 ) );
assertEquals( "value2", obj.values.get( 1 ) );
}
public void testInterpolateObjectWithStringListFieldAndOneLiteralValue()
throws Exception
{
Model model = new Model();
Properties p = new Properties();
p.setProperty( "key", "value" );
p.setProperty( "key2", "value2" );
List<String> values = new ArrayList<String>();
values.add( "key" );
values.add( "${key2}" );
ObjectWithListField obj = new ObjectWithListField( values );
StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
ModelBuildingRequest config = createModelBuildingRequest(p);
final SimpleProblemCollector collector = new SimpleProblemCollector();
interpolator.interpolateObject( obj, model, new File( "." ), config, collector );
assertProblemFree( collector );
assertEquals( "key", obj.values.get( 0 ) );
assertEquals( "value2", obj.values.get( 1 ) );
}
public void testInterpolateObjectWithUnmodifiableStringListField()
throws Exception
{
Model model = new Model();
Properties p = new Properties();
p.setProperty( "key", "value" );
p.setProperty( "key2", "value2" );
List values = Collections.unmodifiableList( Collections.singletonList( "${key}" ) );
ObjectWithListField obj = new ObjectWithListField( values );
StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
ModelBuildingRequest config = createModelBuildingRequest(p);
final SimpleProblemCollector collector = new SimpleProblemCollector();
interpolator.interpolateObject( obj, model, new File( "." ), config, collector );
assertProblemFree( collector );
assertEquals( "${key}", obj.values.get( 0 ) );
}
public void testInterpolateObjectWithStringArrayListField()
throws Exception
{
Model model = new Model();
Properties p = new Properties();
p.setProperty( "key", "value" );
p.setProperty( "key2", "value2" );
p.setProperty( "key3", "value3" );
p.setProperty( "key4", "value4" );
List<String[]> values = new ArrayList<String[]>();
values.add( new String[] { "${key}", "${key2}" } );
values.add( new String[] { "${key3}", "${key4}" } );
ObjectWithListField obj = new ObjectWithListField( values );
StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
ModelBuildingRequest config = createModelBuildingRequest(p);
final SimpleProblemCollector collector = new SimpleProblemCollector();
interpolator.interpolateObject( obj, model, new File( "." ), config, collector );
assertProblemFree( collector );
assertEquals( "value", ( (String[]) obj.values.get( 0 ) )[0] );
assertEquals( "value2", ( (String[]) obj.values.get( 0 ) )[1] );
assertEquals( "value3", ( (String[]) obj.values.get( 1 ) )[0] );
assertEquals( "value4", ( (String[]) obj.values.get( 1 ) )[1] );
}
public void testInterpolateObjectWithStringToStringMapField()
throws Exception
{
Model model = new Model();
Properties p = new Properties();
p.setProperty( "key", "value" );
p.setProperty( "key2", "value2" );
Map<String, String> values = new HashMap<String, String>();
values.put( "key", "${key}" );
values.put( "key2", "${key2}" );
ObjectWithMapField obj = new ObjectWithMapField( values );
StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
ModelBuildingRequest config = createModelBuildingRequest(p);
final SimpleProblemCollector collector = new SimpleProblemCollector();
interpolator.interpolateObject( obj, model, new File( "." ), config, collector );
assertProblemFree( collector );
assertEquals( "value", obj.values.get( "key" ) );
assertEquals( "value2", obj.values.get( "key2" ) );
}
public void testInterpolateObjectWithStringToStringMapFieldAndOneLiteralValue()
throws Exception
{
Model model = new Model();
Properties p = new Properties();
p.setProperty( "key", "value" );
p.setProperty( "key2", "value2" );
Map<String, String> values = new HashMap<String, String>();
values.put( "key", "val" );
values.put( "key2", "${key2}" );
ObjectWithMapField obj = new ObjectWithMapField( values );
StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
ModelBuildingRequest config = createModelBuildingRequest(p);
final SimpleProblemCollector collector = new SimpleProblemCollector();
interpolator.interpolateObject( obj, model, new File( "." ), config, collector );
assertProblemFree( collector );
assertEquals( "val", obj.values.get( "key" ) );
assertEquals( "value2", obj.values.get( "key2" ) );
}
public void testInterpolateObjectWithUnmodifiableStringToStringMapField()
throws Exception
{
Model model = new Model();
Properties p = new Properties();
p.setProperty( "key", "value" );
p.setProperty( "key2", "value2" );
Map values = Collections.unmodifiableMap( Collections.singletonMap( "key", "${key}" ) );
ObjectWithMapField obj = new ObjectWithMapField( values );
StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
ModelBuildingRequest config = createModelBuildingRequest(p);
final SimpleProblemCollector collector = new SimpleProblemCollector();
interpolator.interpolateObject( obj, model, new File( "." ), config, collector );
assertProblemFree( collector );
assertEquals( "${key}", obj.values.get( "key" ) );
}
public void testInterpolateObjectWithStringToStringArrayMapField()
throws Exception
{
Model model = new Model();
Properties p = new Properties();
p.setProperty( "key", "value" );
p.setProperty( "key2", "value2" );
p.setProperty( "key3", "value3" );
p.setProperty( "key4", "value4" );
Map<String, String[]> values = new HashMap<String, String[]>();
values.put( "key", new String[] { "${key}", "${key2}" } );
values.put( "key2", new String[] { "${key3}", "${key4}" } );
ObjectWithMapField obj = new ObjectWithMapField( values );
StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
ModelBuildingRequest config = createModelBuildingRequest(p);
final SimpleProblemCollector collector = new SimpleProblemCollector();
interpolator.interpolateObject( obj, model, new File( "." ), config, collector );
assertProblemFree( collector );
assertEquals( "value", ( (String[]) obj.values.get( "key" ) )[0] );
assertEquals( "value2", ( (String[]) obj.values.get( "key" ) )[1] );
assertEquals( "value3", ( (String[]) obj.values.get( "key2" ) )[0] );
assertEquals( "value4", ( (String[]) obj.values.get( "key2" ) )[1] );
}
public void testConcurrentInterpolation() throws Exception {
final Model model = new Model();
Properties p = new Properties();
p.setProperty( "key", "value" );
p.setProperty( "key2", "value2" );
p.setProperty( "key3", "value3" );
p.setProperty( "key4", "value4" );
List<String[]> values = new ArrayList<String[]>();
values.add( new String[] { "${key}", "${key2}" } );
values.add( new String[] { "${key3}", "${key4}" } );
List values2 = new ArrayList();
values.add( new String[] { "${key}", "${key2}" } );
values.add( new String[] { "${key3}", "${key4}" } );
List values3 = new ArrayList();
values.add( new String[] { "${key}", "${key2}" } );
values.add( new String[] { "${key3}", "${key4}" } );
// There is an interesting issue here; if I send three identical collections into the three Lists in "obj",
// like this:
// final ObjectWithMixedProtection obj = new ObjectWithMixedProtection( values, values, values );
// I will have concurrency issues on the interpolation of the individual collections, since current
// synchronization is per-field and not per-underlying object.
// If this turns out to be a realistic use case, we will need to synchronize on the underlying collection
// in the interpolate method.
final ObjectWithMixedProtection obj = new ObjectWithMixedProtection( values, values2, values3 );
final StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
final ModelBuildingRequest config = createModelBuildingRequest(p);
int numItems = 250;
final CountDownLatch countDownLatch = new CountDownLatch(1);
List<Future<SimpleProblemCollector>> futures = new ArrayList<Future<SimpleProblemCollector>>();
for (int i = 0; i < numItems; i++){
Callable<SimpleProblemCollector> future = new Callable<SimpleProblemCollector>() {
public SimpleProblemCollector call() throws Exception {
countDownLatch.await();
final SimpleProblemCollector collector = new SimpleProblemCollector();
interpolator.interpolateObject( obj, model, new File( "." ), config, collector);
return collector;
}
};
FutureTask<SimpleProblemCollector> task = new FutureTask<SimpleProblemCollector>(future);
futures.add ( task);
new Thread( task).start();
}
countDownLatch.countDown(); // Start all the threads
for(Future<SimpleProblemCollector> result : futures){
result.get(); // ArrayIndexOutOfBoundsException are typical indication of threading issues
}
}
private static final class ObjectWithStringArrayField
{
private final String[] values;
public ObjectWithStringArrayField( String[] values )
{
this.values = values;
}
}
private static final class ObjectWithListField
{
private final List values;
public ObjectWithListField( List values )
{
this.values = values;
}
}
private static final class ObjectWithMapField
{
private final Map values;
public ObjectWithMapField( Map values )
{
this.values = values;
}
}
@SuppressWarnings({"UnusedDeclaration"})
private static final class ObjectWithMixedProtection
{
private List values1;
protected List values2;
List values3;
private ObjectWithMixedProtection(List values1, List values2, List values3) {
this.values1 = values1;
this.values2 = values2;
this.values3 = values3;
}
}
public void testFinalFieldsExcludedFromInterpolation()
{
Properties props = new Properties();
@ -45,16 +459,12 @@ public void testFinalFieldsExcludedFromInterpolation()
StringSearchModelInterpolator interpolator = new StringSearchModelInterpolator();
interpolator.interpolateObject( new ClassWithFinalField(), new Model(), null, request, problems );
assertTrue( problems.getFatals().toString(), problems.getFatals().isEmpty() );
assertTrue( problems.getErrors().toString(), problems.getErrors().isEmpty() );
assertTrue( problems.getWarnings().toString(), problems.getWarnings().isEmpty() );
assertProblemFree( problems );
}
@SuppressWarnings({"UnusedDeclaration"})
static class ClassWithFinalField
{
public static final String CONSTANT = "${expression}";
}
}