Author: krosenvold Date: Wed Aug 22 14:55:33 2012 New Revision: 1376085 URL: http://svn.apache.org/viewvc?rev=1376085&view=rev Log: o Optimized the cache around the hotspot in interpolation somewhat
Modified: maven/maven-3/trunk/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/StringSearchModelInterpolator.java Modified: maven/maven-3/trunk/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/StringSearchModelInterpolator.java URL: http://svn.apache.org/viewvc/maven/maven-3/trunk/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/StringSearchModelInterpolator.java?rev=1376085&r1=1376084&r2=1376085&view=diff ============================================================================== --- maven/maven-3/trunk/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/StringSearchModelInterpolator.java (original) +++ maven/maven-3/trunk/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/StringSearchModelInterpolator.java Wed Aug 22 14:55:33 2012 @@ -22,7 +22,9 @@ package org.apache.maven.model.interpola import org.apache.maven.model.Model; import org.apache.maven.model.building.ModelBuildingRequest; import org.apache.maven.model.building.ModelProblem.Severity; +import org.apache.maven.model.building.ModelProblem.Version; import org.apache.maven.model.building.ModelProblemCollector; +import org.apache.maven.model.building.ModelProblemCollectorRequest; import org.codehaus.plexus.component.annotations.Component; import org.codehaus.plexus.interpolation.InterpolationPostProcessor; import org.codehaus.plexus.interpolation.Interpolator; @@ -41,19 +43,16 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import org.apache.maven.model.building.ModelProblem; -import org.apache.maven.model.building.ModelProblem.Version; -import org.apache.maven.model.building.ModelProblemCollectorRequest; @Component( role = ModelInterpolator.class ) public class StringSearchModelInterpolator extends AbstractStringBasedModelInterpolator { - private static final Map<Class<?>, Field[]> fieldsByClass = - new ConcurrentHashMap<Class<?>, Field[]>( 80, 0.75f, 2 ); // Empirical data from 3.x, actual =40 - private static final Map<Class<?>, Boolean> fieldIsPrimitiveByClass = - new ConcurrentHashMap<Class<?>, Boolean>( 62, 0.75f, 2 ); // Empirical data from 3.x, actual 31 + private static final Map<Class<?>, InterpolateObjectAction.CacheItem> cachedEntries = + new ConcurrentHashMap<Class<?>, InterpolateObjectAction.CacheItem>( 80, 0.75f, 2 ); + // Empirical data from 3.x, actual =40 + public Model interpolateModel( Model model, File projectDir, ModelBuildingRequest config, ModelProblemCollector problems ) @@ -69,8 +68,8 @@ public class StringSearchModelInterpolat 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 ); @@ -96,9 +95,13 @@ public class StringSearchModelInterpolat { private final LinkedList<Object> interpolationTargets; + private final StringSearchModelInterpolator modelInterpolator; + private final List<? extends ValueSource> valueSources; + private final List<? extends InterpolationPostProcessor> postProcessors; + private final ModelProblemCollector problems; public InterpolateObjectAction( Object target, List<? extends ValueSource> valueSources, @@ -129,6 +132,12 @@ public class StringSearchModelInterpolat return null; } + + private String interpolate( String value ) + { + return modelInterpolator.interpolateInternal( value, valueSources, postProcessors, problems ); + } + private void traverseObjectWithParents( Class<?> cls, Object target ) { if ( cls == null ) @@ -136,265 +145,379 @@ public class StringSearchModelInterpolat return; } - if ( cls.isArray() ) + CacheItem cacheEntry = getCacheEntry( cls ); + if ( cacheEntry.isArray() ) + { + evaluateArray( target, this ); + } + else if ( cacheEntry.isQualifiedForInterpolation ) + { + cacheEntry.interpolate( target, problems, this ); + + traverseObjectWithParents( cls.getSuperclass(), target ); + } + } + + + private CacheItem getCacheEntry( Class<?> cls ) + { + CacheItem cacheItem = cachedEntries.get( cls ); + if ( cacheItem == null ) + { + cacheItem = new CacheItem( cls ); + cachedEntries.put( cls, cacheItem ); + } + return cacheItem; + } + + private boolean isQualifiedForInterpolation( Class<?> cls ) + { + return !cls.getName().startsWith( "java" ); + } + + private boolean isQualifiedForInterpolation( Field field, Class<?> fieldType ) + { + if ( Map.class.equals( fieldType ) && "locations".equals( field.getName() ) ) + { + return false; + } + + if ( fieldType.isPrimitive() ) { - evaluateArray( target ); + return false; } - else if ( isQualifiedForInterpolation( cls ) ) + + return !"parent".equals( field.getName() ); + } + + private static void evaluateArray( Object target, InterpolateObjectAction ctx ) + { + int len = Array.getLength( target ); + for ( int i = 0; i < len; i++ ) { - for ( Field currentField : getFields( cls ) ) + Object value = Array.get( target, i ); + if ( value != null ) { - Class<?> type = currentField.getType(); - if ( isQualifiedForInterpolation( currentField, type ) ) + if ( String.class == value.getClass() ) { - synchronized ( currentField ) + String interpolated = ctx.interpolate( (String) value ); + + if ( !interpolated.equals( value ) ) { - interpolateField( cls, target, currentField, type ); + Array.set( target, i, interpolated ); } } + else + { + ctx.interpolationTargets.add( value ); + } } - - traverseObjectWithParents( cls.getSuperclass(), target ); } } - private void interpolateField( Class<?> cls, Object target, Field field, Class<?> type ) + private static class CacheItem { - boolean isAccessible = field.isAccessible(); - field.setAccessible( true ); - try + private final boolean isArray; + + private final boolean isQualifiedForInterpolation; + + private final CacheField[] fields; + + private boolean isQualifiedForInterpolation( Class<?> cls ) { - if ( String.class == type ) - { - interpolateStringField( target, field ); - } - else if ( Collection.class.isAssignableFrom( type ) ) + return !cls.getName().startsWith( "java" ); + } + + private boolean isQualifiedForInterpolation( Field field, Class<?> fieldType ) + { + if ( Map.class.equals( fieldType ) && "locations".equals( field.getName() ) ) { - interpolateCollectionField( target, field ); + return false; } - else if ( Map.class.isAssignableFrom( type ) ) + + if ( fieldType.isPrimitive() ) { - interpolateMapField( target, field ); + return false; } - else + + return !"parent".equals( field.getName() ); + } + + CacheItem( Class clazz ) + { + this.isQualifiedForInterpolation = isQualifiedForInterpolation( clazz ); + this.isArray = clazz.isArray(); + List<CacheField> fields = new ArrayList<CacheField>(); + for ( Field currentField : clazz.getDeclaredFields() ) { - Object value = field.get( target ); - if ( value != null ) + Class<?> type = currentField.getType(); + if ( isQualifiedForInterpolation( currentField, type ) ) { - if ( field.getType().isArray() ) + if ( String.class == type ) + { + if ( !Modifier.isFinal( currentField.getModifiers() ) ) + { + fields.add( new StringField( currentField ) ); + } + } + else if ( Collection.class.isAssignableFrom( type ) ) + { + fields.add( new CollectionField( currentField ) ); + } + else if ( Map.class.isAssignableFrom( type ) ) { - evaluateArray( value ); + fields.add( new MapField( currentField ) ); } else { - interpolationTargets.add( value ); + fields.add( new ObjectField( currentField ) ); } } + } + this.fields = fields.toArray( new CacheField[fields.size()] ); + } - catch ( IllegalArgumentException e ) - { - problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE) - .setMessage( "Failed to interpolate field3: " + field + " on class: " + cls.getName()) - .setException(e)); - } - catch ( IllegalAccessException e ) + + public void interpolate( Object target, ModelProblemCollector problems, + InterpolateObjectAction interpolateObjectAction ) { - problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE) - .setMessage( "Failed to interpolate field4: " + field + " on class: " + cls.getName()) - .setException(e)); + for ( CacheField field : fields ) + { + field.interpolate( target, problems, interpolateObjectAction ); + } } - finally + + public boolean isArray() { - field.setAccessible( isAccessible ); + return isArray; } } - private void interpolateStringField( Object target, Field field ) - throws IllegalAccessException + static abstract class CacheField { - String value = (String) field.get( target ); - if ( value == null || Modifier.isFinal( field.getModifiers() ) ) + protected final Field field; + + CacheField( Field field ) { - return; + this.field = field; } - String interpolated = - modelInterpolator.interpolateInternal( value, valueSources, postProcessors, problems ); - - if ( !interpolated.equals( value ) ) + void interpolate( Object target, ModelProblemCollector problems, + InterpolateObjectAction interpolateObjectAction ) { - field.set( target, interpolated ); + synchronized ( field ) + { + boolean isAccessible = field.isAccessible(); + field.setAccessible( true ); + try + { + doInterpolate( target, interpolateObjectAction ); + } + catch ( IllegalArgumentException e ) + { + interpolateObjectAction.problems.add( + new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ).setMessage( + "Failed to interpolate field3: " + field + " on class: " + + field.getType().getName() ).setException( + e ) ); // todo: Not entirely the same message + } + catch ( IllegalAccessException e ) + { + interpolateObjectAction.problems.add( + new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ).setMessage( + "Failed to interpolate field4: " + field + " on class: " + + field.getType().getName() ).setException( e ) ); + } + finally + { + field.setAccessible( isAccessible ); + } + } + + } + + abstract void doInterpolate( Object target, InterpolateObjectAction ctx ) + throws IllegalAccessException; } - private void interpolateCollectionField( Object target, Field field ) - throws IllegalAccessException + static final class StringField + extends CacheField { - @SuppressWarnings( "unchecked" ) - Collection<Object> c = (Collection<Object>) field.get( target ); - if ( c == null || c.isEmpty() ) + StringField( Field field ) { - return; + super( field ); } - List<Object> originalValues = new ArrayList<Object>( c ); - try + @Override + void doInterpolate( Object target, InterpolateObjectAction ctx ) + throws IllegalAccessException { - c.clear(); + String value = (String) field.get( target ); + if ( value == null ) + { + return; + } + + String interpolated = ctx.interpolate( value ); + + if ( !interpolated.equals( value ) ) + { + field.set( target, interpolated ); + } } - catch ( UnsupportedOperationException e ) + } + + static final class CollectionField + extends CacheField + { + CollectionField( Field field ) { - return; + super( field ); } - for ( Object value : originalValues ) + @Override + void doInterpolate( Object target, InterpolateObjectAction ctx ) + throws IllegalAccessException { - if ( value == null ) + @SuppressWarnings( "unchecked" ) Collection<Object> c = (Collection<Object>) field.get( target ); + if ( c == null || c.isEmpty() ) + { + return; + } + + List<Object> originalValues = new ArrayList<Object>( c ); + try { - // add the null back in...not sure what else to do... - c.add( value ); + c.clear(); } - else if ( String.class == value.getClass() ) + catch ( UnsupportedOperationException e ) { - String interpolated = - modelInterpolator.interpolateInternal( (String) value, valueSources, postProcessors, problems ); + return; + } - if ( !interpolated.equals( value ) ) - { - c.add( interpolated ); - } - else + for ( Object value : originalValues ) + { + if ( value == null ) { + // add the null back in...not sure what else to do... c.add( value ); } - } - else - { - c.add( value ); - if ( value.getClass().isArray() ) + else if ( String.class == value.getClass() ) { - evaluateArray( value ); + String interpolated = ctx.interpolate( (String) value ); + + if ( !interpolated.equals( value ) ) + { + c.add( interpolated ); + } + else + { + c.add( value ); + } } else { - interpolationTargets.add( value ); + c.add( value ); + if ( value.getClass().isArray() ) + { + evaluateArray( value, ctx ); + } + else + { + ctx.interpolationTargets.add( value ); + } } } } } - private void interpolateMapField( Object target, Field field ) - throws IllegalAccessException + static final class MapField + extends CacheField { - @SuppressWarnings( "unchecked" ) - Map<Object, Object> m = (Map<Object, Object>) field.get( target ); - if ( m == null || m.isEmpty() ) + MapField( Field field ) { - return; + super( field ); } - for ( Map.Entry<Object, Object> entry : m.entrySet() ) + @Override + void doInterpolate( Object target, InterpolateObjectAction ctx ) + throws IllegalAccessException { - Object value = entry.getValue(); - - if ( value == null ) + @SuppressWarnings( "unchecked" ) Map<Object, Object> m = (Map<Object, Object>) field.get( target ); + if ( m == null || m.isEmpty() ) { - continue; + return; } - if ( String.class == value.getClass() ) + for ( Map.Entry<Object, Object> entry : m.entrySet() ) { - String interpolated = - modelInterpolator.interpolateInternal( (String) value, valueSources, postProcessors, problems ); + Object value = entry.getValue(); - if ( !interpolated.equals( value ) ) + if ( value == null ) { - try - { - entry.setValue( interpolated ); - } - catch ( UnsupportedOperationException e ) + continue; + } + + if ( String.class == value.getClass() ) + { + String interpolated = ctx.interpolate( (String) value ); + + if ( !interpolated.equals( value ) ) { - continue; + try + { + entry.setValue( interpolated ); + } + catch ( UnsupportedOperationException e ) + { + continue; + } } } + else if ( value.getClass().isArray() ) + { + evaluateArray( value, ctx ); + } + else + { + ctx.interpolationTargets.add( value ); + } } - else if ( value.getClass().isArray() ) - { - evaluateArray( value ); - } - else - { - interpolationTargets.add( value ); - } - } - } - - private Field[] getFields( Class<?> cls ) - { - Field[] 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" ); } - private boolean isQualifiedForInterpolation( Field field, Class<?> fieldType ) + static final class ObjectField + extends CacheField { - if ( Map.class.equals( fieldType ) && "locations".equals( field.getName() ) ) - { - return false; - } + private final boolean isArray; - Boolean primitive = fieldIsPrimitiveByClass.get( fieldType ); - if ( primitive == null ) + ObjectField( Field field ) { - primitive = fieldType.isPrimitive(); - fieldIsPrimitiveByClass.put( fieldType, primitive ); + super( field ); + this.isArray = field.getType().isArray(); } - if ( primitive ) - { - return false; - } - - return !"parent".equals( field.getName() ); - } - - private void evaluateArray( Object target ) - { - int len = Array.getLength( target ); - for ( int i = 0; i < len; i++ ) + @Override + void doInterpolate( Object target, InterpolateObjectAction ctx ) + throws IllegalAccessException { - Object value = Array.get( target, i ); + Object value = field.get( target ); if ( value != null ) { - if ( String.class == value.getClass() ) + if ( isArray ) { - String interpolated = - modelInterpolator.interpolateInternal( (String) value, valueSources, postProcessors, - problems ); - - if ( !interpolated.equals( value ) ) - { - Array.set( target, i, interpolated ); - } + evaluateArray( value, ctx ); } else { - interpolationTargets.add( value ); + ctx.interpolationTargets.add( value ); } } } } + } }