AttachedJvm.java
package io.github.baokhang83.mnemo.warden.agent.attach;
import java.io.Closeable;
import java.io.IOException;
import javax.management.MBeanServerConnection;
import javax.management.remote.JMXConnector;
/**
* A live connection to the target JVM: its PID and the JMX connection opened over its
* loopback-bound JMX port (see {@link TargetAttacher} for why not the Attach API).
*
* <p>{@link #mbeanConnection()} is what lets W-101's {@code GcDetector} and later heap drivers
* read/act on the target's MXBeans exactly as they would locally —
* {@code ManagementFactory.getPlatformMXBeans(connection, Type.class)} takes any {@link
* MBeanServerConnection}, local or remote.
*/
public final class AttachedJvm implements Closeable {
private final long pid;
private final JMXConnector connector;
private final MBeanServerConnection mbeanServerConnection;
AttachedJvm(long pid, JMXConnector connector, MBeanServerConnection mbeanServerConnection) {
this.pid = pid;
this.connector = connector;
this.mbeanServerConnection = mbeanServerConnection;
}
/** The target's PID. */
public long pid() {
return pid;
}
/** The JMX connection to the target, for reading/acting on its MXBeans. */
public MBeanServerConnection mbeanConnection() {
return mbeanServerConnection;
}
/** Whether the target process is still running. */
public boolean isAlive() {
return ProcessHandle.of(pid).map(ProcessHandle::isAlive).orElse(false);
}
/**
* Closes the JMX connector. Safe to call once the target has already exited — that is
* precisely the case this exists for (cleanup after a dead target, before {@code
* AttachSupervisor} retries), so a severed connection is not a failure here, just expected.
*/
@Override
public void close() {
try {
connector.close();
} catch (IOException e) {
// The target's RMI connection is already gone; nothing left to close.
}
}
}