You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by ol...@apache.org on 2019/07/24 02:30:18 UTC

[maven] branch master updated: [MNG-6697] New fast model interpolator not using reflection (#261)

This is an automated email from the ASF dual-hosted git repository.

olamy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven.git


The following commit(s) were added to refs/heads/master by this push:
     new 690841e  [MNG-6697] New fast model interpolator not using reflection (#261)
690841e is described below

commit 690841e9be62a93b468d48364b35608dd1b0c2a9
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Wed Jul 24 04:30:12 2019 +0200

    [MNG-6697] New fast model interpolator not using reflection (#261)
    
    * [MNG-6697] New fast model interpolator not using reflection
    
    * [MNG-6697] Fix management key in case a field has been modified
    
    * [MNG-6697] Remove the unused FIELDS_CACHE and make the InnerInterpolator private
    
    * [MNG-6697] Clean up the code to remove a few warnings
---
 .../model/building/DefaultModelBuilderFactory.java |    4 +-
 .../AbstractStringBasedModelInterpolator.java      |   81 +-
 .../StringSearchModelInterpolator.java             |  130 +-
 .../StringVisitorModelInterpolator.java            | 1457 ++++++++++++++++++++
 maven-model/src/main/mdo/maven.mdo                 |    8 +
 5 files changed, 1547 insertions(+), 133 deletions(-)

diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilderFactory.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilderFactory.java
index 36a0f46..4240574 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilderFactory.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilderFactory.java
@@ -25,7 +25,7 @@ import org.apache.maven.model.composition.DependencyManagementImporter;
 import org.apache.maven.model.inheritance.DefaultInheritanceAssembler;
 import org.apache.maven.model.inheritance.InheritanceAssembler;
 import org.apache.maven.model.interpolation.ModelInterpolator;
-import org.apache.maven.model.interpolation.StringSearchModelInterpolator;
+import org.apache.maven.model.interpolation.StringVisitorModelInterpolator;
 import org.apache.maven.model.io.DefaultModelReader;
 import org.apache.maven.model.io.ModelReader;
 import org.apache.maven.model.locator.DefaultModelLocator;
@@ -126,7 +126,7 @@ public class DefaultModelBuilderFactory
     {
         UrlNormalizer normalizer = newUrlNormalizer();
         PathTranslator pathTranslator = newPathTranslator();
-        return new StringSearchModelInterpolator().setPathTranslator( pathTranslator ).setUrlNormalizer( normalizer );
+        return new StringVisitorModelInterpolator().setPathTranslator( pathTranslator ).setUrlNormalizer( normalizer );
     }
 
     protected ModelValidator newModelValidator()
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/AbstractStringBasedModelInterpolator.java b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/AbstractStringBasedModelInterpolator.java
index 69d7e80..388671d 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/AbstractStringBasedModelInterpolator.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/AbstractStringBasedModelInterpolator.java
@@ -31,16 +31,11 @@ import javax.inject.Inject;
 
 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.apache.maven.model.path.PathTranslator;
 import org.apache.maven.model.path.UrlNormalizer;
 import org.codehaus.plexus.interpolation.AbstractValueSource;
-import org.codehaus.plexus.interpolation.InterpolationException;
 import org.codehaus.plexus.interpolation.InterpolationPostProcessor;
-import org.codehaus.plexus.interpolation.Interpolator;
 import org.codehaus.plexus.interpolation.MapBasedValueSource;
 import org.codehaus.plexus.interpolation.ObjectBasedValueSource;
 import org.codehaus.plexus.interpolation.PrefixAwareRecursionInterceptor;
@@ -93,14 +88,8 @@ public abstract class AbstractStringBasedModelInterpolator
     @Inject
     private UrlNormalizer urlNormalizer;
 
-    private Interpolator interpolator;
-
-    private RecursionInterceptor recursionInterceptor;
-
     public AbstractStringBasedModelInterpolator()
     {
-        interpolator = createInterpolator();
-        recursionInterceptor = new PrefixAwareRecursionInterceptor( PROJECT_PREFIXES );
     }
 
     public AbstractStringBasedModelInterpolator setPathTranslator( PathTranslator pathTranslator )
@@ -218,75 +207,9 @@ public abstract class AbstractStringBasedModelInterpolator
         return processors;
     }
 
-    protected String interpolateInternal( String src, List<? extends ValueSource> valueSources,
-                                          List<? extends InterpolationPostProcessor> postProcessors,
-                                          ModelProblemCollector problems )
-    {
-        if ( !src.contains( "${" ) )
-        {
-            return src;
-        }
-
-        String result = src;
-        synchronized ( this )
-        {
-
-            for ( ValueSource vs : valueSources )
-            {
-                interpolator.addValueSource( vs );
-            }
-
-            for ( InterpolationPostProcessor postProcessor : postProcessors )
-            {
-                interpolator.addPostProcessor( postProcessor );
-            }
-
-            try
-            {
-                try
-                {
-                    result = interpolator.interpolate( result, recursionInterceptor );
-                }
-                catch ( InterpolationException e )
-                {
-                    problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
-                        .setMessage( e.getMessage() ).setException( e ) );
-                }
-
-                interpolator.clearFeedback();
-            }
-            finally
-            {
-                for ( ValueSource vs : valueSources )
-                {
-                    interpolator.removeValuesSource( vs );
-                }
-
-                for ( InterpolationPostProcessor postProcessor : postProcessors )
-                {
-                    interpolator.removePostProcessor( postProcessor );
-                }
-            }
-        }
-
-        return result;
-    }
-
-    protected RecursionInterceptor getRecursionInterceptor()
-    {
-        return recursionInterceptor;
-    }
-
-    protected void setRecursionInterceptor( RecursionInterceptor recursionInterceptor )
-    {
-        this.recursionInterceptor = recursionInterceptor;
-    }
-
-    protected abstract Interpolator createInterpolator();
-
-    protected final Interpolator getInterpolator()
+    protected RecursionInterceptor createRecursionInterceptor()
     {
-        return interpolator;
+        return new PrefixAwareRecursionInterceptor( PROJECT_PREFIXES );
     }
 
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/StringSearchModelInterpolator.java b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/StringSearchModelInterpolator.java
index 0fb953d..3c2ea13 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/StringSearchModelInterpolator.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/StringSearchModelInterpolator.java
@@ -26,8 +26,9 @@ 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.interpolation.InterpolationException;
 import org.codehaus.plexus.interpolation.InterpolationPostProcessor;
-import org.codehaus.plexus.interpolation.Interpolator;
+import org.codehaus.plexus.interpolation.RecursionInterceptor;
 import org.codehaus.plexus.interpolation.StringSearchInterpolator;
 import org.codehaus.plexus.interpolation.ValueSource;
 
@@ -39,6 +40,7 @@ import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
@@ -60,6 +62,10 @@ public class StringSearchModelInterpolator
         new ConcurrentHashMap<>( 80, 0.75f, 2 );
     // Empirical data from 3.x, actual =40
 
+    private interface InnerInterpolator
+    {
+        String interpolate( String value );
+    }
 
     @Override
     public Model interpolateModel( Model model, File projectDir, ModelBuildingRequest config,
@@ -71,32 +77,62 @@ public class StringSearchModelInterpolator
     }
 
     protected void interpolateObject( Object obj, Model model, File projectDir, ModelBuildingRequest config,
-                                      ModelProblemCollector problems )
+                                      final ModelProblemCollector problems )
     {
-        try
-        {
-            List<? extends ValueSource> valueSources = createValueSources( model, projectDir, config, problems );
-            List<? extends InterpolationPostProcessor> postProcessors =
-                createPostProcessors( model, projectDir, config );
+        List<? extends ValueSource> valueSources = createValueSources( model, projectDir, config, problems );
+        List<? extends InterpolationPostProcessor> postProcessors =
+            createPostProcessors( model, projectDir, config );
 
-            InterpolateObjectAction action =
-                new InterpolateObjectAction( obj, valueSources, postProcessors, this, problems );
+        InnerInterpolator innerInterpolator = createInterpolator( valueSources, postProcessors, problems );
+
+        PrivilegedAction<Object> action;
+        action = new InterpolateObjectAction( obj, valueSources, postProcessors, innerInterpolator, problems );
+        AccessController.doPrivileged( action );
 
-            AccessController.doPrivileged( action );
-        }
-        finally
-        {
-            getInterpolator().clearAnswers();
-        }
     }
 
-    @Override
-    protected Interpolator createInterpolator()
+    private InnerInterpolator createInterpolator( List<? extends ValueSource> valueSources,
+                                                  List<? extends InterpolationPostProcessor> postProcessors,
+                                                  final ModelProblemCollector problems )
     {
-        StringSearchInterpolator interpolator = new StringSearchInterpolator();
+        final Map<String, String> cache = new HashMap<>();
+        final StringSearchInterpolator interpolator = new StringSearchInterpolator();
         interpolator.setCacheAnswers( true );
-
-        return interpolator;
+        for ( ValueSource vs : valueSources )
+        {
+            interpolator.addValueSource( vs );
+        }
+        for ( InterpolationPostProcessor postProcessor : postProcessors )
+        {
+            interpolator.addPostProcessor( postProcessor );
+        }
+        final RecursionInterceptor recursionInterceptor = createRecursionInterceptor();
+        return new InnerInterpolator()
+        {
+            @Override
+            public String interpolate( String value )
+            {
+                if ( value != null && value.contains( "${" ) )
+                {
+                    String c = cache.get( value );
+                    if ( c == null )
+                    {
+                        try
+                        {
+                            c = interpolator.interpolate( value, recursionInterceptor );
+                        }
+                        catch ( InterpolationException e )
+                        {
+                            problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
+                                    .setMessage( e.getMessage() ).setException( e ) );
+                        }
+                        cache.put( value, c );
+                    }
+                    return c;
+                }
+                return value;
+            }
+        };
     }
 
     private static final class InterpolateObjectAction
@@ -105,7 +141,7 @@ public class StringSearchModelInterpolator
 
         private final LinkedList<Object> interpolationTargets;
 
-        private final StringSearchModelInterpolator modelInterpolator;
+        private final InnerInterpolator interpolator;
 
         private final List<? extends ValueSource> valueSources;
 
@@ -115,7 +151,7 @@ public class StringSearchModelInterpolator
 
         InterpolateObjectAction( Object target, List<? extends ValueSource> valueSources,
                                  List<? extends InterpolationPostProcessor> postProcessors,
-                                 StringSearchModelInterpolator modelInterpolator, ModelProblemCollector problems )
+                                 InnerInterpolator interpolator, ModelProblemCollector problems )
         {
             this.valueSources = valueSources;
             this.postProcessors = postProcessors;
@@ -123,7 +159,7 @@ public class StringSearchModelInterpolator
             this.interpolationTargets = new LinkedList<>();
             interpolationTargets.add( target );
 
-            this.modelInterpolator = modelInterpolator;
+            this.interpolator = interpolator;
 
             this.problems = problems;
         }
@@ -144,7 +180,7 @@ public class StringSearchModelInterpolator
 
         private String interpolate( String value )
         {
-            return modelInterpolator.interpolateInternal( value, valueSources, postProcessors, problems );
+            return interpolator.interpolate( value );
         }
 
         private void traverseObjectWithParents( Class<?> cls, Object target )
@@ -297,40 +333,30 @@ public class StringSearchModelInterpolator
             CacheField( Field field )
             {
                 this.field = field;
+                field.setAccessible( true );
             }
 
             void interpolate( Object target, InterpolateObjectAction interpolateObjectAction )
             {
-                synchronized ( field )
+                try
                 {
-                    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 );
-                    }
+                    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 ) );
                 }
-
-
             }
 
             abstract void doInterpolate( Object target, InterpolateObjectAction ctx )
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/StringVisitorModelInterpolator.java b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/StringVisitorModelInterpolator.java
new file mode 100644
index 0000000..0ae5bce
--- /dev/null
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/StringVisitorModelInterpolator.java
@@ -0,0 +1,1457 @@
+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 java.io.File;
+import java.util.HashMap;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.apache.maven.model.Activation;
+import org.apache.maven.model.ActivationFile;
+import org.apache.maven.model.ActivationOS;
+import org.apache.maven.model.ActivationProperty;
+import org.apache.maven.model.Build;
+import org.apache.maven.model.BuildBase;
+import org.apache.maven.model.CiManagement;
+import org.apache.maven.model.Contributor;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.model.DependencyManagement;
+import org.apache.maven.model.Developer;
+import org.apache.maven.model.DistributionManagement;
+import org.apache.maven.model.Exclusion;
+import org.apache.maven.model.Extension;
+import org.apache.maven.model.IssueManagement;
+import org.apache.maven.model.License;
+import org.apache.maven.model.MailingList;
+import org.apache.maven.model.Model;
+import org.apache.maven.model.ModelBase;
+import org.apache.maven.model.Notifier;
+import org.apache.maven.model.Organization;
+import org.apache.maven.model.Parent;
+import org.apache.maven.model.Plugin;
+import org.apache.maven.model.PluginExecution;
+import org.apache.maven.model.PluginManagement;
+import org.apache.maven.model.Prerequisites;
+import org.apache.maven.model.Profile;
+import org.apache.maven.model.Relocation;
+import org.apache.maven.model.ReportPlugin;
+import org.apache.maven.model.ReportSet;
+import org.apache.maven.model.Reporting;
+import org.apache.maven.model.Repository;
+import org.apache.maven.model.RepositoryBase;
+import org.apache.maven.model.RepositoryPolicy;
+import org.apache.maven.model.Resource;
+import org.apache.maven.model.Scm;
+import org.apache.maven.model.Site;
+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.interpolation.InterpolationException;
+import org.codehaus.plexus.interpolation.InterpolationPostProcessor;
+import org.codehaus.plexus.interpolation.RecursionInterceptor;
+import org.codehaus.plexus.interpolation.StringSearchInterpolator;
+import org.codehaus.plexus.interpolation.ValueSource;
+import org.codehaus.plexus.util.xml.Xpp3Dom;
+
+/**
+ * StringVisitorModelInterpolator
+ */
+@Named
+@Singleton
+public class StringVisitorModelInterpolator
+    extends AbstractStringBasedModelInterpolator
+{
+
+    interface InnerInterpolator
+    {
+        String interpolate( String value );
+    }
+
+    @Override
+    public Model interpolateModel( Model model, File projectDir, ModelBuildingRequest config,
+                                   ModelProblemCollector problems )
+    {
+        List<? extends ValueSource> valueSources = createValueSources( model, projectDir, config, problems );
+        List<? extends InterpolationPostProcessor> postProcessors =
+            createPostProcessors( model, projectDir, config );
+
+        InnerInterpolator innerInterpolator = createInterpolator( valueSources, postProcessors, problems );
+
+        new ModelVisitor( innerInterpolator ).visit( model );
+
+        return model;
+    }
+
+    private InnerInterpolator createInterpolator( List<? extends ValueSource> valueSources,
+                                                  List<? extends InterpolationPostProcessor> postProcessors,
+                                                  final ModelProblemCollector problems )
+    {
+        final Map<String, String> cache = new HashMap<>();
+        final StringSearchInterpolator interpolator = new StringSearchInterpolator();
+        interpolator.setCacheAnswers( true );
+        for ( ValueSource vs : valueSources )
+        {
+            interpolator.addValueSource( vs );
+        }
+        for ( InterpolationPostProcessor postProcessor : postProcessors )
+        {
+            interpolator.addPostProcessor( postProcessor );
+        }
+        final RecursionInterceptor recursionInterceptor = createRecursionInterceptor();
+        return new InnerInterpolator()
+        {
+            @Override
+            public String interpolate( String value )
+            {
+                if ( value != null && value.contains( "${" ) )
+                {
+                    String c = cache.get( value );
+                    if ( c == null )
+                    {
+                        try
+                        {
+                            c = interpolator.interpolate( value, recursionInterceptor );
+                        }
+                        catch ( InterpolationException e )
+                        {
+                            problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
+                                    .setMessage( e.getMessage() ).setException( e ) );
+                        }
+                        cache.put( value, c );
+                    }
+                    return c;
+                }
+                return value;
+            }
+        };
+    }
+
+    @SuppressWarnings( "StringEquality" )
+    private static final class ModelVisitor
+    {
+        private final InnerInterpolator interpolator;
+
+        ModelVisitor( InnerInterpolator interpolator )
+        {
+            this.interpolator = interpolator;
+        }
+
+        void visit( Model model )
+        {
+            if ( model != null )
+            {
+                visit( (ModelBase) model );
+                // ModelVersion
+                String orgModelVersion = model.getModelVersion();
+                String intModelVersion = interpolate( orgModelVersion );
+                if ( orgModelVersion != intModelVersion )
+                {
+                    model.setModelVersion( intModelVersion );
+                }
+                visit( model.getParent() );
+                // GroupId
+                String orgGroupId = model.getGroupId();
+                String intGroupId = interpolate( orgGroupId );
+                if ( orgGroupId != intGroupId )
+                {
+                    model.setGroupId( intGroupId );
+                }
+                // ArtifactId
+                String orgArtifactId = model.getArtifactId();
+                String intArtifactId = interpolate( orgArtifactId );
+                if ( orgArtifactId != intArtifactId )
+                {
+                    model.setArtifactId( intArtifactId );
+                }
+                // Version
+                String orgVersion = model.getVersion();
+                String intVersion = interpolate( orgVersion );
+                if ( orgVersion != intVersion )
+                {
+                    model.setVersion( intVersion );
+                }
+
+                // Packaging
+                String orgPackaging = model.getPackaging();
+                String intPackaging = interpolate( orgPackaging );
+                if ( orgPackaging != intPackaging )
+                {
+                    model.setPackaging( intPackaging );
+                }
+                // Name
+                String orgName = model.getName();
+                String intName = interpolate( orgName );
+                if ( orgName != intName )
+                {
+                    model.setName( intName );
+                }
+                // Description
+                String orgDescription = model.getDescription();
+                String intDescription = interpolate( orgDescription );
+                if ( orgDescription != intDescription )
+                {
+                    model.setDescription( intDescription );
+                }
+                // Url
+                String orgUrl = model.getUrl();
+                String intUrl = interpolate( orgUrl );
+                if ( orgUrl != intUrl )
+                {
+                    model.setUrl( intUrl );
+                }
+                // ChildProjectUrlInheritAppendPath
+                String orgChildProjectUrlInheritAppendPath = model.getChildProjectUrlInheritAppendPath();
+                String intChildProjectUrlInheritAppendPath = interpolate( orgChildProjectUrlInheritAppendPath );
+                if ( orgChildProjectUrlInheritAppendPath != intChildProjectUrlInheritAppendPath )
+                {
+                    model.setChildProjectUrlInheritAppendPath( intChildProjectUrlInheritAppendPath );
+                }
+                // InceptionYear
+                String orgInceptionYear = model.getInceptionYear();
+                String intInceptionYear = interpolate( orgInceptionYear );
+                if ( orgInceptionYear != intInceptionYear )
+                {
+                    model.setInceptionYear( intInceptionYear );
+                }
+                visit( model.getOrganization() );
+                for ( License license : model.getLicenses() )
+                {
+                    visit( license );
+                }
+                for ( Developer developer : model.getDevelopers() )
+                {
+                    visit( developer );
+                }
+                for ( Contributor contributor : model.getContributors() )
+                {
+                    visit( contributor );
+                }
+                for ( MailingList mailingList : model.getMailingLists() )
+                {
+                    visit( mailingList );
+                }
+                visit( model.getPrerequisites() );
+                visit( model.getScm() );
+                visit( model.getIssueManagement() );
+                visit( model.getCiManagement() );
+                visit( model.getBuild() );
+                for ( Profile profile : model.getProfiles() )
+                {
+                    visit( profile );
+                }
+
+            }
+        }
+
+        private void visit( Parent parent )
+        {
+            if ( parent != null )
+            {
+                String org, val;
+                // GroupId
+                org = parent.getGroupId();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    parent.setGroupId( val );
+                }
+                // ArtifactId
+                org = parent.getArtifactId();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    parent.setArtifactId( val );
+                }
+                // Version
+                org = parent.getVersion();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    parent.setVersion( val );
+                }
+                // RelativePath
+                org = parent.getRelativePath();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    parent.setRelativePath( val );
+                }
+            }
+        }
+
+        private void visit( Organization organization )
+        {
+            if ( organization != null )
+            {
+                String org, val;
+                // Name
+                org = organization.getName();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    organization.setName( val );
+                }
+                // Url
+                org = organization.getUrl();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    organization.setUrl( val );
+                }
+            }
+        }
+
+        private void visit( License license )
+        {
+            if ( license != null )
+            {
+                String org, val;
+                // Name
+                org = license.getName();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    license.setName( val );
+                }
+                // Url
+                org = license.getUrl();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    license.setUrl( val );
+                }
+                // Distribution
+                org = license.getDistribution();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    license.setDistribution( val );
+                }
+                // Comments
+                org = license.getComments();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    license.setComments( val );
+                }
+            }
+        }
+
+        private void visit( Developer developer )
+        {
+            if ( developer != null )
+            {
+                String org, val;
+                // Contributor
+                visit( (Contributor) developer );
+                // Distribution
+                org = developer.getId();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    developer.setId( val );
+                }
+            }
+        }
+
+        private void visit( Contributor contributor )
+        {
+            if ( contributor != null )
+            {
+                String org, val;
+                // Name
+                org = contributor.getName();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    contributor.setName( val );
+                }
+                // Email
+                org = contributor.getEmail();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    contributor.setEmail( val );
+                }
+                // Url
+                org = contributor.getUrl();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    contributor.setUrl( val );
+                }
+                // Organization
+                org = contributor.getOrganization();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    contributor.setOrganization( val );
+                }
+                // OrganizationUrl
+                org = contributor.getOrganizationUrl();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    contributor.setOrganizationUrl( val );
+                }
+                // Roles
+                visit( contributor.getRoles() );
+            }
+        }
+
+        private void visit( MailingList mailingList )
+        {
+            if ( mailingList != null )
+            {
+                String org, val;
+                // Name
+                org = mailingList.getName();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    mailingList.setName( val );
+                }
+                // Subscribe
+                org = mailingList.getSubscribe();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    mailingList.setSubscribe( val );
+                }
+                // Unsubscribe
+                org = mailingList.getUnsubscribe();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    mailingList.setUnsubscribe( val );
+                }
+                // Post
+                org = mailingList.getPost();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    mailingList.setPost( val );
+                }
+                // Archive
+                org = mailingList.getArchive();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    mailingList.setArchive( val );
+                }
+            }
+        }
+
+        private void visit( Prerequisites prerequisites )
+        {
+            if ( prerequisites != null )
+            {
+                String org, val;
+                // Maven
+                org = prerequisites.getMaven();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    prerequisites.setMaven( val );
+                }
+            }
+        }
+
+        private void visit( Scm scm )
+        {
+            if ( scm != null )
+            {
+                String org, val;
+                // Connection
+                org = scm.getConnection();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    scm.setConnection( val );
+                }
+                // DeveloperConnection
+                org = scm.getDeveloperConnection();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    scm.setDeveloperConnection( val );
+                }
+                // Tag
+                org = scm.getTag();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    scm.setTag( val );
+                }
+                // Url
+                org = scm.getUrl();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    scm.setUrl( val );
+                }
+                // ChildScmConnectionInheritAppendPath
+                org = scm.getChildScmConnectionInheritAppendPath();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    scm.setChildScmConnectionInheritAppendPath( val );
+                }
+                // ChildScmDeveloperConnectionInheritAppendPath
+                org = scm.getChildScmDeveloperConnectionInheritAppendPath();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    scm.setChildScmDeveloperConnectionInheritAppendPath( val );
+                }
+                // ChildScmUrlInheritAppendPath
+                org = scm.getChildScmUrlInheritAppendPath();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    scm.setChildScmUrlInheritAppendPath( val );
+                }
+            }
+        }
+
+        private void visit( IssueManagement issueManagement )
+        {
+            if ( issueManagement != null )
+            {
+                String org, val;
+                // System
+                org = issueManagement.getSystem();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    issueManagement.setSystem( val );
+                }
+                // Url
+                org = issueManagement.getUrl();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    issueManagement.setUrl( val );
+                }
+            }
+        }
+
+        private void visit( CiManagement ciManagement )
+        {
+            if ( ciManagement != null )
+            {
+                String org, val;
+                // System
+                org = ciManagement.getSystem();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    ciManagement.setSystem( val );
+                }
+                // Url
+                org = ciManagement.getUrl();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    ciManagement.setUrl( val );
+                }
+                // Notifiers
+                for ( Notifier notifier : ciManagement.getNotifiers() )
+                {
+                    visit( notifier );
+                }
+            }
+        }
+
+        private void visit( Notifier notifier )
+        {
+            if ( notifier != null )
+            {
+                String org, val;
+                // Type
+                org = notifier.getType();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    notifier.setType( val );
+                }
+                // Configuration
+                visit( notifier.getConfiguration() );
+            }
+        }
+
+        private void visit( BuildBase build )
+        {
+            if ( build != null )
+            {
+                String org, val;
+                // Plugins
+                for ( Plugin plugin : build.getPlugins() )
+                {
+                    visit( plugin );
+                }
+                // PluginManagement
+                visit( build.getPluginManagement() );
+                // DefaultGoal
+                org = build.getDefaultGoal();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    build.setDefaultGoal( val );
+                }
+                // Resources
+                for ( Resource resource : build.getResources() )
+                {
+                    visit( resource );
+                }
+                // TestResources
+                for ( Resource resource : build.getTestResources() )
+                {
+                    visit( resource );
+                }
+                // Directory
+                org = build.getDirectory();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    build.setDirectory( val );
+                }
+                // FinalName
+                org = build.getFinalName();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    build.setFinalName( val );
+                }
+                // Filters
+                visit( build.getFilters() );
+            }
+        }
+
+        private void visit( PluginManagement pluginManagement )
+        {
+            if ( pluginManagement != null )
+            {
+                for ( Plugin plugin : pluginManagement.getPlugins() )
+                {
+                    visit( plugin );
+                }
+            }
+        }
+
+        private void visit( Build build )
+        {
+            if ( build != null )
+            {
+                String org, val;
+                // BuildBase
+                visit( (BuildBase) build );
+                // SourceDirectory
+                org = build.getSourceDirectory();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    build.setSourceDirectory( val );
+                }
+                // ScriptSourceDirectory
+                org = build.getScriptSourceDirectory();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    build.setScriptSourceDirectory( val );
+                }
+                // TestSourceDirectory
+                org = build.getTestSourceDirectory();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    build.setTestSourceDirectory( val );
+                }
+                // OutputDirectory
+                org = build.getOutputDirectory();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    build.setOutputDirectory( val );
+                }
+                // TestOutputDirectory
+                org = build.getTestOutputDirectory();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    build.setTestOutputDirectory( val );
+                }
+                // Extensions
+                for ( Extension extension : build.getExtensions() )
+                {
+                    visit( extension );
+                }
+            }
+        }
+
+        private void visit( Resource resource )
+        {
+            if ( resource != null )
+            {
+                String org, val;
+                // Includes
+                visit( resource.getIncludes() );
+                // Excludes
+                visit( resource.getExcludes() );
+                // Directory
+                org = resource.getDirectory();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    resource.setDirectory( val );
+                }
+                // TargetPath
+                org = resource.getTargetPath();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    resource.setTargetPath( val );
+                }
+                // Filtering
+                org = resource.getFiltering();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    resource.setFiltering( val );
+                }
+            }
+        }
+
+        private void visit( Plugin plugin )
+        {
+            if ( plugin != null )
+            {
+                String org, val;
+                // Inherited
+                org = plugin.getInherited();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    plugin.setInherited( val );
+                }
+                // Configuration
+                visit( (Xpp3Dom) plugin.getConfiguration() );
+                // GroupId
+                org = plugin.getGroupId();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    plugin.setGroupId( val );
+                }
+                // ArtifactId
+                org = plugin.getArtifactId();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    plugin.setArtifactId( val );
+                }
+                // Version
+                org = plugin.getVersion();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    plugin.setVersion( val );
+                }
+                // Extensions
+                org = plugin.getExtensions();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    plugin.setExtensions( val );
+                }
+                // Executions
+                for ( PluginExecution execution : plugin.getExecutions() )
+                {
+                    visit( execution );
+                }
+                // Dependencies
+                for ( Dependency dependency : plugin.getDependencies() )
+                {
+                    visit( dependency );
+                }
+            }
+        }
+
+        private void visit( PluginExecution execution )
+        {
+            if ( execution != null )
+            {
+                String org, val;
+                // Inherited
+                org = execution.getInherited();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    execution.setInherited( val );
+                }
+                // Configuration
+                visit( (Xpp3Dom) execution.getConfiguration() );
+                // Id
+                org = execution.getId();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    execution.setId( val );
+                }
+                // Phase
+                org = execution.getPhase();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    execution.setPhase( val );
+                }
+                // Goals
+                visit( execution.getGoals() );
+            }
+        }
+
+        private void visit( Xpp3Dom dom )
+        {
+            if ( dom != null )
+            {
+                String org, val;
+                // Content
+                org = dom.getValue();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    dom.setValue( val );
+                }
+                // Attributes
+                for ( String attr : dom.getAttributeNames() )
+                {
+                    org = dom.getAttribute( attr );
+                    val = interpolate( org );
+                    if ( org != val )
+                    {
+                        dom.setAttribute( attr, val );
+                    }
+                }
+                // Children
+                for ( int i = 0, l = dom.getChildCount(); i < l; i++ )
+                {
+                    visit( dom.getChild( i ) );
+                }
+            }
+        }
+
+        private void visit( Extension extension )
+        {
+            if ( extension != null )
+            {
+                String org, val;
+                // GroupId
+                org = extension.getGroupId();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    extension.setGroupId( val );
+                }
+                // ArtifactId
+                org = extension.getArtifactId();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    extension.setArtifactId( val );
+                }
+                // Version
+                org = extension.getVersion();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    extension.setVersion( val );
+                }
+            }
+        }
+
+        private void visit( Profile profile )
+        {
+            if ( profile != null )
+            {
+                String org, val;
+                // ModelBase
+                visit( (ModelBase) profile );
+                // Id
+                org = profile.getId();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    profile.setId( val );
+                }
+                // Activation
+                visit( profile.getActivation() );
+                // Build
+                visit( profile.getBuild() );
+            }
+        }
+
+        private void visit( Activation activation )
+        {
+            if ( activation != null )
+            {
+                String org, val;
+                // Jdk
+                org = activation.getJdk();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    activation.setJdk( val );
+                }
+                // OS
+                visit( activation.getOs() );
+                // Property
+                visit( activation.getProperty() );
+                // File
+                visit( activation.getFile() );
+            }
+        }
+
+        private void visit( ActivationOS activationOS )
+        {
+            if ( activationOS != null )
+            {
+                String org, val;
+                // Name
+                org = activationOS.getName();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    activationOS.setName( val );
+                }
+                // Family
+                org = activationOS.getFamily();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    activationOS.setFamily( val );
+                }
+                // Arch
+                org = activationOS.getArch();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    activationOS.setArch( val );
+                }
+                // Version
+                org = activationOS.getVersion();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    activationOS.setVersion( val );
+                }
+            }
+        }
+
+        private void visit( ActivationProperty activationProperty )
+        {
+            if ( activationProperty != null )
+            {
+                String org, val;
+                // Name
+                org = activationProperty.getName();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    activationProperty.setName( val );
+                }
+                // Value
+                org = activationProperty.getValue();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    activationProperty.setValue( val );
+                }
+            }
+        }
+
+        private void visit( ActivationFile activationFile )
+        {
+            if ( activationFile != null )
+            {
+                String org, val;
+                // Missing
+                org = activationFile.getMissing();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    activationFile.setMissing( val );
+                }
+                // Exists
+                org = activationFile.getExists();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    activationFile.setExists( val );
+                }
+            }
+        }
+
+        private void visit( ModelBase modelBase )
+        {
+            if ( modelBase != null )
+            {
+                visit( modelBase.getModules() );
+                visit( modelBase.getDistributionManagement() );
+                visit( modelBase.getProperties() );
+                visit( modelBase.getDependencyManagement() );
+                for ( Dependency dependency : modelBase.getDependencies() )
+                {
+                    visit( dependency );
+                }
+                for ( Repository repository : modelBase.getRepositories() )
+                {
+                    visit( repository );
+                }
+                for ( Repository repository : modelBase.getPluginRepositories() )
+                {
+                    visit( repository );
+                }
+                visit( modelBase.getReporting() );
+            }
+        }
+
+        private void visit( DistributionManagement distributionManagement )
+        {
+            if ( distributionManagement != null )
+            {
+                String org, val;
+                // Repository
+                visit( distributionManagement.getRepository() );
+                // SnapshotRepository
+                visit( distributionManagement.getSnapshotRepository() );
+                // Site
+                visit( distributionManagement.getSite() );
+                // DownloadUrl
+                org = distributionManagement.getDownloadUrl();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    distributionManagement.setDownloadUrl( val );
+                }
+                // Relocation
+                visit( distributionManagement.getRelocation() );
+            }
+        }
+
+        private void visit( Site site )
+        {
+            if ( site != null )
+            {
+                String org, val;
+                // Id
+                org = site.getId();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    site.setId( val );
+                }
+                // Name
+                org = site.getName();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    site.setName( val );
+                }
+                // Url
+                org = site.getUrl();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    site.setUrl( val );
+                }
+                // ChildSiteUrlInheritAppendPath
+                org = site.getChildSiteUrlInheritAppendPath();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    site.setChildSiteUrlInheritAppendPath( val );
+                }
+            }
+        }
+
+        private void visit( Relocation relocation )
+        {
+            if ( relocation != null )
+            {
+                String org, val;
+                // GroupId
+                org = relocation.getGroupId();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    relocation.setGroupId( val );
+                }
+                // ArtifactId
+                org = relocation.getArtifactId();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    relocation.setArtifactId( val );
+                }
+                // Version
+                org = relocation.getVersion();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    relocation.setVersion( val );
+                }
+                // Message
+                org = relocation.getMessage();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    relocation.setMessage( val );
+                }
+            }
+        }
+
+        private void visit( DependencyManagement dependencyManagement )
+        {
+            if ( dependencyManagement != null )
+            {
+                // Dependencies
+                for ( Dependency dependency : dependencyManagement.getDependencies() )
+                {
+                    visit( dependency );
+                }
+            }
+        }
+
+        private void visit( Repository repository )
+        {
+            if ( repository != null )
+            {
+                visit( (RepositoryBase) repository );
+                visit( repository.getReleases() );
+                visit( repository.getSnapshots() );
+            }
+        }
+
+        private void visit( RepositoryBase repositoryBase )
+        {
+            if ( repositoryBase != null )
+            {
+                // Id
+                String orgId = repositoryBase.getId();
+                String intId = interpolate( orgId );
+                if ( orgId != intId )
+                {
+                    repositoryBase.setId( intId );
+                }
+                // Name
+                String orgName = repositoryBase.getName();
+                String intName = interpolate( orgName );
+                if ( orgName != intName )
+                {
+                    repositoryBase.setName( intName );
+                }
+                // Url
+                String orgUrl = repositoryBase.getUrl();
+                String intUrl = interpolate( orgUrl );
+                if ( orgUrl != intUrl )
+                {
+                    repositoryBase.setUrl( intUrl );
+                }
+                // Layout
+                String orgLayout = repositoryBase.getLayout();
+                String intLayout = interpolate( orgLayout );
+                if ( orgLayout != intLayout )
+                {
+                    repositoryBase.setLayout( intLayout );
+                }
+            }
+        }
+
+        private void visit( RepositoryPolicy repositoryPolicy )
+        {
+            if ( repositoryPolicy != null )
+            {
+                // Enabled
+                String orgEnabled = repositoryPolicy.getEnabled();
+                String intEnabled = interpolate( orgEnabled );
+                if ( orgEnabled != intEnabled )
+                {
+                    repositoryPolicy.setEnabled( intEnabled );
+                }
+                // UpdatePolicy
+                String orgUpdatePolicy = repositoryPolicy.getUpdatePolicy();
+                String intUpdatePolicy = interpolate( orgUpdatePolicy );
+                if ( orgUpdatePolicy != intUpdatePolicy )
+                {
+                    repositoryPolicy.setUpdatePolicy( intUpdatePolicy );
+                }
+                // ChecksumPolicy
+                String orgChecksumPolicy = repositoryPolicy.getChecksumPolicy();
+                String intChecksumPolicy = interpolate( orgChecksumPolicy );
+                if ( orgChecksumPolicy != intChecksumPolicy )
+                {
+                    repositoryPolicy.setChecksumPolicy( intChecksumPolicy );
+                }
+            }
+        }
+
+        private void visit( Dependency dependency )
+        {
+            if ( dependency != null )
+            {
+                String org, val;
+                // GroupId
+                org = dependency.getGroupId();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    dependency.setGroupId( val );
+                    dependency.clearManagementKey();
+                }
+                // ArtifactId
+                org = dependency.getArtifactId();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    dependency.setArtifactId( val );
+                    dependency.clearManagementKey();
+                }
+                // Version
+                org = dependency.getVersion();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    dependency.setVersion( val );
+                }
+                // Type
+                org = dependency.getType();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    dependency.setType( val );
+                    dependency.clearManagementKey();
+                }
+                // Classifier
+                org = dependency.getClassifier();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    dependency.setClassifier( val );
+                    dependency.clearManagementKey();
+                }
+                // Scope
+                org = dependency.getScope();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    dependency.setScope( val );
+                }
+                // SystemPath
+                org = dependency.getSystemPath();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    dependency.setSystemPath( val );
+                }
+                // Exclusions
+                for ( Exclusion exclusion : dependency.getExclusions() )
+                {
+                    visit( exclusion );
+                }
+                // Optional
+                org = dependency.getOptional();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    dependency.setOptional( val );
+                }
+            }
+        }
+
+        private void visit( Exclusion exclusion )
+        {
+            if ( exclusion != null )
+            {
+                String org, val;
+                // GroupId
+                org = exclusion.getGroupId();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    exclusion.setGroupId( val );
+                }
+                // ArtifactId
+                org = exclusion.getArtifactId();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    exclusion.setArtifactId( val );
+                }
+            }
+        }
+
+        private void visit( Reporting reporting )
+        {
+            if ( reporting != null )
+            {
+                String org, val;
+                // ExcludeDefaults
+                org = reporting.getExcludeDefaults();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    reporting.setExcludeDefaults( val );
+                }
+                // OutputDirectory
+                org = reporting.getOutputDirectory();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    reporting.setOutputDirectory( val );
+                }
+                // Plugins
+                for ( ReportPlugin plugin : reporting.getPlugins() )
+                {
+                    visit( plugin );
+                }
+            }
+        }
+
+        private void visit( ReportPlugin plugin )
+        {
+            if ( plugin != null )
+            {
+                String org, val;
+                // Inherited
+                org = plugin.getInherited();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    plugin.setInherited( val );
+                }
+                // Configuration
+                visit( (Xpp3Dom) plugin.getConfiguration() );
+                // GroupId
+                org = plugin.getGroupId();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    plugin.setGroupId( val );
+                }
+                // ArtifactId
+                org = plugin.getArtifactId();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    plugin.setArtifactId( val );
+                }
+                // Version
+                org = plugin.getVersion();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    plugin.setVersion( val );
+                }
+                // ReportSets
+                for ( ReportSet reportSet : plugin.getReportSets() )
+                {
+                    visit( reportSet );
+                }
+            }
+        }
+
+        private void visit( ReportSet reportSet )
+        {
+            if ( reportSet != null )
+            {
+                String org, val;
+                // Inherited
+                org = reportSet.getInherited();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    reportSet.setInherited( val );
+                }
+                // Configuration
+                visit( (Xpp3Dom) reportSet.getConfiguration() );
+                // Id
+                org = reportSet.getId();
+                val = interpolate( org );
+                if ( org != val )
+                {
+                    reportSet.setId( val );
+                }
+                // Reports
+                visit( reportSet.getReports() );
+            }
+        }
+
+        private void visit( Properties properties )
+        {
+            if ( properties != null )
+            {
+                for ( Map.Entry<Object, Object> entry : properties.entrySet() )
+                {
+                    Object v = entry.getValue();
+                    if ( v instanceof String )
+                    {
+                        String value = (String) v;
+                        String inter = interpolate( value );
+                        if ( value != inter )
+                        {
+                            entry.setValue( inter );
+                        }
+                    }
+                }
+            }
+        }
+
+        private void visit( List<String> list )
+        {
+            if ( list != null )
+            {
+                ListIterator<String> it = list.listIterator();
+                while ( it.hasNext() )
+                {
+                    String value = it.next();
+                    String inter = interpolate( value );
+                    if ( value != inter )
+                    {
+                        it.set( inter );
+                    }
+                }
+            }
+        }
+
+        private String interpolate( String value )
+        {
+            return interpolator.interpolate( value );
+        }
+
+    }
+}
diff --git a/maven-model/src/main/mdo/maven.mdo b/maven-model/src/main/mdo/maven.mdo
index b199ee1..77738f1 100644
--- a/maven-model/src/main/mdo/maven.mdo
+++ b/maven-model/src/main/mdo/maven.mdo
@@ -1153,6 +1153,14 @@
         }
         return managementKey;
     }
+
+    /**
+     * Clears the management key in case one field has been modified.
+     */
+    public void clearManagementKey()
+    {
+        managementKey = null;
+    }
             ]]>
           </code>
         </codeSegment>