package com.atsebak.embeddedlinuxjvm.commandline;
import com.atsebak.embeddedlinuxjvm.console.EmbeddedLinuxJVMConsoleView;
import com.atsebak.embeddedlinuxjvm.localization.EmbeddedLinuxJVMBundle;
import com.atsebak.embeddedlinuxjvm.runner.conf.EmbeddedLinuxJVMConfigurationType;
import com.intellij.execution.ExecutionManager;
import com.intellij.execution.RunManager;
import com.intellij.execution.RunnerAndConfigurationSettings;
import com.intellij.execution.impl.RunManagerImpl;
import com.intellij.execution.ui.ConsoleViewContentType;
import com.intellij.execution.ui.RunContentDescriptor;
import com.intellij.openapi.project.Project;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import lombok.SneakyThrows;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.Collection;
import java.util.List;
public class JavaStatusChecker extends Thread {
private final ChannelExec channelExec;
private final Project project;
private final EmbeddedLinuxJVMConsoleView consoleView;
public JavaStatusChecker(@NotNull EmbeddedLinuxJVMConsoleView consoleView) {
this.consoleView = consoleView;
project = null;
channelExec = null;
}
public JavaStatusChecker(@Nullable ChannelExec channelExec, @NotNull EmbeddedLinuxJVMConsoleView consoleView) {
this.channelExec = channelExec;
this.project = consoleView.getProject();
this.consoleView = consoleView;
}
/**
* Runs until java app finishes from target device
*/
@Override
@SneakyThrows
public void run() {
if (channelExec == null) {
return;
}
while (!channelExec.isClosed()) {
Thread.sleep(1000);
}
stopApplication(channelExec.getExitStatus());
channelExec.disconnect();
channelExec.getSession().disconnect();
}
/**
* Stops java application that needs to, this should be called when the user wants to manually stop the application
* so that it kills the remote java process
*
* @param session
* @param isRunningAsRoot
* @param mainClass
* @throws JSchException
* @throws IOException
*/
public void forceStopJavaApplication(@Nullable Session session, @NotNull boolean isRunningAsRoot, @NotNull String mainClass) throws JSchException, IOException {
if (session == null) {
return;
}
String javaKillCmd = String.format("%s kill -9 $(ps -efww | grep \"%s\"| grep -v grep | tr -s \" \"| cut -d\" \" -f2)",
isRunningAsRoot ? "sudo" : "", mainClass);
Channel channel = session.openChannel("shell");
OutputStream inputstream_for_the_channel = channel.getOutputStream();
PrintStream commander = new PrintStream(inputstream_for_the_channel, true);
channel.connect();
commander.println(javaKillCmd);
commander.close();
channel.disconnect();
session.disconnect();
}
/**
* Stops the applications via the descriptor of configuration. This gets called when the application finishes on the client side without maniually closing it.
*
* @param javaExitCode
*/
public void stopApplication(@NotNull int javaExitCode) {
final RunManagerImpl runManager = (RunManagerImpl) RunManager.getInstance(project);
final Collection<RunnerAndConfigurationSettings> allConfigurations = runManager.getSortedConfigurations();
List<RunContentDescriptor> allDescriptors = ExecutionManager.getInstance(project).getContentManager().getAllDescriptors();
boolean exitMsgDisplay = false;
for (RunnerAndConfigurationSettings runConfiguration : allConfigurations) {
if (runConfiguration.getConfiguration().getFactory().getType() instanceof EmbeddedLinuxJVMConfigurationType) {
for (RunContentDescriptor descriptor : allDescriptors) {
if (runConfiguration.getName().equals(descriptor.getDisplayName())) {
try {
if (!exitMsgDisplay) {
consoleView.print(EmbeddedLinuxJVMBundle.message("exit.code.message", javaExitCode), ConsoleViewContentType.SYSTEM_OUTPUT);
exitMsgDisplay = true;
}
descriptor.setProcessHandler(null);
} catch (Exception e) {
}
}
}
}
}
}
}