Adding components and classes for resolving/loading models more easily.

git-svn-id: https://svn.apache.org/repos/asf/maven/sandbox/trunk/mae@1157286 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/mae-api/src/main/java/org/apache/maven/mae/DefaultMAEExecutionRequest.java b/mae-api/src/main/java/org/apache/maven/mae/DefaultMAEExecutionRequest.java
index 4fc40ee..ed6a440 100644
--- a/mae-api/src/main/java/org/apache/maven/mae/DefaultMAEExecutionRequest.java
+++ b/mae-api/src/main/java/org/apache/maven/mae/DefaultMAEExecutionRequest.java
@@ -19,6 +19,11 @@
 
 package org.apache.maven.mae;
 
+import java.io.File;
+import java.util.Date;
+import java.util.List;
+import java.util.Properties;
+
 import org.apache.maven.artifact.repository.ArtifactRepository;
 import org.apache.maven.execution.DefaultMavenExecutionRequest;
 import org.apache.maven.execution.ExecutionListener;
@@ -30,11 +35,6 @@
 import org.apache.maven.settings.Server;
 import org.apache.maven.settings.Settings;
 
-import java.io.File;
-import java.util.Date;
-import java.util.List;
-import java.util.Properties;
-
 public class DefaultMAEExecutionRequest
     implements MAEExecutionRequest
 {
@@ -44,463 +44,503 @@
     private String password;
 
     private final DefaultMavenExecutionRequest embedded = new DefaultMavenExecutionRequest();
-    
-//    public DefautMAEExecutionRequest()
-//    {
-//    }
 
+    // public DefautMAEExecutionRequest()
+    // {
+    // }
+
+    @Override
     public DefaultMAEExecutionRequest copyOf()
     {
-        return new DefaultMAEExecutionRequest().setPasswordToEncrypt( getPasswordToEncyrpt() )
-                                               .setSettings( getSettings() )
-                                               .setBaseDirectory( new File( getBaseDirectory() ) )
-                                               .setStartTime( getStartTime() )
-                                               .setGoals( getGoals() )
-                                               .setSystemProperties( getSystemProperties() )
-                                               .setUserProperties( getUserProperties() )
-                                               .setReactorFailureBehavior( getReactorFailureBehavior() )
-                                               .setSelectedProjects( getSelectedProjects() )
-                                               .setResumeFrom( getResumeFrom() )
-                                               .setMakeBehavior( getMakeBehavior() )
-                                               .setThreadCount( getThreadCount() )
-                                               .setPerCoreThreadCount( isPerCoreThreadCount() )
-                                               .setRecursive( isRecursive() )
-                                               .setPom( getPom() )
-                                               .setShowErrors( isShowErrors() )
-                                               .setLoggingLevel( getLoggingLevel() )
-                                               .setUpdateSnapshots( isUpdateSnapshots() )
-                                               .setNoSnapshotUpdates( isNoSnapshotUpdates() )
-                                               .setGlobalChecksumPolicy( getGlobalChecksumPolicy() )
-                                               .setLocalRepositoryPath( getLocalRepositoryPath() )
-                                               .setLocalRepositoryPath( getLocalRepositoryPath() )
-                                               .setLocalRepository( getLocalRepository() )
-                                               .setInteractiveMode( isInteractiveMode() )
-                                               .setOffline( isOffline() )
-                                               .setProfiles( getProfiles() )
-                                               .setActiveProfiles( getActiveProfiles() )
-                                               .setInactiveProfiles( getInactiveProfiles() )
-                                               .setProxies( getProxies() )
-                                               .setServers( getServers() )
-                                               .setMirrors( getMirrors() )
-                                               .setPluginGroups( getPluginGroups() )
-                                               .setProjectPresent( isProjectPresent() )
-                                               .setUserSettingsFile( getUserSettingsFile() )
-                                               .setGlobalSettingsFile( getGlobalSettingsFile() )
-                                               .setRemoteRepositories( getRemoteRepositories() )
-                                               .setPluginArtifactRepositories( getPluginArtifactRepositories() )
-                                               .setUserToolchainsFile( getUserToolchainsFile() )
-                                               .setExecutionListener( getExecutionListener() );
+        return new DefaultMAEExecutionRequest().setPasswordToEncrypt( getPasswordToEncyrpt() ).setSettings( getSettings() ).setBaseDirectory( new File(
+                                                                                                                                                        getBaseDirectory() ) ).setStartTime( getStartTime() ).setGoals( getGoals() ).setSystemProperties( getSystemProperties() ).setUserProperties( getUserProperties() ).setReactorFailureBehavior( getReactorFailureBehavior() ).setSelectedProjects( getSelectedProjects() ).setResumeFrom( getResumeFrom() ).setMakeBehavior( getMakeBehavior() ).setThreadCount( getThreadCount() ).setPerCoreThreadCount( isPerCoreThreadCount() ).setRecursive( isRecursive() ).setPom( getPom() ).setShowErrors( isShowErrors() ).setLoggingLevel( getLoggingLevel() ).setUpdateSnapshots( isUpdateSnapshots() ).setNoSnapshotUpdates( isNoSnapshotUpdates() ).setGlobalChecksumPolicy( getGlobalChecksumPolicy() ).setLocalRepositoryPath( getLocalRepositoryPath() ).setLocalRepositoryPath( getLocalRepositoryPath() ).setLocalRepository( getLocalRepository() ).setInteractiveMode( isInteractiveMode() ).setOffline( isOffline() ).setProfiles( getProfiles() ).setActiveProfiles( getActiveProfiles() ).setInactiveProfiles( getInactiveProfiles() ).setProxies( getProxies() ).setServers( getServers() ).setMirrors( getMirrors() ).setPluginGroups( getPluginGroups() ).setProjectPresent( isProjectPresent() ).setUserSettingsFile( getUserSettingsFile() ).setGlobalSettingsFile( getGlobalSettingsFile() ).setRemoteRepositories( getRemoteRepositories() ).setPluginArtifactRepositories( getPluginArtifactRepositories() ).setUserToolchainsFile( getUserToolchainsFile() ).setExecutionListener( getExecutionListener() );
     }
 
+    @Override
     public MavenExecutionRequest asMavenExecutionRequest()
     {
         return embedded;
     }
 
+    @Override
     public DefaultMAEExecutionRequest setPasswordToEncrypt( final String password )
     {
         this.password = password;
         return this;
     }
 
+    @Override
     public String getPasswordToEncyrpt()
     {
         return password;
     }
 
+    @Override
     public DefaultMAEExecutionRequest setSettings( final Settings settings )
     {
         this.settings = settings;
         return this;
     }
 
+    @Override
     public Settings getSettings()
     {
         return settings;
     }
 
+    @Override
     public DefaultMAEExecutionRequest addActiveProfile( final String profile )
     {
         embedded.addActiveProfile( profile );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest addActiveProfiles( final List<String> profiles )
     {
         embedded.addActiveProfiles( profiles );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest addInactiveProfile( final String profile )
     {
         embedded.addInactiveProfile( profile );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest addInactiveProfiles( final List<String> profiles )
     {
         embedded.addInactiveProfiles( profiles );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest addMirror( final Mirror mirror )
     {
         embedded.addMirror( mirror );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest addPluginArtifactRepository( final ArtifactRepository repository )
     {
         embedded.addPluginArtifactRepository( repository );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest addPluginGroup( final String pluginGroup )
     {
         embedded.addPluginGroup( pluginGroup );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest addPluginGroups( final List<String> pluginGroups )
     {
         embedded.addPluginGroups( pluginGroups );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest addProfile( final Profile profile )
     {
         embedded.addProfile( profile );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest addProxy( final Proxy proxy )
     {
         embedded.addProxy( proxy );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest addRemoteRepository( final ArtifactRepository repository )
     {
         embedded.addRemoteRepository( repository );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest addServer( final Server server )
     {
         embedded.addServer( server );
         return this;
     }
 
+    @Override
     public List<String> getActiveProfiles()
     {
         return embedded.getActiveProfiles();
     }
 
+    @Override
     public String getBaseDirectory()
     {
         return embedded.getBaseDirectory();
     }
 
+    @Override
     public ExecutionListener getExecutionListener()
     {
         return embedded.getExecutionListener();
     }
 
+    @Override
     public String getGlobalChecksumPolicy()
     {
         return embedded.getGlobalChecksumPolicy();
     }
 
+    @Override
     public File getGlobalSettingsFile()
     {
         return embedded.getGlobalSettingsFile();
     }
 
+    @Override
     public List<String> getGoals()
     {
         return embedded.getGoals();
     }
 
+    @Override
     public List<String> getInactiveProfiles()
     {
         return embedded.getInactiveProfiles();
     }
 
+    @Override
     public ArtifactRepository getLocalRepository()
     {
         return embedded.getLocalRepository();
     }
 
+    @Override
     public File getLocalRepositoryPath()
     {
         return embedded.getLocalRepositoryPath();
     }
 
+    @Override
     public int getLoggingLevel()
     {
         return embedded.getLoggingLevel();
     }
 
+    @Override
     public String getMakeBehavior()
     {
         return embedded.getMakeBehavior();
     }
 
+    @Override
     public List<Mirror> getMirrors()
     {
         return embedded.getMirrors();
     }
 
+    @Override
     public List<ArtifactRepository> getPluginArtifactRepositories()
     {
         return embedded.getPluginArtifactRepositories();
     }
 
+    @Override
     public List<String> getPluginGroups()
     {
         return embedded.getPluginGroups();
     }
 
+    @Override
     public File getPom()
     {
         return embedded.getPom();
     }
 
+    @Override
     public List<Profile> getProfiles()
     {
         return embedded.getProfiles();
     }
 
+    @Override
     public ProjectBuildingRequest getProjectBuildingRequest()
     {
         return embedded.getProjectBuildingRequest();
     }
 
+    @Override
     public List<Proxy> getProxies()
     {
         return embedded.getProxies();
     }
 
+    @Override
     public String getReactorFailureBehavior()
     {
         return embedded.getReactorFailureBehavior();
     }
 
+    @Override
     public List<ArtifactRepository> getRemoteRepositories()
     {
         return embedded.getRemoteRepositories();
     }
 
+    @Override
     public String getResumeFrom()
     {
         return embedded.getResumeFrom();
     }
 
+    @Override
     public List<String> getSelectedProjects()
     {
         return embedded.getSelectedProjects();
     }
 
+    @Override
     public List<Server> getServers()
     {
         return embedded.getServers();
     }
 
+    @Override
     public Date getStartTime()
     {
         return embedded.getStartTime();
     }
 
+    @Override
     public Properties getSystemProperties()
     {
         return embedded.getSystemProperties();
     }
 
+    @Override
     public String getThreadCount()
     {
         return embedded.getThreadCount();
     }
 
+    @Override
     public Properties getUserProperties()
     {
         return embedded.getUserProperties();
     }
 
+    @Override
     public File getUserSettingsFile()
     {
         return embedded.getUserSettingsFile();
     }
 
+    @Override
     public File getUserToolchainsFile()
     {
         return embedded.getUserToolchainsFile();
     }
 
+    @Override
     public boolean isInteractiveMode()
     {
         return embedded.isInteractiveMode();
     }
 
+    @Override
     public boolean isNoSnapshotUpdates()
     {
         return embedded.isNoSnapshotUpdates();
     }
 
+    @Override
     public boolean isOffline()
     {
         return embedded.isOffline();
     }
 
+    @Override
     public boolean isPerCoreThreadCount()
     {
         return embedded.isPerCoreThreadCount();
     }
 
+    @Override
     public boolean isProjectPresent()
     {
         return embedded.isProjectPresent();
     }
 
+    @Override
     public boolean isRecursive()
     {
         return embedded.isRecursive();
     }
 
+    @Override
     public boolean isShowErrors()
     {
         return embedded.isShowErrors();
     }
 
+    @Override
     public boolean isThreadConfigurationPresent()
     {
         return embedded.isThreadConfigurationPresent();
     }
 
+    @Override
     public boolean isUpdateSnapshots()
     {
         return embedded.isUpdateSnapshots();
     }
 
+    @Override
     public DefaultMAEExecutionRequest setActiveProfiles( final List<String> activeProfiles )
     {
         embedded.setActiveProfiles( activeProfiles );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest setBaseDirectory( final File basedir )
     {
         embedded.setBaseDirectory( basedir );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest setExecutionListener( final ExecutionListener executionListener )
     {
         embedded.setExecutionListener( executionListener );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest setGlobalChecksumPolicy( final String globalChecksumPolicy )
     {
         embedded.setGlobalChecksumPolicy( globalChecksumPolicy );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest setGlobalSettingsFile( final File globalSettingsFile )
     {
         embedded.setGlobalSettingsFile( globalSettingsFile );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest setGoals( final List<String> goals )
     {
         embedded.setGoals( goals );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest setInactiveProfiles( final List<String> inactiveProfiles )
     {
         embedded.setInactiveProfiles( inactiveProfiles );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest setInteractiveMode( final boolean interactive )
     {
         embedded.setInteractiveMode( interactive );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest setLocalRepository( final ArtifactRepository localRepository )
     {
         embedded.setLocalRepository( localRepository );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest setLocalRepositoryPath( final File localRepository )
     {
         embedded.setLocalRepositoryPath( localRepository );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest setLocalRepositoryPath( final String localRepository )
     {
         embedded.setLocalRepositoryPath( localRepository );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest setLoggingLevel( final int loggingLevel )
     {
         embedded.setLoggingLevel( loggingLevel );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest setMakeBehavior( final String makeBehavior )
     {
         embedded.setMakeBehavior( makeBehavior );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest setMirrors( final List<Mirror> mirrors )
     {
         embedded.setMirrors( mirrors );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest setNoSnapshotUpdates( final boolean noSnapshotUpdates )
     {
         embedded.setNoSnapshotUpdates( noSnapshotUpdates );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest setOffline( final boolean offline )
     {
         embedded.setOffline( offline );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest setPerCoreThreadCount( final boolean perCoreThreadCount )
     {
         embedded.setPerCoreThreadCount( perCoreThreadCount );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest setPluginArtifactRepositories( final List<ArtifactRepository> pluginArtifactRepositories )
     {
         embedded.setPluginArtifactRepositories( pluginArtifactRepositories );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest setPluginGroups( final List<String> pluginGroups )
     {
         embedded.setPluginGroups( pluginGroups );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest setPom( final File pom )
     {
         embedded.setPom( pom );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest setProfiles( final List<Profile> profiles )
     {
         embedded.setProfiles( profiles );
@@ -512,78 +552,91 @@
         embedded.setProjectBuildingConfiguration( projectBuildingConfiguration );
     }
 
+    @Override
     public DefaultMAEExecutionRequest setProjectPresent( final boolean projectPresent )
     {
         embedded.setProjectPresent( projectPresent );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest setProxies( final List<Proxy> proxies )
     {
         embedded.setProxies( proxies );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest setReactorFailureBehavior( final String failureBehavior )
     {
         embedded.setReactorFailureBehavior( failureBehavior );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest setRecursive( final boolean recursive )
     {
         embedded.setRecursive( recursive );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest setRemoteRepositories( final List<ArtifactRepository> remoteRepositories )
     {
         embedded.setRemoteRepositories( remoteRepositories );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest setResumeFrom( final String project )
     {
         embedded.setResumeFrom( project );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest setSelectedProjects( final List<String> selectedProjects )
     {
         embedded.setSelectedProjects( selectedProjects );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest setServers( final List<Server> servers )
     {
         embedded.setServers( servers );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest setShowErrors( final boolean showErrors )
     {
         embedded.setShowErrors( showErrors );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest setStartTime( final Date startTime )
     {
         embedded.setStartTime( startTime );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest setSystemProperties( final Properties properties )
     {
         embedded.setSystemProperties( properties );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest setThreadCount( final String threadCount )
     {
         embedded.setThreadCount( threadCount );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest setUpdateSnapshots( final boolean updateSnapshots )
     {
         embedded.setUpdateSnapshots( updateSnapshots );
@@ -596,18 +649,21 @@
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest setUserProperties( final Properties userProperties )
     {
         embedded.setUserProperties( userProperties );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest setUserSettingsFile( final File userSettingsFile )
     {
         embedded.setUserSettingsFile( userSettingsFile );
         return this;
     }
 
+    @Override
     public DefaultMAEExecutionRequest setUserToolchainsFile( final File userToolchainsFile )
     {
         embedded.setUserToolchainsFile( userToolchainsFile );
diff --git a/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/DefaultModelLoader.java b/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/DefaultModelLoader.java
new file mode 100644
index 0000000..7efef81
--- /dev/null
+++ b/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/DefaultModelLoader.java
@@ -0,0 +1,275 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.mae.project;
+
+import static org.apache.maven.mae.project.event.ModelLoaderEventBuilder.newBuiltModelEvent;
+import static org.apache.maven.mae.project.event.ModelLoaderEventBuilder.newErrorEvent;
+import static org.apache.maven.mae.project.event.ModelLoaderEventBuilder.newResolvedModelEvent;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.maven.mae.MAEException;
+import org.apache.maven.mae.project.event.EventDispatcher;
+import org.apache.maven.mae.project.event.ModelLoaderEvent;
+import org.apache.maven.mae.project.internal.SimpleModelResolver;
+import org.apache.maven.mae.project.key.FullProjectKey;
+import org.apache.maven.mae.project.session.ProjectToolsSession;
+import org.apache.maven.mae.project.session.SessionInjector;
+import org.apache.maven.model.Model;
+import org.apache.maven.model.building.FileModelSource;
+import org.apache.maven.model.building.ModelSource;
+import org.apache.maven.model.io.ModelParseException;
+import org.apache.maven.model.io.ModelReader;
+import org.apache.maven.model.resolution.UnresolvableModelException;
+import org.codehaus.plexus.component.annotations.Component;
+import org.codehaus.plexus.component.annotations.Requirement;
+import org.sonatype.aether.RepositorySystemSession;
+import org.sonatype.aether.RequestTrace;
+import org.sonatype.aether.impl.ArtifactResolver;
+import org.sonatype.aether.impl.RemoteRepositoryManager;
+import org.sonatype.aether.repository.RemoteRepository;
+import org.sonatype.aether.util.DefaultRequestTrace;
+
+@Component( role = ModelLoader.class )
+public class DefaultModelLoader
+    implements ModelLoader
+{
+
+    @Requirement
+    private ArtifactResolver artifactResolver;
+
+    @Requirement
+    private RemoteRepositoryManager remoteRepositoryManager;
+
+    @Requirement
+    private ModelReader modelReader;
+
+    @Requirement
+    private SessionInjector sessionInjector;
+
+    @Override
+    public List<Model> loadRawModels( final ProjectToolsSession session, final boolean processModules,
+                                      final RequestTrace trace, final File... poms )
+        throws ProjectToolsException
+    {
+        Map<String, Object> options = getStandardOptions();
+        Map<File, Model> models = new LinkedHashMap<File, Model>();
+
+        List<File> toProcess = new ArrayList<File>( Arrays.asList( poms ) );
+        Map<File, RequestTrace> traces = new HashMap<File, RequestTrace>();
+        while ( !toProcess.isEmpty() )
+        {
+            File file = toProcess.remove( 0 );
+
+            if ( !models.containsKey( file ) )
+            {
+                RequestTrace modelTrace = trace.newChild( file );
+                Model model = loadRaw( new FileModelSource( file ), options, modelTrace, session );
+                model.setPomFile( file );
+
+                models.put( file, model );
+
+                if ( processModules )
+                {
+                    addModulePoms( model, modelTrace, toProcess, traces );
+                }
+            }
+        }
+
+        return new ArrayList<Model>( models.values() );
+    }
+
+    @Override
+    public List<Model> loadRawModel( final File pom, final boolean processModules, final RequestTrace trace,
+                                     final ProjectToolsSession session )
+        throws ProjectToolsException
+    {
+        Map<String, Object> options = getStandardOptions();
+        Map<File, Model> models = new LinkedHashMap<File, Model>();
+
+        List<File> toProcess = new ArrayList<File>( Collections.singleton( pom ) );
+        Map<File, RequestTrace> traces = new HashMap<File, RequestTrace>();
+        while ( !toProcess.isEmpty() )
+        {
+            File file = toProcess.remove( 0 );
+
+            if ( !models.containsKey( file ) )
+            {
+                RequestTrace modelTrace = trace.newChild( file );
+                Model model = loadRaw( new FileModelSource( file ), options, modelTrace, session );
+                model.setPomFile( file );
+
+                models.put( file, model );
+
+                if ( processModules )
+                {
+                    addModulePoms( model, modelTrace, toProcess, traces );
+                }
+            }
+        }
+
+        return new ArrayList<Model>( models.values() );
+    }
+
+    @Override
+    public Model loadRawModel( final FullProjectKey key, final RequestTrace trace, final ProjectToolsSession session )
+        throws ProjectToolsException
+    {
+        ModelSource src = resolveModel( key, trace, session );
+        Map<String, Object> options = getStandardOptions();
+        return loadRaw( src, options, trace, session );
+    }
+
+    @Override
+    public Model loadRawModel( final String groupId, final String artifactId, final String version,
+                               final RequestTrace trace, final ProjectToolsSession session )
+        throws ProjectToolsException
+    {
+        return loadRawModel( new FullProjectKey( groupId, artifactId, version ), trace, session );
+    }
+
+    @Override
+    public ModelSource resolveModel( final FullProjectKey key, final RequestTrace trace,
+                                     final ProjectToolsSession session )
+        throws ProjectToolsException
+    {
+        try
+        {
+            RepositorySystemSession rss = sessionInjector.getRepositorySystemSession( session );
+            List<RemoteRepository> repos = sessionInjector.getRemoteRepositories( session );
+
+            SimpleModelResolver resolver =
+                new SimpleModelResolver( rss, repos, new DefaultRequestTrace( key ), artifactResolver,
+                                         remoteRepositoryManager );
+
+            ModelSource source = resolver.resolveModel( key.getGroupId(), key.getArtifactId(), key.getVersion() );
+
+            ModelLoaderEvent event = newResolvedModelEvent( trace ).withKey( key ).withModelSource( source ).build();
+            getDispatcher( session ).fire( event );
+
+            return source;
+        }
+        catch ( UnresolvableModelException e )
+        {
+            ModelLoaderEvent event = newErrorEvent( trace ).withKey( key ).withError( e ).build();
+            getDispatcher( session ).fire( event );
+
+            throw new ProjectToolsException( "Failed to resolve model: %s. Reason: %s", e, key, e.getMessage() );
+        }
+        catch ( MAEException e )
+        {
+            ModelLoaderEvent event = newErrorEvent( trace ).withKey( key ).withError( e ).build();
+            getDispatcher( session ).fire( event );
+
+            throw new ProjectToolsException( "Failed to initialize model-resolving environment: %s. Reason: %s", e,
+                                             key, e.getMessage() );
+        }
+    }
+
+    @Override
+    public ModelSource resolveModel( final String groupId, final String artifactId, final String version,
+                                     final RequestTrace trace, final ProjectToolsSession session )
+        throws ProjectToolsException
+    {
+        return resolveModel( new FullProjectKey( groupId, artifactId, version ), trace, session );
+    }
+
+    private Model loadRaw( final ModelSource source, final Map<String, Object> options, final RequestTrace trace,
+                           final ProjectToolsSession session )
+        throws ProjectToolsException
+    {
+        ModelLoaderEvent event = null;
+
+        Model model;
+        try
+        {
+            model = modelReader.read( source.getInputStream(), options );
+
+            event = newBuiltModelEvent( trace ).withModel( model ).withModelSource( source ).build();
+            return model;
+        }
+        catch ( ModelParseException e )
+        {
+            event = newErrorEvent( trace ).withModelSource( source ).withError( e ).build();
+            throw new ProjectToolsException( "Failed to parse model: %s. Reason: %s", e, source, e.getMessage() );
+        }
+        catch ( IOException e )
+        {
+            event = newErrorEvent( trace ).withModelSource( source ).withError( e ).build();
+            throw new ProjectToolsException( "Failed to read model: %s. Reason: %s", e, source, e.getMessage() );
+        }
+        finally
+        {
+            getDispatcher( session ).fire( event );
+        }
+    }
+
+    private void addModulePoms( final Model model, final RequestTrace trace, final List<File> toProcess,
+                                final Map<File, RequestTrace> traces )
+    {
+        if ( model.getModules() != null )
+        {
+            File dir = model.getPomFile().getParentFile();
+            if ( dir == null )
+            {
+                dir = new File( System.getProperty( "user.dir" ) );
+            }
+
+            for ( String mod : model.getModules() )
+            {
+                File modFile = new File( dir, mod );
+                if ( modFile.exists() )
+                {
+                    traces.put( modFile, trace.newChild( modFile ) );
+                    toProcess.add( modFile );
+                }
+            }
+        }
+    }
+
+    private synchronized EventDispatcher<ModelLoaderEvent> getDispatcher( final ProjectToolsSession session )
+    {
+        EventDispatcher<ModelLoaderEvent> d = session.getEventDispatcher( ModelLoaderEvent.class );
+        if ( d == null )
+        {
+            d = new EventDispatcher<ModelLoaderEvent>();
+            session.setEventDispatcher( ModelLoaderEvent.class, d );
+        }
+
+        return d;
+    }
+
+    private Map<String, Object> getStandardOptions()
+    {
+        Map<String, Object> options = new HashMap<String, Object>();
+        options.put( ModelReader.IS_STRICT, Boolean.FALSE.toString() );
+
+        return options;
+    }
+
+}
diff --git a/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/DefaultProjectLoader.java b/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/DefaultProjectLoader.java
index 4ca6c64..f53d288 100644
--- a/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/DefaultProjectLoader.java
+++ b/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/DefaultProjectLoader.java
@@ -1,25 +1,43 @@
 /*
- * Copyright 2011 Red Hat, Inc.
+ * 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
  * 
- * Licensed 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
  * 
- *   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.
+ * 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.
  */
 
 package org.apache.maven.mae.project;
 
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
 import org.apache.commons.io.IOUtils;
 import org.apache.log4j.Logger;
 import org.apache.maven.RepositoryUtils;
 import org.apache.maven.artifact.ArtifactUtils;
+import org.apache.maven.mae.project.key.FullProjectKey;
 import org.apache.maven.mae.project.session.ProjectToolsSession;
 import org.apache.maven.mae.project.session.SessionInjector;
 import org.apache.maven.model.Model;
@@ -43,20 +61,6 @@
 import org.sonatype.aether.resolution.ArtifactResolutionException;
 import org.sonatype.aether.resolution.ArtifactResult;
 
-import java.io.File;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.Reader;
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
 @Component( role = ProjectLoader.class )
 public class DefaultProjectLoader
     implements ProjectLoader
@@ -136,14 +140,8 @@
                         builder.append( "\n" ).append( result.getProjectId() );
                         for ( final ModelProblem problem : problems )
                         {
-                            builder.append( "\n\t" )
-                              .append( ( ++i ) ).append( " " )
-                              .append( problem.getMessage() )
-                              .append( "\n\t\t" )
-                              .append( problem.getSource() )
-                              .append( "@" )
-                              .append( problem.getLineNumber() )
-                              .append( ":" + problem.getColumnNumber() );
+                            builder.append( "\n\t" ).append( ( ++i ) ).append( " " ).append( problem.getMessage() ).append( "\n\t\t" ).append( problem.getSource() ).append( "@" ).append( problem.getLineNumber() ).append( ":"
+                                                                                                                                                                                                                                 + problem.getColumnNumber() );
 
                             if ( problem.getException() != null )
                             {
@@ -155,7 +153,7 @@
                             }
                         }
                     }
-                    
+
                     sb.append( builder );
                 }
             }
@@ -183,10 +181,8 @@
             while ( parent != null )
             {
                 final org.apache.maven.artifact.Artifact pomArtifact =
-                    mavenRepositorySystem.createArtifact( project.getGroupId(),
-                                                          project.getArtifactId(),
-                                                          project.getVersion(),
-                                                          "pom" );
+                    mavenRepositorySystem.createArtifact( project.getGroupId(), project.getArtifactId(),
+                                                          project.getVersion(), "pom" );
 
                 final Artifact aetherPomArtifact = RepositoryUtils.toArtifact( pomArtifact );
 
@@ -260,12 +256,8 @@
                     final List<ModelProblem> problems = result.getProblems();
                     for ( final ModelProblem problem : problems )
                     {
-                        sb.append( problem.getMessage() )
-                          .append( "\n\t" )
-                          .append( problem.getSource() )
-                          .append( "@" )
-                          .append( problem.getLineNumber() )
-                          .append( ":" + problem.getColumnNumber() );
+                        sb.append( problem.getMessage() ).append( "\n\t" ).append( problem.getSource() ).append( "@" ).append( problem.getLineNumber() ).append( ":"
+                                                                                                                                                                     + problem.getColumnNumber() );
 
                         if ( problem.getException() != null )
                         {
@@ -286,6 +278,13 @@
     }
 
     @Override
+    public MavenProject buildProjectInstance( final FullProjectKey key, final ProjectToolsSession session )
+        throws ProjectToolsException
+    {
+        return buildProjectInstance( key.getGroupId(), key.getArtifactId(), key.getVersion(), session );
+    }
+
+    @Override
     public MavenProject buildProjectInstance( final String groupId, final String artifactId, final String version,
                                               final ProjectToolsSession session )
         throws ProjectToolsException
@@ -328,12 +327,7 @@
             int i = 0;
             if ( results == null )
             {
-                sb.append( "Cannot build project instance for: " )
-                  .append( groupId )
-                  .append( ':' )
-                  .append( artifactId )
-                  .append( ':' )
-                  .append( version );
+                sb.append( "Cannot build project instance for: " ).append( groupId ).append( ':' ).append( artifactId ).append( ':' ).append( version );
 
                 final StringWriter sWriter = new StringWriter();
                 final PrintWriter pWriter = new PrintWriter( sWriter );
@@ -348,12 +342,8 @@
                     final List<ModelProblem> problems = result.getProblems();
                     for ( final ModelProblem problem : problems )
                     {
-                        sb.append( problem.getMessage() )
-                          .append( "\n\t" )
-                          .append( problem.getSource() )
-                          .append( "@" )
-                          .append( problem.getLineNumber() )
-                          .append( ":" + problem.getColumnNumber() );
+                        sb.append( problem.getMessage() ).append( "\n\t" ).append( problem.getSource() ).append( "@" ).append( problem.getLineNumber() ).append( ":"
+                                                                                                                                                                     + problem.getColumnNumber() );
 
                         if ( problem.getException() != null )
                         {
@@ -373,12 +363,8 @@
         }
         catch ( final ArtifactResolutionException e )
         {
-            throw new ProjectToolsException( "Failed to resolve POM: %s:%s:%s\nReason: %s",
-                                             e,
-                                             groupId,
-                                             artifactId,
-                                             version,
-                                             e.getMessage() );
+            throw new ProjectToolsException( "Failed to resolve POM: %s:%s:%s\nReason: %s", e, groupId, artifactId,
+                                             version, e.getMessage() );
         }
     }
 
@@ -476,10 +462,8 @@
 
                 if ( !moduleFile.isFile() )
                 {
-                    LOGGER.warn( String.format( "In reactor of: %s: Child module %s of %s does not exist.",
-                                                topPom,
-                                                moduleFile,
-                                                pom ) );
+                    LOGGER.warn( String.format( "In reactor of: %s: Child module %s of %s does not exist.", topPom,
+                                                moduleFile, pom ) );
                     continue;
                 }
 
@@ -519,17 +503,13 @@
         catch ( final IOException e )
         {
             LOGGER.error( String.format( "Failed to read POM: %s.\nReason: %s", pom, e.getMessage() ), e );
-            throw new ProjectToolsException( "Failed to read POM: %s. Reason: %s",
-                                             e,
-                                             pom.getAbsolutePath(),
+            throw new ProjectToolsException( "Failed to read POM: %s. Reason: %s", e, pom.getAbsolutePath(),
                                              e.getMessage() );
         }
         catch ( final XmlPullParserException e )
         {
             LOGGER.error( String.format( "Failed to read POM: %s.\nReason: %s", pom, e.getMessage() ), e );
-            throw new ProjectToolsException( "Failed to read POM: %s. Reason: %s",
-                                             e,
-                                             pom.getAbsolutePath(),
+            throw new ProjectToolsException( "Failed to read POM: %s. Reason: %s", e, pom.getAbsolutePath(),
                                              e.getMessage() );
         }
         finally
diff --git a/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/ModelLoader.java b/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/ModelLoader.java
new file mode 100644
index 0000000..539af71
--- /dev/null
+++ b/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/ModelLoader.java
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.mae.project;
+
+import java.io.File;
+import java.util.List;
+
+import org.apache.maven.mae.project.key.FullProjectKey;
+import org.apache.maven.mae.project.session.ProjectToolsSession;
+import org.apache.maven.model.Model;
+import org.apache.maven.model.building.ModelSource;
+import org.sonatype.aether.RequestTrace;
+
+public interface ModelLoader
+{
+
+    List<Model> loadRawModel( File pom, boolean processModules, RequestTrace trace, ProjectToolsSession session )
+        throws ProjectToolsException;
+
+    List<Model> loadRawModels( ProjectToolsSession session, boolean processModules, RequestTrace trace, File... poms )
+        throws ProjectToolsException;
+
+    Model loadRawModel( FullProjectKey key, RequestTrace trace, ProjectToolsSession session )
+        throws ProjectToolsException;
+
+    Model loadRawModel( String groupId, String artifactId, String version, RequestTrace trace,
+                        ProjectToolsSession session )
+        throws ProjectToolsException;
+
+    ModelSource resolveModel( FullProjectKey key, RequestTrace trace, ProjectToolsSession session )
+        throws ProjectToolsException;
+
+    ModelSource resolveModel( String groupId, String artifactId, String version, RequestTrace trace,
+                              ProjectToolsSession session )
+        throws ProjectToolsException;
+
+}
diff --git a/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/ProjectLoader.java b/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/ProjectLoader.java
index 9e290a6..876fd03 100644
--- a/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/ProjectLoader.java
+++ b/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/ProjectLoader.java
@@ -1,32 +1,37 @@
 /*
- * Copyright 2011 Red Hat, Inc.
+ * 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
  * 
- * Licensed 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
  * 
- *   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.
+ * 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.
  */
 
 package org.apache.maven.mae.project;
 
-import org.apache.maven.mae.project.session.ProjectToolsSession;
-import org.apache.maven.project.MavenProject;
-
 import java.io.File;
 import java.util.List;
 import java.util.Set;
 
+import org.apache.maven.mae.project.key.FullProjectKey;
+import org.apache.maven.mae.project.session.ProjectToolsSession;
+import org.apache.maven.project.MavenProject;
+
 public interface ProjectLoader
 {
 
-    List<MavenProject> buildReactorProjectInstances( final ProjectToolsSession session, final boolean recursive, final File... rootPoms )
+    List<MavenProject> buildReactorProjectInstances( final ProjectToolsSession session, final boolean recursive,
+                                                     final File... rootPoms )
         throws ProjectToolsException;
 
     MavenProject buildProjectInstance( final File pomFile, final ProjectToolsSession session )
@@ -36,6 +41,9 @@
                                        final ProjectToolsSession session )
         throws ProjectToolsException;
 
+    MavenProject buildProjectInstance( final FullProjectKey key, final ProjectToolsSession session )
+        throws ProjectToolsException;
+
     Set<String> retrieveReactorProjectIds( final File rootPom )
         throws ProjectToolsException;
 
diff --git a/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/ProjectToolsException.java b/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/ProjectToolsException.java
index 6a6a42c..607afc9 100644
--- a/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/ProjectToolsException.java
+++ b/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/ProjectToolsException.java
@@ -1,17 +1,20 @@
 /*
- * Copyright 2011 Red Hat, Inc.
+ * 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
  * 
- * Licensed 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
  * 
- *   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.
+ * 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.
  */
 
 package org.apache.maven.mae.project;
diff --git a/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/event/EventDispatcher.java b/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/event/EventDispatcher.java
new file mode 100644
index 0000000..9a6c4ba
--- /dev/null
+++ b/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/event/EventDispatcher.java
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.mae.project.event;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.maven.mae.project.ProjectToolsException;
+
+public class EventDispatcher<E>
+{
+
+    private final List<ProjectToolsListener<E>> listeners = new ArrayList<ProjectToolsListener<E>>();
+
+    public EventDispatcher()
+    {
+    }
+
+    public EventDispatcher( final ProjectToolsListener<E>... listeners )
+    {
+        for ( ProjectToolsListener<E> listener : listeners )
+        {
+            addListener( listener );
+        }
+    }
+
+    public void fire( final E event )
+        throws ProjectToolsException
+    {
+        if ( event == null )
+        {
+            return;
+        }
+
+        for ( ProjectToolsListener<E> listener : new ArrayList<ProjectToolsListener<E>>( listeners ) )
+        {
+            listener.onEvent( event );
+        }
+    }
+
+    public synchronized void addListener( final ProjectToolsListener<E> listener )
+    {
+        if ( listener == null )
+        {
+            return;
+        }
+
+        if ( !listeners.contains( listener ) )
+        {
+            listeners.add( listener );
+        }
+    }
+
+    public synchronized void removeListener( final ProjectToolsListener<E> listener )
+    {
+        if ( listener == null )
+        {
+            return;
+        }
+
+        listeners.remove( listener );
+    }
+
+}
diff --git a/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/event/ModelLoaderEvent.java b/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/event/ModelLoaderEvent.java
new file mode 100644
index 0000000..0f9e266
--- /dev/null
+++ b/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/event/ModelLoaderEvent.java
@@ -0,0 +1,143 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.mae.project.event;
+
+import java.io.File;
+
+import org.apache.maven.mae.project.key.FullProjectKey;
+import org.apache.maven.model.Model;
+import org.apache.maven.model.building.ModelSource;
+import org.sonatype.aether.RequestTrace;
+
+public class ModelLoaderEvent
+{
+
+    private final ModelLoaderEventType type;
+
+    private final Model model;
+
+    private final File pom;
+
+    private final Throwable error;
+
+    private final FullProjectKey key;
+
+    private final ModelSource modelSource;
+
+    private final RequestTrace trace;
+
+    ModelLoaderEvent( final ModelLoaderEventType type, final FullProjectKey key, final ModelSource modelSource,
+                      final Model model, final File pom, final RequestTrace trace, final Throwable error )
+    {
+        this.type = type;
+        this.key = key;
+        this.modelSource = modelSource;
+        this.model = model;
+        this.pom = pom;
+        this.trace = trace;
+        this.error = error;
+    }
+
+    public RequestTrace getTrace()
+    {
+        return trace;
+    }
+
+    public ModelLoaderEventType getType()
+    {
+        return type;
+    }
+
+    public ModelSource getModelSource()
+    {
+        return modelSource;
+    }
+
+    public Model getModel()
+    {
+        return model;
+    }
+
+    public File getPom()
+    {
+        return pom;
+    }
+
+    public Throwable getError()
+    {
+        return error;
+    }
+
+    public FullProjectKey getKey()
+    {
+        return key;
+    }
+
+    @Override
+    public int hashCode()
+    {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ( ( key == null ) ? 0 : key.hashCode() );
+        result = prime * result + ( ( type == null ) ? 0 : type.hashCode() );
+        return result;
+    }
+
+    @Override
+    public boolean equals( final Object obj )
+    {
+        if ( this == obj )
+        {
+            return true;
+        }
+        if ( obj == null )
+        {
+            return false;
+        }
+        if ( getClass() != obj.getClass() )
+        {
+            return false;
+        }
+        ModelLoaderEvent other = (ModelLoaderEvent) obj;
+        if ( key == null )
+        {
+            if ( other.key != null )
+            {
+                return false;
+            }
+        }
+        else if ( !key.equals( other.key ) )
+        {
+            return false;
+        }
+        if ( type != other.type )
+        {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString()
+    {
+        return "ModelLoaderEvent [type=" + type + ", model=" + key + "]";
+    }
+
+}
diff --git a/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/event/ModelLoaderEventBuilder.java b/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/event/ModelLoaderEventBuilder.java
new file mode 100644
index 0000000..669ebbd
--- /dev/null
+++ b/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/event/ModelLoaderEventBuilder.java
@@ -0,0 +1,141 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.mae.project.event;
+
+import static org.apache.maven.mae.project.event.ModelLoaderEventType.BUILT;
+import static org.apache.maven.mae.project.event.ModelLoaderEventType.ERROR;
+import static org.apache.maven.mae.project.event.ModelLoaderEventType.RESOLVED;
+
+import java.io.File;
+
+import org.apache.maven.mae.project.ProjectToolsException;
+import org.apache.maven.mae.project.key.FullProjectKey;
+import org.apache.maven.model.Model;
+import org.apache.maven.model.building.ModelSource;
+import org.sonatype.aether.RequestTrace;
+
+public class ModelLoaderEventBuilder
+{
+
+    private final ModelLoaderEventType type;
+
+    private Model model;
+
+    private File pom;
+
+    private FullProjectKey key;
+
+    private Throwable error;
+
+    private ModelSource modelSource;
+
+    private final RequestTrace trace;
+
+    private ModelLoaderEventBuilder( final ModelLoaderEventType type, final RequestTrace trace )
+    {
+        this.type = type;
+        this.trace = trace;
+    }
+
+    public ModelLoaderEventBuilder withModelSource( final ModelSource modelSource )
+    {
+        this.modelSource = modelSource;
+        return this;
+    }
+
+    public ModelLoaderEventBuilder withModel( final Model model )
+        throws ProjectToolsException
+    {
+        this.model = model;
+        this.key = new FullProjectKey( model );
+        this.pom = model.getPomFile();
+        return this;
+    }
+
+    public ModelLoaderEventBuilder withPom( final File pom )
+    {
+        this.pom = pom;
+        return this;
+    }
+
+    public ModelLoaderEventBuilder withKey( final FullProjectKey key )
+    {
+        this.key = key;
+        return this;
+    }
+
+    public ModelLoaderEventBuilder withError( final Throwable error )
+    {
+        this.error = error;
+        return this;
+    }
+
+    public ModelLoaderEvent build()
+    {
+        if ( type == ERROR && error == null )
+        {
+            throw new IllegalArgumentException( "Cannot build error event when error has not been set!" );
+        }
+        else if ( type == BUILT )
+        {
+            if ( model == null )
+            {
+                throw new IllegalArgumentException( "Cannot build " + type + " event when model is missing!" );
+            }
+            else if ( key == null )
+            {
+                throw new IllegalArgumentException( "Cannot build " + type + " event when key is missing!" );
+            }
+        }
+        else if ( type == RESOLVED )
+        {
+            if ( modelSource == null )
+            {
+                throw new IllegalArgumentException( "Cannot build " + type + " event when modelSource is missing!" );
+            }
+            else if ( key == null )
+            {
+                throw new IllegalArgumentException( "Cannot build " + type + " event when key is missing!" );
+            }
+        }
+        else if ( type != ERROR && error != null )
+        {
+            throw new IllegalArgumentException( "Cannot build " + type + " event when error is set!" );
+        }
+
+        return new ModelLoaderEvent( type, key, modelSource, model, pom, trace, error );
+    }
+
+    public static final ModelLoaderEventBuilder newBuiltModelEvent( final RequestTrace trace )
+    {
+        return new ModelLoaderEventBuilder( BUILT, trace );
+    }
+
+    public static final ModelLoaderEventBuilder newResolvedModelEvent( final RequestTrace trace )
+    {
+        return new ModelLoaderEventBuilder( RESOLVED, trace );
+    }
+
+    public static final ModelLoaderEventBuilder newErrorEvent( final RequestTrace trace )
+    {
+        return new ModelLoaderEventBuilder( ERROR, trace );
+    }
+
+}
diff --git a/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/event/ModelLoaderEventType.java b/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/event/ModelLoaderEventType.java
new file mode 100644
index 0000000..befbfda
--- /dev/null
+++ b/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/event/ModelLoaderEventType.java
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.mae.project.event;
+
+public enum ModelLoaderEventType
+{
+    ERROR, RESOLVED, BUILT;
+
+}
diff --git a/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/event/ModelLoaderListener.java b/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/event/ModelLoaderListener.java
new file mode 100644
index 0000000..851803a
--- /dev/null
+++ b/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/event/ModelLoaderListener.java
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.mae.project.event;
+
+public interface ModelLoaderListener
+    extends ProjectToolsListener<ModelLoaderEvent>
+{
+}
diff --git a/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/event/ProjectToolsListener.java b/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/event/ProjectToolsListener.java
new file mode 100644
index 0000000..fa75a5e
--- /dev/null
+++ b/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/event/ProjectToolsListener.java
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.mae.project.event;
+
+import org.apache.maven.mae.project.ProjectToolsException;
+
+public interface ProjectToolsListener<T>
+{
+
+    void onEvent( T event )
+        throws ProjectToolsException;
+
+}
diff --git a/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/internal/SimpleModelResolver.java b/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/internal/SimpleModelResolver.java
new file mode 100644
index 0000000..7da8166
--- /dev/null
+++ b/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/internal/SimpleModelResolver.java
@@ -0,0 +1,147 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.mae.project.internal;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.maven.model.Repository;
+import org.apache.maven.model.building.FileModelSource;
+import org.apache.maven.model.building.ModelSource;
+import org.apache.maven.model.resolution.InvalidRepositoryException;
+import org.apache.maven.model.resolution.ModelResolver;
+import org.apache.maven.model.resolution.UnresolvableModelException;
+import org.apache.maven.repository.internal.ArtifactDescriptorUtils;
+import org.apache.maven.repository.internal.DefaultArtifactDescriptorReader;
+import org.sonatype.aether.RepositorySystemSession;
+import org.sonatype.aether.RequestTrace;
+import org.sonatype.aether.artifact.Artifact;
+import org.sonatype.aether.impl.ArtifactResolver;
+import org.sonatype.aether.impl.RemoteRepositoryManager;
+import org.sonatype.aether.repository.RemoteRepository;
+import org.sonatype.aether.resolution.ArtifactRequest;
+import org.sonatype.aether.resolution.ArtifactResolutionException;
+import org.sonatype.aether.util.artifact.DefaultArtifact;
+
+/**
+ * A model resolver to assist building of dependency POMs. This resolver gives priority to those repositories that have
+ * been initially specified and repositories discovered in dependency POMs are recessively merged into the search chain.
+ * 
+ * @author Benjamin Bentmann
+ * @see DefaultArtifactDescriptorReader
+ */
+public class SimpleModelResolver
+    implements ModelResolver
+{
+
+    private final RequestTrace trace;
+
+    private final String context;
+
+    private final ArtifactResolver resolver;
+
+    private final RemoteRepositoryManager remoteRepositoryManager;
+
+    private final Set<String> repositoryIds;
+
+    private final RepositorySystemSession session;
+
+    private List<RemoteRepository> repositories;
+
+    public SimpleModelResolver( final RepositorySystemSession session, final List<RemoteRepository> remoteRepositories,
+                                final RequestTrace trace, final ArtifactResolver resolver,
+                                final RemoteRepositoryManager remoteRepositoryManager )
+    {
+        this( session, remoteRepositories, trace, null, resolver, remoteRepositoryManager );
+    }
+
+    public SimpleModelResolver( final RepositorySystemSession session, final List<RemoteRepository> repositories,
+                                final RequestTrace trace, final String context, final ArtifactResolver resolver,
+                                final RemoteRepositoryManager remoteRepositoryManager )
+    {
+        this.session = session;
+        this.trace = trace;
+        this.context = context;
+        this.resolver = resolver;
+        this.remoteRepositoryManager = remoteRepositoryManager;
+        this.repositoryIds = new HashSet<String>();
+        this.repositories = repositories;
+    }
+
+    private SimpleModelResolver( final SimpleModelResolver original )
+    {
+        this.session = original.session;
+        this.trace = original.trace;
+        this.context = original.context;
+        this.resolver = original.resolver;
+        this.remoteRepositoryManager = original.remoteRepositoryManager;
+        this.repositoryIds = new HashSet<String>( original.repositoryIds );
+        this.repositories = new ArrayList<RemoteRepository>( original.repositories );
+    }
+
+    @Override
+    public void addRepository( final Repository repository )
+        throws InvalidRepositoryException
+    {
+        if ( !repositoryIds.add( repository.getId() ) )
+        {
+            return;
+        }
+
+        List<RemoteRepository> newRepositories =
+            Collections.singletonList( ArtifactDescriptorUtils.toRemoteRepository( repository ) );
+
+        this.repositories =
+            remoteRepositoryManager.aggregateRepositories( session, repositories, newRepositories, true );
+    }
+
+    @Override
+    public ModelResolver newCopy()
+    {
+        return new SimpleModelResolver( this );
+    }
+
+    @Override
+    public ModelSource resolveModel( final String groupId, final String artifactId, final String version )
+        throws UnresolvableModelException
+    {
+        Artifact pomArtifact = new DefaultArtifact( groupId, artifactId, "", "pom", version );
+
+        try
+        {
+            ArtifactRequest request = new ArtifactRequest( pomArtifact, repositories, context );
+            request.setTrace( trace );
+            pomArtifact = resolver.resolveArtifact( session, request ).getArtifact();
+        }
+        catch ( ArtifactResolutionException e )
+        {
+            throw new UnresolvableModelException( e.getMessage(), groupId, artifactId, version, e );
+        }
+
+        File pomFile = pomArtifact.getFile();
+
+        return new FileModelSource( pomFile );
+    }
+
+}
diff --git a/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/key/FullProjectKey.java b/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/key/FullProjectKey.java
new file mode 100644
index 0000000..8510168
--- /dev/null
+++ b/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/key/FullProjectKey.java
@@ -0,0 +1,176 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.mae.project.key;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.mae.project.ProjectToolsException;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.model.Model;
+import org.apache.maven.model.Parent;
+import org.apache.maven.project.MavenProject;
+
+public class FullProjectKey
+    extends VersionlessProjectKey
+{
+
+    private final String version;
+
+    private Dependency bomDep;
+
+    public FullProjectKey( final String groupId, final String artifactId, final String version )
+    {
+        super( groupId, artifactId );
+        this.version = version;
+    }
+
+    public FullProjectKey( final ProjectKey key, final String version )
+    {
+        this( key.getGroupId(), key.getArtifactId(), version );
+    }
+
+    public FullProjectKey( final Parent parent )
+    {
+        this( parent.getGroupId(), parent.getArtifactId(), parent.getVersion() );
+    }
+
+    public FullProjectKey( final Dependency dependency )
+    {
+        this( dependency.getGroupId(), dependency.getArtifactId(), dependency.getVersion() );
+    }
+
+    public FullProjectKey( final Model model )
+        throws ProjectToolsException
+    {
+        this( selectGroupId( model ), model.getArtifactId(), selectVersion( model ) );
+    }
+
+    public FullProjectKey( final MavenProject project )
+    {
+        this( project.getGroupId(), project.getArtifactId(), project.getVersion() );
+    }
+
+    private static String selectVersion( final Model model )
+        throws ProjectToolsException
+    {
+        String version = model.getVersion();
+        if ( version == null )
+        {
+            Parent parent = model.getParent();
+            if ( parent != null )
+            {
+                version = parent.getVersion();
+            }
+        }
+
+        if ( version == null )
+        {
+            throw new ProjectToolsException( "Invalid model (missing version): %s", model );
+        }
+
+        return version;
+    }
+
+    private static String selectGroupId( final Model model )
+        throws ProjectToolsException
+    {
+        String gid = model.getGroupId();
+        if ( gid == null )
+        {
+            Parent parent = model.getParent();
+            if ( parent != null )
+            {
+                gid = parent.getGroupId();
+            }
+        }
+
+        if ( gid == null )
+        {
+            throw new ProjectToolsException( "Invalid model (missing groupId): %s", model );
+        }
+
+        return gid;
+    }
+
+    public String getVersion()
+    {
+        return version;
+    }
+
+    @Override
+    public int hashCode()
+    {
+        final int prime = 31;
+        int result = super.hashCode();
+        result = prime * result + ( ( version == null ) ? 0 : version.hashCode() );
+        return result;
+    }
+
+    @Override
+    public boolean equals( final Object obj )
+    {
+        if ( this == obj )
+        {
+            return true;
+        }
+        if ( !super.equals( obj ) )
+        {
+            return false;
+        }
+        if ( getClass() != obj.getClass() )
+        {
+            return false;
+        }
+        final FullProjectKey other = (FullProjectKey) obj;
+        if ( version == null )
+        {
+            if ( other.version != null )
+            {
+                return false;
+            }
+        }
+        else if ( !version.equals( other.version ) )
+        {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString()
+    {
+        return super.getId() + ":" + version;
+    }
+
+    public synchronized Dependency getBomDependency()
+    {
+        if ( bomDep == null )
+        {
+            bomDep = new Dependency();
+            bomDep.setGroupId( getGroupId() );
+            bomDep.setArtifactId( getArtifactId() );
+            bomDep.setVersion( version );
+            bomDep.setType( "pom" );
+            bomDep.setScope( Artifact.SCOPE_IMPORT );
+        }
+
+        return bomDep;
+    }
+
+}
diff --git a/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/key/ProjectKey.java b/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/key/ProjectKey.java
new file mode 100644
index 0000000..1f5e513
--- /dev/null
+++ b/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/key/ProjectKey.java
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.mae.project.key;
+
+public interface ProjectKey
+{
+
+    String getGroupId();
+
+    String getArtifactId();
+
+    String getId();
+
+}
diff --git a/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/key/VersionlessProjectKey.java b/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/key/VersionlessProjectKey.java
new file mode 100644
index 0000000..c0ee1a3
--- /dev/null
+++ b/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/key/VersionlessProjectKey.java
@@ -0,0 +1,184 @@
+/*
+ * 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.
+ */
+
+package org.apache.maven.mae.project.key;
+
+import org.apache.maven.model.Dependency;
+import org.apache.maven.model.Parent;
+import org.apache.maven.model.Plugin;
+import org.apache.maven.model.ReportPlugin;
+
+public class VersionlessProjectKey
+    implements Comparable<ProjectKey>, ProjectKey
+{
+    private final String groupId;
+
+    private final String artifactId;
+
+    public VersionlessProjectKey( final String groupId, final String artifactId )
+    {
+        this.groupId = groupId;
+        this.artifactId = artifactId;
+    }
+
+    public VersionlessProjectKey( final Dependency dep )
+    {
+        groupId = dep.getGroupId();
+        artifactId = dep.getArtifactId();
+    }
+
+    public VersionlessProjectKey( final Plugin plugin )
+    {
+        groupId = plugin.getGroupId();
+        artifactId = plugin.getArtifactId();
+    }
+
+    public VersionlessProjectKey( final Parent parent )
+    {
+        groupId = parent.getGroupId();
+        artifactId = parent.getArtifactId();
+    }
+
+    public VersionlessProjectKey( final String ga )
+    {
+        String[] parts = ga.split( ":" );
+        if ( parts.length < 2 )
+        {
+            throw new IllegalArgumentException( "Invalid versionless POM key: '" + ga + "'" );
+        }
+
+        groupId = parts[0].trim();
+        artifactId = parts[1].trim();
+    }
+
+    public VersionlessProjectKey( final ReportPlugin plugin )
+    {
+        groupId = plugin.getGroupId();
+        artifactId = plugin.getArtifactId();
+    }
+
+    public VersionlessProjectKey( final ProjectKey tk )
+    {
+        groupId = tk.getGroupId();
+        artifactId = tk.getArtifactId();
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see com.redhat.rcm.version.model.ProjectKey#getGroupId()
+     */
+    @Override
+    public String getGroupId()
+    {
+        return groupId;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see com.redhat.rcm.version.model.ProjectKey#getArtifactId()
+     */
+    @Override
+    public String getArtifactId()
+    {
+        return artifactId;
+    }
+
+    @Override
+    public int hashCode()
+    {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ( ( artifactId == null ) ? 0 : artifactId.hashCode() );
+        result = prime * result + ( ( groupId == null ) ? 0 : groupId.hashCode() );
+        return result;
+    }
+
+    @Override
+    public boolean equals( final Object obj )
+    {
+        if ( this == obj )
+        {
+            return true;
+        }
+        if ( obj == null )
+        {
+            return false;
+        }
+        if ( getClass() != obj.getClass() )
+        {
+            return false;
+        }
+        final VersionlessProjectKey other = (VersionlessProjectKey) obj;
+        if ( artifactId == null )
+        {
+            if ( other.artifactId != null )
+            {
+                return false;
+            }
+        }
+        else if ( !artifactId.equals( other.artifactId ) )
+        {
+            return false;
+        }
+        if ( groupId == null )
+        {
+            if ( other.groupId != null )
+            {
+                return false;
+            }
+        }
+        else if ( !groupId.equals( other.groupId ) )
+        {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString()
+    {
+        return getId();
+    }
+
+    @Override
+    public int compareTo( final ProjectKey other )
+    {
+        if ( other == null )
+        {
+            return -1;
+        }
+
+        int comp = getGroupId().compareTo( other.getGroupId() );
+        if ( comp == 0 )
+        {
+            comp = getArtifactId().compareTo( other.getArtifactId() );
+        }
+
+        return comp;
+    }
+
+    @Override
+    public String getId()
+    {
+        return groupId + ":" + artifactId;
+    }
+
+}
diff --git a/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/session/DefaultSessionInjector.java b/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/session/DefaultSessionInjector.java
index 8437db7..de90ce0 100644
--- a/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/session/DefaultSessionInjector.java
+++ b/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/session/DefaultSessionInjector.java
@@ -1,21 +1,28 @@
 /*
- * Copyright 2011 Red Hat, Inc.
+ * 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
  * 
- * Licensed 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
  * 
- *   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.
+ * 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.
  */
 
 package org.apache.maven.mae.project.session;
 
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
 import org.apache.log4j.Logger;
 import org.apache.maven.artifact.InvalidRepositoryException;
 import org.apache.maven.artifact.repository.ArtifactRepository;
@@ -36,10 +43,6 @@
 import org.sonatype.aether.repository.RemoteRepository;
 import org.sonatype.aether.util.DefaultRepositorySystemSession;
 
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-
 @Component( role = SessionInjector.class )
 public class DefaultSessionInjector
     implements SessionInjector
@@ -63,8 +66,7 @@
             if ( pbr == null )
             {
                 pbr =
-                    embedder.serviceManager()
-                            .createProjectBuildingRequest( session.getTemplateProjectBuildingRequest() );
+                    embedder.serviceManager().createProjectBuildingRequest( session.getTemplateProjectBuildingRequest() );
 
                 pbr.setValidationLevel( session.getPomValidationLevel() );
                 pbr.setProcessPlugins( session.isProcessPomPlugins() );
@@ -75,8 +77,7 @@
 
                 final RepositorySystemSession rss = getRepositorySystemSession( session );
                 pbr.setRepositorySession( rss );
-                pbr.setLocalRepository( mavenRepositorySystem.createLocalRepository( rss.getLocalRepository()
-                                                                                        .getBasedir() ) );
+                pbr.setLocalRepository( mavenRepositorySystem.createLocalRepository( rss.getLocalRepository().getBasedir() ) );
                 pbr.setRemoteRepositories( getArtifactRepositories( session ) );
 
                 session.setProjectBuildingRequest( pbr );
@@ -93,8 +94,7 @@
         }
         catch ( final InvalidRepositoryException e )
         {
-            throw new ProjectToolsException( "Failed to create local-repository instance. Reason: %s",
-                                             e,
+            throw new ProjectToolsException( "Failed to create local-repository instance. Reason: %s", e,
                                              e.getMessage() );
         }
 
@@ -111,8 +111,8 @@
         if ( sess == null )
         {
             final DefaultRepositorySystemSession rss =
-                new DefaultRepositorySystemSession( embedder.serviceManager()
-                                                            .createAetherRepositorySystemSession( session.getExecutionRequest() ) );
+                new DefaultRepositorySystemSession(
+                                                    embedder.serviceManager().createAetherRepositorySystemSession( session.getExecutionRequest() ) );
 
             // session.setWorkspaceReader( new ImportWorkspaceReader( workspace ) );
             rss.setConfigProperty( ProjectToolsSession.SESSION_KEY, session );
@@ -211,10 +211,9 @@
                     }
                     catch ( final InvalidRepositoryException e )
                     {
-                        throw new ProjectToolsException( "Failed to create remote artifact repository instance from: %s\nReason: %s",
-                                                         e,
-                                                         repo,
-                                                         e.getMessage() );
+                        throw new ProjectToolsException(
+                                                         "Failed to create remote artifact repository instance from: %s\nReason: %s",
+                                                         e, repo, e.getMessage() );
                     }
                 }
             }
@@ -225,8 +224,7 @@
             }
             catch ( final InvalidRepositoryException e )
             {
-                throw new ProjectToolsException( "Failed to create default (central) repository instance: %s",
-                                                 e,
+                throw new ProjectToolsException( "Failed to create default (central) repository instance: %s", e,
                                                  e.getMessage() );
             }
 
diff --git a/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/session/ProjectToolsSession.java b/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/session/ProjectToolsSession.java
index 03a8c51..a1b4dd4 100644
--- a/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/session/ProjectToolsSession.java
+++ b/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/session/ProjectToolsSession.java
@@ -1,23 +1,31 @@
 /*
- * Copyright 2011 Red Hat, Inc.
+ * 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
  * 
- * Licensed 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
  * 
- *   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.
+ * 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.
  */
 
 package org.apache.maven.mae.project.session;
 
+import java.io.File;
+import java.util.Collection;
+import java.util.List;
+
 import org.apache.maven.artifact.repository.ArtifactRepository;
 import org.apache.maven.execution.MavenExecutionRequest;
+import org.apache.maven.mae.project.event.EventDispatcher;
 import org.apache.maven.model.Repository;
 import org.apache.maven.project.MavenProject;
 import org.apache.maven.project.ProjectBuildingRequest;
@@ -27,10 +35,6 @@
 import org.sonatype.aether.graph.DependencyFilter;
 import org.sonatype.aether.repository.RemoteRepository;
 
-import java.io.File;
-import java.util.Collection;
-import java.util.List;
-
 public interface ProjectToolsSession
 {
 
@@ -109,4 +113,8 @@
 
     ProjectBuildingRequest getTemplateProjectBuildingRequest();
 
+    <E> EventDispatcher<E> getEventDispatcher( Class<E> eventType );
+
+    <E> ProjectToolsSession setEventDispatcher( Class<E> eventType, EventDispatcher<E> dispatcher );
+
 }
diff --git a/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/session/SessionInjector.java b/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/session/SessionInjector.java
index 2c4dff1..e3e2f05 100644
--- a/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/session/SessionInjector.java
+++ b/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/session/SessionInjector.java
@@ -1,21 +1,26 @@
 /*
- * Copyright 2011 Red Hat, Inc.
+ * 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
  * 
- * Licensed 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
  * 
- *   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.
+ * 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.
  */
 
 package org.apache.maven.mae.project.session;
 
+import java.util.List;
+
 import org.apache.maven.artifact.repository.ArtifactRepository;
 import org.apache.maven.mae.MAEException;
 import org.apache.maven.mae.project.ProjectToolsException;
@@ -23,8 +28,6 @@
 import org.sonatype.aether.RepositorySystemSession;
 import org.sonatype.aether.repository.RemoteRepository;
 
-import java.util.List;
-
 /**
  * 
  */
diff --git a/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/session/SessionWorkspaceReader.java b/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/session/SessionWorkspaceReader.java
index b80c39c..bfce7b2 100644
--- a/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/session/SessionWorkspaceReader.java
+++ b/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/session/SessionWorkspaceReader.java
@@ -1,30 +1,33 @@
 /*
- * Copyright 2011 Red Hat, Inc.
+ * 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
  * 
- * Licensed 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
  * 
- *   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.
+ * 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.
  */
 
 package org.apache.maven.mae.project.session;
 
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
 import org.apache.maven.project.MavenProject;
 import org.sonatype.aether.artifact.Artifact;
 import org.sonatype.aether.repository.WorkspaceReader;
 import org.sonatype.aether.repository.WorkspaceRepository;
 
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-
 public class SessionWorkspaceReader
     implements WorkspaceReader
 {
diff --git a/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/session/SimpleProjectToolsSession.java b/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/session/SimpleProjectToolsSession.java
index e3a3bc3..83ca8cf 100644
--- a/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/session/SimpleProjectToolsSession.java
+++ b/mae-components/mae-project-tools/src/main/java/org/apache/maven/mae/project/session/SimpleProjectToolsSession.java
@@ -1,25 +1,37 @@
 /*
- * Copyright 2011 Red Hat, Inc.
+ * 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
  * 
- * Licensed 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
  * 
- *   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.
+ * 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.
  */
 
 package org.apache.maven.mae.project.session;
 
 import static org.apache.maven.artifact.ArtifactUtils.key;
 
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
 import org.apache.maven.artifact.repository.ArtifactRepository;
 import org.apache.maven.execution.MavenExecutionRequest;
+import org.apache.maven.mae.project.event.EventDispatcher;
 import org.apache.maven.model.Repository;
 import org.apache.maven.model.building.ModelBuildingRequest;
 import org.apache.maven.project.DefaultProjectBuildingRequest;
@@ -32,14 +44,6 @@
 import org.sonatype.aether.repository.RemoteRepository;
 import org.sonatype.aether.util.DefaultRepositorySystemSession;
 
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
 public class SimpleProjectToolsSession
     implements ProjectToolsSession
 {
@@ -444,6 +448,7 @@
         return this;
     }
 
+    @Override
     @SuppressWarnings( "unchecked" )
     public <T> T setState( final T state )
     {
@@ -455,17 +460,20 @@
         return null;
     }
 
+    @Override
     public void clearStates()
     {
         states.clear();
     }
 
+    @Override
     @SuppressWarnings( "unchecked" )
     public <T> T clearState( final Class<T> type )
     {
         return (T) states.remove( type );
     }
 
+    @Override
     public <T> T getState( final Class<T> type )
     {
         final Object state = states.get( type );
@@ -488,6 +496,7 @@
         return pomValidationLevel;
     }
 
+    @Override
     public ProjectToolsSession setPomValidationLevel( final int pomValidationLevel )
     {
         this.pomValidationLevel = pomValidationLevel;
@@ -511,4 +520,20 @@
         return this;
     }
 
+    private final Map<Class<?>, EventDispatcher<?>> eventDispatchers = new HashMap<Class<?>, EventDispatcher<?>>();
+
+    @SuppressWarnings( "unchecked" )
+    @Override
+    public <E> EventDispatcher<E> getEventDispatcher( final Class<E> eventType )
+    {
+        return (EventDispatcher<E>) eventDispatchers.get( eventType );
+    }
+
+    @Override
+    public <E> ProjectToolsSession setEventDispatcher( final Class<E> eventType, final EventDispatcher<E> dispatcher )
+    {
+        eventDispatchers.put( eventType, dispatcher );
+        return this;
+    }
+
 }
diff --git a/mae-components/mae-project-tools/src/main/java/org/apache/maven/repository/internal/ConfigurableArtifactDescriptorReader.java b/mae-components/mae-project-tools/src/main/java/org/apache/maven/repository/internal/ConfigurableArtifactDescriptorReader.java
index 920ca2a..fde6b75 100644
--- a/mae-components/mae-project-tools/src/main/java/org/apache/maven/repository/internal/ConfigurableArtifactDescriptorReader.java
+++ b/mae-components/mae-project-tools/src/main/java/org/apache/maven/repository/internal/ConfigurableArtifactDescriptorReader.java
@@ -1,22 +1,4 @@
 /*
- * Copyright 2011 Red Hat, Inc.
- * 
- * Licensed 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.
- */
-
-package org.apache.maven.repository.internal;
-
-/*
  * 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
@@ -24,9 +6,9 @@
  * 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
- *
+ * 
+ * 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
@@ -35,6 +17,17 @@
  * under the License.
  */
 
+package org.apache.maven.repository.internal;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
 import org.apache.maven.mae.project.session.ProjectToolsSession;
 import org.apache.maven.model.DependencyManagement;
 import org.apache.maven.model.DistributionManagement;
@@ -88,15 +81,6 @@
 import org.sonatype.aether.util.artifact.DefaultArtifactType;
 import org.sonatype.aether.util.listener.DefaultRepositoryEvent;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
-
 /**
  * @author Benjamin Bentmann
  */
diff --git a/mae-components/mae-project-tools/src/test/java/org/apache/maven/mae/project/ProjectLoaderTest.java b/mae-components/mae-project-tools/src/test/java/org/apache/maven/mae/project/ProjectLoaderTest.java
index c03e8cd..ca81abb 100644
--- a/mae-components/mae-project-tools/src/test/java/org/apache/maven/mae/project/ProjectLoaderTest.java
+++ b/mae-components/mae-project-tools/src/test/java/org/apache/maven/mae/project/ProjectLoaderTest.java
@@ -1,17 +1,20 @@
 /*
- * Copyright 2011 Red Hat, Inc.
+ * 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
  * 
- * Licensed 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
  * 
- *   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.
+ * 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.
  */
 
 package org.apache.maven.mae.project;
@@ -19,17 +22,16 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
-import org.apache.maven.mae.project.ProjectLoader;
+import java.io.File;
+import java.io.IOException;
+import java.util.Set;
+
 import org.apache.maven.mae.project.testutil.TestFixture;
 import org.apache.maven.project.MavenProject;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
-import java.io.File;
-import java.io.IOException;
-import java.util.Set;
-
 public class ProjectLoaderTest
 {
 
diff --git a/mae-components/mae-project-tools/src/test/java/org/apache/maven/mae/project/testutil/TestFixture.java b/mae-components/mae-project-tools/src/test/java/org/apache/maven/mae/project/testutil/TestFixture.java
index 9e80a60..b4c9c7a 100644
--- a/mae-components/mae-project-tools/src/test/java/org/apache/maven/mae/project/testutil/TestFixture.java
+++ b/mae-components/mae-project-tools/src/test/java/org/apache/maven/mae/project/testutil/TestFixture.java
@@ -1,21 +1,35 @@
 /*
- * Copyright 2011 Red Hat, Inc.
+ * 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
  * 
- * Licensed 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
  * 
- *   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.
+ * 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.
  */
 
 package org.apache.maven.mae.project.testutil;
 
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
 import org.apache.commons.io.FileUtils;
 import org.apache.log4j.ConsoleAppender;
 import org.apache.log4j.Level;
@@ -47,17 +61,6 @@
 import org.codehaus.plexus.component.annotations.Requirement;
 import org.junit.Assert;
 
-import java.io.File;
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Set;
-
 @Component( role = TestFixture.class )
 public final class TestFixture
     extends AbstractMAEApplication