Skip to content

Add a connect API for inter-process-communication between maven and IDE #88

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
14 changes: 10 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Plexus Build API
=======================
================

[![Apache License, Version 2.0, January 2004](https://img.shields.io/github/license/codehaus-plexus/plexus-classworlds.svg?label=License)](http://www.apache.org/licenses/)
[![Maven Central](https://img.shields.io/maven-central/v/org.codehaus.plexus/plexus-build-api.svg?label=Maven%20Central)](https://search.maven.org/artifact/org.codehaus.plexus/plexus-build-api)
Expand All @@ -13,9 +13,8 @@ It supports
- fine-grained error/info markers (referring to specific files in particular line numbers)
- notifications about updated files


Current Implementations
-----
-----------------------

### Default Implementation

Expand All @@ -27,6 +26,13 @@ The default implementation shipping with this artifact is supposed to impose min
Currently only versions up to 0.0.7 (with old Maven coordinates `org.sonatype.plexus:plexus-build-api`) are supported, this limitation is tracked in [Issue 944](https://github.com/eclipse-m2e/m2e-core/issues/944).

History
-----
-------

The project was relocated from <https://github.com/sonatype/sisu-build-api>. Also its Maven coordinates changed from `org.sonatype.plexus:plexus-build-api` to `org.codehaus.plexus:plexus-build-api`, the API is still the same, though.

## Provided APIs

### IDE connection to maven process

This API is usually not used by mojos but for IDE integration, if enabled as a maven-core extension plexus-build-api supply a way to communicate with the running maven build and get events.
The default implementation open a tcp connections to a port specified by the system property `plexus.build.ipc.port` using key/value encoded message format. If no such value is given all messages are silently discarded.
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,12 @@ See the Apache License Version 2.0 for the specific language governing permissio
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-core</artifactId>
<version>3.9.9</version>
<scope>provided</scope>
</dependency>

</dependencies>

Expand Down
14 changes: 10 additions & 4 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,8 @@
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.codehaus.plexus.build.connect.BuildConnection;
import org.codehaus.plexus.build.connect.messages.RefreshMessage;
import org.codehaus.plexus.logging.AbstractLogEnabled;
import org.codehaus.plexus.util.Scanner;
import org.codehaus.plexus.util.io.CachingOutputStream;
Expand Down Expand Up @@ -56,15 +58,18 @@ public class DefaultBuildContext implements BuildContext {

private final Map<String, Object> contextMap = new ConcurrentHashMap<>();
private org.sonatype.plexus.build.incremental.BuildContext legacy;
private BuildConnection connection;

/**
* @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 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
*/
@Inject
public DefaultBuildContext(org.sonatype.plexus.build.incremental.BuildContext legacy) {
public DefaultBuildContext(org.sonatype.plexus.build.incremental.BuildContext legacy, BuildConnection connection) {
this.legacy = legacy;
this.connection = connection;
}

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

/** {@inheritDoc} */
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
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 org.codehaus.plexus.build.connect.messages.Message;

/**
* A {@link BuildConnection} allow communication between a an IDE and a maven
* build to observe the state of the build and act on certain events. This is
* usually not used directly by mojos but invoked internally by other APIs.
*/
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
* @return the reply message or <code>null</code> if this connection is not
* enabled and the message was discarded.
*/
Message send(Message message);

/**
* This method allows code to perform an eager check if a buildconnection is
* present to send messages. This can be used to guard operations to prevent
* allocate resources or objects if the message will be dropped.
*
* @return <code>true</code> if the connection can be used to send messages or
* 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();
}
51 changes: 51 additions & 0 deletions src/main/java/org/codehaus/plexus/build/connect/Configuration.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
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 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
*/
public static final String CONFIG_SEND_AFTER_PROJECTS_READ = "afterProjectsRead";

/**
* @return <code>true</code> if {@link #CONFIG_SEND_AFTER_PROJECTS_READ} is
* provided
*/
public boolean isSendProjects();

/**
* Creates a Configuration from a message
*
* @param message
* @return the configuration backed by the message payload
*/
public static Configuration of(Message message) {
return new Configuration() {

@Override
public boolean isSendProjects() {
return message.getBooleanProperty(CONFIG_SEND_AFTER_PROJECTS_READ, false);
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
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 javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;

import org.apache.maven.AbstractMavenLifecycleParticipant;
import org.apache.maven.MavenExecutionException;
import org.apache.maven.execution.MavenSession;
import org.codehaus.plexus.build.connect.messages.Message;
import org.codehaus.plexus.build.connect.messages.ProjectsReadMessage;
import org.codehaus.plexus.build.connect.messages.SessionMessage;

/**
* Listen to session events and send them to the connection
*/
@Named
@Singleton
public class SessionListener extends AbstractMavenLifecycleParticipant {

@Inject
private BuildConnection connection;

private boolean sendProjects;
private boolean started;

@Override
public void afterSessionStart(MavenSession session) throws MavenExecutionException {
started = true;
Message reply = connection.send(new SessionMessage(session, true));
if (reply != null) {
sendProjects = Configuration.of(reply).isSendProjects();
}
}

@Override
public void afterProjectsRead(MavenSession session) throws MavenExecutionException {
if (connection.isEnabled()) {
if (!started) {
afterSessionStart(session);
}
if (sendProjects) {
connection.send(new ProjectsReadMessage(session.getAllProjects()));
}
}
}

@Override
public void afterSessionEnd(MavenSession session) throws MavenExecutionException {
connection.send(new SessionMessage(session, false));
started = false;
}
}
Loading