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(); + } } } }