problem killing a process in a Java application - java

I have created a Java application where the main method (start of the program) initiates a Process object and an object of MainWindow class which creates a JFrame.
public static void main(String[] args) throws Exception {
File file = new File("./access/run.bat");
ProcessBuilder process_builder = new ProcessBuilder("cmd", "/c", file.getName());
process_builder.directory(file.getParentFile());
Process process = process_builder.start();
MainWindow window = new MainWindow(process);
}
I would like to terminate (kill) the process which has been instantiated with a process.destroy() when the window has been closed. Here is some code of the MainWindow class:
public MainWindow(final Process process) throws TransformerException, ParserConfigurationException, Exception{
JFrame mainWindowFrame = new JFrame();
*****some code here*****
mainWindowFrame.addWindowListener(new WindowListener() {
public void windowClosed(WindowEvent arg0) {
process.destroy();
System.exit(0);
}
*****some code here*****
}
}
When the window is closed, unfortunately, the process is not killed...can anyone give me an explanation for this and a possible solution? Thanks!!!

According to the documentation here then windowClosed is called only if the window is disposed. To do that, you can either call dispose on the window or set the default close operation: in your code, after creating the JFrame, add the following:
mainWindowFrame.setDefaultCloseOperation(javax.swing.JFrame.DISPOSE_ON_CLOSE);
After looking at your code, I suggest you work differently:
in your listener, you are destroying the process and then exiting. therefore, you can set the deafualt close operation to exit and then implement the process destroying in the
implementation of windowClosing method : modifying the code of MainWindow to the following:
public MainWindow(final Process process) throws TransformerException, ParserConfigurationException, Exception{
JFrame mainWindowFrame = new JFrame();
mainWindowFrame.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
*****some code here*****
mainWindowFrame.addWindowListener(new WindowListener() {
public void windowClosing(WindowEvent arg0) {
process.destroy();
}
*****some code here*****
}
}

The Javadoc of the Process class says this :
The subprocess is not killed when there are no more references
to the Process object, but rather the subprocess
continues executing asynchronously.
There is no requirement that a process represented
by a Process object execute asynchronously or concurrently
with respect to the Java process that owns the Process object.
After searching on the Internet, it seems that it's a issue in the Java platform since Java 1.3. I found this blog entry that explains many issues about Process in Java.
The problem is that the process becomes an orphan after killing the application. In your code, you are killing the Process from the GUI since the GUI (the MainWindow class) has its own thread and it is not the Process parent. It's a parent/child problem.
There are two ways to correct that :
Since the main thread is the parent process, so the main thread must call the destroy method. So you must keep a reference to the process object.
The second way is to create the process while launching the MainWindow. In the argument of the MainWindow class, you can pass the arguments of the process. So when the windowClosed method is called, if the MainWindow is closed, the Process will be destroy since the latter is the children of the MainWindow.

Related

Java deleteOnExit and addShutdownHook - which comes first?

I have a number of temporary files that I call deleteOnExit() on.
I also have a runnable that I register with addShutdownHook() to run when System.exit is called.
Is there any guarantee that the temporary files will still be available when my shutdown hook runs?
When we look at the underneath implementations, both are dealing with Shutdown-Hook.
When we deal with addShutdownHook (ApplicationShutdownHooks), we have a piece of code like below in our code.
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
<<---Do the Implementations here--->>
}
});
Internally inside Java Source Code ApplicationShutdownHooks are implemented as below and called from Runtime class as mentioned in this link http://www.docjar.com/html/api/java/lang/Runtime.java.html
class ApplicationShutdownHooks {
/* The set of registered hooks */
private static IdentityHashMap<Thread, Thread> hooks;
static {
try {
Shutdown.add(1 /* shutdown hook invocation order */,
false /* not registered if shutdown in progress */,
new Runnable() {
public void run() {
runHooks();
}
}
);
Whereas when we deal with File.deleteOnExit(), Java internally registers for a shutdown as below.
// DeleteOnExitHook must be the last shutdown hook to be invoked.
// Application shutdown hooks may add the first file to the
// delete on exit list and cause the DeleteOnExitHook to be
// registered during shutdown in progress. So set the
// registerShutdownInProgress parameter to true.
sun.misc.SharedSecrets.getJavaLangAccess()
.registerShutdownHook(2 /* Shutdown hook invocation order */,
true /* register even if shutdown in progress */,
new Runnable() {
public void run() {
runHooks();
}
}
);
Note: Above piece of Code that registers the hook can be found in JavaSourceCode as below: http://hg.openjdk.java.net/icedtea/jdk7/jdk/file/10672183380a/src/share/classes/java/io/DeleteOnExitHook.java
http://hg.openjdk.java.net/icedtea/jdk7/jdk/file/10672183380a/src/share/classes/java/io/File.java
If Shutdown Hook runs fine, we will have all the files cleared off from System. However there is no guarantee that Shutdown Hooks runs fine everytime. There are some rare scenrios as well for which you can refer the below links:
ApplicationShutdownHooks : https://docs.oracle.com/javase/7/docs/api/java/lang/Runtime.html#addShutdownHook
(java.lang.Thread)
deleteOnExit:
https://docs.oracle.com/javase/7/docs/api/java/io/File.html#deleteOnExit()
And More specifically, we should use ApplicationShutdownHooks rather than deleteOnExit() because deleteOnExit() uses a lot of memory that will not be released until the JVM terminates.
Note: Also since deleteOnExit(), applies to File instances and not Path, we also need to convert the Path
to a File by calling the method as below:
Path path = FileSystems.getDefault.getPath(".");
File asFile = path.toFile();
asFile.deleteOnExit();

Use a thread to wait until the user has picked a file

I have a mainClass in Java, that starts a GUI in swing. I ask the user to open a file using a JFileChooser. I want the main to wait until the user has finished picking the file and then continue with the rest of the code in main. How do I do this using threads? Thanks in advance.
Here is the skeleton code:
public class MainClass {
public static void main(String[] args) {
GUI gui= new GUI();
//wait for user input here
//Continue with code
System.out.println("User has picked a file");
}
}
GUI.java
public class GUI{
//User picks file using JFileChooser
JFileChooser chooseFile= new JFileChooser();
//Notify mainclass we're done with fiction to continue with code
}
OK, Two things.
You don't need multiple threads
The thing is, you can accomplish your goal of waiting for a user to select a file simply by using a Modal dialog. This works about like the following:
import javax.swing.*;
public class DialogTest {
public static void main(String[] args) {
JFileChooser chooser = new JFileChooser();
chooser.showOpenDialog(null);
System.out.println("File chooser is now closed. File is: " +
chooser.getSelectedFile().toString());
}
}
The showOpenDialog method will not return until the user has either selected a file, clicked cancel, or else clicked the X. Just be aware that getSelectedFile() will return null if the user cancels.
If you do need threads (you know, for something else)
Swing uses what it calls the Event Dispatch Thread. Swing is not thread safe, as mentioned in the comment. What this means is that any and all method calls to Swing components should be done from the EDT. You can schedule code to be run on the EDT by using SwingUtilities.invokeLater(Runnable). You can schedule something to run in a background thread (using a thread pool) by using a Swing Worker. Most of your code will probably just run on the EDT. Long-running operations can be sent to a background thread using swing workers.

Thread in JME doesn't work

In JME I try to use threading but when I run the program the function never starts.
I have a server socket who is listening to input from Netbeans.
Listener
while (isRunning) {
//Reads and prints the input
String receivedString = (String) in.readObject();
System.out.println(receivedString);
String[] parts = receivedString.split(";");
if(parts[0].equals("craneCon"))
{
final int containerId = Integer.parseInt(parts[1]);
m.enqueue(new Callable<Spatial>(){
public Spatial call() throws Exception{
m.removeContainersFromMaritime(containerId);
return null;
}
});
}
So in the main there is the function removeContainersFromMaritime
public void removeContainersFromMaritime(final int idContainer)
{
Node container = Maritime.listOfContainers.get(idContainer);
martime.detachChild(Maritime.listOfContainers.get(idContainer));
seagoingcrane.attachChild(Maritime.listOfContainers.get(idContainer));
container.setLocalTranslation(0,5,0);
System.out.println(Maritime.listOfContainers.get(0).getWorldTranslation().z);
}
The connection is alright but the method is never executed. How can I fix this?
jMonkeyEngine uses a swing-style threading model where there is a single render thread that does all the work. Any changes to the scene graph have to be done from that render thread.
To get into the render thread you can implement AppStates, Controls or you can enqueue Callables which are then executed on the render thread in a similar way to Swing's invokeLater.
The code snippet you posted looks about right, so assuming m is your running jME3 SimpleApplication then m.enqueue() will cause the enqueued callable to be executed next time around the render loop (i.e. at the start of the next frame).
If you are not seeing it executed then either:
Your application is not running
You created more than one application and enqueued it to the wrong one
The code is actually running and you just think it isn't.
Stepping through the code in the debugger and/or adding debug statements (for example breakpoint inside removeContainersFromMaritime to see if it is actually called should allow you to narrow this down.
I might be missing something but what is "m" in m.enqueue(...)?
I'm guessing it is an executor service of some sort and it's probably where the problem lies.
You could try instead:
new Thread() {public void run()
{
m.removeContainersFromMaritime(containerId);
}}.start();
It will at least show you if the problem is coming from "m" as an executor.

Multiple instances of perl script running in parallel via JButton action listener

I'm executing a Perl script via "Runtime.getRuntime().exec("perl C:/script.pl")"
as part of a Jbutton action listener. I would like to be able to click the button twice and get two instances of the same Perl script running. The script is reading in a text file so it acts a little differently depending on the text file the second time it is started but in general the script does the same thing.
I've tried to combat this by wrapping the runtime command in a new thread and executing a ".run()" on it each time the button is pressed but this only seems to interrupt the first instance and start the new one. There seems to be no way to execute two of the same Perl script in parallel. Any ideas on how I can accomplish this?
ActionListener edit = new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
class GetThread implements Runnable {
public void run() {
try {
Runtime.getRuntime().exec("C:/Perl/bin/perl5.16.3.exe C:/Perl/get.pl", null, new File("C:/Perl"));
} catch (IOException e1) {
exceptionLog(e1);
}
}
}
GetThread get = new GetThread();
get.run();
}
}
http://docs.oracle.com/javase/7/docs/api/java/lang/Runtime.html says
Every Java application has a single instance of class Runtime that allows the application to interface with the environment in which the application is running. The current runtime can be obtained from the getRuntime method.
It may be blocking on your call.

How to wait for an attribution in startup() to complete before continuing?

I'm making a desktop application which watches a folder using watchservice from java.nio.file . But I need the gui to be loaded before I start watching, because the path to be watched is in a JFieldText on the UI.
public class FileArchiverApp extends SingleFrameApplication {
static FileArchiverView gui;
#Override protected void startup() {
gui = new FileArchiverView(this); //HERE0 I have to wait for this.
show(gui);
...
public static void main(String[] args) throws IOException {
launch(FileArchiverApp.class, args);
....
WatchService watcher = FileSystems.getDefault().newWatchService();
// HERE1 while(gui==null) System.out.println("hi") ;
try {
Path dir = Paths.get(gui.getOriginPath()); // HERE2 I get nullpointer if gui was not ready
WatchKey key = dir.register(watcher, ENTRY_CREATE );
} catch ( Exception x) {
System.err.println(x);
}
while(true){ /*wait for new file event loop*/ }
}
The function getOriginPath() returns the getText() form the text field I mentioned.
In HERE0 is the attribution I mentioned. I get a nullpointer in HERE2 if gui wasn't ready.
I've tried things. If I put that thing in HERE1 it works, but of course I don't want to do that.
How could I make it?
And its taking to long(like two seconds) or the gui to stop being null with this HERE1 I don't know if it is because of the println, but I was expecting it to be almost instantaneous. Is it normal?
Thanks.
Given the limited information posted, I have to make some assumptions. Assumption 1 is that you give the JTextField a default value and use that as the path to the file you wish to watch. Assumption 2 is that you have not coded with an eye towards MVC-like design.
If both are correct, then it sounds like you have the tail wagging the dog -- the view holding the critical data, not the model. Why not fix your problem by going towards MVC and not getting the critical data from the view but rather from the model. Start the model up first thing, including getting the default path from your program Properties, get your listener going, start your view, and then if the view asks the controller to change the watched file, have the controller change the model. And then listeners in the model will notify your any observers of change.

Categories

Resources