Modified: maven/components/branches/maven-2.0.10-RC/maven-project/src/main/java/org/apache/maven/project/interpolation/StringSearchModelInterpolator.java URL: http://svn.apache.org/viewvc/maven/components/branches/maven-2.0.10-RC/maven-project/src/main/java/org/apache/maven/project/interpolation/StringSearchModelInterpolator.java?rev=687867&r1=687866&r2=687867&view=diff ============================================================================== --- maven/components/branches/maven-2.0.10-RC/maven-project/src/main/java/org/apache/maven/project/interpolation/StringSearchModelInterpolator.java (original) +++ maven/components/branches/maven-2.0.10-RC/maven-project/src/main/java/org/apache/maven/project/interpolation/StringSearchModelInterpolator.java Thu Aug 21 14:27:09 2008 @@ -1,13 +1,32 @@ package org.apache.maven.project.interpolation; +import java.io.File; +import java.lang.reflect.Array; +import java.lang.reflect.Field; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.WeakHashMap; + +import org.apache.maven.model.Model; +import org.apache.maven.project.ProjectBuilderConfiguration; import org.apache.maven.project.path.PathTranslator; import org.codehaus.plexus.interpolation.Interpolator; import org.codehaus.plexus.interpolation.StringSearchInterpolator; +import org.codehaus.plexus.logging.Logger; public class StringSearchModelInterpolator extends AbstractStringBasedModelInterpolator { + private static final Map fieldsByClass = new WeakHashMap(); + private static final Map fieldIsPrimitiveByClass = new WeakHashMap(); + public StringSearchModelInterpolator() { } @@ -17,9 +36,326 @@ super( pathTranslator ); } + public Model interpolate( Model model, File projectDir, ProjectBuilderConfiguration config, boolean debugEnabled ) + throws ModelInterpolationException + { + interpolateObject( model, model, projectDir, config, debugEnabled ); + + return model; + } + + protected void interpolateObject( Object obj, Model model, File projectDir, ProjectBuilderConfiguration config, + boolean debugEnabled ) + throws ModelInterpolationException + { + List valueSources = createValueSources( model, projectDir, config ); + List postProcessors = createPostProcessors( model, projectDir, config ); + + InterpolateObjectAction action = + new InterpolateObjectAction( obj, valueSources, postProcessors, debugEnabled, + this, getLogger() ); + + ModelInterpolationException error = + (ModelInterpolationException) AccessController.doPrivileged( action ); + + if ( error != null ) + { + throw error; + } + } + protected Interpolator createInterpolator() { return new StringSearchInterpolator(); } + + private static final class InterpolateObjectAction implements PrivilegedAction + { + + private final boolean debugEnabled; + private final LinkedList interpolationTargets; + private final StringSearchModelInterpolator modelInterpolator; + private final Logger logger; + private final List valueSources; + private final List postProcessors; + + public InterpolateObjectAction( Object target, List valueSources, List postProcessors, + boolean debugEnabled, + StringSearchModelInterpolator modelInterpolator, Logger logger ) + { + this.valueSources = valueSources; + this.postProcessors = postProcessors; + this.debugEnabled = debugEnabled; + + this.interpolationTargets = new LinkedList(); + interpolationTargets.add( target ); + + this.modelInterpolator = modelInterpolator; + this.logger = logger; + } + + public Object run() + { + while( !interpolationTargets.isEmpty() ) + { + Object obj = interpolationTargets.removeFirst(); + + try + { + traverseObjectWithParents( obj.getClass(), obj ); + } + catch ( ModelInterpolationException e ) + { + return e; + } + } + + return null; + } + + private void traverseObjectWithParents( Class cls, Object target ) + throws ModelInterpolationException + { + if ( cls == null ) + { + return; + } + + + if ( cls.isArray() ) + { + evaluateArray( target ); + } + else if ( isQualifiedForInterpolation( cls ) ) + { + Field[] fields = (Field[]) fieldsByClass.get( cls ); + if ( fields == null ) + { + 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 ) ) + { + boolean isAccessible = fields[i].isAccessible(); + fields[i].setAccessible( true ); + try + { + try + { + if ( String.class == type ) + { + String value = (String) fields[i].get( target ); + if ( value != null ) + { + String interpolated = modelInterpolator.interpolateInternal( value, valueSources, postProcessors, debugEnabled ); + + if ( !interpolated.equals( value ) ) + { + fields[i].set( target, interpolated ); + } + } + } + else if ( Collection.class.isAssignableFrom( type ) ) + { + Collection c = (Collection) fields[i].get( target ); + if ( c != null && !c.isEmpty() ) + { + List originalValues = new ArrayList( c ); + try + { + c.clear(); + } + catch( UnsupportedOperationException e ) + { + if ( debugEnabled && logger != null ) + { + logger.debug( "Skipping interpolation of field: " + fields[i] + " in: " + cls.getName() + "; it is an unmodifiable collection." ); + } + continue; + } + + for ( Iterator it = originalValues.iterator(); it.hasNext(); ) + { + Object value = it.next(); + if ( value != null ) + { + if( String.class == value.getClass() ) + { + String interpolated = modelInterpolator.interpolateInternal( (String) value, valueSources, postProcessors, debugEnabled ); + + if ( !interpolated.equals( value ) ) + { + c.add( interpolated ); + } + else + { + c.add( value ); + } + } + else + { + c.add( value ); + if ( value.getClass().isArray() ) + { + evaluateArray( value ); + } + else + { + interpolationTargets.add( value ); + } + } + } + else + { + // add the null back in...not sure what else to do... + c.add( value ); + } + } + } + } + else if ( Map.class.isAssignableFrom( type ) ) + { + Map m = (Map) fields[i].get( target ); + if ( m != null && !m.isEmpty() ) + { + for ( Iterator it = m.entrySet().iterator(); it.hasNext(); ) + { + Map.Entry entry = (Map.Entry) it.next(); + + Object value = entry.getValue(); + + if ( value != null ) + { + if( String.class == value.getClass() ) + { + String interpolated = modelInterpolator.interpolateInternal( (String) value, valueSources, postProcessors, debugEnabled ); + + if ( !interpolated.equals( value ) ) + { + try + { + entry.setValue( interpolated ); + } + catch( UnsupportedOperationException e ) + { + if ( debugEnabled && logger != null ) + { + logger.debug( "Skipping interpolation of field: " + fields[i] + " (key: " + entry.getKey() + ") in: " + cls.getName() + "; it is an unmodifiable collection." ); + } + continue; + } + } + } + else + { + if ( value.getClass().isArray() ) + { + evaluateArray( value ); + } + else + { + interpolationTargets.add( value ); + } + } + } + } + } + } + else + { + Object value = fields[i].get( target ); + if ( value != null ) + { + if ( fields[i].getType().isArray() ) + { + evaluateArray( value ); + } + else + { + interpolationTargets.add( value ); + } + } + } + } + catch ( IllegalArgumentException e ) + { + throw new ModelInterpolationException( "Failed to interpolate field: " + fields[i] + " on class: " + cls.getName(), e ); + } + catch ( IllegalAccessException e ) + { + throw new ModelInterpolationException( "Failed to interpolate field: " + fields[i] + " on class: " + cls.getName(), e ); + } + } + finally + { + fields[i].setAccessible( isAccessible ); + } + } + } + + traverseObjectWithParents( cls.getSuperclass(), target ); + } + } + + private boolean isQualifiedForInterpolation( Class cls ) + { + return !cls.getPackage().getName().startsWith( "java" ); + } + + private boolean isQualifiedForInterpolation( Field field, Class fieldType ) + { + if ( !fieldIsPrimitiveByClass.containsKey( fieldType ) ) + { + fieldIsPrimitiveByClass.put( fieldType, Boolean.valueOf( fieldType.isPrimitive() ) ); + } + + if ( ((Boolean) fieldIsPrimitiveByClass.get( fieldType )).booleanValue() ) + { + return false; + } + +// if ( fieldType.isPrimitive() ) +// { +// return false; +// } + + if ( "parent".equals( field.getName() ) ) + { + return false; + } + + return true; + } + + private void evaluateArray( Object target ) + throws ModelInterpolationException + { + int len = Array.getLength( target ); + for( int i = 0; i < len; i++ ) + { + Object value = Array.get( target, i ); + if ( value != null ) + { + if ( String.class == value.getClass() ) + { + String interpolated = modelInterpolator.interpolateInternal( (String) value, valueSources, postProcessors, debugEnabled ); + + if ( !interpolated.equals( value ) ) + { + Array.set( target, i, interpolated ); + } + } + else + { + interpolationTargets.add( value ); + } + } + } + } + } }
Modified: maven/components/branches/maven-2.0.10-RC/maven-project/src/test/java/org/apache/maven/project/MavenProjectDynamismTest.java URL: http://svn.apache.org/viewvc/maven/components/branches/maven-2.0.10-RC/maven-project/src/test/java/org/apache/maven/project/MavenProjectDynamismTest.java?rev=687867&r1=687866&r2=687867&view=diff ============================================================================== --- maven/components/branches/maven-2.0.10-RC/maven-project/src/test/java/org/apache/maven/project/MavenProjectDynamismTest.java (original) +++ maven/components/branches/maven-2.0.10-RC/maven-project/src/test/java/org/apache/maven/project/MavenProjectDynamismTest.java Thu Aug 21 14:27:09 2008 @@ -90,6 +90,8 @@ + " should have a an interpolated POM groupId as its value.", children[i].getValue(), project.getGroupId() ); } + + project.getProperties().setProperty( "foo", "bar" ); projectBuilder.restoreDynamicState( project, new DefaultProjectBuilderConfiguration() ); @@ -219,6 +221,9 @@ assertEquals( "Concrete build directory should be absolute.", new File( baseDir, "target" ).getAbsolutePath(), new File( build.getDirectory() ).getAbsolutePath() ); + + // Next, we have to change something to ensure the project is restored to its dynamic state. + project.getProperties().setProperty( "restoreTrigger", "true" ); // -------------------------------------------------------------------- // NOW, RESTORE THE DYNAMIC STATE FOR THE BUILD SECTION AND @@ -320,6 +325,9 @@ resources ); assertResourcePresent( "concrete resources", "myDir", resources ); + // Next, we have to change something to ensure the project is restored to its dynamic state. + project.getProperties().setProperty( "restoreTrigger", "true" ); + projectBuilder.restoreDynamicState( project, config ); build = project.getBuild(); @@ -353,6 +361,9 @@ assertFilterPresent( "concrete filters", "myDir/filters.properties", filters ); + // Next, we have to change something to ensure the project is restored to its dynamic state. + project.getProperties().setProperty( "restoreTrigger", "true" ); + projectBuilder.restoreDynamicState( project, config ); build = project.getBuild(); @@ -444,6 +455,9 @@ project.addCompileSourceRoot( newSourceRoot ); + // Next, we have to change something to ensure the project is restored to its dynamic state. + project.getProperties().setProperty( "restoreTrigger", "true" ); + projectBuilder.restoreDynamicState( project, config ); compileSourceRoots = project.getCompileSourceRoots(); Modified: maven/components/branches/maven-2.0.10-RC/maven-project/src/test/java/org/apache/maven/project/interpolation/AbstractModelInterpolatorTest.java URL: http://svn.apache.org/viewvc/maven/components/branches/maven-2.0.10-RC/maven-project/src/test/java/org/apache/maven/project/interpolation/AbstractModelInterpolatorTest.java?rev=687867&r1=687866&r2=687867&view=diff ============================================================================== --- maven/components/branches/maven-2.0.10-RC/maven-project/src/test/java/org/apache/maven/project/interpolation/AbstractModelInterpolatorTest.java (original) +++ maven/components/branches/maven-2.0.10-RC/maven-project/src/test/java/org/apache/maven/project/interpolation/AbstractModelInterpolatorTest.java Thu Aug 21 14:27:09 2008 @@ -279,7 +279,7 @@ Model out = interpolator.interpolate( model, context ); - assertEquals( out.getProperties().getProperty( "outputDirectory" ), "/path/to/home" ); + assertEquals( "/path/to/home", out.getProperties().getProperty( "outputDirectory" ) ); } public void testEnvarExpressionThatEvaluatesToNullReturnsTheLiteralString() Modified: maven/components/branches/maven-2.0.10-RC/maven-project/src/test/java/org/apache/maven/project/interpolation/ModelInterpolationEdgeCases.java URL: http://svn.apache.org/viewvc/maven/components/branches/maven-2.0.10-RC/maven-project/src/test/java/org/apache/maven/project/interpolation/ModelInterpolationEdgeCases.java?rev=687867&r1=687866&r2=687867&view=diff ============================================================================== --- maven/components/branches/maven-2.0.10-RC/maven-project/src/test/java/org/apache/maven/project/interpolation/ModelInterpolationEdgeCases.java (original) +++ maven/components/branches/maven-2.0.10-RC/maven-project/src/test/java/org/apache/maven/project/interpolation/ModelInterpolationEdgeCases.java Thu Aug 21 14:27:09 2008 @@ -184,7 +184,8 @@ private Model interpolate( Model model ) throws Throwable { - ModelInterpolator interpolator = new RegexBasedModelInterpolator(); + RegexBasedModelInterpolator interpolator = new RegexBasedModelInterpolator(); + interpolator.initialize(); return interpolator.interpolate( model, new HashMap(), true ); } Modified: maven/components/branches/maven-2.0.10-RC/maven-project/src/test/java/org/apache/maven/project/interpolation/StringSearchModelInterpolatorTest.java URL: http://svn.apache.org/viewvc/maven/components/branches/maven-2.0.10-RC/maven-project/src/test/java/org/apache/maven/project/interpolation/StringSearchModelInterpolatorTest.java?rev=687867&r1=687866&r2=687867&view=diff ============================================================================== --- maven/components/branches/maven-2.0.10-RC/maven-project/src/test/java/org/apache/maven/project/interpolation/StringSearchModelInterpolatorTest.java (original) +++ maven/components/branches/maven-2.0.10-RC/maven-project/src/test/java/org/apache/maven/project/interpolation/StringSearchModelInterpolatorTest.java Thu Aug 21 14:27:09 2008 @@ -19,6 +19,17 @@ * under the License. */ +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import org.apache.maven.model.Model; +import org.apache.maven.project.DefaultProjectBuilderConfiguration; +import org.apache.maven.project.ProjectBuilderConfiguration; import org.apache.maven.project.path.PathTranslator; /** @@ -45,4 +56,281 @@ return 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(); + + ProjectBuilderConfiguration config = new DefaultProjectBuilderConfiguration().setExecutionProperties( p ); + + interpolator.interpolateObject( values, model, new File( "." ), config, true ); + + assertEquals( "value", values[0] ); + assertEquals( "value2", values[1] ); + } + + 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(); + + ProjectBuilderConfiguration config = new DefaultProjectBuilderConfiguration().setExecutionProperties( p ); + + interpolator.interpolateObject( obj, model, new File( "." ), config, true ); + + 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 values = new ArrayList(); + values.add( "${key}" ); + values.add( "${key2}" ); + + ObjectWithListField obj = new ObjectWithListField( values ); + + StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator(); + + ProjectBuilderConfiguration config = new DefaultProjectBuilderConfiguration().setExecutionProperties( p ); + + interpolator.interpolateObject( obj, model, new File( "." ), config, true ); + + 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 values = new ArrayList(); + values.add( "key" ); + values.add( "${key2}" ); + + ObjectWithListField obj = new ObjectWithListField( values ); + + StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator(); + + ProjectBuilderConfiguration config = new DefaultProjectBuilderConfiguration().setExecutionProperties( p ); + + interpolator.interpolateObject( obj, model, new File( "." ), config, true ); + + 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(); + + ProjectBuilderConfiguration config = new DefaultProjectBuilderConfiguration().setExecutionProperties( p ); + + interpolator.interpolateObject( obj, model, new File( "." ), config, true ); + + 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 values = new ArrayList(); + values.add( new String[] { "${key}", "${key2}" } ); + values.add( new String[] { "${key3}", "${key4}" } ); + + ObjectWithListField obj = new ObjectWithListField( values ); + + StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator(); + + ProjectBuilderConfiguration config = new DefaultProjectBuilderConfiguration().setExecutionProperties( p ); + + interpolator.interpolateObject( obj, model, new File( "." ), config, true ); + + 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 values = new HashMap(); + values.put( "key", "${key}" ); + values.put( "key2", "${key2}" ); + + ObjectWithMapField obj = new ObjectWithMapField( values ); + + StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator(); + + ProjectBuilderConfiguration config = new DefaultProjectBuilderConfiguration().setExecutionProperties( p ); + + interpolator.interpolateObject( obj, model, new File( "." ), config, true ); + + 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 values = new HashMap(); + values.put( "key", "val" ); + values.put( "key2", "${key2}" ); + + ObjectWithMapField obj = new ObjectWithMapField( values ); + + StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator(); + + ProjectBuilderConfiguration config = new DefaultProjectBuilderConfiguration().setExecutionProperties( p ); + + interpolator.interpolateObject( obj, model, new File( "." ), config, true ); + + 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(); + + ProjectBuilderConfiguration config = new DefaultProjectBuilderConfiguration().setExecutionProperties( p ); + + interpolator.interpolateObject( obj, model, new File( "." ), config, true ); + + 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 values = new HashMap(); + values.put( "key", new String[] { "${key}", "${key2}" } ); + values.put( "key2", new String[] { "${key3}", "${key4}" } ); + + ObjectWithMapField obj = new ObjectWithMapField( values ); + + StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator(); + + ProjectBuilderConfiguration config = new DefaultProjectBuilderConfiguration().setExecutionProperties( p ); + + interpolator.interpolateObject( obj, model, new File( "." ), config, true ); + + 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] ); + } + + 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; + } + } + } Modified: maven/components/branches/maven-2.0.10-RC/pom.xml URL: http://svn.apache.org/viewvc/maven/components/branches/maven-2.0.10-RC/pom.xml?rev=687867&r1=687866&r2=687867&view=diff ============================================================================== --- maven/components/branches/maven-2.0.10-RC/pom.xml (original) +++ maven/components/branches/maven-2.0.10-RC/pom.xml Thu Aug 21 14:27:09 2008 @@ -244,6 +244,9 @@ </modules> <properties> + <!-- + <mavenHintDynamicBuild>true</mavenHintDynamicBuild> + --> <mavenVersion>2.0.10-RC10-SNAPSHOT</mavenVersion> <wagonVersion>1.0-beta-4</wagonVersion> </properties>