You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by kr...@apache.org on 2012/08/22 16:55:33 UTC

svn commit: r1376085 - /maven/maven-3/trunk/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/StringSearchModelInterpolator.java

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 );
                     }
                 }
             }
         }
+
     }
 
 }