I have built a program that sends command to another Jar(After running it). After playing around with Streams , I figured how to prevent the second Jar from crashing with every command sent. But now , another error popped up! The second jar prints Uknown Command if the command sent is not valid. After sending the command reload for example , I get feedback that the command was excecuted , but then my log wont stop printing Unknown Command !
I am sending the commands like this:
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(f.outputStream));
try {
writer.write("reload");
writer.flush();
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
This is inside a thread. Then I run the thread.
Related
working on a problem where ProcessBuilder is being used to start a batch file on a remote machine. However I wan't to have the ability to either wait for the processes completion or not. When waiting everything works perfectly, however when not waiting the process never actually finishes on the remote machine. I believe this is because I am returning immediately after starting the process and this is causing a hang (process which should take 1 second to 1 minutes is running for 15 minutes before finally closing). Is there a way I can get the process to finish and not have to wait for it to complete? Any help would be appreciated.
Path batchFile = pathService.getFilePath(login.getNode(), "run.bat");
// When file does not exists there is no point in executing it
if (!Files.exists(batchFile)) {
return;
}
try {
// Run batch file
Process process = new ProcessBuilder(ImmutableList.of(
"cmd",
"/c",
batchFile.toString()))
.directory(pathService.getRootPath(login.getNode()).toFile())
.redirectErrorStream(true)
.start();
if (!waitForCompletion) {
return;
}
String standardOutput = collectString(process.getInputStream());
String standardError = collectString(process.getErrorStream());
if (!process.waitFor(120, TimeUnit.SECONDS)) {
LOGGER.warn("Process '{}' is hanging with output '{}' and error '{}'", batchFile.toString(), standardOutput, standardError);
}
} catch (IOException | InterruptedException e) {
LOGGER.error(e.getMessage());
}
Note the warnings of the Process javadoc:
Because some native platforms only provide limited buffer size for
standard input and output streams, failure to promptly write the input
stream or read the output stream of the process may cause the process
to block, or even deadlock.
When you exit your method early with if (!waitForCompletion) then you skip consuming stdout. If your sub-process is writing a lot of output to stdout then it will block if stdout buffer is filled => process freezes.
If that is the case, you can avoid the issue by one of:
Add .inheritIO() when ProcessBuilder to ensure output is passed onto default for current Java process
Send STDOUT/ERR to a file instead, adding .redirectInput(new File("somefile.log"))
Add a background task to consume stdout, something like this but with suitable try/catch in the Runnable for you to deal with IOException / logging etc:
if (!waitForCompletion) {
// Ensure STDOUT is consumed
new Thread(() -> collectString(process.getInputStream())).start();
}
I have a reader module written in Java that checks whether a reader is connected to the system and if yes it scans any tags present in its vicinity.
If the reader is not connected, the program continuously throws following exception stack trace:
Exception de.feig.FedmException:
Error -111 - Error in Module FEDM: No port handle set
(in Function: FedmIscReader_SendProtocol(0xB0), Line: 3362)
native Library Version: 04.07.0
Here is the code that is generating the above exception:
try {
fedm = new FedmIscReader();
}
catch (de.feig.FedmException e) {
e.printStackTrace();
return;
}
catch(java.lang.Exception e) {
e.printStackTrace();
return;
}
The problem here is that I'm writing the output of this program into a nohup file on Ubuntu system and this file size grows to a large extent since the above exception is written continuously to this file.
I want this exception to be written to nohup only once and continue detecting for any reader connections. How do I achieve this?
Any suggestion or solution for this is greatly appreciated.
Thanks
I am working on an application that starts a minecraft server with one click of a button. I've successfully got the server to startup, but now I am trying to figure out a way to stop the server through the same cmd process.
Here's my code for starting the server...
public static void startServer() {
System.out.println("Starting server...");
try {
server = Runtime.getRuntime().exec(
"java -jar -Xmx1024M -Xms1024M minecraft_server.jar nogui");
output = server.getOutputStream();
input = server.getInputStream();
writer = new BufferedWriter(new OutputStreamWriter(output));
} catch (IOException e) {
e.printStackTrace();
}
}
This tells the runtime to execute a run.bat file that is in the same directory of the application. This method also initialized the OutputStream and InputStream objects that I created at the top of this class.
Here's my code for stopping the server...
public static void stopServer() {
System.out.println("Stopping server...");
// server.destroy();
try {
writer.write("stop\n\r");
} catch (IOException e) {
e.printStackTrace();
}
}
"stop" is a command that I'm trying to issue to the server to stop it, but for some reason the command is never being issued to the server.
More info:
The server is being run in cmd.exe, and therefore all server cmds need to be issued in cmd.
The server is named minecraft_server.jar so I have to use the command line to run the server and get output from the server and write input to it.
The run.bat file contains the text java -Xmx1024M -Xms1024M -jar minecraft_server.jar nogui.
My main goal is to write the command "stop" to the server to stop it.
As #clearlyspam23 stated, you are killing the process the moment you write anything to it.
Second, you are writing to the process' output stream, you want to write in the input stream. Edit: nope
Also, any server command is usually validated with a 'Enter' keystroke, so you might need to add a carriage return ('\r') right after your command to simulate that.
I'm using Java Process as below :
Runtime rt = Runtime.getRuntime();
try {
Process pr = rt.exec(cmd);
response = IOUtils.toString(pr.getInputStream(), "UTF-8");
response = response.substring(2, response.length()-4);
logger.debug("response :" + response);
} catch (IOException e) {
logger.error(e);
e.printStackTrace();
}
I can see the loggers in my local machine(Mac OSX). But when I run the same program in a Redhat Linux machine, I'm having problem seeing the logs. I don't have any clue whats happening after pr.getInputStream(). Having a logger before that statement is working fine. I want to see the response of the exec(cmd). How can I achieve this. I suspect something is wrong when I'm trying to read the InputStream.
Try reading input stream and error stream in two threads other than the one that launched the process.
I have seen processes gets stuck writing to error or output streams if no one is reading what they are writing.
I have a utility where Jmeter sends a request and the utility sends back response to Jmeter. When load increases, the Utility shuts down with an "EXCEPTION_ACCESS_VIOLATION".
Since it is an error, I am not able to handle it in a catch block. I made a second utility to restart the first utility when the error occurs. Below is the code of the second, restart, utility. In this second utility's code, at the second while, my program sometimes hangs. How do I detect this and restart the process?
public static void main(String[] args)
{
String line = null;
String currPID = null;
try
{
while(true)
{
Process process = Runtime.getRuntime().exec("java -XX:+HeapDumpOnOutOfMemoryError -Xms250M -Xmx500M -XX:ErrorFile=NUL ws ");
BufferedReader input = new BufferedReader(new InputStreamReader(process.getInputStream()));
while ((line = input.readLine()) != null) //Program stucks at this Line
{
if(line.trim().length() != 0)
{
if(line.startsWith("PID"))
{
currPID = line.substring(line.indexOf("#")+1);
}
}
}
System.out.println("Ended");
}
}
catch(Exception e)
{
e.printStackTrace();
}
}
I analysed process through jvisualvm where i found two java process is in running mode when i start second(restart) utility. I can see first utility is restarting regularly because its PID is changing frequently in jvisualvm and same happening in task manager. Everything is going on very well manner.
After sometime i found only one process is in Jvisualvm ie second(restart) utility.
It means first utility JVM is crashed just guessing not sure. Something unusual is happening here. Because if JVM is crashed so It should be restarted.
So i opened task manager and found first utility PID exists there but it is not changing as happening in starting. If i kill the process(first utility) explicitly from task manager.
Seconds utility again restarts first utility same thing happens again, After some time first utility disappeared from jvisualvm, exists in taskmanager and delete process from taskmanager. What needs to do?
Try using .ready() function.
try {
if (stdError.ready())
{
while((line= stdError.readLine()) != null){
logger.error(line);
}
}
}
Do the same for the stdout.
It worked like a charm for me.
Your problem with hanging appears to be at the call to readLine.
readLine is for reading lines. The method will not return until the call is sure the end of line has been reached. It expects either a newline character or the complete cease of communications.
Is your first utility not sending a new line char?
Does your first utility fail to close the stream?
Your while call will hang indefinitely if the answer to both questions is yes.
You might be better off consuming with a custom implementation of the Scanner class.
Try to use getErrorStream() it'll catches the error message, if you use getInputStream() it'll reads only the success message or feedback messages.
for ex: if you execute the following command & read the process message using getInputStream(),
Process process = Runtime.getRuntime().exec("net use u: \\sharedIP\sharedFolder");
BufferedReader input = new BufferedReader(new inputStreamReader(process.getInputStream()));
you can only get feedback messages like "network drive connected successfully" but not the error messages.
if you use getErrorStream() to read the process message it'll read the error messages like "the network drive was not found". when the process executed it'll give a message to either getInputStream() or getErrorStream(). so use both method to read the message from the process, if i'm correct this'll work. I'm just trying to give you an idea but i'm not sure.