This is an automated email from the ASF dual-hosted git repository.

gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-mvnd.git


The following commit(s) were added to refs/heads/master by this push:
     new 7726c16b fix: Daemon invoker lifespan must be shared with daemon 
process lifespan (#1196)
7726c16b is described below

commit 7726c16bc8f3883d9ee8cd852b463ed9467a9376
Author: Tamas Cservenak <ta...@cservenak.net>
AuthorDate: Fri Nov 8 16:48:53 2024 +0100

    fix: Daemon invoker lifespan must be shared with daemon process lifespan 
(#1196)
    
    * fix: Daemon lifecycle must be shared with daemon invoker
    
    As long daemon is alive, the daemon invoker must be kept
    alive as it holds the "resident" object graph of Maven.
    
    * Add hack
    
    This is a bug in resident invoker
---
 .../main/java/org/apache/maven/cli/DaemonCli.java  |  2 +-
 .../org/apache/maven/cli/DaemonMavenCling.java     | 52 ++++++++++++++--------
 .../org/apache/maven/cli/DaemonMavenInvoker.java   | 18 ++++++--
 .../java/org/mvndaemon/mvnd/daemon/Server.java     |  6 ++-
 4 files changed, 54 insertions(+), 24 deletions(-)

diff --git a/daemon/src/main/java/org/apache/maven/cli/DaemonCli.java 
b/daemon/src/main/java/org/apache/maven/cli/DaemonCli.java
index 0486ff34..07637b8d 100644
--- a/daemon/src/main/java/org/apache/maven/cli/DaemonCli.java
+++ b/daemon/src/main/java/org/apache/maven/cli/DaemonCli.java
@@ -28,7 +28,7 @@ import org.apache.maven.logging.BuildEventListener;
 /**
  * Simple interface to bridge maven 3.9.x and 4.0.x CLI
  */
-public interface DaemonCli {
+public interface DaemonCli extends AutoCloseable {
     int main(
             List<String> args,
             String workingDir,
diff --git a/daemon/src/main/java/org/apache/maven/cli/DaemonMavenCling.java 
b/daemon/src/main/java/org/apache/maven/cli/DaemonMavenCling.java
index aded3ca4..d2debc27 100644
--- a/daemon/src/main/java/org/apache/maven/cli/DaemonMavenCling.java
+++ b/daemon/src/main/java/org/apache/maven/cli/DaemonMavenCling.java
@@ -33,7 +33,30 @@ import org.codehaus.plexus.classworlds.ClassWorld;
 import org.codehaus.plexus.classworlds.realm.ClassRealm;
 import org.mvndaemon.mvnd.cli.EnvHelper;
 
+/**
+ * The main Daemon entry point: it shares lifecycle with daemon invoker 
(subclass of resident invoker) that keeps Maven
+ * resident, as long as this class is used. Once not needed, proper shut down 
using {@link #close()} method
+ * is required.
+ * <p>
+ * While daemon invoker is stateful (keeps Maven object graph), daemon parser 
is stateless and reusable, no need to
+ * create instance per incoming call.
+ */
 public class DaemonMavenCling implements DaemonCli {
+    private final DaemonMavenParser parser;
+    private final DaemonMavenInvoker invoker;
+
+    public DaemonMavenCling() {
+        this.parser = new DaemonMavenParser();
+        this.invoker = new DaemonMavenInvoker(ProtoLookup.builder()
+                .addMapping(
+                        ClassWorld.class, ((ClassRealm) 
Thread.currentThread().getContextClassLoader()).getWorld())
+                .build());
+    }
+
+    @Override
+    public void close() {
+        invoker.close();
+    }
 
     @Override
     public int main(
@@ -49,24 +72,17 @@ public class DaemonMavenCling implements DaemonCli {
         EnvHelper.environment(workingDir, env);
         System.setProperty("maven.multiModuleProjectDirectory", projectDir);
 
-        try (DaemonMavenInvoker invoker = new 
DaemonMavenInvoker(ProtoLookup.builder()
-                .addMapping(
-                        ClassWorld.class, ((ClassRealm) 
Thread.currentThread().getContextClassLoader()).getWorld())
-                .addMapping(BuildEventListener.class, buildEventListener)
-                .build())) {
-            DaemonMavenParser parser = new DaemonMavenParser();
-            return invoker.invoke(parser.parse(ParserRequest.builder(
-                            "mvnd", "Maven Daemon", args, new ProtoLogger(), 
new DaemonMessageBuilderFactory())
-                    .cwd(Paths.get(workingDir))
-                    .in(in)
-                    .out(out)
-                    .err(err)
-                    .lookup(ProtoLookup.builder()
-                            .addMapping(Environment.class, () -> env)
-                            .addMapping(BuildEventListener.class, 
buildEventListener)
-                            .build())
-                    .build()));
-        }
+        return invoker.invoke(parser.parse(ParserRequest.builder(
+                        "mvnd", "Maven Daemon", args, new ProtoLogger(), new 
DaemonMessageBuilderFactory())
+                .cwd(Paths.get(workingDir))
+                .in(in)
+                .out(out)
+                .err(err)
+                .lookup(ProtoLookup.builder()
+                        .addMapping(Environment.class, () -> env)
+                        .addMapping(BuildEventListener.class, 
buildEventListener)
+                        .build())
+                .build()));
     }
 
     /**
diff --git a/daemon/src/main/java/org/apache/maven/cli/DaemonMavenInvoker.java 
b/daemon/src/main/java/org/apache/maven/cli/DaemonMavenInvoker.java
index a13f463d..d2a19c18 100644
--- a/daemon/src/main/java/org/apache/maven/cli/DaemonMavenInvoker.java
+++ b/daemon/src/main/java/org/apache/maven/cli/DaemonMavenInvoker.java
@@ -44,9 +44,19 @@ public class DaemonMavenInvoker extends 
DefaultResidentMavenInvoker {
         super(protoLookup);
     }
 
-    @Override
-    protected void configureLogging(LocalContext context) throws Exception {
-        super.configureLogging(context);
+    // TODO: this is a hack, and fixes issue in DefaultResidentMavenInvoker 
that does not copy TCCL
+    private ClassLoader tccl;
+
+    protected int doInvoke(LocalContext context) throws Exception {
+        try {
+            if (tccl != null) {
+                context.currentThreadContextClassLoader = tccl;
+                
Thread.currentThread().setContextClassLoader(context.currentThreadContextClassLoader);
+            }
+            return super.doInvoke(context);
+        } finally {
+            this.tccl = context.currentThreadContextClassLoader;
+        }
     }
 
     @Override
@@ -85,7 +95,7 @@ public class DaemonMavenInvoker extends 
DefaultResidentMavenInvoker {
 
     @Override
     protected org.apache.maven.logging.BuildEventListener 
doDetermineBuildEventListener(LocalContext context) {
-        return protoLookup.lookup(BuildEventListener.class);
+        return 
context.invokerRequest.lookup().lookup(BuildEventListener.class);
     }
 
     @Override
diff --git a/daemon/src/main/java/org/mvndaemon/mvnd/daemon/Server.java 
b/daemon/src/main/java/org/mvndaemon/mvnd/daemon/Server.java
index 290ca27a..b8e00634 100644
--- a/daemon/src/main/java/org/mvndaemon/mvnd/daemon/Server.java
+++ b/daemon/src/main/java/org/mvndaemon/mvnd/daemon/Server.java
@@ -187,7 +187,11 @@ public class Server implements AutoCloseable, Runnable {
                     try {
                         registry.close();
                     } finally {
-                        socket.close();
+                        try {
+                            socket.close();
+                        } finally {
+                            cli.close();
+                        }
                     }
                 }
             }

Reply via email to