Skip to content

Commit 5c55b41

Browse files
committed
Experiements with new build connection from plexus-build-extension
1 parent 9bab8e8 commit 5c55b41

File tree

5 files changed

+261
-21
lines changed

5 files changed

+261
-21
lines changed

org.eclipse.m2e.launching/src/org/eclipse/m2e/internal/launch/MavenBuildProjectDataConnection.java

Lines changed: 46 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,23 @@
1313

1414
package org.eclipse.m2e.internal.launch;
1515

16+
import java.io.File;
1617
import java.io.IOException;
1718
import java.util.Arrays;
1819
import java.util.Map;
1920
import java.util.Objects;
2021
import java.util.concurrent.ConcurrentHashMap;
2122
import java.util.stream.Stream;
2223

23-
import org.eclipse.core.runtime.CoreException;
2424
import org.eclipse.debug.core.DebugPlugin;
2525
import org.eclipse.debug.core.ILaunch;
2626
import org.eclipse.debug.core.ILaunchesListener2;
2727

28+
import org.codehaus.plexus.build.connect.TcpBuildConnection;
29+
import org.codehaus.plexus.build.connect.TcpBuildConnection.ServerConnection;
30+
2831
import org.eclipse.m2e.core.embedder.ArtifactKey;
29-
import org.eclipse.m2e.core.internal.launch.MavenEmbeddedRuntime;
3032
import org.eclipse.m2e.internal.launch.MavenRuntimeLaunchSupport.VMArguments;
31-
import org.eclipse.m2e.internal.maven.listener.M2EMavenBuildDataBridge;
3233
import org.eclipse.m2e.internal.maven.listener.M2EMavenBuildDataBridge.MavenBuildConnection;
3334
import org.eclipse.m2e.internal.maven.listener.M2EMavenBuildDataBridge.MavenProjectBuildData;
3435

@@ -70,23 +71,50 @@ public void launchesChanged(ILaunch[] launches) { // ignore
7071

7172
static void openListenerConnection(ILaunch launch, VMArguments arguments) {
7273
try {
73-
if(MavenLaunchUtils.getMavenRuntime(launch.getLaunchConfiguration()) instanceof MavenEmbeddedRuntime) {
74-
75-
Map<ArtifactKey, MavenProjectBuildData> projects = new ConcurrentHashMap<>();
76-
77-
MavenBuildConnection connection = M2EMavenBuildDataBridge.prepareConnection(
78-
launch.getLaunchConfiguration().getName(),
79-
d -> projects.put(new ArtifactKey(d.groupId, d.artifactId, d.version, null), d));
80-
81-
if(LAUNCH_PROJECT_DATA.putIfAbsent(launch, new MavenBuildConnectionData(projects, connection)) != null) {
82-
connection.close();
83-
throw new IllegalStateException(
84-
"Maven bridge already created for launch of" + launch.getLaunchConfiguration().getName());
85-
}
86-
arguments.append(connection.getMavenVMArguments());
74+
// if(MavenLaunchUtils.getMavenRuntime(launch.getLaunchConfiguration()) instanceof MavenEmbeddedRuntime) {
75+
//
76+
// Map<ArtifactKey, MavenProjectBuildData> projects = new ConcurrentHashMap<>();
77+
//
78+
// MavenBuildConnection connection = M2EMavenBuildDataBridge.prepareConnection(
79+
// launch.getLaunchConfiguration().getName(),
80+
// d -> projects.put(new ArtifactKey(d.groupId, d.artifactId, d.version, null), d));
81+
//
82+
// if(LAUNCH_PROJECT_DATA.putIfAbsent(launch, new MavenBuildConnectionData(projects, connection)) != null) {
83+
// connection.close();
84+
// throw new IllegalStateException(
85+
// "Maven bridge already created for launch of" + launch.getLaunchConfiguration().getName());
86+
// }
87+
//
88+
// arguments.append(connection.getMavenVMArguments());
89+
// } else {
90+
MavenRunState state = new MavenRunState();
91+
ServerConnection con = TcpBuildConnection.createServer(msg -> {
92+
System.out.println(msg);
93+
return state.handleMessage(msg);
94+
});
95+
state.getProject(new ArtifactKey("test", "me", "0.0.1-SNAPSHOT", null)).thenAccept(rp -> rp.onStart(() -> {
96+
System.out.println("project is started!!");
97+
}));
98+
File location = getJarLocation();
99+
if(location != null) {
100+
//TODO see bug https://issues.apache.org/jira/browse/MNG-8112
101+
arguments.appendProperty("maven.ext.class.path", location.getAbsolutePath());
87102
}
88-
} catch(CoreException | IOException ex) { // ignore
103+
con.setupProcess(arguments::appendProperty);
104+
// }
105+
} catch(Exception ex) { // ignore
106+
ex.printStackTrace();
107+
}
108+
}
109+
110+
private static File getJarLocation() {
111+
try {
112+
return new File(TcpBuildConnection.class.getProtectionDomain().getCodeSource().getLocation().toURI());
113+
} catch(Exception e) {
89114
}
115+
//TODO better way to find it?!?
116+
//Maybe just consume as a (wrapped) bundle as we only need it to start the server not on the maven classpath!
117+
return null;
90118
}
91119

92120
static MavenProjectBuildData getBuildProject(ILaunch launch, String groupId, String artifactId, String version) {
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
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+
14+
package org.eclipse.m2e.internal.launch;
15+
16+
import java.util.HashMap;
17+
import java.util.Map;
18+
import java.util.concurrent.CompletableFuture;
19+
import java.util.concurrent.ConcurrentHashMap;
20+
21+
import org.codehaus.plexus.build.connect.Configuration;
22+
import org.codehaus.plexus.build.connect.messages.InitMessage;
23+
import org.codehaus.plexus.build.connect.messages.Message;
24+
import org.codehaus.plexus.build.connect.messages.MojoMessage;
25+
import org.codehaus.plexus.build.connect.messages.ProjectMessage;
26+
import org.codehaus.plexus.build.connect.messages.ProjectsMessage;
27+
import org.codehaus.plexus.build.connect.messages.SessionMessage;
28+
29+
import org.eclipse.m2e.core.embedder.ArtifactKey;
30+
31+
32+
/**
33+
* Captures the run state of a maven process
34+
*/
35+
public class MavenRunState {
36+
37+
private String mavenName;
38+
39+
private String mavenBuildNumber;
40+
41+
private String mavenVersion;
42+
43+
private String workingDirectory;
44+
45+
private final Map<ArtifactKey, CompletableFuture<RemoteMavenProject>> projects = new ConcurrentHashMap<>();
46+
47+
Map<String, String> handleMessage(Message msg) {
48+
if(msg instanceof InitMessage init) {
49+
this.mavenName = init.getProperty("versionProperties.distributionName");
50+
this.mavenBuildNumber = init.getProperty("versionProperties.buildNumber");
51+
this.mavenVersion = init.getProperty("versionProperties.version");
52+
this.workingDirectory = init.getProperty("workingDirectory");
53+
Map<String, String> config = new HashMap<String, String>();
54+
config.put(Configuration.CONFIG_SEND_PROJECTS, "true");
55+
return config;
56+
}
57+
if(msg instanceof ProjectsMessage projects) {
58+
projects.projects().forEach(pi -> {
59+
RemoteMavenProject project = new RemoteMavenProject(pi);
60+
getProject(project.getArtifactKey()).complete(project);
61+
});
62+
}
63+
if(msg instanceof ProjectMessage project) {
64+
ArtifactKey key = new ArtifactKey(project.getGroupId(), project.getArtifactId(), project.getVersion(), null);
65+
getProject(key).thenAccept(rp -> rp.handleEvent(project));
66+
System.out.println("--- " + project.getType() + " --- " + key);
67+
System.out.println();
68+
System.out.println(project.getBaseDir());
69+
return null;
70+
}
71+
if(msg instanceof MojoMessage mojo) {
72+
System.out.println("--- " + mojo.getType() + " ---");
73+
System.out.println(mojo.getGroupId() + ":" + mojo.getArtifactId() + ":" + mojo.getVersion() + " - "
74+
+ mojo.getLifecyclePhase() + " [" + mojo.getExecutionId() + "] " + mojo.getGoal());
75+
return null;
76+
}
77+
if(msg instanceof SessionMessage session) {
78+
if(!session.isSessionStart()) {
79+
projects.values().forEach(cf -> {
80+
cf.thenAccept(rp -> rp.cancel());
81+
cf.cancel(true);
82+
});
83+
projects.clear();
84+
}
85+
}
86+
return null;
87+
}
88+
89+
public CompletableFuture<RemoteMavenProject> getProject(ArtifactKey key) {
90+
CompletableFuture<RemoteMavenProject> computeIfAbsent = projects.computeIfAbsent(key,
91+
nil -> new CompletableFuture<>());
92+
return computeIfAbsent;
93+
}
94+
95+
}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
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+
14+
package org.eclipse.m2e.internal.launch;
15+
16+
import java.io.IOException;
17+
import java.io.StringReader;
18+
import java.nio.file.Path;
19+
import java.util.concurrent.CompletableFuture;
20+
import java.util.function.Consumer;
21+
22+
import org.codehaus.plexus.build.connect.messages.ProjectMessage;
23+
import org.codehaus.plexus.build.connect.messages.ProjectMessage.EventType;
24+
import org.codehaus.plexus.build.connect.messages.ProjectsMessage.ProjectInfo;
25+
26+
import org.apache.maven.model.Model;
27+
import org.apache.maven.model.io.DefaultModelReader;
28+
29+
import org.eclipse.m2e.core.embedder.ArtifactKey;
30+
31+
32+
/**
33+
* Represents a maven project from a remote maven launch
34+
*/
35+
public class RemoteMavenProject {
36+
37+
private ArtifactKey artifactKey;
38+
39+
private Path baseDir;
40+
41+
private String modelString;
42+
43+
private Model model;
44+
45+
private CompletableFuture<?> starting = new CompletableFuture<>();
46+
47+
private CompletableFuture<Result> finished = new CompletableFuture<>();
48+
49+
RemoteMavenProject(ProjectInfo projectInfo) {
50+
artifactKey = new ArtifactKey(projectInfo.getGroupId(), projectInfo.getArtifactId(), projectInfo.getVersion(),
51+
null);
52+
this.baseDir = projectInfo.getBaseDir();
53+
this.modelString = projectInfo.getModel();
54+
}
55+
56+
/**
57+
* @return the artifactKey
58+
*/
59+
public ArtifactKey getArtifactKey() {
60+
return this.artifactKey;
61+
}
62+
63+
/**
64+
* @return the baseDir
65+
*/
66+
public Path getBaseDir() {
67+
return this.baseDir;
68+
}
69+
70+
public synchronized Model getModel() {
71+
if(model != null) {
72+
return model;
73+
}
74+
try {
75+
if(modelString == null) {
76+
return model = new Model();
77+
}
78+
try {
79+
return model = new DefaultModelReader().read(new StringReader(modelString), null);
80+
} catch(IOException ex) {
81+
return model = new Model();
82+
}
83+
} finally {
84+
model = null;
85+
}
86+
}
87+
88+
public CompletableFuture<Void> onStart(Runnable runnable) {
89+
return starting.thenAcceptAsync(nil -> runnable.run());
90+
}
91+
92+
public CompletableFuture<Void> onFinish(Consumer<Result> consumer) {
93+
return finished.thenAcceptAsync(result -> consumer.accept(result));
94+
}
95+
96+
void handleEvent(ProjectMessage project) {
97+
if(project.getType() == EventType.ProjectStarted) {
98+
starting.complete(null);
99+
} else if(project.getType() == EventType.ProjectSucceeded) {
100+
finished.complete(Result.SUCCESS);
101+
} else if(project.getType() == EventType.ProjectSkipped) {
102+
finished.complete(Result.SKIPPED);
103+
} else if(project.getType() == EventType.ProjectFailed) {
104+
finished.complete(Result.FAILED);
105+
}
106+
}
107+
108+
void cancel() {
109+
starting.cancel(true);
110+
finished.cancel(true);
111+
}
112+
113+
public static enum Result {
114+
SUCCESS, FAILED, SKIPPED;
115+
}
116+
117+
}

org.eclipse.m2e.maven.runtime/pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
</parent>
2222

2323
<artifactId>org.eclipse.m2e.maven.runtime</artifactId>
24-
<version>3.9.900-SNAPSHOT</version>
24+
<version>3.9.901-SNAPSHOT</version>
2525
<packaging>jar</packaging>
2626

2727
<name>M2E Embedded Maven Runtime (includes Incubating components)</name>
@@ -30,7 +30,7 @@
3030
<!-- maven core version -->
3131
<maven-core.version>3.9.9</maven-core.version>
3232
<!-- below are m2e-specific addons -->
33-
<plexus-build-api.version>1.2.0</plexus-build-api.version>
33+
<plexus-build-api.version>1.2.1-SNAPSHOT</plexus-build-api.version>
3434
<jars.directory>target/jars</jars.directory>
3535
<outputDirectory.sources>${project.build.directory}/classes-source</outputDirectory.sources>
3636
<failIfMacSigningFailed>false</failIfMacSigningFailed>

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@
9999
<dependency>
100100
<groupId>org.eclipse.m2e</groupId>
101101
<artifactId>org.eclipse.m2e.maven.runtime</artifactId>
102-
<version>3.9.900-SNAPSHOT</version>
102+
<version>3.9.901-SNAPSHOT</version>
103103
</dependency>
104104
</dependencies>
105105

0 commit comments

Comments
 (0)