You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by ah...@apache.org on 2015/04/01 02:23:48 UTC

[06/50] [abbrv] maven git commit: MNG-5771 user-defined core extensions

MNG-5771 user-defined core extensions

read ${maven.projectBasedir}/.mvn/extensions.xml and create core
extensions realms during maven runtime bootstrap. this required
short-lived bootstrap plexus container to resolve extensions.

individual extensions realms are wired to maven.ext realm according
to META-INF/maven/extension.xml exported packages specification

Signed-off-by: Igor Fedorenko <if...@apache.org>


Project: http://git-wip-us.apache.org/repos/asf/maven/repo
Commit: http://git-wip-us.apache.org/repos/asf/maven/commit/6efacdb3
Tree: http://git-wip-us.apache.org/repos/asf/maven/tree/6efacdb3
Diff: http://git-wip-us.apache.org/repos/asf/maven/diff/6efacdb3

Branch: refs/heads/slf4j-log4j2
Commit: 6efacdb3fc5e8369fa3586c0603184dc785303da
Parents: e2a0792
Author: Igor Fedorenko <if...@apache.org>
Authored: Sat Feb 14 09:59:02 2015 -0500
Committer: Igor Fedorenko <if...@apache.org>
Committed: Fri Feb 20 14:05:54 2015 -0500

----------------------------------------------------------------------
 .../maven/DefaultArtifactFilterManager.java     |  26 +-
 .../classrealm/DefaultClassRealmManager.java    |  45 +---
 .../maven/extension/internal/CoreExports.java   |  75 ++++++
 .../extension/internal/CoreExportsProvider.java |  53 ++++
 .../extension/internal/CoreExtensionEntry.java  | 141 +++++++++++
 .../extension/internal/DefaultCoreExports.java  |  97 --------
 .../DefaultPluginDependenciesResolver.java      |  33 ++-
 maven-embedder/pom.xml                          |  14 ++
 .../java/org/apache/maven/cli/MavenCli.java     | 246 ++++++++++++++++---
 .../internal/BootstrapCoreExtensionManager.java | 143 +++++++++++
 maven-embedder/src/main/mdo/core-extensions.mdo |  74 ++++++
 11 files changed, 765 insertions(+), 182 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/maven/blob/6efacdb3/maven-core/src/main/java/org/apache/maven/DefaultArtifactFilterManager.java
----------------------------------------------------------------------
diff --git a/maven-core/src/main/java/org/apache/maven/DefaultArtifactFilterManager.java b/maven-core/src/main/java/org/apache/maven/DefaultArtifactFilterManager.java
index 80bfd62..46f8af0 100644
--- a/maven-core/src/main/java/org/apache/maven/DefaultArtifactFilterManager.java
+++ b/maven-core/src/main/java/org/apache/maven/DefaultArtifactFilterManager.java
@@ -29,9 +29,7 @@ import javax.inject.Singleton;
 
 import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
 import org.apache.maven.artifact.resolver.filter.ExclusionSetFilter;
-import org.apache.maven.extension.internal.DefaultCoreExports;
-
-import com.google.common.collect.ImmutableSet;
+import org.apache.maven.extension.internal.CoreExportsProvider;
 
 /**
  * @author Jason van Zyl
@@ -46,16 +44,24 @@ public class DefaultArtifactFilterManager
     // this is a live injected collection
     protected final List<ArtifactFilterManagerDelegate> delegates;
 
-    protected final Set<String> coreArtifacts;
+    protected Set<String> excludedArtifacts;
 
-    protected final Set<String> excludedArtifacts;
+    private final Set<String> coreArtifacts;
 
     @Inject
-    public DefaultArtifactFilterManager( List<ArtifactFilterManagerDelegate> delegates, DefaultCoreExports extensions )
+    public DefaultArtifactFilterManager( List<ArtifactFilterManagerDelegate> delegates, CoreExportsProvider coreExports )
     {
         this.delegates = delegates;
-        this.coreArtifacts = ImmutableSet.copyOf( extensions.getExportedArtifacts() );
-        this.excludedArtifacts = new LinkedHashSet<String>( extensions.getExportedArtifacts() );
+        this.coreArtifacts = coreExports.get().getExportedArtifacts();
+    }
+
+    private synchronized Set<String> getExcludedArtifacts()
+    {
+        if ( excludedArtifacts == null )
+        {
+            excludedArtifacts = new LinkedHashSet<String>( coreArtifacts );
+        }
+        return excludedArtifacts;
     }
 
     /**
@@ -65,7 +71,7 @@ public class DefaultArtifactFilterManager
      */
     public ArtifactFilter getArtifactFilter()
     {
-        Set<String> excludes = new LinkedHashSet<String>( excludedArtifacts );
+        Set<String> excludes = new LinkedHashSet<String>( getExcludedArtifacts() );
 
         for ( ArtifactFilterManagerDelegate delegate : delegates )
         {
@@ -87,7 +93,7 @@ public class DefaultArtifactFilterManager
 
     public void excludeArtifact( String artifactId )
     {
-        excludedArtifacts.add( artifactId );
+        getExcludedArtifacts().add( artifactId );
     }
 
     public Set<String> getCoreArtifactExcludes()

http://git-wip-us.apache.org/repos/asf/maven/blob/6efacdb3/maven-core/src/main/java/org/apache/maven/classrealm/DefaultClassRealmManager.java
----------------------------------------------------------------------
diff --git a/maven-core/src/main/java/org/apache/maven/classrealm/DefaultClassRealmManager.java b/maven-core/src/main/java/org/apache/maven/classrealm/DefaultClassRealmManager.java
index 206fa58..ab9607a 100644
--- a/maven-core/src/main/java/org/apache/maven/classrealm/DefaultClassRealmManager.java
+++ b/maven-core/src/main/java/org/apache/maven/classrealm/DefaultClassRealmManager.java
@@ -23,7 +23,6 @@ import java.io.File;
 import java.net.MalformedURLException;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
@@ -37,7 +36,7 @@ import javax.inject.Singleton;
 
 import org.apache.maven.artifact.ArtifactUtils;
 import org.apache.maven.classrealm.ClassRealmRequest.RealmType;
-import org.apache.maven.extension.internal.DefaultCoreExports;
+import org.apache.maven.extension.internal.CoreExportsProvider;
 import org.apache.maven.model.Model;
 import org.apache.maven.model.Plugin;
 import org.codehaus.plexus.MutablePlexusContainer;
@@ -49,8 +48,6 @@ import org.codehaus.plexus.logging.Logger;
 import org.codehaus.plexus.util.StringUtils;
 import org.eclipse.aether.artifact.Artifact;
 
-import com.google.common.collect.ImmutableMap;
-
 /**
  * Manages the class realms used by Maven. <strong>Warning:</strong> This is an internal utility class that is only
  * public for technical reasons, it is not part of the public API. In particular, this class can be changed or deleted
@@ -63,6 +60,7 @@ import com.google.common.collect.ImmutableMap;
 public class DefaultClassRealmManager
     implements ClassRealmManager
 {
+    public static final String API_REALMID = "maven.api";
 
     /**
      * During normal command line build, ClassWorld is loaded by jvm system classloader, which only includes
@@ -83,25 +81,22 @@ public class DefaultClassRealmManager
     // this is a live injected collection
     private final List<ClassRealmManagerDelegate> delegates;
 
-    private final Map<String, ClassLoader> coreImports;
-
-    private ClassRealm mavenRealm;
+    private final ClassRealm mavenApiRealm;
 
     @Inject
     public DefaultClassRealmManager( Logger logger, PlexusContainer container,
-                                     List<ClassRealmManagerDelegate> delegates, DefaultCoreExports coreExtensions )
+                                     List<ClassRealmManagerDelegate> delegates, CoreExportsProvider exports )
     {
         this.logger = logger;
         this.world = ( (MutablePlexusContainer) container ).getClassWorld();
         this.containerRealm = container.getContainerRealm();
         this.delegates = delegates;
 
-        Map<String, ClassLoader> coreImports = new HashMap<String, ClassLoader>();
-        for ( String corePackage : coreExtensions.getExportedPackages() )
-        {
-            coreImports.put( corePackage, containerRealm );
-        }
-        this.coreImports = ImmutableMap.copyOf( coreImports );
+        Map<String, ClassLoader> foreignImports = exports.get().getExportedPackages();
+
+        this.mavenApiRealm =
+            createRealm( API_REALMID, RealmType.Core, null /* parent */, null /* parentImports */, 
+                         foreignImports, null /* artifacts */ );
     }
 
     private ClassRealm newRealm( String id )
@@ -133,27 +128,9 @@ public class DefaultClassRealmManager
         }
     }
 
-    public synchronized ClassRealm getMavenApiRealm()
+    public ClassRealm getMavenApiRealm()
     {
-        if ( mavenRealm == null )
-        {
-            mavenRealm = newRealm( "maven.api" );
-
-            List<ClassRealmConstituent> constituents = new ArrayList<ClassRealmConstituent>();
-
-            List<String> parentImports = new ArrayList<String>();
-
-            Map<String, ClassLoader> foreignImports = new HashMap<String, ClassLoader>( coreImports );
-
-            callDelegates( mavenRealm, RealmType.Core, mavenRealm.getParentClassLoader(), parentImports,
-                           foreignImports, constituents );
-
-            wireRealm( mavenRealm, parentImports, foreignImports );
-
-            populateRealm( mavenRealm, constituents );
-        }
-
-        return mavenRealm;
+        return mavenApiRealm;
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/maven/blob/6efacdb3/maven-core/src/main/java/org/apache/maven/extension/internal/CoreExports.java
----------------------------------------------------------------------
diff --git a/maven-core/src/main/java/org/apache/maven/extension/internal/CoreExports.java b/maven-core/src/main/java/org/apache/maven/extension/internal/CoreExports.java
new file mode 100644
index 0000000..f1fa9e3
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/extension/internal/CoreExports.java
@@ -0,0 +1,75 @@
+package org.apache.maven.extension.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
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.codehaus.plexus.classworlds.realm.ClassRealm;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * Provides information about artifacts (identified by groupId:artifactId string key) and classpath elements exported by
+ * Maven core itself and loaded Maven core extensions.
+ * 
+ * @since 3.2.6
+ */
+public class CoreExports
+{
+    private final Set<String> artifacts;
+
+    private final Map<String, ClassLoader> packages;
+
+    public CoreExports( CoreExtensionEntry entry )
+    {
+        this( entry.getClassRealm(), entry.getExportedArtifacts(), entry.getExportedPackages() );
+    }
+
+    public CoreExports( ClassRealm realm, Set<String> exportedArtifacts, Set<String> exportedPackages )
+    {
+        Map<String, ClassLoader> packages = new LinkedHashMap<String, ClassLoader>();
+        for ( String pkg : exportedPackages )
+        {
+            packages.put( pkg, realm );
+        }
+        this.artifacts = ImmutableSet.copyOf( exportedArtifacts );
+        this.packages = ImmutableMap.copyOf( packages );
+    }
+
+    /**
+     * Returns artifacts exported by Maven core and core extensions. Artifacts are identified by their
+     * groupId:artifactId string key.
+     */
+    public Set<String> getExportedArtifacts()
+    {
+        return artifacts;
+    }
+
+    /**
+     * Returns packages exported by Maven core and core extensions.
+     */
+    public Map<String, ClassLoader> getExportedPackages()
+    {
+        return packages;
+    }
+}

http://git-wip-us.apache.org/repos/asf/maven/blob/6efacdb3/maven-core/src/main/java/org/apache/maven/extension/internal/CoreExportsProvider.java
----------------------------------------------------------------------
diff --git a/maven-core/src/main/java/org/apache/maven/extension/internal/CoreExportsProvider.java b/maven-core/src/main/java/org/apache/maven/extension/internal/CoreExportsProvider.java
new file mode 100644
index 0000000..e7e4534
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/extension/internal/CoreExportsProvider.java
@@ -0,0 +1,53 @@
+package org.apache.maven.extension.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
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.codehaus.plexus.PlexusContainer;
+import org.eclipse.sisu.Nullable;
+
+@Named
+@Singleton
+public class CoreExportsProvider
+{
+
+    private final CoreExports exports;
+
+    @Inject
+    public CoreExportsProvider( PlexusContainer container, @Nullable CoreExports exports )
+    {
+        if ( exports == null )
+        {
+            this.exports = new CoreExports( CoreExtensionEntry.discoverFrom( container.getContainerRealm() ) );
+        }
+        else
+        {
+            this.exports = exports;
+        }
+    }
+
+    public CoreExports get()
+    {
+        return exports;
+    }
+}

http://git-wip-us.apache.org/repos/asf/maven/blob/6efacdb3/maven-core/src/main/java/org/apache/maven/extension/internal/CoreExtensionEntry.java
----------------------------------------------------------------------
diff --git a/maven-core/src/main/java/org/apache/maven/extension/internal/CoreExtensionEntry.java b/maven-core/src/main/java/org/apache/maven/extension/internal/CoreExtensionEntry.java
new file mode 100644
index 0000000..d74c390
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/extension/internal/CoreExtensionEntry.java
@@ -0,0 +1,141 @@
+package org.apache.maven.extension.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
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import org.apache.maven.project.ExtensionDescriptor;
+import org.apache.maven.project.ExtensionDescriptorBuilder;
+import org.codehaus.plexus.classworlds.realm.ClassRealm;
+import org.codehaus.plexus.util.IOUtil;
+
+import com.google.common.collect.ImmutableSet;
+
+/**
+ * Provides information about artifacts (identified by groupId:artifactId string key) and classpath elements exported by
+ * Maven core itself or a Maven core extension.
+ * 
+ * @since 3.2.6
+ */
+public class CoreExtensionEntry
+{
+    private final ClassRealm realm;
+
+    private final Set<String> artifacts;
+
+    private final Set<String> packages;
+
+    public CoreExtensionEntry( ClassRealm realm, Collection<String> artifacts, Collection<String> packages )
+    {
+        this.realm = realm;
+        this.artifacts = ImmutableSet.copyOf( artifacts );
+        this.packages = ImmutableSet.copyOf( packages );
+    }
+
+    /**
+     * Returns ClassLoader used to load extension classes.
+     */
+    public ClassRealm getClassRealm()
+    {
+        return realm;
+    }
+
+    /**
+     * Returns artifacts exported by the extension, identified by groupId:artifactId string key.
+     */
+    public Set<String> getExportedArtifacts()
+    {
+        return artifacts;
+    }
+
+    /**
+     * Returns classpath elements exported by the extension.
+     */
+    public Set<String> getExportedPackages()
+    {
+        return packages;
+    }
+
+    private static final ExtensionDescriptorBuilder builder = new ExtensionDescriptorBuilder();
+
+    public static CoreExtensionEntry discoverFrom( ClassRealm loader )
+    {
+        Set<String> artifacts = new LinkedHashSet<String>();
+        Set<String> packages = new LinkedHashSet<String>();
+
+        try
+        {
+            Enumeration<URL> urls = loader.getResources( builder.getExtensionDescriptorLocation() );
+            while ( urls.hasMoreElements() )
+            {
+                InputStream is = urls.nextElement().openStream();
+                try
+                {
+                    ExtensionDescriptor descriptor = builder.build( is );
+                    artifacts.addAll( descriptor.getExportedArtifacts() );
+                    packages.addAll( descriptor.getExportedPackages() );
+                }
+                finally
+                {
+                    IOUtil.close( is );
+                }
+            }
+        }
+        catch ( IOException ignored )
+        {
+            // exports descriptors are entirely optional
+        }
+
+        return new CoreExtensionEntry( loader, artifacts, packages );
+    }
+
+    public static CoreExtensionEntry discoverFrom( ClassRealm loader, Collection<File> classpath )
+    {
+        Set<String> artifacts = new LinkedHashSet<String>();
+        Set<String> packages = new LinkedHashSet<String>();
+
+        try
+        {
+            for ( File entry : classpath )
+            {
+                ExtensionDescriptor descriptor = builder.build( entry );
+                if ( descriptor != null )
+                {
+                    artifacts.addAll( descriptor.getExportedArtifacts() );
+                    packages.addAll( descriptor.getExportedPackages() );
+                }
+            }
+        }
+        catch ( IOException ignored )
+        {
+            // exports descriptors are entirely optional
+        }
+
+        return new CoreExtensionEntry( loader, artifacts, packages );
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/maven/blob/6efacdb3/maven-core/src/main/java/org/apache/maven/extension/internal/DefaultCoreExports.java
----------------------------------------------------------------------
diff --git a/maven-core/src/main/java/org/apache/maven/extension/internal/DefaultCoreExports.java b/maven-core/src/main/java/org/apache/maven/extension/internal/DefaultCoreExports.java
deleted file mode 100644
index c4253ee..0000000
--- a/maven-core/src/main/java/org/apache/maven/extension/internal/DefaultCoreExports.java
+++ /dev/null
@@ -1,97 +0,0 @@
-package org.apache.maven.extension.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
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.Enumeration;
-import java.util.LinkedHashSet;
-import java.util.Set;
-
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
-import org.apache.maven.project.ExtensionDescriptor;
-import org.apache.maven.project.ExtensionDescriptorBuilder;
-import org.codehaus.plexus.PlexusContainer;
-import org.codehaus.plexus.util.IOUtil;
-
-import com.google.common.collect.ImmutableSet;
-
-/**
- * @since 3.2.6
- */
-@Named
-@Singleton
-public class DefaultCoreExports
-{
-    private static final ExtensionDescriptorBuilder builder = new ExtensionDescriptorBuilder();
-
-    private final Set<String> artifacts;
-
-    private final Set<String> packages;
-
-    @Inject
-    public DefaultCoreExports( PlexusContainer container )
-        throws IOException
-    {
-        Set<String> artifacts = new LinkedHashSet<String>();
-        Set<String> packages = new LinkedHashSet<String>();
-
-        Enumeration<URL> extensions =
-            container.getContainerRealm().getResources( builder.getExtensionDescriptorLocation() );
-        while ( extensions.hasMoreElements() )
-        {
-            InputStream is = extensions.nextElement().openStream();
-            try
-            {
-                ExtensionDescriptor descriptor = builder.build( is );
-
-                artifacts.addAll( descriptor.getExportedArtifacts() );
-                packages.addAll( descriptor.getExportedPackages() );
-            }
-            finally
-            {
-                IOUtil.close( is );
-            }
-        }
-        this.artifacts = ImmutableSet.copyOf( artifacts );
-        this.packages = ImmutableSet.copyOf( packages );
-    }
-
-    /**
-     * Returns artifacts exported by Maven core and core extensions. Artifacts are identified by their
-     * groupId:artifactId.
-     */
-    public Set<String> getExportedArtifacts()
-    {
-        return artifacts;
-    }
-
-    /**
-     * Returns packages exported by Maven core and core extensions.
-     */
-    public Set<String> getExportedPackages()
-    {
-        return packages;
-    }
-}

http://git-wip-us.apache.org/repos/asf/maven/blob/6efacdb3/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultPluginDependenciesResolver.java
----------------------------------------------------------------------
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultPluginDependenciesResolver.java b/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultPluginDependenciesResolver.java
index 5a0edf5..885c8ec 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultPluginDependenciesResolver.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultPluginDependenciesResolver.java
@@ -136,10 +136,32 @@ public class DefaultPluginDependenciesResolver
         return pluginArtifact;
     }
 
+    /**
+     * @since 3.2.6
+     */
+    public DependencyNode resolveCoreExtension( Plugin plugin, DependencyFilter dependencyFilter,
+                                                List<RemoteRepository> repositories, RepositorySystemSession session )
+        throws PluginResolutionException
+    {
+        return resolveInternal( plugin, null /* pluginArtifact */, dependencyFilter, null /* transformer */,
+                                repositories, session );
+    }
+
     public DependencyNode resolve( Plugin plugin, Artifact pluginArtifact, DependencyFilter dependencyFilter,
                                    List<RemoteRepository> repositories, RepositorySystemSession session )
         throws PluginResolutionException
     {
+        DependencyFilter resolutionFilter =
+            new ExclusionsDependencyFilter( artifactFilterManager.getCoreArtifactExcludes() );
+        resolutionFilter = AndDependencyFilter.newInstance( resolutionFilter, dependencyFilter );
+        return resolveInternal( plugin, pluginArtifact, resolutionFilter, new PlexusUtilsInjector(), repositories, session );
+    }
+
+    private DependencyNode resolveInternal( Plugin plugin, Artifact pluginArtifact, DependencyFilter dependencyFilter,
+                                            DependencyGraphTransformer transformer,
+                                            List<RemoteRepository> repositories, RepositorySystemSession session )
+        throws PluginResolutionException
+    {
         RequestTrace trace = RequestTrace.newChild( null, plugin );
 
         if ( pluginArtifact == null )
@@ -148,11 +170,7 @@ public class DefaultPluginDependenciesResolver
         }
 
         DependencyFilter collectionFilter = new ScopeDependencyFilter( "provided", "test" );
-
-        DependencyFilter resolutionFilter =
-            new ExclusionsDependencyFilter( artifactFilterManager.getCoreArtifactExcludes() );
-        resolutionFilter = AndDependencyFilter.newInstance( resolutionFilter, dependencyFilter );
-        resolutionFilter = new AndDependencyFilter( collectionFilter, resolutionFilter );
+        DependencyFilter resolutionFilter = AndDependencyFilter.newInstance( collectionFilter, dependencyFilter );
 
         DependencyNode node;
 
@@ -161,9 +179,8 @@ public class DefaultPluginDependenciesResolver
             DependencySelector selector =
                 AndDependencySelector.newInstance( session.getDependencySelector(), new WagonExcluder() );
 
-            DependencyGraphTransformer transformer =
-                ChainedDependencyGraphTransformer.newInstance( session.getDependencyGraphTransformer(),
-                                                               new PlexusUtilsInjector() );
+            transformer =
+                ChainedDependencyGraphTransformer.newInstance( session.getDependencyGraphTransformer(), transformer );
 
             DefaultRepositorySystemSession pluginSession = new DefaultRepositorySystemSession( session );
             pluginSession.setDependencySelector( selector );

http://git-wip-us.apache.org/repos/asf/maven/blob/6efacdb3/maven-embedder/pom.xml
----------------------------------------------------------------------
diff --git a/maven-embedder/pom.xml b/maven-embedder/pom.xml
index cd3f583..2dc5fde 100644
--- a/maven-embedder/pom.xml
+++ b/maven-embedder/pom.xml
@@ -122,9 +122,23 @@
     </pluginManagement>
     <plugins>
       <plugin>
+        <groupId>org.eclipse.sisu</groupId>
+        <artifactId>sisu-maven-plugin</artifactId>
+      </plugin>
+      <plugin>
         <groupId>org.codehaus.plexus</groupId>
         <artifactId>plexus-component-metadata</artifactId>
       </plugin>
+      <plugin>
+        <groupId>org.codehaus.modello</groupId>
+        <artifactId>modello-maven-plugin</artifactId>
+        <configuration>
+          <version>1.0.0</version>
+          <models>
+            <model>src/main/mdo/core-extensions.mdo</model>
+          </models>
+        </configuration>
+      </plugin>
     </plugins>
   </build>
 </project>

http://git-wip-us.apache.org/repos/asf/maven/blob/6efacdb3/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java
----------------------------------------------------------------------
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java b/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java
index 3878dae..1c2ffc0 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java
@@ -19,11 +19,14 @@ package org.apache.maven.cli;
  * under the License.
  */
 
+import java.io.BufferedInputStream;
 import java.io.Console;
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.PrintStream;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -47,6 +50,9 @@ import org.apache.maven.building.Problem;
 import org.apache.maven.building.Source;
 import org.apache.maven.cli.event.DefaultEventSpyContext;
 import org.apache.maven.cli.event.ExecutionEventLogger;
+import org.apache.maven.cli.internal.BootstrapCoreExtensionManager;
+import org.apache.maven.cli.internal.extension.model.CoreExtension;
+import org.apache.maven.cli.internal.extension.model.io.xpp3.CoreExtensionsXpp3Reader;
 import org.apache.maven.cli.logging.Slf4jConfiguration;
 import org.apache.maven.cli.logging.Slf4jConfigurationFactory;
 import org.apache.maven.cli.logging.Slf4jLoggerManager;
@@ -64,6 +70,8 @@ import org.apache.maven.execution.MavenExecutionRequest;
 import org.apache.maven.execution.MavenExecutionRequestPopulationException;
 import org.apache.maven.execution.MavenExecutionRequestPopulator;
 import org.apache.maven.execution.MavenExecutionResult;
+import org.apache.maven.extension.internal.CoreExports;
+import org.apache.maven.extension.internal.CoreExtensionEntry;
 import org.apache.maven.lifecycle.LifecycleExecutionException;
 import org.apache.maven.model.building.ModelProcessor;
 import org.apache.maven.project.MavenProject;
@@ -87,7 +95,9 @@ import org.codehaus.plexus.classworlds.realm.ClassRealm;
 import org.codehaus.plexus.classworlds.realm.NoSuchRealmException;
 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
 import org.codehaus.plexus.logging.LoggerManager;
+import org.codehaus.plexus.util.IOUtil;
 import org.codehaus.plexus.util.StringUtils;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
 import org.eclipse.aether.transfer.TransferListener;
 import org.slf4j.ILoggerFactory;
 import org.slf4j.Logger;
@@ -134,6 +144,8 @@ public class MavenCli
 
     private static final String EXT_CLASS_PATH = "maven.ext.class.path";
 
+    private static final String EXTENSIONS_FILENAME = ".mvn/extensions.xml";
+
     private ClassWorld classWorld;
 
     private LoggerManager plexusLoggerManager;
@@ -485,21 +497,44 @@ public class MavenCli
             cliRequest.classWorld = new ClassWorld( "plexus.core", Thread.currentThread().getContextClassLoader() );
         }
 
-        DefaultPlexusContainer container;
+        ClassRealm coreRealm = cliRequest.classWorld.getClassRealm( "plexus.core" );
+        if ( coreRealm == null )
+        {
+            coreRealm = cliRequest.classWorld.getRealms().iterator().next();
+        }
+
+        List<File> extClassPath = parseExtClasspath( cliRequest );
+
+        CoreExtensionEntry coreEntry = CoreExtensionEntry.discoverFrom( coreRealm );
+        List<CoreExtensionEntry> extensions =
+            loadCoreExtensions( cliRequest, coreRealm, coreEntry.getExportedArtifacts() );
+
+        ClassRealm containerRealm = setupContainerRealm( cliRequest.classWorld, coreRealm, extClassPath, extensions );
 
         ContainerConfiguration cc = new DefaultContainerConfiguration()
             .setClassWorld( cliRequest.classWorld )
-            .setRealm( setupContainerRealm( cliRequest ) )
+            .setRealm( containerRealm )
             .setClassPathScanning( PlexusConstants.SCANNING_INDEX )
             .setAutoWiring( true )
             .setName( "maven" );
 
-        container = new DefaultPlexusContainer( cc, new AbstractModule()
+        Set<String> exportedArtifacts = new HashSet<String>( coreEntry.getExportedArtifacts() );
+        Set<String> exportedPackages = new HashSet<String>( coreEntry.getExportedPackages() );
+        for ( CoreExtensionEntry extension : extensions )
+        {
+            exportedArtifacts.addAll( extension.getExportedArtifacts() );
+            exportedPackages.addAll( extension.getExportedPackages() );
+        }
+
+        final CoreExports exports = new CoreExports( containerRealm, exportedArtifacts, exportedPackages );
+
+        DefaultPlexusContainer container = new DefaultPlexusContainer( cc, new AbstractModule()
         {
             @Override
             protected void configure()
             {
                 bind( ILoggerFactory.class ).toInstance( slf4jLoggerFactory );
+                bind( CoreExports.class ).toInstance( exports );
             }
         } );
 
@@ -508,6 +543,11 @@ public class MavenCli
 
         container.setLoggerManager( plexusLoggerManager );
 
+        for ( CoreExtensionEntry extension : extensions )
+        {
+            container.discoverComponents( extension.getClassRealm() );
+        }
+
         customizeContainer( container );
 
         container.getLoggerManager().setThresholds( cliRequest.request.getLoggingLevel() );
@@ -543,49 +583,170 @@ public class MavenCli
         return container;
     }
 
-    private ClassRealm setupContainerRealm( CliRequest cliRequest )
-        throws Exception
+    private List<CoreExtensionEntry> loadCoreExtensions( CliRequest cliRequest, ClassRealm containerRealm,
+                                                         Set<String> providedArtifacts )
     {
-        ClassRealm containerRealm = null;
+        if ( cliRequest.projectBaseDirectory == null )
+        {
+            return Collections.emptyList();
+        }
 
-        String extClassPath = cliRequest.userProperties.getProperty( EXT_CLASS_PATH );
-        if ( extClassPath == null )
+        File extensionsFile = new File( cliRequest.projectBaseDirectory, EXTENSIONS_FILENAME );
+        if ( !extensionsFile.isFile() )
         {
-            extClassPath = cliRequest.systemProperties.getProperty( EXT_CLASS_PATH );
+            return Collections.emptyList();
         }
 
-        if ( StringUtils.isNotEmpty( extClassPath ) )
+        try
         {
-            String[] jars = StringUtils.split( extClassPath, File.pathSeparator );
+            List<CoreExtension> extensions = readCoreExtensionsDescriptor( extensionsFile );
+            if ( extensions.isEmpty() )
+            {
+                return Collections.emptyList();
+            }
+
+            ContainerConfiguration cc = new DefaultContainerConfiguration() //
+                .setClassWorld( cliRequest.classWorld ) //
+                .setRealm( containerRealm ) //
+                .setClassPathScanning( PlexusConstants.SCANNING_INDEX ) //
+                .setAutoWiring( true ) //
+                .setName( "maven" );
 
-            if ( jars.length > 0 )
+            DefaultPlexusContainer container = new DefaultPlexusContainer( cc, new AbstractModule()
             {
-                ClassRealm coreRealm = cliRequest.classWorld.getClassRealm( "plexus.core" );
-                if ( coreRealm == null )
+                @Override
+                protected void configure()
                 {
-                    coreRealm = cliRequest.classWorld.getRealms().iterator().next();
+                    bind( ILoggerFactory.class ).toInstance( slf4jLoggerFactory );
                 }
+            } );
 
-                ClassRealm extRealm = cliRequest.classWorld.newRealm( "maven.ext", null );
+            try
+            {
+                container.setLookupRealm( null );
 
-                slf4jLogger.debug( "Populating class realm " + extRealm.getId() );
+                container.setLoggerManager( plexusLoggerManager );
 
-                for ( String jar : jars )
-                {
-                    File file = resolveFile( new File( jar ), cliRequest.workingDirectory );
+                container.getLoggerManager().setThresholds( cliRequest.request.getLoggingLevel() );
+
+                Thread.currentThread().setContextClassLoader( container.getContainerRealm() );
 
-                    slf4jLogger.debug( "  Included " + file );
+                executionRequestPopulator = container.lookup( MavenExecutionRequestPopulator.class );
+                settingsBuilder = container.lookup( SettingsBuilder.class );
 
-                    extRealm.addURL( file.toURI().toURL() );
+                MavenExecutionRequest request = DefaultMavenExecutionRequest.copy( cliRequest.request );
+                settings( cliRequest, request );
+                request = populateRequest( cliRequest, request );
+                request = executionRequestPopulator.populateDefaults( request );
+
+                BootstrapCoreExtensionManager resolver = container.lookup( BootstrapCoreExtensionManager.class );
+                return resolver.loadCoreExtensions( request, providedArtifacts, extensions );
+            }
+            finally
+            {
+                executionRequestPopulator = null;
+                settingsBuilder = null;
+                container.dispose();
+            }
+        }
+        catch ( RuntimeException e )
+        {
+            // runtime exceptions are most likely bugs in maven, let them bubble up to the user
+            throw e;
+        }
+        catch ( Exception e )
+        {
+            slf4jLogger.warn( "Failed to read extensions descriptor " + extensionsFile + ": " + e.getMessage() );
+        }
+        return Collections.emptyList();
+    }
+
+    private List<CoreExtension> readCoreExtensionsDescriptor( File extensionsFile )
+        throws IOException, XmlPullParserException
+    {
+        CoreExtensionsXpp3Reader parser = new CoreExtensionsXpp3Reader();
+        InputStream is = null;
+        try
+        {
+            is = new BufferedInputStream( new FileInputStream( extensionsFile ) );
+            return parser.read( is ).getExtensions();
+        }
+        finally
+        {
+            IOUtil.close( is );
+        }
+    }
+
+    private ClassRealm setupContainerRealm( ClassWorld classWorld, ClassRealm coreRealm, List<File> extClassPath,
+                                            List<CoreExtensionEntry> extensions )
+        throws Exception
+    {
+        if ( !extClassPath.isEmpty() || !extensions.isEmpty() )
+        {
+            ClassRealm extRealm = classWorld.newRealm( "maven.ext", null );
+
+            extRealm.setParentRealm( coreRealm );
+
+            slf4jLogger.debug( "Populating class realm " + extRealm.getId() );
+
+            for ( File file : extClassPath )
+            {
+                slf4jLogger.debug( "  Included " + file );
+
+                extRealm.addURL( file.toURI().toURL() );
+            }
+
+            for ( CoreExtensionEntry entry : reverse( extensions ) )
+            {
+                Set<String> exportedPackages = entry.getExportedPackages();
+                ClassRealm realm = entry.getClassRealm();
+                for ( String exportedPackage : exportedPackages )
+                {
+                    extRealm.importFrom( realm, exportedPackage );
                 }
+                if ( exportedPackages.isEmpty() )
+                {
+                    // sisu uses realm imports to establish component visibility
+                    extRealm.importFrom( realm, realm.getId() );
+                }
+            }
+
+            return extRealm;
+        }
+
+        return coreRealm;
+    }
 
-                extRealm.setParentRealm( coreRealm );
+    private static <T> List<T> reverse( List<T> list )
+    {
+        List<T> copy = new ArrayList<T>( list );
+        Collections.reverse( copy );
+        return copy;
+    }
 
-                containerRealm = extRealm;
+    private List<File> parseExtClasspath( CliRequest cliRequest )
+    {
+        String extClassPath = cliRequest.userProperties.getProperty( EXT_CLASS_PATH );
+        if ( extClassPath == null )
+        {
+            extClassPath = cliRequest.systemProperties.getProperty( EXT_CLASS_PATH );
+        }
+
+        List<File> jars = new ArrayList<File>();
+
+        if ( StringUtils.isNotEmpty( extClassPath ) )
+        {
+            for ( String jar : StringUtils.split( extClassPath, File.pathSeparator ) )
+            {
+                File file = resolveFile( new File( jar ), cliRequest.workingDirectory );
+
+                slf4jLogger.debug( "  Included " + file );
+
+                jars.add( file );
             }
         }
 
-        return containerRealm;
+        return jars;
     }
 
     //
@@ -814,6 +975,12 @@ public class MavenCli
     private void settings( CliRequest cliRequest )
         throws Exception
     {
+        settings( cliRequest, cliRequest.request );
+    }
+
+    private void settings( CliRequest cliRequest, MavenExecutionRequest request )
+        throws Exception
+    {
         File userSettingsFile;
 
         if ( cliRequest.commandLine.hasOption( CLIManager.ALTERNATE_USER_SETTINGS ) )
@@ -851,8 +1018,8 @@ public class MavenCli
             globalSettingsFile = DEFAULT_GLOBAL_SETTINGS_FILE;
         }
 
-        cliRequest.request.setGlobalSettingsFile( globalSettingsFile );
-        cliRequest.request.setUserSettingsFile( userSettingsFile );
+        request.setGlobalSettingsFile( globalSettingsFile );
+        request.setUserSettingsFile( userSettingsFile );
 
         SettingsBuildingRequest settingsRequest = new DefaultSettingsBuildingRequest();
         settingsRequest.setGlobalSettingsFile( globalSettingsFile );
@@ -860,7 +1027,10 @@ public class MavenCli
         settingsRequest.setSystemProperties( cliRequest.systemProperties );
         settingsRequest.setUserProperties( cliRequest.userProperties );
 
-        eventSpyDispatcher.onEvent( settingsRequest );
+        if ( eventSpyDispatcher != null )
+        {
+            eventSpyDispatcher.onEvent( settingsRequest );
+        }
 
         slf4jLogger.debug( "Reading global settings from "
             + getLocation( settingsRequest.getGlobalSettingsSource(),
@@ -870,9 +1040,12 @@ public class MavenCli
 
         SettingsBuildingResult settingsResult = settingsBuilder.build( settingsRequest );
 
-        eventSpyDispatcher.onEvent( settingsResult );
+        if ( eventSpyDispatcher != null )
+        {
+            eventSpyDispatcher.onEvent( settingsResult );
+        }
 
-        executionRequestPopulator.populateFromSettings( cliRequest.request, settingsResult.getEffectiveSettings() );
+        executionRequestPopulator.populateFromSettings( request, settingsResult.getEffectiveSettings() );
 
         if ( !settingsResult.getProblems().isEmpty() && slf4jLogger.isWarnEnabled() )
         {
@@ -982,7 +1155,11 @@ public class MavenCli
 
     private MavenExecutionRequest populateRequest( CliRequest cliRequest )
     {
-        MavenExecutionRequest request = cliRequest.request;
+        return populateRequest( cliRequest, cliRequest.request );
+    }
+
+    private MavenExecutionRequest populateRequest( CliRequest cliRequest, MavenExecutionRequest request )
+    {
         CommandLine commandLine = cliRequest.commandLine;
         String workingDirectory = cliRequest.workingDirectory;
         boolean quiet = cliRequest.quiet;
@@ -1127,7 +1304,10 @@ public class MavenCli
         }
 
         ExecutionListener executionListener = new ExecutionEventLogger();
-        executionListener = eventSpyDispatcher.chainListener( executionListener );
+        if ( eventSpyDispatcher != null )
+        {
+            executionListener = eventSpyDispatcher.chainListener( executionListener );
+        }
 
         String alternatePomFile = null;
         if ( commandLine.hasOption( CLIManager.ALTERNATE_POM_FILE ) )
@@ -1172,7 +1352,7 @@ public class MavenCli
 
             request.setPom( pom );
         }
-        else
+        else if ( modelProcessor != null )
         {
             File pom = modelProcessor.locatePom( baseDirectory );
 

http://git-wip-us.apache.org/repos/asf/maven/blob/6efacdb3/maven-embedder/src/main/java/org/apache/maven/cli/internal/BootstrapCoreExtensionManager.java
----------------------------------------------------------------------
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/internal/BootstrapCoreExtensionManager.java b/maven-embedder/src/main/java/org/apache/maven/cli/internal/BootstrapCoreExtensionManager.java
new file mode 100644
index 0000000..a431bde
--- /dev/null
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/internal/BootstrapCoreExtensionManager.java
@@ -0,0 +1,143 @@
+package org.apache.maven.cli.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
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.apache.maven.RepositoryUtils;
+import org.apache.maven.cli.internal.extension.model.CoreExtension;
+import org.apache.maven.execution.MavenExecutionRequest;
+import org.apache.maven.extension.internal.CoreExtensionEntry;
+import org.apache.maven.internal.aether.DefaultRepositorySystemSessionFactory;
+import org.apache.maven.model.Plugin;
+import org.apache.maven.plugin.PluginResolutionException;
+import org.apache.maven.plugin.internal.DefaultPluginDependenciesResolver;
+import org.codehaus.plexus.DefaultPlexusContainer;
+import org.codehaus.plexus.PlexusContainer;
+import org.codehaus.plexus.classworlds.ClassWorld;
+import org.codehaus.plexus.classworlds.realm.ClassRealm;
+import org.codehaus.plexus.logging.Logger;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.graph.DependencyFilter;
+import org.eclipse.aether.graph.DependencyNode;
+import org.eclipse.aether.repository.RemoteRepository;
+import org.eclipse.aether.util.filter.ExclusionsDependencyFilter;
+import org.eclipse.aether.util.graph.visitor.PreorderNodeListGenerator;
+
+@Named
+public class BootstrapCoreExtensionManager
+{
+    private final Logger log;
+
+    private final DefaultPluginDependenciesResolver pluginDependenciesResolver;
+
+    private final DefaultRepositorySystemSessionFactory repositorySystemSessionFactory;
+
+    private final ClassWorld classWorld;
+
+    private final ClassRealm parentRealm;
+
+    @Inject
+    public BootstrapCoreExtensionManager( Logger log, DefaultPluginDependenciesResolver pluginDependenciesResolver,
+                                          DefaultRepositorySystemSessionFactory repositorySystemSessionFactory,
+                                          PlexusContainer container )
+    {
+        this.log = log;
+        this.pluginDependenciesResolver = pluginDependenciesResolver;
+        this.repositorySystemSessionFactory = repositorySystemSessionFactory;
+        this.classWorld = ( (DefaultPlexusContainer) container ).getClassWorld();
+        this.parentRealm = container.getContainerRealm();
+    }
+
+    public List<CoreExtensionEntry> loadCoreExtensions( MavenExecutionRequest request, Set<String> providedArtifacts,
+                                                        List<CoreExtension> extensions )
+        throws Exception
+    {
+        RepositorySystemSession repoSession = repositorySystemSessionFactory.newRepositorySession( request );
+        List<RemoteRepository> repositories = RepositoryUtils.toRepos( request.getPluginArtifactRepositories() );
+
+        return resolveCoreExtensions( repoSession, repositories, providedArtifacts, extensions );
+    }
+
+    private List<CoreExtensionEntry> resolveCoreExtensions( RepositorySystemSession repoSession,
+                                                            List<RemoteRepository> repositories,
+                                                            Set<String> providedArtifacts,
+                                                            List<CoreExtension> configuration )
+        throws Exception
+    {
+        List<CoreExtensionEntry> extensions = new ArrayList<CoreExtensionEntry>();
+
+        DependencyFilter dependencyFilter = new ExclusionsDependencyFilter( providedArtifacts );
+
+        for ( CoreExtension extension : configuration )
+        {
+            List<Artifact> artifacts = resolveExtension( extension, repoSession, repositories, dependencyFilter );
+            if ( !artifacts.isEmpty() )
+            {
+                extensions.add( createExtension( extension, artifacts ) );
+            }
+        }
+
+        return Collections.unmodifiableList( extensions );
+    }
+
+    private CoreExtensionEntry createExtension( CoreExtension extension, List<Artifact> artifacts )
+        throws Exception
+    {
+        String realmId =
+            "coreExtension>" + extension.getGroupId() + ":" + extension.getArtifactId() + ":" + extension.getVersion();
+        ClassRealm realm = classWorld.newRealm( realmId, null );
+        log.debug( "Populating class realm " + realm.getId() );
+        realm.setParentRealm( parentRealm );
+        for ( Artifact artifact : artifacts )
+        {
+            File file = artifact.getFile();
+            log.debug( "  Included " + file );
+            realm.addURL( file.toURI().toURL() );
+        }
+        return CoreExtensionEntry.discoverFrom( realm, Collections.singleton( artifacts.get( 0 ).getFile() ) );
+    }
+
+    private List<Artifact> resolveExtension( CoreExtension extension, RepositorySystemSession repoSession,
+                                             List<RemoteRepository> repositories, DependencyFilter dependencyFilter )
+        throws PluginResolutionException
+    {
+        Plugin plugin = new Plugin();
+        plugin.setGroupId( extension.getGroupId() );
+        plugin.setArtifactId( extension.getArtifactId() );
+        plugin.setVersion( extension.getVersion() );
+
+        DependencyNode root =
+            pluginDependenciesResolver.resolveCoreExtension( plugin, dependencyFilter, repositories, repoSession );
+        PreorderNodeListGenerator nlg = new PreorderNodeListGenerator();
+        root.accept( nlg );
+        List<Artifact> artifacts = nlg.getArtifacts( false );
+
+        return artifacts;
+    }
+}

http://git-wip-us.apache.org/repos/asf/maven/blob/6efacdb3/maven-embedder/src/main/mdo/core-extensions.mdo
----------------------------------------------------------------------
diff --git a/maven-embedder/src/main/mdo/core-extensions.mdo b/maven-embedder/src/main/mdo/core-extensions.mdo
new file mode 100644
index 0000000..f4b0215
--- /dev/null
+++ b/maven-embedder/src/main/mdo/core-extensions.mdo
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  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.
+
+-->
+
+<model xmlns="http://modello.codehaus.org/MODELLO/1.4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <id>CoreExtensions</id>
+  <name>CoreExtensions</name>
+
+  <defaults>
+    <default>
+      <key>package</key>
+      <value>org.apache.maven.cli.internal.extension.model</value>
+    </default>
+  </defaults>
+
+  <classes>
+    <class rootElement="true" xml.tagName="extensions">
+      <name>CoreExtensions</name>
+      <version>1.0.0+</version>
+      <fields>
+        <field>
+          <name>extensions</name>
+          <version>1.0.0+</version>
+          <association xml.itemsStyle="flat">
+            <type>CoreExtension</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+      </fields>
+    </class>
+    <class xml.tagName="extension">
+      <name>CoreExtension</name>
+      <version>1.0.0+</version>
+      <fields>
+        <field>
+          <name>groupId</name>
+          <version>1.0.0+</version>
+          <required>true</required>
+          <type>String</type>
+        </field>
+        <field>
+          <name>artifactId</name>
+          <version>1.0.0+</version>
+          <required>true</required>
+          <type>String</type>
+        </field>
+        <field>
+          <name>version</name>
+          <version>1.0.0+</version>
+          <required>true</required>
+          <type>String</type>
+        </field>
+      </fields>
+    </class>
+  </classes>
+</model>