I created a class that starts and ends a process in java. I tried mspaint.exe with or without args and it starts the process,
but when I tried to start calculator(calc.exe) it doesn't work.
Is there a reason it will only start specific processes?
public class XProcess {
private Process process;
private String cmd;
public XProcess(String command) {
this.cmd = command;
}
public synchronized void start() throws IOException{
process = Runtime.getRuntime().exec(this.cmd);
}
public synchronized void destroy(){
process.destroy();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) throws IOException, InterruptedException {
XProcess process = new XProcess("mspaint.exe");
process.start();
Thread.sleep(5000);
process.destroy();
}
}
The javadoc for Process's destroy() explains it quite nicely
Kills the subprocess. Whether the subprocess represented by this
Process object is forcibly terminated or not is implementation
dependent.
Generally, an attempt to destroy (or kill) a process is a request. The Operating System could intercept the request, or the process itself could refuse the request.
The proper way to shutdown a process is for the process to internally quit, with the parent process (the one that launched the child process) listening for the child's exit. Anything else tends to be spotty as to whether it will work in all cases, with all processes.
This is why many processes (Tomcat is an example) accept a shutdown command as a network request, so it can then handle the request, shutting down internally.
Are you using some recent Windows? 10 or probably even 8?
Then it's unrelated to Java, the new Calculator is a Windows Store app, calc.exe is probably just a wrapper that starts it in a new container process and exists right after that, it's gone by the time you try to destroy it.
Related
How do I stop a Java process gracefully in Linux and Windows?
When does Runtime.getRuntime().addShutdownHook get called, and when does it not?
What about finalizers, do they help here?
Can I send some sort of signal to a Java process from a shell?
I am looking for preferably portable solutions.
Shutdown hooks execute in all cases where the VM is not forcibly killed. So, if you were to issue a "standard" kill (SIGTERM from a kill command) then they will execute. Similarly, they will execute after calling System.exit(int).
However a hard kill (kill -9 or kill -SIGKILL) then they won't execute. Similarly (and obviously) they won't execute if you pull the power from the computer, drop it into a vat of boiling lava, or beat the CPU into pieces with a sledgehammer. You probably already knew that, though.
Finalizers really should run as well, but it's best not to rely on that for shutdown cleanup, but rather rely on your shutdown hooks to stop things cleanly. And, as always, be careful with deadlocks (I've seen far too many shutdown hooks hang the entire process)!
Ok, after all the possibilities I have chosen to work with "Java Monitoring and Management"
Overview is here
That allows you to control one application from another one in relatively easy way. You can call the controlling application from a script to stop controlled application gracefully before killing it.
Here is the simplified code:
Controlled application:
run it with the folowing VM parameters:
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=9999
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
//ThreadMonitorMBean.java
public interface ThreadMonitorMBean
{
String getName();
void start();
void stop();
boolean isRunning();
}
// ThreadMonitor.java
public class ThreadMonitor implements ThreadMonitorMBean
{
private Thread m_thrd = null;
public ThreadMonitor(Thread thrd)
{
m_thrd = thrd;
}
#Override
public String getName()
{
return "JMX Controlled App";
}
#Override
public void start()
{
// TODO: start application here
System.out.println("remote start called");
}
#Override
public void stop()
{
// TODO: stop application here
System.out.println("remote stop called");
m_thrd.interrupt();
}
public boolean isRunning()
{
return Thread.currentThread().isAlive();
}
public static void main(String[] args)
{
try
{
System.out.println("JMX started");
ThreadMonitorMBean monitor = new ThreadMonitor(Thread.currentThread());
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
ObjectName name = new ObjectName("com.example:type=ThreadMonitor");
server.registerMBean(monitor, name);
while(!Thread.interrupted())
{
// loop until interrupted
System.out.println(".");
try
{
Thread.sleep(1000);
}
catch(InterruptedException ex)
{
Thread.currentThread().interrupt();
}
}
}
catch(Exception e)
{
e.printStackTrace();
}
finally
{
// TODO: some final clean up could be here also
System.out.println("JMX stopped");
}
}
}
Controlling application:
run it with the stop or start as the command line argument
public class ThreadMonitorConsole
{
public static void main(String[] args)
{
try
{
// connecting to JMX
System.out.println("Connect to JMX service.");
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://:9999/jmxrmi");
JMXConnector jmxc = JMXConnectorFactory.connect(url, null);
MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();
// Construct proxy for the the MBean object
ObjectName mbeanName = new ObjectName("com.example:type=ThreadMonitor");
ThreadMonitorMBean mbeanProxy = JMX.newMBeanProxy(mbsc, mbeanName, ThreadMonitorMBean.class, true);
System.out.println("Connected to: "+mbeanProxy.getName()+", the app is "+(mbeanProxy.isRunning() ? "" : "not ")+"running");
// parse command line arguments
if(args[0].equalsIgnoreCase("start"))
{
System.out.println("Invoke \"start\" method");
mbeanProxy.start();
}
else if(args[0].equalsIgnoreCase("stop"))
{
System.out.println("Invoke \"stop\" method");
mbeanProxy.stop();
}
// clean up and exit
jmxc.close();
System.out.println("Done.");
}
catch(Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
That's it. :-)
An another way: your application can open a server socet and wait for an information arrived to it. For example a string with a "magic" word :) and then react to make shutdown: System.exit(). You can send such information to the socke using an external application like telnet.
Here is a bit tricky, but portable solution:
In your application implement a shutdown hook
When you want to shut down your JVM gracefully, install a Java Agent that calls System.exit() using the Attach API.
I implemented the Java Agent. It is available on Github: https://github.com/everit-org/javaagent-shutdown
Detailed description about the solution is available here: https://everitorg.wordpress.com/2016/06/15/shutting-down-a-jvm-process/
Similar Question Here
Finalizers in Java are bad. They add a lot of overhead to garbage collection. Avoid them whenever possible.
The shutdownHook will only get called when the VM is shutting down. I think it very well may do what you want.
Thanks for you answers. Shutdown hooks seams like something that would work in my case.
But I also bumped into the thing called Monitoring and Management beans:
http://java.sun.com/j2se/1.5.0/docs/guide/management/overview.html
That gives some nice possibilities, for remote monitoring, and manipulation of the java process. (Was introduced in Java 5)
Signalling in Linux can be done with "kill" (man kill for the available signals), you'd need the process ID to do that. (ps ax | grep java) or something like that, or store the process id when the process gets created (this is used in most linux startup files, see /etc/init.d)
Portable signalling can be done by integrating a SocketServer in your java application. It's not that difficult and gives you the freedom to send any command you want.
If you meant finally clauses in stead of finalizers; they do not get extecuted when System.exit() is called.
Finalizers should work, but shouldn't really do anything more significant but print a debug statement. They're dangerous.
I have a jar file that displays a JFrame when it is executed.
I don't want to allow duplicate execution of my Jar file.
Every time before creating the frame, using Java I want check whether the Jar is already executing. If my app. already has an instance on-screen, I want to bring it to front.
How can I do that?
Please suggest me a way.
There is no regular method in java for single instance of an application.
However you can use Socket programming technique to achieve your goal.
When the instance is creating it attempts to listen a ServerSocket. If it could open the ServerSocket it means there are no another instance of the application. So, it keeps the ServerSocket live until the program is shutdown. If it could not open the ServerSocket, it means the application already have another instance. So you can exit application silently. Additionally you don't need to reset your settings when shutdown the application.
Try following example
public class SingletonApplication extends JFrame implements Runnable {
//count of tried instances
private int triedInstances = 0;
//the port number using
private static final int PORT = 5555;
public static void main(String[] args) {
SingletonApplication application = new SingletonApplication();
application.setTitle("My Singleton Application");
application.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
application.setSize(500, 500);
application.setVisible(true);
}
public SingletonApplication() {
super();
//run socket listening inside a thread
Thread thread = new Thread(this);
thread.start();
}
#Override
public void run() {
try {
//create server socket
ServerSocket serverSocket = new ServerSocket(PORT);
//listing the socket to check new instances
while (true) {
try {
//another instance accessed the socket
serverSocket.accept();
//bring this to front
toFront();
//change the title (addtional);
triedInstances++;
setTitle("Tried another instances : " + triedInstances);
} catch (IOException ex) {
//cannot accept socket
}
}
} catch (IOException ex) {
//fail if there is an instance already exists
try {
//connect to the main instance server socket
new Socket(InetAddress.getLocalHost(), PORT);
} catch (IOException ex1) {
//do nothing
} finally {
//exit the system leavng the first instance
System.exit(0);
}
}
}
}
EDIT:
Additionally: It can pass your runtime arguments into the main instance of the application via the client Socket. So, it's possible to make the main instance to perform required task such opening file or playing music by adding some additional code to read the InputStream of accepted Socket when calling accept() method.
I had the same situation.
What I did is I used to open a file in write mode and delete the file when I close the application.
By doing this I have a known proof that my program is running.
Each time I open the application I check for the existence of that file and if I find my file, it is running then I used to alert him
"An instance is already running".
Even if one tries to delete that file it says that it is open in another application.
I used a socket too, via RMI.
The application is an RMI host/server, accepts a Remote Method Invokation on a port.
In the main, at startup on tries as RMI client to get an RMI server on that port.
Is it there one does a remote call passing the command line args (to open another document for instance). And then quits.
As a server on being called that remote method one brings the application to front using toFront() of the window.
JUnique accomplishes the first part--blocking multiple instances of the same program. Getting the existing instance to come to the front is another task that I'm not sure how to approach.
Loading a windows keystore(Windows-MY) which contains a token based key is leaving the java process as a background process.
I had registered a shutdown hook, the hook is getting executed and Visual VM is reporting the application is terminated, but the ports opened by the process is not released(like jmx port) unless the process is terminated explicitly using task manager.
A very simple test case used is as below, but to test the case you have to plugin a key token.
public static void main(String[] args) throws Exception {
KeyStore keyStore = KeyStore.getInstance("Windows-MY");
keyStore.load(null, null);
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
System.out.println("Close");
}
});
//System.exit(1); even with explicit call to exit nothing is happening
}
Edit: Looks like giving the example of ports have done more harm than good. I gave the example of the jmx port as just an example for the fact that the original process was not terminated. If the processes is terminated then the ports are released.
How do I stop a Java process gracefully in Linux and Windows?
When does Runtime.getRuntime().addShutdownHook get called, and when does it not?
What about finalizers, do they help here?
Can I send some sort of signal to a Java process from a shell?
I am looking for preferably portable solutions.
Shutdown hooks execute in all cases where the VM is not forcibly killed. So, if you were to issue a "standard" kill (SIGTERM from a kill command) then they will execute. Similarly, they will execute after calling System.exit(int).
However a hard kill (kill -9 or kill -SIGKILL) then they won't execute. Similarly (and obviously) they won't execute if you pull the power from the computer, drop it into a vat of boiling lava, or beat the CPU into pieces with a sledgehammer. You probably already knew that, though.
Finalizers really should run as well, but it's best not to rely on that for shutdown cleanup, but rather rely on your shutdown hooks to stop things cleanly. And, as always, be careful with deadlocks (I've seen far too many shutdown hooks hang the entire process)!
Ok, after all the possibilities I have chosen to work with "Java Monitoring and Management"
Overview is here
That allows you to control one application from another one in relatively easy way. You can call the controlling application from a script to stop controlled application gracefully before killing it.
Here is the simplified code:
Controlled application:
run it with the folowing VM parameters:
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=9999
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
//ThreadMonitorMBean.java
public interface ThreadMonitorMBean
{
String getName();
void start();
void stop();
boolean isRunning();
}
// ThreadMonitor.java
public class ThreadMonitor implements ThreadMonitorMBean
{
private Thread m_thrd = null;
public ThreadMonitor(Thread thrd)
{
m_thrd = thrd;
}
#Override
public String getName()
{
return "JMX Controlled App";
}
#Override
public void start()
{
// TODO: start application here
System.out.println("remote start called");
}
#Override
public void stop()
{
// TODO: stop application here
System.out.println("remote stop called");
m_thrd.interrupt();
}
public boolean isRunning()
{
return Thread.currentThread().isAlive();
}
public static void main(String[] args)
{
try
{
System.out.println("JMX started");
ThreadMonitorMBean monitor = new ThreadMonitor(Thread.currentThread());
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
ObjectName name = new ObjectName("com.example:type=ThreadMonitor");
server.registerMBean(monitor, name);
while(!Thread.interrupted())
{
// loop until interrupted
System.out.println(".");
try
{
Thread.sleep(1000);
}
catch(InterruptedException ex)
{
Thread.currentThread().interrupt();
}
}
}
catch(Exception e)
{
e.printStackTrace();
}
finally
{
// TODO: some final clean up could be here also
System.out.println("JMX stopped");
}
}
}
Controlling application:
run it with the stop or start as the command line argument
public class ThreadMonitorConsole
{
public static void main(String[] args)
{
try
{
// connecting to JMX
System.out.println("Connect to JMX service.");
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://:9999/jmxrmi");
JMXConnector jmxc = JMXConnectorFactory.connect(url, null);
MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();
// Construct proxy for the the MBean object
ObjectName mbeanName = new ObjectName("com.example:type=ThreadMonitor");
ThreadMonitorMBean mbeanProxy = JMX.newMBeanProxy(mbsc, mbeanName, ThreadMonitorMBean.class, true);
System.out.println("Connected to: "+mbeanProxy.getName()+", the app is "+(mbeanProxy.isRunning() ? "" : "not ")+"running");
// parse command line arguments
if(args[0].equalsIgnoreCase("start"))
{
System.out.println("Invoke \"start\" method");
mbeanProxy.start();
}
else if(args[0].equalsIgnoreCase("stop"))
{
System.out.println("Invoke \"stop\" method");
mbeanProxy.stop();
}
// clean up and exit
jmxc.close();
System.out.println("Done.");
}
catch(Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
That's it. :-)
An another way: your application can open a server socet and wait for an information arrived to it. For example a string with a "magic" word :) and then react to make shutdown: System.exit(). You can send such information to the socke using an external application like telnet.
Here is a bit tricky, but portable solution:
In your application implement a shutdown hook
When you want to shut down your JVM gracefully, install a Java Agent that calls System.exit() using the Attach API.
I implemented the Java Agent. It is available on Github: https://github.com/everit-org/javaagent-shutdown
Detailed description about the solution is available here: https://everitorg.wordpress.com/2016/06/15/shutting-down-a-jvm-process/
Similar Question Here
Finalizers in Java are bad. They add a lot of overhead to garbage collection. Avoid them whenever possible.
The shutdownHook will only get called when the VM is shutting down. I think it very well may do what you want.
Thanks for you answers. Shutdown hooks seams like something that would work in my case.
But I also bumped into the thing called Monitoring and Management beans:
http://java.sun.com/j2se/1.5.0/docs/guide/management/overview.html
That gives some nice possibilities, for remote monitoring, and manipulation of the java process. (Was introduced in Java 5)
Signalling in Linux can be done with "kill" (man kill for the available signals), you'd need the process ID to do that. (ps ax | grep java) or something like that, or store the process id when the process gets created (this is used in most linux startup files, see /etc/init.d)
Portable signalling can be done by integrating a SocketServer in your java application. It's not that difficult and gives you the freedom to send any command you want.
If you meant finally clauses in stead of finalizers; they do not get extecuted when System.exit() is called.
Finalizers should work, but shouldn't really do anything more significant but print a debug statement. They're dangerous.
I'm now using LocateRegistry.createRegistry(1099) rathern than using the registry in a external process. However the registry dies after the main program ends. For instance, if I make a simple program that creates the registry it'll not work because after the main executino the code ends. I was expecting the LocateRegistry code to create a thread, but it seems that this is not the case. Is this the normal behavior of using LocateRegistry or I'm missing something?
Code sample:
// ommited imports
public class RMITest {
public static void main(String[] args) {
LocateRegistry.createRegistry(1099);
// JVM will exit now!!!
}
}
The RMI Server start and suddenly dies. How
I was expecting the LocateRegistry code to create a thread
It's not that simple.
Exporting the first object on a new port creates a thread that listens on that port, and unexporting the last object listening on a port causes that thread to exit. This is for all remote objects, not just local Registry objects.
Unexporting can happen automatically via local GC, which in turn can be trigged by remote DGC.
Your JVM exits because you aren't saving the value returned by LocateRegistry.createRegistry() in a static variable, so it gets GC'd, so the object gets unexported, so there are no remote objects exported on port 1099, so the thread that listens on 1099 exits, so there are no non-daemon threads, so the JVM exits.
Solution: store the result of LocateRegistry.createRegistry() in a static variable. You can use that to unexport the Registry when you want your JVM to exit.
There are two possible ways to start the RMI registry.
LocateRegistry.createRegistry(1099); The java application executing the registry must not finish. In your case you could start a new "never ending" thread (see below for source code)
rmiregistry This is a tool included in the java distribution that starts an RMI registry service. see rmiregistry - The Java Remote Object Registry
Sample code for RMI registry server.
import java.io.IOException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
public class RmiTest {
public static void main(String[] args) throws IOException {
final Object monitor = new Object();
new Thread(new Runnable() {
public void run() {
try {
LocateRegistry.createRegistry(1099);
synchronized (monitor) {
monitor.wait();
}
} catch (RemoteException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("RMI Registry Thread finished.");
}
}, "RMI Registry Thread").start();
System.out.println("Press enter to exit...");
System.in.read();
synchronized (monitor) {
monitor.notify();
}
}
}
LocateRegistry.createRegistry(1099);
creates a new daemon thread named RMI TCP Accept-1099 on my machine. This thread essentially listens for new TCP/IP connections on 1099.
Daemon threads are automatically killed when JVM exits. And in your case JVM exits when you leave main() method. More precisely - it exits when there are no more non-daemon threads - and apparently there is only one non-daemon thread in your application (named main).
So you have two options:
don't let main() method to finish by adding infinite sleep().
create some non-daemon thread. Of course only do this when the thread actually does something useful rather than preventing JVM to exit.