Skip to content

Commit 32d7e12

Browse files
committed
Make the remove maven listener a process in the launch
Currently m2e uses an additional socket connection to receive project events from the remote maven project. This is not visible to the user and requires some internal maps to maintain state. This refactors this into a more generic event facility and make it visible as a Process in the debug view, this also has the advantage that the process itself can be used to maintain the state.
1 parent 55614a8 commit 32d7e12

File tree

7 files changed

+172
-81
lines changed

7 files changed

+172
-81
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
import org.eclipse.m2e.internal.launch.MavenRuntimeLaunchSupport.VMArguments;
3131
import org.eclipse.m2e.internal.maven.listener.M2EMavenBuildDataBridge;
3232
import org.eclipse.m2e.internal.maven.listener.M2EMavenBuildDataBridge.MavenBuildConnection;
33-
import org.eclipse.m2e.internal.maven.listener.M2EMavenBuildDataBridge.MavenProjectBuildData;
33+
import org.eclipse.m2e.internal.maven.listener.MavenProjectBuildData;
3434

3535

3636
public class MavenBuildProjectDataConnection {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@
6565

6666
import org.eclipse.m2e.core.internal.IMavenConstants;
6767
import org.eclipse.m2e.core.project.IBuildProjectFileResolver;
68-
import org.eclipse.m2e.internal.maven.listener.M2EMavenBuildDataBridge.MavenProjectBuildData;
68+
import org.eclipse.m2e.internal.maven.listener.MavenProjectBuildData;
6969

7070

7171
/**

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
</parent>
2121

2222
<artifactId>org.eclipse.m2e.maven.runtime</artifactId>
23-
<version>3.9.600-SNAPSHOT</version>
23+
<version>3.9.601-SNAPSHOT</version>
2424
<packaging>jar</packaging>
2525

2626
<name>M2E Embedded Maven Runtime (includes Incubating components)</name>

org.eclipse.m2e.maven.runtime/src/main/java/org/eclipse/m2e/internal/maven/listener/M2EMavenBuildDataBridge.java

Lines changed: 30 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -21,22 +21,16 @@
2121
import java.nio.ByteBuffer;
2222
import java.nio.channels.ServerSocketChannel;
2323
import java.nio.channels.SocketChannel;
24-
import java.nio.file.Path;
25-
import java.nio.file.Paths;
26-
import java.util.HashMap;
27-
import java.util.Map;
28-
import java.util.Objects;
29-
import java.util.StringJoiner;
3024
import java.util.concurrent.atomic.AtomicBoolean;
3125
import java.util.function.Consumer;
3226

3327
import javax.inject.Named;
3428
import javax.inject.Singleton;
3529

30+
import org.apache.maven.AbstractMavenLifecycleParticipant;
31+
import org.apache.maven.MavenExecutionException;
3632
import org.apache.maven.eventspy.EventSpy;
37-
import org.apache.maven.execution.ExecutionEvent;
38-
import org.apache.maven.execution.ExecutionEvent.Type;
39-
import org.apache.maven.project.MavenProject;
33+
import org.apache.maven.execution.MavenSession;
4034
import org.slf4j.Logger;
4135
import org.slf4j.LoggerFactory;
4236

@@ -48,9 +42,9 @@
4842
* @author Hannes Wellmann
4943
*
5044
*/
51-
@Named
5245
@Singleton
53-
public class M2EMavenBuildDataBridge implements EventSpy {
46+
@Named("m2e")
47+
public class M2EMavenBuildDataBridge extends AbstractMavenLifecycleParticipant {
5448

5549
private static final String SOCKET_FILE_PROPERTY_NAME = "m2e.build.project.data.socket.port";
5650
private static final String DATA_SET_SEPARATOR = ";;";
@@ -60,7 +54,7 @@ public class M2EMavenBuildDataBridge implements EventSpy {
6054
private SocketChannel writeChannel;
6155

6256
@Override
63-
public void init(Context context) throws IOException {
57+
public synchronized void afterSessionStart(MavenSession session) throws MavenExecutionException {
6458
String socketPort = System.getProperty(SOCKET_FILE_PROPERTY_NAME);
6559
if (socketPort != null) {
6660
try {
@@ -76,79 +70,38 @@ public void init(Context context) throws IOException {
7670
}
7771

7872
@Override
79-
public void close() throws IOException {
80-
writeChannel.close();
73+
public void afterSessionEnd(MavenSession session) throws MavenExecutionException {
74+
close();
8175
}
8276

83-
@Override
84-
public void onEvent(Object event) throws Exception {
85-
if (writeChannel != null && event instanceof ExecutionEvent
86-
&& ((ExecutionEvent) event).getType() == Type.ProjectStarted) {
87-
88-
String message = serializeProjectData(((ExecutionEvent) event).getProject());
89-
90-
ByteBuffer buffer = ByteBuffer.wrap(message.getBytes());
91-
synchronized (writeChannel) {
92-
while (buffer.hasRemaining()) {
93-
writeChannel.write(buffer);
94-
}
77+
private synchronized void close() {
78+
if (writeChannel != null) {
79+
try {
80+
writeChannel.close();
81+
} catch (IOException e) {
82+
// nothing we want to do here...
9583
}
9684
}
85+
writeChannel = null;
9786
}
9887

99-
private static String serializeProjectData(MavenProject project) {
100-
StringJoiner data = new StringJoiner(",");
101-
add(data, "groupId", project.getGroupId());
102-
add(data, "artifactId", project.getArtifactId());
103-
add(data, "version", project.getVersion());
104-
add(data, "file", project.getFile());
105-
add(data, "basedir", project.getBasedir());
106-
add(data, "build.directory", project.getBuild().getDirectory());
107-
return data.toString() + DATA_SET_SEPARATOR;
108-
}
109-
110-
private static void add(StringJoiner data, String key, Object value) {
111-
data.add(key + "=" + value);
88+
public synchronized boolean isActive() {
89+
return writeChannel != null;
11290
}
11391

114-
/**
115-
* <p>
116-
* This method is supposed to be called from M2E within the Eclipse-IDE JVM.
117-
* </p>
118-
*
119-
* @param dataSet the data-set to parse
120-
* @return the {@link MavenProjectBuildData} parsed from the given string
121-
*/
122-
private static MavenProjectBuildData parseMavenBuildProject(String dataSet) {
123-
Map<String, String> data = new HashMap<>(8);
124-
for (String entry : dataSet.split(",")) {
125-
String[] keyValue = entry.split("=");
126-
if (keyValue.length != 2) {
127-
throw new IllegalStateException("Invalid data-set format" + dataSet);
128-
}
129-
data.put(keyValue[0], keyValue[1]);
92+
public synchronized void sendMessage(String message) {
93+
System.out.println("send: " + message);
94+
if (writeChannel == null) {
95+
return;
13096
}
131-
return new MavenProjectBuildData(data);
132-
}
133-
134-
public static final class MavenProjectBuildData {
135-
public final String groupId;
136-
public final String artifactId;
137-
public final String version;
138-
public final Path projectBasedir;
139-
public final Path projectFile;
140-
public final Path projectBuildDirectory;
141-
142-
MavenProjectBuildData(Map<String, String> data) {
143-
if (data.size() != 6) {
144-
throw new IllegalArgumentException();
97+
ByteBuffer buffer = ByteBuffer.wrap((message + DATA_SET_SEPARATOR).getBytes());
98+
while (buffer.hasRemaining()) {
99+
try {
100+
writeChannel.write(buffer);
101+
} catch (IOException e) {
102+
// channel seems dead...
103+
close();
145104
}
146-
this.groupId = Objects.requireNonNull(data.get("groupId"));
147-
this.artifactId = Objects.requireNonNull(data.get("artifactId"));
148-
this.version = Objects.requireNonNull(data.get("version"));
149-
this.projectBasedir = Paths.get(data.get("basedir"));
150-
this.projectFile = Paths.get(data.get("file"));
151-
this.projectBuildDirectory = Paths.get(data.get("build.directory"));
152105
}
153106
}
154107

@@ -187,8 +140,8 @@ public static MavenBuildConnection prepareConnection(String label, Consumer<Mave
187140
for (int terminatorIndex; (terminatorIndex = message.indexOf(DATA_SET_SEPARATOR)) >= 0;) {
188141
String dataSet = message.substring(0, terminatorIndex);
189142
message.delete(0, terminatorIndex + DATA_SET_SEPARATOR.length());
190-
191-
MavenProjectBuildData buildData = parseMavenBuildProject(dataSet);
143+
System.out.println("got messagE: " + dataSet);
144+
MavenProjectBuildData buildData = MavenProjectBuildData.parseMavenBuildProject(dataSet);
192145
datasetListener.accept(buildData);
193146
}
194147
// Explicit cast for compatibility with covariant return type on JDK 9's
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/********************************************************************************
2+
* Copyright (c) 2022, 2024 Hannes Wellmann 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+
* Hannes Wellmann - initial API and implementation
12+
* Christoph Läubrich - factor out into dedicated component
13+
********************************************************************************/
14+
package org.eclipse.m2e.internal.maven.listener;
15+
16+
import javax.inject.Inject;
17+
import javax.inject.Named;
18+
import javax.inject.Singleton;
19+
20+
import org.apache.maven.eventspy.EventSpy;
21+
import org.apache.maven.execution.ExecutionEvent;
22+
import org.apache.maven.execution.ExecutionEvent.Type;
23+
24+
@Singleton
25+
@Named("m2e")
26+
public class M2eEventSpy implements EventSpy {
27+
28+
private M2EMavenBuildDataBridge bridge;
29+
30+
@Inject
31+
public M2eEventSpy(M2EMavenBuildDataBridge bridge) {
32+
this.bridge = bridge;
33+
}
34+
35+
@Override
36+
public void init(Context context) throws Exception {
37+
38+
}
39+
40+
@Override
41+
public void onEvent(Object event) throws Exception {
42+
System.out.println("M2eEventSpy.onEvent() " + event);
43+
if (bridge.isActive()) {
44+
if (event instanceof ExecutionEvent) {
45+
ExecutionEvent executionEvent = (ExecutionEvent) event;
46+
if (executionEvent.getType() == Type.ProjectStarted) {
47+
String message = MavenProjectBuildData.serializeProjectData(((ExecutionEvent) event).getProject());
48+
bridge.sendMessage(message);
49+
}
50+
}
51+
}
52+
}
53+
54+
@Override
55+
public void close() throws Exception {
56+
57+
}
58+
59+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/********************************************************************************
2+
* Copyright (c) 2022, 2024 Hannes Wellmann 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+
* Hannes Wellmann - initial API and implementation
12+
* Christoph Läubrich - factor out into dedicated component
13+
********************************************************************************/
14+
package org.eclipse.m2e.internal.maven.listener;
15+
16+
import java.nio.file.Path;
17+
import java.nio.file.Paths;
18+
import java.util.HashMap;
19+
import java.util.Map;
20+
import java.util.Objects;
21+
import java.util.StringJoiner;
22+
23+
import org.apache.maven.project.MavenProject;
24+
25+
public final class MavenProjectBuildData {
26+
public final String groupId;
27+
public final String artifactId;
28+
public final String version;
29+
public final Path projectBasedir;
30+
public final Path projectFile;
31+
public final Path projectBuildDirectory;
32+
33+
MavenProjectBuildData(Map<String, String> data) {
34+
if (data.size() != 6) {
35+
throw new IllegalArgumentException();
36+
}
37+
this.groupId = Objects.requireNonNull(data.get("groupId"));
38+
this.artifactId = Objects.requireNonNull(data.get("artifactId"));
39+
this.version = Objects.requireNonNull(data.get("version"));
40+
this.projectBasedir = Paths.get(data.get("basedir"));
41+
this.projectFile = Paths.get(data.get("file"));
42+
this.projectBuildDirectory = Paths.get(data.get("build.directory"));
43+
}
44+
45+
/**
46+
* <p>
47+
* This method is supposed to be called from M2E within the Eclipse-IDE JVM.
48+
* </p>
49+
*
50+
* @param dataSet the data-set to parse
51+
* @return the {@link MavenProjectBuildData} parsed from the given string
52+
*/
53+
static MavenProjectBuildData parseMavenBuildProject(String dataSet) {
54+
Map<String, String> data = new HashMap<>(8);
55+
for (String entry : dataSet.split(",")) {
56+
String[] keyValue = entry.split("=");
57+
if (keyValue.length != 2) {
58+
throw new IllegalStateException("Invalid data-set format" + dataSet);
59+
}
60+
data.put(keyValue[0], keyValue[1]);
61+
}
62+
return new MavenProjectBuildData(data);
63+
}
64+
65+
static String serializeProjectData(MavenProject project) {
66+
StringJoiner data = new StringJoiner(",");
67+
add(data, "groupId", project.getGroupId());
68+
add(data, "artifactId", project.getArtifactId());
69+
add(data, "version", project.getVersion());
70+
add(data, "file", project.getFile());
71+
add(data, "basedir", project.getBasedir());
72+
add(data, "build.directory", project.getBuild().getDirectory());
73+
return data.toString();
74+
}
75+
76+
private static void add(StringJoiner data, String key, Object value) {
77+
data.add(key + "=" + value);
78+
}
79+
}

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@
103103
<dependency>
104104
<groupId>org.eclipse.m2e</groupId>
105105
<artifactId>org.eclipse.m2e.maven.runtime</artifactId>
106-
<version>3.9.600-SNAPSHOT</version>
106+
<version>3.9.601-SNAPSHOT</version>
107107
</dependency>
108108
</dependencies>
109109

0 commit comments

Comments
 (0)