System-independent machine shutdown in Java [duplicate] - java

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Shutting down a computer using Java
I am making a personal program that will shut down my computer after a certain amount of time or at a certain time/date. However, I am running multiple operating systems and want to do this with one simple Java program. Is there any way to send a system-independent machine shutdown request in Java without any using any external libraries? I know you can use java.awt.Desktop.getDesktop().browse(new URI("shutdown /s")); in Windows, but, again, I want system independence.

No. There is not.
This is outside the scope of the JVM or standard Java class library.
Happy coding.

Why not use schedulers? All major operating systems supports such feature(cron, at etc). There may be other factors like permission which comes to play in modern windows (windows 7 ), linux etc.
If you want to really use some system call, Try using JNA. That simplifies platform specific access a lot.

#robjb gave me the best solution. Though it is a little too inflexible for my tastes, I will be suing it until I run into a problem.
String shutdownCommand;
StringPP operatingSystem = new StringPP(System.getProperty("os.name"));
if (operatingSystem.containsIgnoreCase("linux") ||
operatingSystem.containsIgnoreCase("mac") ||
operatingSystem.containsIgnoreCase("unix"))
{
shutdownCommand = "sudo shutdown -h -t 30";
}
else if (operatingSystem.containsIgnoreCase("windows"))
{
shutdownCommand = "shutdown /s /d P:0:0 /t 30 /c \"Blue Husky Timer 2 is shutting down your system, as you requested. \n"
+ "You have 30 seconds to save and close programs\"";
}
else
{
throw new UnsupportedOperationException("Unsupported operating system.");
}
try
{
Runtime.getRuntime().exec(shutdownCommand);
}
catch (Throwable t)
{
Main.LOG.logThrowable(t);
}
System.exit(0);
In the above example, StringPP is a custom class that augments the capabilities of a String with methods such as the above used #containsIgnoreCase. Main.LOG is a logging utility that I made and use.

Related

C# - Stop ServiceProcess wrapper after java process is stopped

I'm building a c sharp serviceProcess that will start a Batch file (the batch file will start a java application).
If i stop the service it kills the java process. Stopping the java process can take up to 2 minutes. The service has to wait for the java application to stop, so i made a sleep.
System.Threading.Thread.Sleep( );
Is it possible to check if the "java" process is closed and after that stop the ServiceProcess.
You can access the process using the Process-class. It allows you to get several information about a specific process. When you start the java.exe directly (using Process.Start) you already have the Process-instance.
When using a batch-file, you need to find the process, which is not a problem at all. You can find a process using Process.GetProcessesByName, but you'd find all all java-processes running on your machine.
You could try something like the following:
Process[] proc = Process.GetProcessesByName("Java");
if (proc.Count() != 0)
{
//Process Alive
Process prod = proc[0];
prod.Kill();
prod.WaitForExit();
}
else
{
//Process Dead
}
A better option would be to use the process ID(if you know it)
Warning: This will kill the first java process it finds, you need to check which one you need to kill...

java api to run windows batch programs? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How do I run a batch file from my Java Application?
Are there Java classes to run Windows batch files? For example, start the batch files and receive the results of the batch runs?
Apache Commons Exec is a good way to go. Solves several problems you'd encounter if using pure ProcessBuilder or Runtime.exec.
From the project description:
Executing external processes from Java is a well-known problem area. It is inheriently platform dependent and requires the developer to know and test for platform specific behaviors, for example using cmd.exe on Windows or limited buffer sizes causing deadlocks. The JRE support for this is very limited, albeit better with the new Java SE 1.5 ProcessBuilder class.
The usual ProcessBuilder stuff works with batch files, as does Runtime#exec. The command you're executing is cmd.exe, the batch file name is an argument to it. I believe the argument sequence is cmd.exe, /c, batch_file_name. (Edit: Yup, and in fact, I found a question here that this question duplicates on SO where that's in the answer.)
Runtime.getRuntime().exec("cmd /c start batFileName.bat"); should work.
But to read the output from java process, remove start from the above comman.
Yes, according to my knowledge, RunTime classe can. And ofcourse, ProcessBuilder also like that. I have run number of batch files using Java. Following is the google search result. It has links which are equally important
GOOGLE RESULT
If you want to use native Java and no 3rd party packages then try this using Runtime and Process. I'm not the best Java coder in the world but this should get what you want. It might need some modification to add a loop for reading everything from the input stream.
import java.util.*;
import java.lang.*;
import java.io.*;
public class test
{
public static void main(String args[])
{
try
{
Runtime rt = Runtime.getRuntime();
Process batch = rt.exec("test.bat");
batch.waitFor();
//exitValue() contains the ERRORLEVEL from batch file
System.out.println(batch.exitValue());
//getInputStream will get all output from stdout
//getErrorStream will get all error output from stderr
InputStream inStream = batch.getInputStream();
byte[] text = new byte[inStream.available()];
inStream.read(text);
System.out.println(new String(text));
}
catch (IOException ex)
{
}
catch (InterruptedException ex)
{
}
}
}

How do I find the process ID (pid) of a process started in java? [duplicate]

This question already has answers here:
How to get PID of process I've just started within java program?
(18 answers)
Closed 9 years ago.
If I get a process object in Java through Runtime.getRuntime().exec(...), or ProcessBuilder.start(), I can wait for it through Process.waitFor(), which is like Thread.join(), or I could kill it with Process.destroy(), which is like the deprecated Thread.stop().
BUT: How do I find the pid of the Process Object? I don't see a method for doing that in The Official Documentation. Can I do this in Java? If so, how?
This guy calls out to bash to get the PID. I'm not sure if there is an java solution to the problem.
/**
* Gets a string representing the pid of this program - Java VM
*/
public static String getPid() throws IOException,InterruptedException {
Vector<String> commands=new Vector<String>();
commands.add("/bin/bash");
commands.add("-c");
commands.add("echo $PPID");
ProcessBuilder pb=new ProcessBuilder(commands);
Process pr=pb.start();
pr.waitFor();
if (pr.exitValue()==0) {
BufferedReader outReader=new BufferedReader(new InputStreamReader(pr.getInputStream()));
return outReader.readLine().trim();
} else {
System.out.println("Error while getting PID");
return "";
}
}
Source:
http://www.coderanch.com/t/109334/Linux-UNIX/UNIX-process-ID-java-program
Similar to the other tools mentioned, there is the jps command line tool that comes with the Java runtime. It spits out the PIDs of all running JVMs. The benefit is the output one needs to parse is confined to only the JVM processes.
Leo, after looking into this issue for about a week myself I think Jhurtado's approach is likely the "best" approach we can manage in Java right now. "best" is in quotes because it has the very nasty side effect of basically being a "guess" at what your child PID is.
If your Java app is spawning native processes quickly in a high-load system, there is NO guarantee that the PID you pickup in your diff calculation is the PID of the Process started by the current Thread or that the PID of the process you pick was even spawned by our app (maybe the host system was already running that process anyway).
That being said, if you are not spawning dozens of processes or the native Process you are spawning is really unique (some custom util you ship with your app) then this approach works fine in which case the PID of the native process you are looking for is the one you want.
On windows you can use 'tasklist' as Jhurtado pointed out to get the full list of PIDs and filter for the one you want (using the /FI filter switch didn't work for me in testing).
On any *nix system you can use "ps ax | grep " where NAME is some process name like 'nginx' or 'httpd' that you want to filter for to get your list.
Additionally, if you need to kill stray processes (for example, on VM exit) on *nix you can of course use "kill -9 " and on Windows, interestingly enough, you can use 'taskkill '.
Hardly optimal unfortunately.
I ran into the same issue as you. I found a pretty decent solution, I recommend a slight sleep before it thought to ensure the process has officially started up.
Process p = Runtime.getRuntime().exec("cmd /c tasklist");
StringWriter writer = new StringWriter();
IOUtils.copy(p.getInputStream(), writer);
String theString = writer.toString();
//System.out.println(theString);
id = findLastString("javaw.exe .{1,} Console 1", theString);
System.out.println(id);
where findLastString is defined as
public static String findLastString(String pattern, String in) {
Pattern p = Pattern.compile(pattern);
Matcher matcher = p.matcher(in);
String it= "";
while(matcher.find()) {
it = matcher.group();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
int firstIndex=pattern.indexOf(".{1,}");
int lastIndex=it.substring(firstIndex).indexOf(pattern.substring(pattern.indexOf(".{1,}")+5))+firstIndex;
String dotOn = it.substring(pattern.indexOf(".{1,}"));
it=it.substring(firstIndex, lastIndex);
return it;
}
Basically this will get the list of running processes, and find the most recently ran one with, in this instance, the name javaw.exe (My program was starting a separate java process). You can replace javaw.exe with the name of the process, which you can find by using Task Manager. You will need to get the Apache common IO jar too.
I think in Java your best shot is to get the tasklist before and after spawning your child process. Make a diff and get your PID.
you can get the Tasklist by issuing a Runtime.getRuntime.exec("tasklist");
Notice that tasklist.exe is not included with Windows XP Home edition, but still you can download it.

How to stop the execution of Java program from Command line?

My main field is .Net but recently I have got something to do with Java. I have to create a shell utility in Java that could run in background reading few database records after specified duration and do further processing. It's a kind of scheduler. Now I have few concerns:
How to make this work as a service. I want to execute it through a shell script and the utility should start running. Off course the control should get back to the calling script.
Secondly, eventually i may want to stop this process from running. How to achieve this?
I understand these are basic question but I really have no idea where to begin and what options are best for me.
Any help / advise please?
I would go for the running the program using a scheduler or a service. However, if you wish to use a bat file and do this programmatically, I have outlined a possible approach below:
In your Java program, you can get the PID programmatically, and then write it to a file:
public static void writePID(String fileLocation) throws IOException
{
// Use the engine management bean in java to find out the pid
// and to write to a file
if (fileLocation.length() == 0)
{
fileLocation = DEFAULT_PID_FILE;
}
String pid = ManagementFactory.getRuntimeMXBean().getName();
if (pid.indexOf("#") != -1)
{
pid = pid.substring(0, pid.indexOf("#"));
}
BufferedWriter writer = new BufferedWriter(new FileWriter(fileLocation));
writer.write(pid);
writer.newLine();
writer.flush();
writer.close();
}
You can then write a stop .bat file that will kill the running program in windows. You could do something like:
setlocal
IF EXIST app.pid FOR /F %%i in ('type app.pid') do TASKKILL /F /PID %%i
IF EXIST app.pid DEL app.pid
endlocal
Of course, app.pid is the file written by the Java method above.
I am not sure how you would be able to write a script that launches a java program, and reverts control on termination. I would be interested to see if anybody has a solution for that.
I assume that you are playing your java program with a Linux/Unix box.
To run your application as a daemon, you can try
nohup java YourJavaClass &
To stop your application, you can either:
kill [psIdofYourApplication]
or
fg [your application job Id]
Ctrl-C
If you want to do some postprocessing after the application receiving 'kill/stop' signal. check out addShutdownHook(Thread hook)
Or sun.misc.SignalHandler
ps ux
see pid
kill pid
Or you'd better provide a stopping script that signals the application, which does System.exit(0)
You didn't specify the platform. If on Windows you should look into integrating with the Service Control to create a Windows service. http://en.wikipedia.org/wiki/Windows_service. Once you've implemented the service hooks, it is possible to start and stop the service through the service control GUI or using net stop MyService syntax from the command line.
As I understand, you want something like this:
if ( System.in.avaliable() > 0 ) {
in = new BufferedReader( new InputStreamReader( System.in );
String InLine = in.readLine();
...
}
Am I right?

How do I launch a completely independent process from a Java program?

I am working on a program written in Java which, for some actions, launches external programs using user-configured command lines. Currently it uses Runtime.exec() and does not retain the Process reference (the launched programs are either a text editor or archive utility, so no need for the system in/out/err streams).
There is a minor problem with this though, in that when the Java program exits, it doesn't really quit until all the launched programs are exited.
I would greatly prefer it if the launched programs were completely independent of the JVM which launched them.
The target operating system is multiple, with Windows, Linux and Mac being the minimum, but any GUI system with a JVM is really what is desired (hence the user configurability of the actual command lines).
Does anyone know how to make the launched program execute completely independently of the JVM?
Edit in response to a comment
The launch code is as follows. The code may launch an editor positioned at a specific line and column, or it may launch an archive viewer. Quoted values in the configured command line are treated as ECMA-262 encoded, and are decoded and the quotes stripped to form the desired exec parameter.
The launch occurs on the EDT.
static Throwable launch(String cmd, File fil, int lin, int col) throws Throwable {
String frs[][]={
{ "$FILE$" ,fil.getAbsolutePath().replace('\\','/') },
{ "$LINE$" ,(lin>0 ? Integer.toString(lin) : "") },
{ "$COLUMN$",(col>0 ? Integer.toString(col) : "") },
};
String[] arr; // array of parsed tokens (exec(cmd) does not handle quoted values)
cmd=TextUtil.replace(cmd,frs,true,"$$","$");
arr=(String[])ArrayUtil.removeNulls(TextUtil.stringComponents(cmd,' ',-1,true,true,true));
for(int xa=0; xa<arr.length; xa++) {
if(TextUtil.isQuoted(arr[xa],true)) {
arr[xa]=TextDecode.ecma262(TextUtil.stripQuotes(arr[xa]));
}
}
log.println("Launching: "+cmd);
Runtime.getRuntime().exec(arr);
return null;
}
This appears to be happening only when the program is launched from my IDE. I am closing this question since the problem exists only in my development environment; it is not a problem in production. From the test program in one of the answers, and further testing I have conducted I am satisfied that it is not a problem that will be seen by any user of the program on any platform.
There is a parent child relation between your processes and you have to break that.
For Windows you can try:
Runtime.getRuntime().exec("cmd /c start editor.exe");
For Linux the process seem to run detached anyway, no nohup necessary.
I tried it with gvim, midori and acroread.
import java.io.IOException;
public class Exec {
public static void main(String[] args) {
try {
Runtime.getRuntime().exec("/usr/bin/acroread");
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("Finished");
}
}
I think it is not possible to to it with Runtime.exec in a platform independent way.
for POSIX-Compatible system:
Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c", "your command"}).waitFor();
I have some observations that may help other people facing similar issue.
When you use Runtime.getRuntime().exec() and then you ignore the java.lang.Process handle you get back (like in the code from original poster), there is a chance that the launched process may hang.
I have faced this issue in Windows environment and traced the problem to the stdout and stderr streams. If the launched application is writing to these streams, and the buffer for these stream fills up then the launched application may appear to hang when it tries to write to the streams. The solutions are:
Capture the Process handle and empty out the streams continually - but if you want to terminate the java application right after launching the process then this is not a feasible solution
Execute the process call as cmd /c <<process>> (this is only for Windows environment).
Suffix the process command and redirect the stdout and stderr streams to nul using 'command > nul 2>&1'
It may help if you post a test section of minimal code needed to reproduce the problem. I tested the following code on Windows and a Linux system.
public class Main {
/**
* #param args the command line arguments
*/
public static void main(String[] args) throws Exception {
Runtime.getRuntime().exec(args[0]);
}
}
And tested with the following on Linux:
java -jar JustForTesting.jar /home/monceaux/Desktop/__TMP/test.sh
where test.sh looks like:
#!/bin/bash
ping -i 20 localhost
as well as this on Linux:
java -jar JustForTesting.jar gedit
And tested this on Windows:
java -jar JustForTesting.jar notepad.exe
All of these launched their intended programs, but the Java application had no problems exiting. I have the following versions of Sun's JVM as reported by java -version :
Windows: 1.6.0_13-b03
Linux: 1.6.0_10-b33
I have not had a chance to test on my Mac yet. Perhaps there is some interaction occuring with other code in your project that may not be clear. You may want to try this test app and see what the results are.
You want to launch the program in the background, and separate it from the parent. I'd consider nohup(1).
I suspect this would require a actual process fork. Basically, the C equivalent of what you want is:
pid_t id = fork();
if(id == 0)
system(command_line);
The problem is you can't do a fork() in pure Java. What I would do is:
Thread t = new Thread(new Runnable()
{
public void run()
{
try
{
Runtime.getRuntime().exec(command);
}
catch(IOException e)
{
// Handle error.
e.printStackTrace();
}
}
});
t.start();
That way the JVM still won't exit, but no GUI and only a limited memory footprint will remain.
I tried everything mentioned here but without success. Main parent Java process can't quit until the quit of subthread even with cmd /c start and redirecting streams tu nul.
Only one reliable solution for me is this:
try {
Runtime.getRuntime().exec("psexec -i cmd /c start cmd.cmd");
}
catch (Exception e) {
// handle it
}
I know that this is not clear, but this small utility from SysInternals is very helpful and proven. Here is the link.
One way I can think of is to use Runtime.addShutdownHook to register a thread that kills off all the processes (you'd need to retain the process objects somewhere of course).
The shutdown hook is only called when the JVM exits so it should work fine.
A little bit of a hack but effective.

Categories

Resources