Skip to content

Use EventSpy to handle execution of events #89

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 13 additions & 6 deletions src/main/java/org/codehaus/plexus/build/DefaultBuildContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.maven.plugin.LegacySupport;
import org.codehaus.plexus.build.connect.BuildConnection;
import org.codehaus.plexus.build.connect.messages.RefreshMessage;
import org.codehaus.plexus.logging.AbstractLogEnabled;
Expand Down Expand Up @@ -59,17 +60,23 @@ public class DefaultBuildContext implements BuildContext {
private final Map<String, Object> contextMap = new ConcurrentHashMap<>();
private org.sonatype.plexus.build.incremental.BuildContext legacy;
private BuildConnection connection;
private LegacySupport legacySupport;

/**
* @param legacy the legacy API we delegate to by default, this allow us to
* support "older" plugins and implementors of the API while
* still having a way to move forward!
* @param connection the connection we use to forward refresh events
* @param legacy the legacy API we delegate to by default, this allow us
* to support "older" plugins and implementors of the API
* while still having a way to move forward!
* @param connection the connection we use to forward refresh events
* @param legacySupport legacy support to get the current session
*/
@Inject
public DefaultBuildContext(org.sonatype.plexus.build.incremental.BuildContext legacy, BuildConnection connection) {
public DefaultBuildContext(
org.sonatype.plexus.build.incremental.BuildContext legacy,
BuildConnection connection,
LegacySupport legacySupport) {
this.legacy = legacy;
this.connection = connection;
this.legacySupport = legacySupport;
}

/** {@inheritDoc} */
Expand Down Expand Up @@ -122,7 +129,7 @@ public Scanner newScanner(File basedir) {
/** {@inheritDoc} */
public void refresh(File file) {
legacy.refresh(file);
connection.send(new RefreshMessage(file.toPath()));
connection.send(new RefreshMessage(file.toPath()), legacySupport.getSession());
}

/** {@inheritDoc} */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*/
package org.codehaus.plexus.build.connect;

import org.apache.maven.execution.MavenSession;
import org.codehaus.plexus.build.connect.messages.Message;

/**
Expand All @@ -25,11 +26,12 @@ public interface BuildConnection {
* Send a message and returns the reply from the other endpoint, should only be
* called from a maven thread!
*
* @param message the message to send
* @param message the message to send
* @param mavenSession the maven session to reference
* @return the reply message or <code>null</code> if this connection is not
* enabled and the message was discarded.
*/
Message send(Message message);
Message send(Message message, MavenSession mavenSession);

/**
* This method allows code to perform an eager check if a buildconnection is
Expand All @@ -40,11 +42,4 @@ public interface BuildConnection {
* if they will be discarded
*/
boolean isEnabled();

/**
* Obtains the current configuration, can only be called from a maven thread
*
* @return the active configuration
*/
Configuration getConfiguration();
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,19 @@
package org.codehaus.plexus.build.connect;

import org.codehaus.plexus.build.connect.messages.Message;
import org.codehaus.plexus.build.connect.messages.ProjectsReadMessage;

/**
* Provides access to the configuration provided by the server
*/
public interface Configuration {

/**
* If this property is set to <code>true</code> in reply to a session start, a
* {@link ProjectsReadMessage} will be send to the endpoint containing all
* projects with their effective model
* If this property is set to <code>true</code> in reply to a InitMessage
*/
public static final String CONFIG_SEND_AFTER_PROJECTS_READ = "afterProjectsRead";
public static final String CONFIG_SEND_PROJECTS = "sendProjectInfos";

/**
* @return <code>true</code> if {@link #CONFIG_SEND_AFTER_PROJECTS_READ} is
* @return <code>true</code> if {@link #CONFIG_SEND_PROJECTS} is
* provided
*/
public boolean isSendProjects();
Expand All @@ -44,7 +41,7 @@ public static Configuration of(Message message) {

@Override
public boolean isSendProjects() {
return message.getBooleanProperty(CONFIG_SEND_AFTER_PROJECTS_READ, false);
return message.getBooleanProperty(CONFIG_SEND_PROJECTS, false);
}
};
}
Expand Down
100 changes: 100 additions & 0 deletions src/main/java/org/codehaus/plexus/build/connect/EventListener.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
Copyright (c) 2025 Christoph Läubrich All rights reserved.

This program is licensed to you under the Apache License Version 2.0,
and you may not use this file except in compliance with the Apache License Version 2.0.
You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.

Unless required by applicable law or agreed to in writing,
software distributed under the Apache License Version 2.0 is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
*/
package org.codehaus.plexus.build.connect;

import java.util.LinkedHashMap;
import java.util.Map;

import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;

import org.apache.maven.eventspy.EventSpy;
import org.apache.maven.execution.ExecutionEvent;
import org.apache.maven.execution.ExecutionEvent.Type;
import org.apache.maven.execution.MavenSession;
import org.codehaus.plexus.build.connect.messages.InitMessage;
import org.codehaus.plexus.build.connect.messages.Message;
import org.codehaus.plexus.build.connect.messages.ProjectMessage;
import org.codehaus.plexus.build.connect.messages.ProjectsMessage;
import org.codehaus.plexus.build.connect.messages.SessionMessage;

/**
* Listen to all maven events and forward them to the endpoint
*/
@Named
@Singleton
public class EventListener implements EventSpy {

private BuildConnection connection;
private Configuration configuration;

/**
* Creates endpoint for the given connection
*
* @param connection injected
*/
@Inject
public EventListener(BuildConnection connection) {
this.connection = connection;
}

@Override
public void init(Context context) throws Exception {
Map<String, String> data = new LinkedHashMap<>();
context.getData().forEach((k, v) -> {
data.put(k, String.valueOf(v));
});
Message message = connection.send(new InitMessage(data), null);
if (message != null) {
configuration = Configuration.of(message);
}
}

@Override
public void onEvent(Object event) throws Exception {
if (configuration == null) {
return;
}
if (event instanceof ExecutionEvent) {
handleExecutionEvent((ExecutionEvent) event);
}
}

private void handleExecutionEvent(ExecutionEvent executionEvent) {
MavenSession session = executionEvent.getSession();
Type type = executionEvent.getType();
switch (type) {
case SessionStarted:
connection.send(new SessionMessage(session, true), session);
if (configuration.isSendProjects()) {
connection.send(new ProjectsMessage(session.getProjects()), session);
}
break;
case SessionEnded:
connection.send(new SessionMessage(session, false), session);
break;
case ProjectStarted:
case ProjectFailed:
case ProjectSkipped:
case ProjectSucceeded:
connection.send(new ProjectMessage(executionEvent.getProject(), type), session);
break;
default:
break;
}
}

@Override
public void close() throws Exception {}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
*/
package org.codehaus.plexus.build.connect;

import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;

Expand All @@ -25,16 +24,16 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.UUID;
import java.util.WeakHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.BiConsumer;
import java.util.function.Function;

import org.apache.maven.plugin.LegacySupport;
import org.apache.maven.execution.MavenSession;
import org.codehaus.plexus.build.connect.messages.Message;
import org.codehaus.plexus.build.connect.messages.SessionMessage;

/**
* Default implementation using the system property
Expand All @@ -48,10 +47,7 @@ public class TcpBuildConnection implements BuildConnection {

private static final int PORT = Integer.getInteger(PLEXUS_BUILD_IPC_PORT, 0);

@Inject
private LegacySupport support;

private Map<String, Configuration> configMap = new ConcurrentHashMap<>();
private final Map<MavenSession, String> sessionMap = new WeakHashMap<>();

private final ThreadLocal<TcpClientConnection> connections =
ThreadLocal.withInitial(() -> new TcpClientConnection());
Expand All @@ -62,47 +58,23 @@ public boolean isEnabled() {
}

@Override
public Message send(Message message) {
public Message send(Message message, MavenSession mavenSession) {
if (isEnabled()) {
String sessionId;
boolean sessionStart;
if (message instanceof SessionMessage) {
sessionId = message.getSessionId();
sessionStart = ((SessionMessage) message).isSessionStart();
} else {
sessionId = getThreadSessionId();
sessionStart = false;
}
String sessionId = getId(mavenSession);
byte[] messageBytes = message.serialize(sessionId);
byte[] replyBytes = connections.get().send(messageBytes);
if (replyBytes.length > 0) {
Message reply = Message.decode(replyBytes);
if (reply != null && sessionStart) {
configMap.put(sessionId, Configuration.of(reply));
}
return reply;
return Message.decode(replyBytes);
}
}
return null;
}

private String getThreadSessionId() {
// We must use LegacySupport here to get the currents threads session (what
// might be cloned)
return SessionMessage.getId(support.getSession());
}

@Override
public Configuration getConfiguration() {
String id = getThreadSessionId();
if (id == null) {
throw new IllegalStateException("No session attached to current thread!");
}
Configuration configuration = configMap.get(id);
if (configuration == null) {
throw new IllegalStateException("No configuration active for session " + id + "!");
private synchronized String getId(MavenSession session) {
if (session == null) {
return Thread.currentThread().getName();
}
return configuration;
return sessionMap.computeIfAbsent(session, x -> UUID.randomUUID().toString());
}

/**
Expand Down
Loading