mirror of
https://github.com/apache/maven-mvnd.git
synced 2025-09-09 15:09:23 +00:00
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
This commit is contained in:
@@ -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,
|
||||
|
@@ -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()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -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
|
||||
|
@@ -187,7 +187,11 @@ public class Server implements AutoCloseable, Runnable {
|
||||
try {
|
||||
registry.close();
|
||||
} finally {
|
||||
socket.close();
|
||||
try {
|
||||
socket.close();
|
||||
} finally {
|
||||
cli.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user