Skip to content

Commit 21c35cb

Browse files
committed
Add plexus container facade for Maven 4 compatibility
1 parent 363672e commit 21c35cb

File tree

4 files changed

+153
-100
lines changed

4 files changed

+153
-100
lines changed

org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/IMavenPlexusContainer.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import org.codehaus.plexus.PlexusContainer;
1717

1818
import org.eclipse.m2e.core.embedder.IComponentLookup;
19+
import org.eclipse.m2e.internal.maven.compat.PlexusContainerFacade;
1920

2021

2122
/**
@@ -24,9 +25,9 @@
2425
*/
2526
public interface IMavenPlexusContainer {
2627

27-
static final String MVN_FOLDER = ".mvn";
28+
static final String MVN_FOLDER = PlexusContainerFacade.MVN_FOLDER;
2829

29-
static final String EXTENSIONS_FILENAME = MVN_FOLDER + "/extensions.xml";
30+
static final String EXTENSIONS_FILENAME = PlexusContainerFacade.EXTENSIONS_FILENAME;
3031

3132
/**
3233
* Maven allows to use a magic {@value #MVN_FOLDER} folder where one can configure several aspects of the maven run

org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/embedder/PlexusContainerManager.java

Lines changed: 20 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,8 @@
1515
package org.eclipse.m2e.core.internal.embedder;
1616

1717
import java.io.File;
18-
import java.io.FileInputStream;
19-
import java.io.InputStream;
2018
import java.net.MalformedURLException;
2119
import java.util.Collection;
22-
import java.util.Collections;
2320
import java.util.HashMap;
2421
import java.util.HashSet;
2522
import java.util.List;
@@ -56,21 +53,17 @@
5653
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
5754
import org.codehaus.plexus.logging.LoggerManager;
5855

59-
import org.apache.maven.cli.internal.BootstrapCoreExtensionManager;
6056
import org.apache.maven.cli.internal.ExtensionResolutionException;
61-
import org.apache.maven.cli.internal.extension.model.CoreExtension;
62-
import org.apache.maven.cli.internal.extension.model.io.xpp3.CoreExtensionsXpp3Reader;
6357
import org.apache.maven.execution.MavenExecutionRequest;
6458
import org.apache.maven.execution.MavenExecutionRequestPopulator;
65-
import org.apache.maven.execution.scope.internal.MojoExecutionScopeModule;
6659
import org.apache.maven.extension.internal.CoreExports;
6760
import org.apache.maven.extension.internal.CoreExtensionEntry;
68-
import org.apache.maven.session.scope.internal.SessionScopeModule;
6961

7062
import org.eclipse.m2e.core.embedder.IComponentLookup;
7163
import org.eclipse.m2e.core.embedder.IMavenConfiguration;
7264
import org.eclipse.m2e.core.internal.Messages;
7365
import org.eclipse.m2e.internal.maven.compat.ExtensionResolutionExceptionFacade;
66+
import org.eclipse.m2e.internal.maven.compat.PlexusContainerFacade;
7467

7568

7669
/**
@@ -82,8 +75,6 @@
8275
public class PlexusContainerManager {
8376
private static final ILog LOG = Platform.getLog(PlexusContainerManager.class);
8477

85-
private static final String CONTAINER_CONFIGURATION_NAME = "maven";
86-
8778
private static final String MAVEN_EXTENSION_REALM_PREFIX = "maven.ext.";
8879

8980
private static final String PLEXUS_CORE_REALM = "plexus.core";
@@ -180,8 +171,7 @@ public IMavenPlexusContainer aquire(File basedir) throws Exception {
180171
containerMap.put(canonicalDirectory, plexusContainer);
181172
} catch(ExtensionResolutionException e) {
182173
//TODO how can we create an error marker on the extension file?
183-
File file = new File(directory, IMavenPlexusContainer.EXTENSIONS_FILENAME);
184-
new ExtensionResolutionExceptionFacade(e).throwForFile(file);
174+
ExtensionResolutionExceptionFacade.throwForFile(e, new File(directory, IMavenPlexusContainer.EXTENSIONS_FILENAME));
185175
}
186176
}
187177
return plexusContainer;
@@ -215,15 +205,27 @@ private static IMavenPlexusContainer newPlexusContainer(File multiModuleProjectD
215205
multiModuleProjectDirectory);
216206
ClassRealm coreRealm = classWorld.getRealm(PLEXUS_CORE_REALM);
217207
CoreExtensionEntry coreEntry = CoreExtensionEntry.discoverFrom(coreRealm);
218-
219-
List<CoreExtensionEntry> extensions = loadCoreExtensions(coreRealm, coreEntry, multiModuleProjectDirectory,
220-
loggerManager, mavenConfiguration);
208+
List<CoreExtensionEntry> extensions = PlexusContainerFacade.loadCoreExtensions(coreRealm, coreEntry,
209+
multiModuleProjectDirectory, loggerManager, container -> {
210+
Optional<MavenProperties> mavenProperties = MavenProperties.getMavenArgs(multiModuleProjectDirectory);
211+
IMavenConfiguration workspaceConfiguration = IMavenConfiguration.getWorkspaceConfiguration();
212+
MavenExecutionRequest request = MavenExecutionContext.createExecutionRequest(mavenConfiguration,
213+
wrap(container), mavenProperties.map(mavenCfg -> mavenCfg.getSettingsLocations(workspaceConfiguration))
214+
.orElseGet(workspaceConfiguration::getSettingsLocations),
215+
multiModuleProjectDirectory);
216+
container.lookup(MavenExecutionRequestPopulator.class).populateDefaults(request);
217+
request.setBaseDirectory(multiModuleProjectDirectory);
218+
request.setMultiModuleProjectDirectory(multiModuleProjectDirectory);
219+
Properties userProperties = request.getUserProperties();
220+
mavenProperties.ifPresent(prop -> prop.getCliProperties(userProperties::setProperty));
221+
return request;
222+
});
221223
List<File> extClassPath = List.of(); //TODO should we allow to set an ext-class path for m2e?
222224
ClassRealm containerRealm = setupContainerRealm(coreRealm, extClassPath, extensions);
223225

224226
ContainerConfiguration cc = new DefaultContainerConfiguration().setClassWorld(classWorld).setRealm(containerRealm)
225227
.setClassPathScanning(PlexusConstants.SCANNING_INDEX).setAutoWiring(true).setJSR250Lifecycle(true)
226-
.setName(CONTAINER_CONFIGURATION_NAME);
228+
.setName(PlexusContainerFacade.CONTAINER_CONFIGURATION_NAME);
227229

228230
Set<String> exportedArtifacts = new HashSet<>(coreEntry.getExportedArtifacts());
229231
Set<String> exportedPackages = new HashSet<>(coreEntry.getExportedPackages());
@@ -241,6 +243,7 @@ protected void configure() {
241243
bind(CoreExports.class).toInstance(exports);
242244
}
243245
}, new ExtensionModule());
246+
PlexusContainerFacade facade = new PlexusContainerFacade(container);
244247
classWorld.addListener(new LifecycleManagerDisposer(container));
245248
container.setLookupRealm(null);
246249
Thread thread = Thread.currentThread();
@@ -249,8 +252,7 @@ protected void configure() {
249252
thread.setContextClassLoader(container.getContainerRealm());
250253
container.setLoggerManager(loggerManager);
251254
for(CoreExtensionEntry extension : extensions) {
252-
container.discoverComponents(extension.getClassRealm(), new SessionScopeModule(container),
253-
new MojoExecutionScopeModule(container));
255+
facade.loadExtension(extension);
254256
}
255257
} finally {
256258
thread.setContextClassLoader(ccl);
@@ -304,60 +306,6 @@ private static ClassRealm setupContainerRealm(ClassRealm coreRealm, List<File> e
304306
return extRealm;
305307
}
306308

307-
private static List<CoreExtensionEntry> loadCoreExtensions(ClassRealm coreRealm, CoreExtensionEntry coreEntry,
308-
File multiModuleProjectDirectory, LoggerManager loggerManager, IMavenConfiguration mavenConfiguration)
309-
throws Exception {
310-
if(multiModuleProjectDirectory == null) {
311-
return Collections.emptyList();
312-
}
313-
File extensionsXml = new File(multiModuleProjectDirectory, IMavenPlexusContainer.EXTENSIONS_FILENAME);
314-
if(!extensionsXml.isFile()) {
315-
return Collections.emptyList();
316-
}
317-
List<CoreExtension> extensions;
318-
try (InputStream is = new FileInputStream(extensionsXml)) {
319-
extensions = new CoreExtensionsXpp3Reader().read(is).getExtensions();
320-
}
321-
if(extensions.isEmpty()) {
322-
return Collections.emptyList();
323-
}
324-
325-
ContainerConfiguration cc = new DefaultContainerConfiguration().setClassWorld(coreRealm.getWorld())
326-
.setRealm(coreRealm).setClassPathScanning(PlexusConstants.SCANNING_INDEX).setAutoWiring(true)
327-
.setJSR250Lifecycle(true).setName(CONTAINER_CONFIGURATION_NAME);
328-
329-
DefaultPlexusContainer container = new DefaultPlexusContainer(cc, new AbstractModule() {
330-
@Override
331-
protected void configure() {
332-
bind(ILoggerFactory.class).toInstance(LoggerFactory.getILoggerFactory());
333-
}
334-
});
335-
336-
Thread thread = Thread.currentThread();
337-
ClassLoader ccl = thread.getContextClassLoader();
338-
try {
339-
container.setLookupRealm(null);
340-
container.setLoggerManager(loggerManager);
341-
thread.setContextClassLoader(container.getContainerRealm());
342-
Optional<MavenProperties> mavenProperties = MavenProperties.getMavenArgs(multiModuleProjectDirectory);
343-
IMavenConfiguration workspaceConfiguration = IMavenConfiguration.getWorkspaceConfiguration();
344-
MavenExecutionRequest request = MavenExecutionContext.createExecutionRequest(mavenConfiguration,
345-
wrap(container), mavenProperties.map(mavenCfg -> mavenCfg.getSettingsLocations(workspaceConfiguration))
346-
.orElseGet(workspaceConfiguration::getSettingsLocations),
347-
multiModuleProjectDirectory);
348-
container.lookup(MavenExecutionRequestPopulator.class).populateDefaults(request);
349-
request.setBaseDirectory(multiModuleProjectDirectory);
350-
request.setMultiModuleProjectDirectory(multiModuleProjectDirectory);
351-
Properties userProperties = request.getUserProperties();
352-
mavenProperties.ifPresent(prop -> prop.getCliProperties(userProperties::setProperty));
353-
BootstrapCoreExtensionManager resolver = container.lookup(BootstrapCoreExtensionManager.class);
354-
return resolver.loadCoreExtensions(request, coreEntry.getExportedArtifacts(), extensions);
355-
} finally {
356-
thread.setContextClassLoader(ccl);
357-
container.dispose();
358-
}
359-
}
360-
361309
private static final class M2EClassWorld extends ClassWorld {
362310

363311
private File multiModuleProjectDirectory;

org.eclipse.m2e.maven.runtime/src/main/java/org/eclipse/m2e/internal/maven/compat/ExtensionResolutionExceptionFacade.java

Lines changed: 18 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -20,33 +20,25 @@
2020
import org.codehaus.plexus.PlexusContainerException;
2121

2222
/**
23-
* Facade for {@link ExtensionResolutionException} to avoid direct usage that might change in Maven 4.
24-
* This facade wraps the exception and provides a method to throw it as a PlexusContainerException
25-
* with appropriate context information.
23+
* Facade for {@link ExtensionResolutionException} to avoid direct usage that
24+
* might change in Maven 4. This facade wraps the exception and provides a
25+
* method to throw it as a PlexusContainerException with appropriate context
26+
* information.
2627
*/
2728
public class ExtensionResolutionExceptionFacade {
2829

29-
private final ExtensionResolutionException exception;
30-
31-
public ExtensionResolutionExceptionFacade(ExtensionResolutionException exception) {
32-
if(exception == null) {
33-
throw new IllegalArgumentException("exception cannot be null");
34-
}
35-
this.exception = exception;
36-
}
37-
38-
/**
39-
* Throws a PlexusContainerException with information about the failed extension and the file where it was defined.
40-
*
41-
* @param file the extensions file where the failed extension was defined
42-
* @throws PlexusContainerException always thrown with details about the failed extension
43-
*/
44-
public void throwForFile(File file) throws PlexusContainerException {
45-
CoreExtension extension = exception.getExtension();
46-
throw new PlexusContainerException(
47-
"can't create plexus container because the extension " + extension.getGroupId() + ":"
48-
+ extension.getArtifactId() + ":" + extension.getVersion() + " can't be loaded (defined in "
49-
+ file.getAbsolutePath() + ").",
50-
exception);
51-
}
30+
/**
31+
* Throws a PlexusContainerException with information about the failed extension
32+
* and the file where it was defined.
33+
*
34+
* @param file the extensions file where the failed extension was defined
35+
* @throws PlexusContainerException always thrown with details about the failed
36+
* extension
37+
*/
38+
public static void throwForFile(ExtensionResolutionException exception, File file) throws PlexusContainerException {
39+
CoreExtension extension = exception.getExtension();
40+
throw new PlexusContainerException("can't create plexus container because the extension "
41+
+ extension.getGroupId() + ":" + extension.getArtifactId() + ":" + extension.getVersion()
42+
+ " can't be loaded (defined in " + file.getAbsolutePath() + ").", exception);
43+
}
5244
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/********************************************************************************
2+
* Copyright (c) 2025 Christoph Läubrich and others
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License 2.0 which is available at
6+
* http://www.eclipse.org/legal/epl-2.0.
7+
*
8+
* SPDX-License-Identifier: EPL-2.0
9+
*
10+
* Contributors:
11+
* Christoph Läubrich - initial API and implementation
12+
********************************************************************************/
13+
package org.eclipse.m2e.internal.maven.compat;
14+
15+
import java.io.File;
16+
import java.io.FileInputStream;
17+
import java.io.InputStream;
18+
import java.util.Collections;
19+
import java.util.List;
20+
21+
import org.apache.maven.cli.internal.BootstrapCoreExtensionManager;
22+
import org.apache.maven.cli.internal.extension.model.CoreExtension;
23+
import org.apache.maven.cli.internal.extension.model.io.xpp3.CoreExtensionsXpp3Reader;
24+
import org.apache.maven.execution.MavenExecutionRequest;
25+
import org.apache.maven.execution.scope.internal.MojoExecutionScopeModule;
26+
import org.apache.maven.extension.internal.CoreExtensionEntry;
27+
import org.apache.maven.session.scope.internal.SessionScopeModule;
28+
import org.codehaus.plexus.ContainerConfiguration;
29+
import org.codehaus.plexus.DefaultContainerConfiguration;
30+
import org.codehaus.plexus.DefaultPlexusContainer;
31+
import org.codehaus.plexus.PlexusConstants;
32+
import org.codehaus.plexus.PlexusContainer;
33+
import org.codehaus.plexus.classworlds.realm.ClassRealm;
34+
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
35+
import org.codehaus.plexus.logging.LoggerManager;
36+
import org.slf4j.ILoggerFactory;
37+
import org.slf4j.LoggerFactory;
38+
39+
import com.google.inject.AbstractModule;
40+
41+
public class PlexusContainerFacade {
42+
43+
public static final String CONTAINER_CONFIGURATION_NAME = "maven";
44+
45+
public static final String MVN_FOLDER = ".mvn";
46+
47+
public static final String EXTENSIONS_FILENAME = MVN_FOLDER + "/extensions.xml";
48+
49+
private PlexusContainer container;
50+
51+
public PlexusContainerFacade(PlexusContainer container) {
52+
this.container = container;
53+
}
54+
55+
public static List<CoreExtensionEntry> loadCoreExtensions(ClassRealm coreRealm, CoreExtensionEntry coreEntry,
56+
File multiModuleProjectDirectory, LoggerManager loggerManager, MavenExecutionRequesFactory requestFactory)
57+
throws Exception {
58+
if (multiModuleProjectDirectory == null) {
59+
return Collections.emptyList();
60+
}
61+
File extensionsXml = new File(multiModuleProjectDirectory, EXTENSIONS_FILENAME);
62+
if (!extensionsXml.isFile()) {
63+
return Collections.emptyList();
64+
}
65+
List<CoreExtension> extensions;
66+
try (InputStream is = new FileInputStream(extensionsXml)) {
67+
extensions = new CoreExtensionsXpp3Reader().read(is).getExtensions();
68+
}
69+
if (extensions.isEmpty()) {
70+
return Collections.emptyList();
71+
}
72+
73+
ContainerConfiguration cc = new DefaultContainerConfiguration().setClassWorld(coreRealm.getWorld())
74+
.setRealm(coreRealm).setClassPathScanning(PlexusConstants.SCANNING_INDEX).setAutoWiring(true)
75+
.setJSR250Lifecycle(true).setName(CONTAINER_CONFIGURATION_NAME);
76+
77+
DefaultPlexusContainer container = new DefaultPlexusContainer(cc, new AbstractModule() {
78+
@Override
79+
protected void configure() {
80+
bind(ILoggerFactory.class).toInstance(LoggerFactory.getILoggerFactory());
81+
}
82+
});
83+
84+
Thread thread = Thread.currentThread();
85+
ClassLoader ccl = thread.getContextClassLoader();
86+
try {
87+
container.setLookupRealm(null);
88+
container.setLoggerManager(loggerManager);
89+
thread.setContextClassLoader(container.getContainerRealm());
90+
91+
BootstrapCoreExtensionManager resolver = container.lookup(BootstrapCoreExtensionManager.class);
92+
return resolver.loadCoreExtensions(requestFactory.createFor(container), coreEntry.getExportedArtifacts(),
93+
extensions);
94+
} finally {
95+
thread.setContextClassLoader(ccl);
96+
container.dispose();
97+
}
98+
}
99+
100+
public static interface MavenExecutionRequesFactory {
101+
public MavenExecutionRequest createFor(PlexusContainer container) throws Exception;
102+
}
103+
104+
public void loadExtension(CoreExtensionEntry extension) throws ComponentLookupException {
105+
if (container instanceof DefaultPlexusContainer) {
106+
((DefaultPlexusContainer) container).discoverComponents(extension.getClassRealm(),
107+
new SessionScopeModule(container),
108+
new MojoExecutionScopeModule(container));
109+
}
110+
}
111+
112+
}

0 commit comments

Comments
 (0)