Is it possible to programmatically close a Java process through JMX - java

I'm currently writing an app to monitor another Java process and take specific actions when certain targets are hit. For example, if a thread deadlocks for a certain time, kill the thread, if the memory usage goes over a specific amount, send email alerts and kill the process, etc.
My app will run as a stand-alone app, monitoring specific other apps (locally, though from what I can see remote or local makes no difference here).
I'm monitoring the external JVMs via MXBeans, but cannot see a clean way to kill the external process short of a system call like 'kill -9 ' (I'm working in UNIX by the way).
Is there any way to kill a JVM through the MXBean interfaces?
Graham

Sure. Implement an MBean on the target server that calls System.exit(), and invoke that as a JMX operation from the client.

If you're using Spring, you can simply annotate your bean to have one of its operations being exposed as an MBean operation. So it would be something like this:
#MBeanOperation(description="Kill the service")
public void die() {
System.exit();
}
... or perhaps stop the application context yourself.

Related

Start/stop java application from an external script

I have a Stand-alone Java application. At the moment I am running this Java application using a start-script i.e. startApplicatoin.bat in windows and startApplicatoin.sh in Linux which sets up the class-paths and then it executes: java -classpath .
Now I have to add a stopApplication.bat and stopApplication.sh script. This stop script has to shutdown/close this java application gracefully.
To achieve this I am planning to take the following steps:
1. When my java application runs it will store the process-id of the launched application in a file i.e. in a known file myapplication.pid.
Looks like ManagementFactory.getRuntimeMXBean().getName() call will work on both Linux and Windows to get the process ID. So I shall collect process ID in this way and will store it in the specified file myapplication.pid.
2. Then when running stop application script, this script will issue a “kill” request to the process-id as specified by that myapplication.pid file.
For Windows I shall run the "taskkill" command to stop this application. And for Linux environment "kill" command will serve that purpose.
And in my java code I shall add a addShutdownHook which will enable the graceful shutdown operations that I want to run i.e. there I shall handle whatever stuffs I want to persist before this program is going to stop.
http://docs.oracle.com/javase/7/docs/api/java/lang/Runtime.html#addShutdownHook%28java.lang.Thread%29
Now I would like to do a sanity check to ensure the way I am thinking is the proper way to do. Or there is a better way to do this. Any suggestion is appreciated. And thanks in advance.
If you're wanting a "graceful" shutdown, it may be more practical (and easier cross-platform) to open a socket in your long-running process and have your "stop" script connect to it and issue a shutdown command; this might even be practical through JMX, depending on how your application overall is structured. Approaches that are "inline" rather than requiring interaction with the OS are generally easier to reason about and test.
This looks like a Daemon.
The easiest way to run a daemon with start/stop functionality without resorting to a lot of scripting is with jsvc. This allows your code to implement an interface with four methods:
void init(String[] arguments): Here open configuration files, create a trace file, create ServerSockets, Threads
void start(): Start the Thread, accept incoming connections
void stop(): Inform the Thread to terminate the run(), close the ServerSockets
void destroy(): Destroy any object created in init()
You then have platform specific binaries that deal with keeping track of the process and stopping it when requested to do so.
The most useful thing is that jsvc can start a process as a superuser (root on unix) and then drop to a peon user the for auction running of the process.
This is how Tomcat (for example) works, it starts as root and performs privileged actions such as binding to port 80. It then drops down to a peon use called tomcat for security reasons.

Invoke Threads using JMX

How can I use JMX to invoke a thread using jConsole or jManage ?
I want to initially create 5 threads. Let them run. Then when one of them gets stuck, I want to create a new thread to continue operations.
I do not want to kill process until complete data is not processed / until really required.
You question seems a little bit vague; in general thread always runs some logic, so you should do some development here.
Basically JMX provides a way to install component (called MBean) and run it along with JVM process.
Java allows to start a JMX server along with the JVM process, in order to do that you should supply some properties to the process.
Then you can use this server for installing your own MBean that can do whatever you want, and of course run the thread.
Once you have a deployed mbean component and your jvm proces is up and running you can use jConsole and you should see your mbean among others.
Then just call the method.
There is a really good tutorial here
Hope this helps

How to deal with ^C in JVM console applications?

When a JVM-ran (written in Scala actually, but I tend to believe that the solution is going to be pretty much the same for Groovy, Clojure or pure Java) console program of mine gets terminated by the user pressing Ctrl+C (or by the system shut-down sequence, I don't know if there is any difference for a program), how do I make sure the external resources the application modifies (databases, files, web service abstracted resources) are left in a predictable, non-logically-corrupt state?
You can try to implement a shutdown hook as others pointed BUT:
In rare circumstances the virtual machine may abort, that is, stop
running without shutting down cleanly. This occurs when the virtual
machine is terminated externally, for example with the SIGKILL signal
on Unix or the TerminateProcess call on Microsoft Windows. The virtual
machine may also abort if a native method goes awry by, for example,
corrupting internal data structures or attempting to access
nonexistent memory. If the virtual machine aborts then no guarantee
can be made about whether or not any shutdown hooks will be run.
I guess, you would have to introduce transactional context into your application I believe. For databases that's quite easy, for file system you can look into Apache Commons Transaction
Take a look at Runtime.addShutdownHook.
You would typically use it as so:
Runtime.addShutdownHook(new Thread() {
public void run() {
// do your clean up here.
}
});
You can trap this signal and close off resources. Most services do not need to be closed gracefully, however files you write to usually do.
It is possible just adding a shutdown hook is all you need. But I would test this for your situation.

I want my service to run unelevated, but as a user who happens to be an Administrator (Windows / UAC)

Like the title says, I have written a program runs 'in the background', preferably as a Windows service. (It happens to be written in Java, with the service part provided by the tanuki wrapper, if this matters. Also, I'm running Vista, but am assuming that this happens on all versions of Windows with UAC.) I run the service as 'User X'.
I also have a companion GUI program which is typically run from the start menu (unprivileged - i.e. 'asInvoker') - also as 'User X'.
The background program (aka the service) creates files. My main need is for the unelevated GUI program to be able to read, write, and delete these files that are created by the service.
This works without hassle as long as 'User X' is not a member of the Administrators group. (Of course an admin login is required to create the service, but that's okay.)
It also works if I turn off UAC, or if I run the background program not as a service (eg. from a command prompt).
But I just can't get it to work when 'User X' is a member of Administrators, and the background program is running as a service.
The symptoms of this problem are that process explorer shows my service process as running privileged (which I glean from the processes properties' Security tab showing 'BUILTIN\Administrators - Owner'). Also, all files created by the service are owned by 'Administrators'.
If I run my background program unprivileged from a command prompt, then process explorer shows 'BUILTIN\Administrators - Deny' and all files created by the program are owned by 'User X'.
Interesting question. I just looked up some information and cannot seem to find an answer for your question as asked initially, but I have a few alternative suggestions.
First, is it feasible to change your service app so that it creates the files required then it changes the permissions on them to what you want?
Second, does the service itself really have to run as "User X"? If so, why? Is there any way around that restriction? If you can bypass that requirement, then you can just make a normal user for the service to run as.
Third, you said preferably as a service, but not that this is a requirement. Does the environment this is used in allow you to use a scheduled task? The task scheduler itself runs as a system service, and it spawns other processes to do the work of the tasks you set up. And, when setting up a scheduled task, there is an option (a check box if you're using the GUI interface) to run the task with highest privileges or not. If you go this route, you can either have the task run at logon, or you can have it run at system start (in which case, make sure you do NOT have selected "run only if logged on"). This should otherwise be similar to your service setup.
Based on your comment below, I think the third suggestion might still be an option. You could still have status information similar to that of a service by making the program handle this in its own way. Your application could have a socket open for its cross-process communication. The background process could open a ServerSocket on a known port, and it could listen for status requests.
Your client application that your users are using could attempt to connect to this socket. If the socket connects, the process is running, otherwise it is not.
If you wanted only a "running/not running" status, this would be sufficient, and the ServerSocket could accept() a connection and then immediately shutdown and close the resulting Socket; you don't even have to accept or send any information since the initial connection is all you need.
If you want to keep the ability to startup/shutdown the task, you could use this same ServerSocket for that ability. If you aren't using the socket for any other data (only for the running-or-not mentioned above), you could have the background process terminate upon receiving any data at all on the socket, regardless of what it is, and the client (or whatever you use to shut down the background process) need only connect and send a byte instead of connect and immediately disconnect.
For startup, if you want to restrain the background process to one instance, there are a few ways to easily do that. I think you should be able to configure it via the task scheduler to only allow one instance of the task. Even if not, you could have a background process starting up connect to the given port it would otherwise listen on to see if it gets a connection from something else already there, if yes this is a second instance of it so abort. Or, even simpler yet, the creation of the ServerSocket should automatically fail if you are using a static port number, so just let the new ServerSocket(myPort) fail on its own, catch the exception, and abort. So there are three different ways to ensure that your process is acting like a proper service.
To start it up in the first place, you can tell the task scheduler to start it up on user logon, or on system boot as mentioned before. You can also configure the task so that users can initiate it themselves (if for whatever reason it's not already running), in fact, you could even have the client the user's are interacting with check on the status of the process and possibly start it automatically if it's not already started - try making a new process and exec() a command such as "schtasks /run /tn "Your Task Name""
I think that covers all the bases you mentioned, and then some. And all of the above should be pretty simple. If you do decide that this might be the route you'd like to take and if either I've overlooked something or you have other criteria which further restrict you from this, let us know again.
In the end I implemented a work-around using Windows scheduled tasks, similar to what is described above, but instead of implementing my own 'start/stop' interface, I wrote a Windows service that manages my program, run as a task. When the service starts, it starts a task, and when the service is asked to stop, is stops the task. So instead of using a socket for the parent to query if the child is running, I use schtasks /Query and parse the output. To make the task exit if the parent exits, I used an RMI keepalive method on my app that was already there.
Windows scheduled tasks have some undesirable defaults for a service that are modifiable through the task scheduler GUI, but not through schtasks' command-line options - namely ExecutionTimeLimit, DisallowStartIfOnBatteries, StopIfGoingOnBatteries.) But these options can be queried and modified using the '/XML' option to schtasks /Query and /Create. So that's what I did.
I also needed to detect if I'm running on a newer or older version of Windows, because if it's an older version (without UAC) then this will all be unnecessary but more importantly defining the task will not work without supplying a password, because the /NP option to schtasks is not available.
The only weakness (other than being complicated) that I know of with my implementation is due to schtasks' note on the /NP option - "Only local resources are available." This turns out to mean that mapped network drives won't be accessible (and I hope that's all it means.) I have SMB support implemented independently, in Java, in my app where it is needed, so this weakness wasn't the end of the world.
This was a lot of work for what can probably be done with a single Win32 call. Maybe one day I will figure out how to do that.

Is it possible to kill a Java Virtual Machine from another Virtual Machine?

I have a Java application that launches another java application. The launcher has a watchdog timer and receives periodic notifications from the second VM. However, if no notifications are received then the second virtual machine should be killed and the launcher will perform some additional clean-up activities.
The question is, is there any way to do this using only java? so far I have to use some native methods to perform this operation and it is somehow ugly.
Thanks!
I may be missing something but can't you call the destroy() method on the Process object returned by Runtime.exec()?
You can use java.lang.Process to do what you want. Once you have created the nested process and have a reference to the Process instance, you can get references to its standard out and err streams. You can periodically monitor those, and call .destroy() if you want to close the process. The whole thing might look something like this:
Process nestedProcess = new ProcessBuilder("java mysubprocess").start();
InputStream nestedStdOut = nestedProcess.getInputStream(); //kinda backwards, I know
InputStream nestedStdErr = nestedProcess.getErrorStream();
while (true) {
/*
TODO: read from the std out or std err (or get notifications some other way)
Then put the real "kill-me" logic here instead of if (false)
*/
if (false) {
nestedProcess.destroy();
//perform post-destruction cleanup here
return;
}
Thread.currentThread().sleep(1000L); //wait for a bit
}
Hope this helps,
Sean
You could also publish a service (via burlap, hessian, etc) on the second JVM that calls System.exit() and consume it from the watchdog JVM. If you only want to shut the second JVM down when it stops sending those periodic notifications, it might not be in a state to respond to the service call.
Calling shell commands with java.lang.Runtime.exec() is probably your best bet.
The usual way to do this is to call Process.destroy()... however it is an incomplete solution since when using the sun JVM on *nix destroy maps onto a SIGTERM which is not guaranteed to terminate the process (for that you need SIGKILL as well). The net result is that you can't do real process management using Java.
There are some open bugs about this issue see:
link text
OK the twist of the gist is as follows:
I was using the Process API to close the second virtual machine, but it wouldn't work.
The reason is that my second application is an Eclipse RCP Application, and I launched it using the eclipse.exe launcher included.
However, that means that the Process API destroy() method will target the eclipse.exe process. Killing this process leaves the Java Process unscathed. So, one of my colleagues here wrote a small application that will kill the right application.
So one of the solutions to use the Process API (and remove redundant middle steps) is to get away with the Eclipse launcher, having my first virtual machine duplicate all its functionality.
I guess I will have to get to work.
java.lang.Process has a waitFor() method to wait for a process to die, and a destroy() method to kill the subprocess.
You can have the java code detect the platform at runtime and fire off the platform's kill process command. This is really an refinement on your current solution.
There's also Process.destroy(), if you're using the ProcessBuilder API
Not exactly process management, but you could start an rmi server in the java virtual machine you are launching, and bind a remote instance with a method that does whatever cleanup required and calls System.exit(). The first vm could then call that remote method to shutdown the second vm.
You should be able to do that java.lang.Runtime.exec and shell commands.

Categories

Resources