My Java programme starts several other Java processes. When the programme is closed, all created processes should be terminated.
If the programme is stopped via an internal stop command, all data can be saved and the processes shut down. I use a shutdown hook for this, and it works very well so far.
But if the programme terminates abruptly or is not closed correctly by the user, all processes remain running and the programme does not work the next time it is started.
How can I make it so that code is executed when the programme stops abruptly, or rather, how can I stop the processes?
As suggested, I should have included some code. Here is a simplified version of the code:
Class which starts the process:
#Override
public void startProcess() throws IOException {
String command = "java -jar server.jar nogui";
this.process = Runtime.getRuntime().exec(command, null, new CloudFolder(super.getPath()).get());
final InputReader reader = new InputReader();
reader.open();
String in = reader.getInput();
if (in.equals("stop")) {
this.process.destroy();
this.process.getOutputStream().close();
}
}
Main class:
public static void main(String[] args) {
// normally the startProcess() Method would be
// called right here.
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
public void run() {
// Just to see if it worked
File file = new File("closing");
try {
file.createNewFile();
} catch (IOException exception) {
exception.printStackTrace();
}
}
}, "Shutdown-thread"));
}
Related
Is it possible in Java to seperate a subprocess so that it isn't longer a subprocess in the end?
Or to run a external process, that isn't a subprocess.
I want to start some big external process in linux. But with ProcessBuilder or Runtime.exec, it's my subprocesses and when I try to start big processes for example four minecraft server, I get a pthread_create exception in the end.
Is this possible in Java?
I just tested a small sample
import java.io.IOException;
public class Forking {
public static void main(String[] args) {
Process exec = null;
try {
exec = Runtime.getRuntime().exec("sleep 360");
} catch (IOException e) {
e.printStackTrace();
}
if (exec != null) {
System.out.println(exec.isAlive());
}
}
}
It runs with no exceptions and after it exits if you ps aux|grep sleep you will see that the sleep 360 is there running.
I wrote a process manager program one of the things that it does is to exit all running processes when it shut down
,so there is the code
public void stop_all() throws IOException {
Process p = Runtime.getRuntime().exec("kill -9 -1");
System.out.println("killed");
}
and there is the action on the button
private void exitButton(java.awt.event.ActionEvent evt) {
Run ob = new Run();
try {
ob.stop_all();
} catch (IOException ex) {
Logger.getLogger(mainmenu.class.getName()).log(Level.SEVERE, null, ex);
}
this.dispose();
}
i have no idea why it doesn't work ,
i execute that command in the terminal and it works fine
please help :)
I am still skeptical about the permissions of the program. But, from this reference you need to specify the command path in your exec().
So your code should probably be:
public void stop_all() throws IOException {
Process p = Runtime.getRuntime().exec("/bin/kill -9 -1");
System.out.println("killed");
}
I am trying to call a bat file from my Java function. Looks like some issue in the way I am calling the bat file. The batch file is not called from the method. Any help would be appreciated.
private static void Run_Main() throws InterruptedException, SQLException, IOException {
int set_value=0;
while ((set_value=Find_Flag()) !=0){
System.out.println("Set_Value"+set_value);
System.out.println("Staging load is not completed ..Revisiting after 15 minutes....");
Thread.sleep(900000);
set_value=Find_Flag();
}
System.out.println("Staging load is Completed and launching Proudction Load now");
//Runtime.getRuntime().exec(new String[] { "cmd.exe", "/c", "C:/exec/DW_Init_Load.bat" } );
String filePath = "C:/exec/DW_Init_Load.bat";
try {
Process p = Runtime.getRuntime().exec(filePath);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Production Load is finished");
}
I am interested to know what is the mistake I have made in the code
Adding p.waitFor() helped me solve this issues. Initially the block is not waiting for the process to complete.
Is there a way I can get appium to startup within the code I am writing for a junit test? Since appium only needs to run when my test is running it doesnt make sense to me to keep the appium server always going.
Right now I am using junit and maven to run test builds. Due to stability issues with appium it will sometimes die in the middle of the build, thus failing all remaining tests. I want to know if it is possible to add something to the #Before method to start the appium server before connecting the WebDriver to it, and then terminating it in the #After method. This should address any issues with appium failures since it can reset before starting the next test.
Still looking into starting and ending processes in general in java to see if this will work. If I figure this out I will update this post to help anyone else interested in testing this way.
Figured out how to get this to work by just running the terminal command within the code
#Before
public void setUp() throws Exception {
closeSimulatorAndInstruments(); // also closes any appium servers
appium = Runtime.getRuntime().exec("/usr/local/bin/appium");
Thread.sleep(1000); // wait for appium to start up, not sure how to check the status
... // start test
}
#After
public void tearDown() throws Exception {
captureScreenshot(testName.getMethodName());
driver.quit();
appium.destroy(); // kills the appium server so it wont collide with the next run
}
I'm seeing issues with my CI box running jenkins attempting to do this but it's probably unrelated. Locally this is working great since I don't have to remember to run appium separately anymore or check to see if it died. This is not advised however if you need to see the appium output which may contain important errors
I have written a library for this.
/**
*#author Raghu Nair
*/
public class Appium {
private static volatile Appium instance;
public static Appium getInstance(String outFile, String errFile) {
if (instance == null) {
synchronized (Appium.class) {
if (instance == null) {
instance = new Appium(outFile, errFile);
}
}
}
return instance;
}
Process process;
final String outFile;
final String errFile;
private Appium(String outFile, String errFile) {
this.outFile = outFile;
this.errFile = errFile;
}
public void start() throws IOException {
if (process != null) {
stop();
}
String processName = System.getProperty("appium.bin");
String processString = processName + " -lt 180000";
ProcessBuilder builder = new ProcessBuilder("bash");
process = builder.start();
OutputStream outStream = System.out;
if (outFile != null) {
outStream = new FileOutputStream(outFile);
}
OutputStream errStream = System.err;
if (errFile != null) {
errStream = new FileOutputStream(errFile);
}
handleStream(process.getInputStream(), new PrintWriter(outStream));
handleStream(process.getErrorStream(), new PrintWriter(errStream));
try (PrintWriter writer = new PrintWriter(process.getOutputStream())) {
//writer.println("kill -9 `ps -ef | grep appium | cut -d' ' -f2`");
writer.println("export PATH=$PATH:/usr/bin/:/usr/local/bin/");
writer.println(processString);
writer.flush();
}
}
private void handleStream(final InputStream processOut, final PrintWriter writer) {
Thread outHandler;
outHandler = new Thread(new Runnable() {
#Override
public void run() {
try {
BufferedReader stdout = new BufferedReader(
new InputStreamReader(processOut));
String line;
while ((line = stdout.readLine()) != null) {
writer.println(line);
writer.flush();
}
} catch (IOException ex) {
ex.printStackTrace(System.err);
}
}
});
outHandler.start();
}
public void stop() {
System.out.println("Stopping the process");
if (process != null) {
try {
process.destroy();
process.getErrorStream().close();
process.getInputStream().close();
process.getOutputStream().close();
} catch (IOException ex) {
ex.printStackTrace(System.err);
}
}
}
public static void main(String[] args) throws Exception {
System.setProperty("appium.bin", "/Applications/Appium.app//Contents/Resources/node_modules/.bin/appium");
Appium appium = Appium.getInstance("/Users/<user>/tmp/appium.out", "/Users/<user>/tmp/appium.err");
appium.start();
TimeUnit.SECONDS.sleep(30);
appium.stop();
}
I've solved this in a very similar way using a DefaultExecutor to keep track of the Appium process so it can be destroyed at the end of the tests. This also allows the Appium output to be logged out during the tests using a DefaultExecuteResultHandler.
To avoid using a sleep to wait for Appium to start, you could create your WebDriver instance inside a try-catch
for (int i = 10; i > 0; i--) {
try {
driver = new RemoteWebDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);
// If we successfully attach to appium, exit the loop.
i = 0;
} catch (UnreachableBrowserException e) {
LOGGER.info("Waiting for Appium to start");
}
}
You could add a sleep in the catch block if you wanted to poll less frequently.
I see we can improve a bit above solution.
Create Profiles for each environment ( define appium home)
you could redirect the Process output stream to a file. File name could be defined in profile are in java file.
I'm currently developping a ftp client based on the package commons.net, in order to run tests to see the speed of the connection.
Basically my ftp test consists in connect to the server, logging onto it, and then start a cycle of download/upload as long as necessary, until the user decides to stop it via a button, then the current cycle will end and so will the test.
However, while running those tests, a situation requiering a timout mechanism has occured. the server was transmitting the file, and send the return code 226 (transfer complete) before it was indeed completed.
So my thread remains stuck, trying to empty the inputStream when it is not possible anymore.
My idea was to start a threaded timer with the downloading process, that will be reset each time a byte is transferred to my client.
When the timeout occurs, then an exception or so would be raised, and my client would react to it, abording the download.
I have read and try many solutions, among them:
- raising an exception from a thread -> the thread catches the exception and not the client;
- interrupt the client from the thread, so the client raises itself an interruptedException -> doesn't seem to work;
- using an executor with a timeout -> since I can't know the "normal" duration of a download, I can't give it to the executor when I start the task, moreover, the timer has to be reset when I receive data.
I read a lot about it on many forums, and didn't find any solution that seem to be adapted AND work in this case. If anyone has an idea of another way to do it?
This is the code of the action I am performing:
public double get(String fileName) {
[...]
org.apache.commons.net.io.Util.copyStream(stO,stD,client.getBufferSize(),
this.localSize,
new org.apache.commons.net.io.CopyStreamAdapter() {
public void bytesTransferred(long totalBytesTransferred,
int bytesTransferred,long streamSize) {
setProgressDL(totalBytesTransferred);
//reset the timer here
}
});
[...]
}
Here is some of the code of my test, launching my client:
public class TestFtp extends Thread {
[...]
public void run() {
System.out.println("Launching FTP test");
FtpClient client = new FtpClient(this.model, this, this.model.getFtpServer());
try {
//Attempting connection on the server
client.connect();
try {
// Attempting login
client.login(this.model.getUsername(), this.model.getPassword());
do {
client.changeDirectory("get");
// start timer
client.get(this.model.getDistantFileName());
// stop timer
client.changeToParentDirectory();
client.changeDirectory("put");
client.set(this.model.getDistantFileName(),
this.model.getNewFileName());
client.changeToParentDirectory();
try {
// Little pause between each test
Thread.sleep(500);
} catch (InterruptedException e) {}
// Continue test until the user stops it
} while (this.continuous);
// Once the test is over, logout
client.logout();
} catch (FTPLoginException e) {
// If login fails, the test ends
System.out.println("Unable to login to the server.");
}
} catch (FTPConnectException e) {
// If connection error, the test ends
System.out.println("Unable to connect to the server.");
}
}
Thank you by advance if anyone can help, and if you need further information on my actual code, I can put more of it in here.
If you do not want to throw unecessary Exceptions, you should use a boolean flag that controls the execution of the thread (or runnable):
public class TestFtp extends Thread {
[...]
boolean abort;
public void run() {
[...]
do{
[...]
} while (this.continuous && !abort);
if (abort){
// You might want to do something here
}else{
// The stuff you normally do
}
}
}
And then simply set the abort flag to false from outside.
This way you can better control how you thread will terminate, as thread.interrupt(); will have an undefined behavior.
Well, I'm sorry but I admit I haven't read all your code, but if you want to interrupt a running thread, do two things:
run the thread code inside a try/catch block like this:
Example:
public void run() {
try {
// code to run
} catch (InterruptedException ie) {
// thread interrupted, may want to do some clean up
// but must return as quickly as possible to avoid halting external code
}
}
Call the interrupt() method of the thread above externally when the need arises.
Example:
thread.interrupt();
This will tell the VM to throw the InterruptedException in your thread no matter what it's doing, giving you a chance to do some stuff.
I hope this is what you're looking for...
EDIT
Ok, a concrete example that works:
public class Driver {
private static int count = 0;
public static void main(String[] args) {
Thread t = new Thread(new Runnable() {
#Override
public void run() {
try {
bigTask();
} catch (InterruptedException ie) {
System.out.println("Interrupted thread! Count is " + count);
}
}
});
t.start();
try {
Thread.sleep(1000);
System.out.println("Trying to interrupt thread");
t.interrupt();
} catch (InterruptedException e) {}
}
private static void bigTask() throws InterruptedException {
List<BigDecimal> bigs = new ArrayList<BigDecimal>();
for (int i = 0; i < 10000000; i++) {
bigs.add(BigDecimal.valueOf(i));
if (Thread.interrupted()) {
throw new InterruptedException();
}
count = i;
}
System.out.println("Ok, added ten million items, count is " + count);
}
}