[MNG-7160] Ability to customize core extensions classloaders (#616)

This commit is contained in:
Guillaume Nodet 2022-06-15 10:43:17 +02:00 committed by Hervé Boutemy
parent bb6bbf882d
commit 115febf29b
6 changed files with 69 additions and 24 deletions

View File

@ -29,7 +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.CoreExportsProvider;
import org.apache.maven.extension.internal.CoreExports;
/**
* @author Jason van Zyl
@ -50,10 +50,10 @@ public class DefaultArtifactFilterManager
@Inject
public DefaultArtifactFilterManager( List<ArtifactFilterManagerDelegate> delegates,
CoreExportsProvider coreExports )
CoreExports coreExports )
{
this.delegates = delegates;
this.coreArtifacts = coreExports.get().getExportedArtifacts();
this.coreArtifacts = coreExports.getExportedArtifacts();
}
private synchronized Set<String> getExcludedArtifacts()

View File

@ -37,7 +37,7 @@ import javax.inject.Singleton;
import org.apache.maven.artifact.ArtifactUtils;
import org.apache.maven.classrealm.ClassRealmRequest.RealmType;
import org.apache.maven.extension.internal.CoreExportsProvider;
import org.apache.maven.extension.internal.CoreExports;
import org.apache.maven.model.Model;
import org.apache.maven.model.Plugin;
import org.codehaus.plexus.MutablePlexusContainer;
@ -92,20 +92,20 @@ public class DefaultClassRealmManager
@Inject
public DefaultClassRealmManager( Logger logger, PlexusContainer container,
List<ClassRealmManagerDelegate> delegates, CoreExportsProvider exports )
List<ClassRealmManagerDelegate> delegates, CoreExports exports )
{
this.logger = logger;
this.world = ( (MutablePlexusContainer) container ).getClassWorld();
this.containerRealm = container.getContainerRealm();
this.delegates = delegates;
Map<String, ClassLoader> foreignImports = exports.get().getExportedPackages();
Map<String, ClassLoader> foreignImports = exports.getExportedPackages();
this.mavenApiRealm =
createRealm( API_REALMID, RealmType.Core, null /* parent */, null /* parentImports */,
foreignImports, null /* artifacts */ );
this.providedArtifacts = exports.get().getExportedArtifacts();
this.providedArtifacts = exports.getExportedArtifacts();
}
private ClassRealm newRealm( String id )

View File

@ -19,34 +19,34 @@ package org.apache.maven.extension.internal;
* under the License.
*/
import java.util.Objects;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
import javax.inject.Singleton;
import org.codehaus.plexus.PlexusContainer;
import org.eclipse.sisu.Nullable;
/**
* CoreExportsProvider
*/
@Named
@Singleton
public class CoreExportsProvider
public class CoreExportsProvider implements Provider<CoreExports>
{
private final CoreExports exports;
@Inject
public CoreExportsProvider( PlexusContainer container, @Nullable CoreExports exports )
public CoreExportsProvider( PlexusContainer container )
{
if ( exports == null )
{
this.exports = new CoreExports( CoreExtensionEntry.discoverFrom( container.getContainerRealm() ) );
}
else
{
this.exports = exports;
}
this( new CoreExports( CoreExtensionEntry.discoverFrom( container.getContainerRealm() ) ) );
}
public CoreExportsProvider( CoreExports exports )
{
this.exports = Objects.requireNonNull( exports );
}
public CoreExports get()

View File

@ -188,7 +188,7 @@ under the License.
<groupId>org.codehaus.modello</groupId>
<artifactId>modello-maven-plugin</artifactId>
<configuration>
<version>1.0.0</version>
<version>1.1.0</version>
<models>
<model>src/main/mdo/core-extensions.mdo</model>
</models>

View File

@ -31,6 +31,7 @@ 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.CoreExports;
import org.apache.maven.extension.internal.CoreExtensionEntry;
import org.apache.maven.internal.aether.DefaultRepositorySystemSessionFactory;
import org.apache.maven.model.Plugin;
@ -59,12 +60,18 @@ import org.eclipse.aether.util.graph.visitor.PreorderNodeListGenerator;
@Named
public class BootstrapCoreExtensionManager
{
public static final String STRATEGY_PARENT_FIRST = "parent-first";
public static final String STRATEGY_PLUGIN = "plugin";
public static final String STRATEGY_SELF_FIRST = "self-first";
private final Logger log;
private final DefaultPluginDependenciesResolver pluginDependenciesResolver;
private final DefaultRepositorySystemSessionFactory repositorySystemSessionFactory;
private final CoreExports coreExports;
private final ClassWorld classWorld;
private final ClassRealm parentRealm;
@ -72,11 +79,13 @@ public class BootstrapCoreExtensionManager
@Inject
public BootstrapCoreExtensionManager( Logger log, DefaultPluginDependenciesResolver pluginDependenciesResolver,
DefaultRepositorySystemSessionFactory repositorySystemSessionFactory,
CoreExports coreExports,
PlexusContainer container )
{
this.log = log;
this.pluginDependenciesResolver = pluginDependenciesResolver;
this.repositorySystemSessionFactory = repositorySystemSessionFactory;
this.coreExports = coreExports;
this.classWorld = ( (DefaultPlexusContainer) container ).getClassWorld();
this.parentRealm = container.getContainerRealm();
}
@ -121,14 +130,42 @@ public class BootstrapCoreExtensionManager
{
String realmId =
"coreExtension>" + extension.getGroupId() + ":" + extension.getArtifactId() + ":" + extension.getVersion();
ClassRealm realm = classWorld.newRealm( realmId, null );
final ClassRealm realm = classWorld.newRealm( realmId, null );
Set<String> providedArtifacts = Collections.emptySet();
String classLoadingStrategy = extension.getClassLoadingStrategy();
if ( STRATEGY_PARENT_FIRST.equals( classLoadingStrategy ) )
{
realm.importFrom( parentRealm, "" );
}
else if ( STRATEGY_PLUGIN.equals( classLoadingStrategy ) )
{
coreExports.getExportedPackages().forEach( ( p, cl ) -> realm.importFrom( cl, p ) );
providedArtifacts = coreExports.getExportedArtifacts();
}
else if ( STRATEGY_SELF_FIRST.equals( classLoadingStrategy ) )
{
realm.setParentRealm( parentRealm );
}
else
{
throw new IllegalArgumentException( "Unsupported class-loading strategy '"
+ classLoadingStrategy + "'. Supported values are: " + STRATEGY_PARENT_FIRST
+ ", " + STRATEGY_PLUGIN + " and " + STRATEGY_SELF_FIRST );
}
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() );
String id = artifact.getGroupId() + ":" + artifact.getArtifactId();
if ( providedArtifacts.contains( id ) )
{
log.debug( " Excluded " + id );
}
else
{
File file = artifact.getFile();
log.debug( " Included " + id + " located at " + file );
realm.addURL( file.toURI().toURL() );
}
}
return CoreExtensionEntry.discoverFrom( realm, Collections.singleton( artifacts.get( 0 ).getFile() ) );
}

View File

@ -82,6 +82,14 @@
<required>true</required>
<type>String</type>
</field>
<field>
<name>classLoadingStrategy</name>
<description>The class loading strategy: 'self-first' (the default), 'parent-first' (loads classes from the parent, then from the extension) or 'plugin' (follows the rules from extensions defined as plugins).</description>
<version>1.1.0+</version>
<defaultValue>self-first</defaultValue>
<required>false</required>
<type>String</type>
</field>
</fields>
<codeSegments>
<codeSegment>