blob: 37d0512813ef72ec4d6c3b40272d5cad35365bd6 [file] [log] [blame]
package org.jetbrains.debugger;
import com.intellij.openapi.util.ActionCallback;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.io.NettyUtil;
import org.jetbrains.jsonProtocol.Request;
import org.jetbrains.rpc.MessageHandler;
import org.jetbrains.rpc.MessageWriter;
public class StandaloneVmHelper extends MessageWriter {
private volatile Channel channel;
private final VmEx vm;
public StandaloneVmHelper(@NotNull VmEx vm) {
this.vm = vm;
}
@Override
public boolean write(@NotNull CharSequence content) {
return write(((Object)content));
}
public boolean write(@NotNull Object content) {
Channel currentChannel = channel;
if (currentChannel == null || !currentChannel.isActive()) {
return false;
}
currentChannel.writeAndFlush(content);
return true;
}
public interface VmEx extends Vm {
MessageHandler<?, ?, ?, ?> getCommandProcessor();
@Nullable
Request createDisconnectRequest();
}
public void setChannel(@NotNull Channel channel) {
this.channel = channel;
channel.closeFuture().addListener(new MyChannelFutureListener());
}
private class MyChannelFutureListener implements ChannelFutureListener {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
// don't report in case of explicit detach()
if (channel != null) {
vm.getCommandProcessor().closed();
vm.getDebugListener().disconnected();
}
}
}
public boolean isAttached() {
return channel != null;
}
@NotNull
public ActionCallback detach() {
final Channel currentChannel = channel;
if (currentChannel == null) {
return ActionCallback.DONE;
}
vm.getCommandProcessor().cancelWaitingRequests();
Request disconnectRequest = vm.createDisconnectRequest();
if (disconnectRequest == null) {
vm.getCommandProcessor().closed();
channel = null;
return closeChannel(currentChannel);
}
ActionCallback callback = vm.getCommandProcessor().send(disconnectRequest);
vm.getCommandProcessor().closed();
channel = null;
final ActionCallback subCallback = new ActionCallback();
callback.doWhenProcessed(new Runnable() {
@Override
public void run() {
try {
vm.getCommandProcessor().cancelWaitingRequests();
NettyUtil.closeAndReleaseFactory(currentChannel);
}
finally {
subCallback.setDone();
}
}
});
return subCallback;
}
@NotNull
protected ActionCallback closeChannel(@NotNull Channel channel) {
NettyUtil.closeAndReleaseFactory(channel);
return ActionCallback.DONE;
}
}