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 0486ff34d..07637b8d0 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 @@ /** * Simple interface to bridge maven 3.9.x and 4.0.x CLI */ -public interface DaemonCli { +public interface DaemonCli extends AutoCloseable { int main( List 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 aded3ca44..d2debc275 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.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. + *

+ * 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 int main( 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 a13f463d2..d2a19c188 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 DaemonMavenInvoker(ProtoLookup protoLookup) { 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 @@ private PrintStream printStream(OutputStream outputStream) { @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 290ca27af..b8e00634e 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 void close() { try { registry.close(); } finally { - socket.close(); + try { + socket.close(); + } finally { + cli.close(); + } } } }