I was trying to use a restartApplication method that I found on stack overflow, but for some reason it only will restart my application once. For example, in this simple JOptionPane program below, if the user enters the letter "a", it will restart the program. Once the program restarts, if the user types in "a" again, it just terminates the execution. How can I enable it to restart itself continuously?
I added in some println() statements to see if I could get any more info, and it just confirmed that the program is ending right after I type in the letter "a" on the second time around.
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import javax.swing.JOptionPane;
public class JOptionTest{
public static void restartApplication()
{
final String javaBin = System.getProperty("java.home") + File.separator + "bin" + File.separator + "java";
final File currentJar = new File("C:\\Documents and Settings\\My Documents\\hello3.jar");//UpdateReportElements.class.getProtectionDomain().getCodeSource().getLocation().toURI());
/* is it a jar file? */
if(!currentJar.getName().endsWith(".jar"))
return;
/* Build command: java -jar application.jar */
final ArrayList<String> command = new ArrayList<String>();
command.add(javaBin);
command.add("-jar");
command.add(currentJar.getPath());
final ProcessBuilder builder = new ProcessBuilder(command);
try {
builder.start();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.exit(0);
}
public static void main(String[] args){
String str = JOptionPane.showInputDialog(null, "Enter some text",1);
System.out.println(str);
//String a= "a";
if (str.equals("a")){
System.out.println(str+ "right about to restart");
restartApplication();
}
}
}
See this line?
System.exit(0);
you are calling restartApplication a Single time and when it ends you exit the java process.
If you want to restart continuously, then remove this line and probably iterate forever:
public static void restartApplication()
{
while(true){
final String javaBin = System.getProperty("java.home") + File.separator + "bin" + File.separator + "java";
final File currentJar = new File("C:\\Documents and Settings\\XBBKKYL\\My Documents\\hello3.jar");//UpdateReportElements.class.getProtectionDomain().getCodeSource().get Location().toURI());
/* is it a jar file? */
if(!currentJar.getName().endsWith(".jar"))
return;
/* Build command: java -jar application.jar */
final ArrayList<String> command = new ArrayList<String>();
command.add(javaBin);
command.add("-jar");
command.add(currentJar.getPath());
final ProcessBuilder builder = new ProcessBuilder(command);
try {
builder.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
I have not tested this, it's just an idea
Related
I am trying to run a command from Java that will start a process that runs for several minutes. I need to just trigger the command and get the process handle and continue with other operations in a loop. At regular intervals, I will have to monitor that the process is still active.
I also need the console window to display to show the output of the process for the user.
Currently, I have tried methods from both Runtime and ProcessBuilder classes to run my command but neither of them has helped me achieve my objective.
Sample code:
//Changing the directory and running Maven exec: java command on the POM file in that directory.
String cmd = "cd C:/Test & mvn exec:java";
String finalCmd = "cmd /c \""+ cmd +"\"";
Process process = Runtime.getRuntime().exec(finalCmd);
Thread.sleep(10);
boolean alive = process.isAlive();
The value of variable alive is True, but I don't see the process got started. When the program execution is complete, only then the process starts and I am not sure why that happens.
Also to display the console window, I found from google that I need to use the below command:
String finalCmd = "cmd /c start cmd.exe /c \"" + cmd + "\"";
However, with this, the process starts immediately but I do not get the process handle as I find the alive variable shows false.
Does someone know how this objective can be achieved? I am ok if it's not possible to do both at the same time but at least I need to get the process execution to start and get the handle to monitor the process state later in my code.
Couple of things that are happening incorrectly here:
We need to pass our command as string tokens to the exec() command
We need to wait for the process to exit with process.waitFor() instead of sleeping, this will block the current thread so if you don't want that you need to execute this in another thread or use an ExecutorService.
Advisable to check the output value of waitFor() to see if our command executed properly (value of 0) or not (any other value,
typically a positive 1 in case of unsuccessful execution)
Optionally (to see the output) we need to redirect the standard OUT and ERR somewhere, say print it to console(), though you could put it to a file some GUI window etc.
So at a minimum the following code should work:
Process process = Runtime.getRuntime().exec(new String[] {"cmd", "/c", "cd", "C:\\dev", "&&", "dir"});
int outputVal = process.waitFor();
boolean alive = process.isAlive();
System.out.format("alive %s, outputVal: %d\n",alive, outputVal);
Further suggestions:
use ProcessBuilder instead of runTime.exec(), it allows more control
and is the recommended way since JDK 1.5
read the inputStream
So the code will look some thing like this:
List<String> cmdList = Arrays.asList("cmd", "/c", "cd", "C:\\dev", "&&", "dir");
ProcessBuilder pb = new ProcessBuilder(cmdList);
pb.redirectErrorStream(true); //redirect STD ERR to STD OUT
Process process = pb.start();
try (final BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
String line = null;
while ((line = br.readLine()) != null) {
System.out.println("std-out-line: " + line);
}
}
int outputVal = process.waitFor();
System.out.format("outputVal: %d\n", outputVal);
Since waitFor() is a blocking call, you can execute this in a separate thread or using an executorService. Sample code here:
final StringBuffer outputSb = new StringBuffer();
ExecutorService executorService = null;
try {
executorService = Executors.newSingleThreadExecutor();
final Future<Integer> future = executorService.submit(new Callable<Integer>() {
#Override
public Integer call() throws Exception {
try (final BufferedReader br = new BufferedReader(
new InputStreamReader(process.getInputStream()))) {
String line = null;
while ((line = br.readLine()) != null) {
outputSb.append("std-out-line: ");
outputSb.append(line);
outputSb.append('\n');
}
}
int exitValue = process.waitFor();
System.out.format("exitValue: %d\n", exitValue);
return exitValue;
}
});
while (!future.isDone()) {
System.out.println("Waiting for command to finish doing something else..");
Thread.sleep(1 * 1000);
}
int exitValue = future.get();
System.out.println("Output: " + outputSb);
} finally {
executorService.shutdown();
}
Here's a solution that uses WMIC.
public static void main( String[] args ) throws Exception {
// Vars
Process process;
String output;
// Execution
process = Runtime.getRuntime().exec("cmd /c wmic process call create calc.exe | findstr ProcessId");
output = readTrimmedOutput(process.getInputStream());
System.out.println("Output from command: " + output);
// Basic string manipulation to get process id
String str_proc_id = output.split(" = ")[1].replace(";","");
System.out.println("ProcessId is: " + str_proc_id);
// Some thread delay that you can comment/uncomment for testing if running or not
Thread.sleep(5000);
// Finding if process is still running
process = Runtime.getRuntime().exec("cmd /c wmic process get processid | findstr " + str_proc_id);
output = readTrimmedOutput(process.getInputStream());
boolean isRunning = output.contains(str_proc_id);
System.out.println("Is process still running? " + isRunning);
}
private static String readTrimmedOutput(InputStream is) throws Exception {
BufferedReader breader = new BufferedReader(new InputStreamReader(is));
String line = breader.readLine();
return line != null ? line.trim() : "";
}
Sample output
Output from command: ProcessId = 6480;
ProcessId is: 6480
Is process still running? true
For showing/displaying cmd console change some lines to:
// Execution
String your_command = "cmd.exe /c \"dir\"";
process = Runtime.getRuntime().exec("cmd /c wmic process call create \"" + your_command + "\" | findstr ProcessId");
References:
https://msdn.microsoft.com/en-us/library/aa394531(v=vs.85).aspx
https://www.computerhope.com/wmic.htm
since I didn't quite understand what you really need,i brought a comprehensive example of openning cmd from a java class (for instance class A) and starting a process of another java class (class B) and doing some operation from class B while class B is informing class A of whether it is processing yet or not. so the whole thing is to excecute class B from command promt that class A started and sending information from class B to A to notify it that it's still running.
in my example i took Main class as class A and myProcess class as class B.
as you can see in code below the Main class is Opening cmd and is executing myProcess class then myProcess class is sending a information about the process through the socket that was created in Main class
//imports
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
//class
public class Main
{
//fields
//methods
public static void main(String[] args) throws Exception
{
Runtime run = Runtime.getRuntime();
String new_dir = "C:\\Users\\Parsa\\Desktop\\New folder (2)";//imagine the directory of myProcess.class is in this folder
startServer();
run.exec("cmd.exe /c cd \""+new_dir+"\" & start cmd.exe /k \"java myProcess\"");
}
public static void startServer()
{
Thread myThread = new Thread()
{
#Override
public void run()
{
ServerSocket ss;// creating an open port for receiving data from network
try {
ss = new ServerSocket(60010);//open port number 60010--> it can really be anything that is empty
Socket s = ss.accept();//Listens for a connection to be made to this socket and accepts it
BufferedReader in = new BufferedReader(
new InputStreamReader(s.getInputStream()));//get the inputstream and change it to a buffered reader in order to get a string from remote network
String line = null;
while ((line = in.readLine()) != null) //read the input
{
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
};
myThread.start();
}
}
myProcess class:
by the way you need to compile the myProcess class manually by command prompt and excecute myProcess.class file from Main class
and the myProcess class is
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.net.URL;
import java.net.URLConnection;
import java.net.UnknownHostException;
import java.util.Timer;
import java.util.TimerTask;
public class myProcess extends Thread
{
//field
//methods
public static void main(String[] args) throws Exception
{
System.out.println("myProcess has started");
startSender();
}
public static void startSender()
{
Thread myThread = new Thread()
{
#Override
public void run()
{
try
{
Socket s = new Socket("localhost", 60010);
BufferedWriter out = new BufferedWriter(
new OutputStreamWriter(s.getOutputStream()));
for(int i = 0 ; i<10 ; i++)
{
out.write("Process in running");
out.newLine();
out.flush();
Thread.sleep(200);
}
out.close();
//do whatever here
System.out.println("myProcess output");
}
catch (Exception e)
{
e.printStackTrace();
}
}
};
myThread.start();
if(!myThread.isAlive())
{
System.out.println("myProcess has finished");
}
}
}
since i didn't exactly understand what you wanted ,this is probably not exactly what you want, but... it will definitely help you if you manipulate the code.
I believe that you need to launch you application as the process and not the CMD and then launch a child process of the CMD. It is the same as in Linux.
The CMD that you launched is alive=true but when you started java from that CMD is another process which is a child of the CMD but it will not return you the expected results.
HTH,
Gal
PS. you might want to take a look at https://commons.apache.org/proper/commons-exec/ which is superior in functionality to Java in my opinion.
I have one requirement where I need to start and stop postgreSQL service through java code. I have written below code but I am getting below error:
System error 5 has occurred.
Access is denied.
System error 5 has occurred.
Access is denied.
Below is my code:
package frontend.guifx.pginstallation;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import common.core.Logger;
import frontend.guifx.util.ConstPG;
public class StartAndStopPostgres {
public static String version = "9.5";
public static void main(String[] args){
try {
System.out.println("Execution starts");
copyPostgreSqlConfFileAndRestartPg();
System.out.println("Execution finished");
} catch (IOException | InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static void copyPostgreSqlConfFileAndRestartPg() throws IOException, InterruptedException {
// TODO Auto-generated method stub
Path path = Paths.get("data/PGLogs");
//if directory exists?
if (!Files.exists(path)) {
try {
Files.createDirectories(path);
} catch (IOException e) {
//fail to create directory
e.printStackTrace();
}
}
Logger.print(StartAndStopPostgres.class, new String[] { "Copying postgresql.conf file ........" });
Path source = Paths.get("data/postgresql.windows.conf");
String copyConfFileTo = getInstallationPath(version);
copyConfFileTo = copyConfFileTo.substring(0, copyConfFileTo.lastIndexOf("\\"));
Path outputDirectoryPath = Paths.get(copyConfFileTo+File.separator+"data");
Files.copy(source, outputDirectoryPath.resolve(outputDirectoryPath.getFileSystem().getPath("postgresql.conf")), StandardCopyOption.REPLACE_EXISTING);
Logger.print(StartAndStopPostgres.class, new String[] { "Tunning datbase starts........" });
Runtime rt = Runtime.getRuntime();
final File file = new File(System.getProperty("java.io.tmpdir") + File.separator + ConstPG.CREATE_RESTART_PG_BAT_FILE);
PrintWriter writer = new PrintWriter(file, "UTF-8");
writer.println("net stop postgresql-x64-"+version);
writer.println("net start postgresql-x64-"+version);
writer.close();
String executeSqlCommand = file.getAbsolutePath();
Process process = rt.exec(executeSqlCommand);
/*final List<String> commands = new ArrayList<String>();
commands.add("cmd.exe");
commands.add("/C");
commands.add("net stop postgresql-x64-9.5");
commands.add("net start postgresql-x64-9.5");
ProcessBuilder b = new ProcessBuilder(commands);
Process process = b.start();*/
//public static final String PG_RESTART_PG_LOG_FILE = PG_LOGS+"/pgRestartProcess.log";
File createPgRestartProcessFile = new File(ConstPG.PG_RESTART_PG_LOG_FILE);
redirectProcessExecutionOutput(process, createPgRestartProcessFile);
int exitVal = process.waitFor();
Logger.print(StartAndStopPostgres.class, new String[] { "EXIT VALUE after tunning the PostgreSql database :::::::::::::::::::::" + exitVal + " Logs written to file at: " + createPgRestartProcessFile.getAbsolutePath() });
}
public static String getInstallationPath( String version) {
//public static final String PROGRAMME_FILES = "C:\\Program Files\\";
// public static final String PROGRAMME_FILES_X86 = "C:\\Program Files (x86)\\";
// public static final String POSTGRESQL = "PostgreSQL";
// public static final String PSQL_PATH = "\\bin\\psql.exe";
//Const values used below are as above
String psql = findFile(ConstPG.PROGRAMME_FILES, ConstPG.POSTGRESQL + "\\" + version + ConstPG.PSQL_PATH);
if (psql == null) {
psql = findFile(ConstPG.PROGRAMME_FILES_X86, ConstPG.POSTGRESQL + "\\" + version + ConstPG.PSQL_PATH);
}
if(psql != null){
psql = psql.substring(0, psql.lastIndexOf("\\"));
}
return psql;
}
public static String findFile(String directoryName, String fileName) {
File directory = new File(directoryName);
// get all the files from a directory
File[] fList = directory.listFiles();
String absolutePath;
if (fList != null) {
for (File file : fList) {
if (file.isFile()) {
absolutePath = file.getAbsolutePath();
if (absolutePath.contains(fileName))
return (absolutePath);
} else if (file.isDirectory()) {
absolutePath = findFile(file.getAbsolutePath(), fileName);
if (absolutePath != null)
return (absolutePath);
}
}
}
return (null);
}
private static void redirectProcessExecutionOutput(Process process, File processFile) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String line = null;
FileWriter fw = new FileWriter(processFile.getAbsoluteFile());
BufferedWriter bw = new BufferedWriter(fw);
while ((line = reader.readLine()) != null) {
Logger.print(StartAndStopPostgres.class, new String[] { line });
bw.write(line);
bw.newLine();
}
bw.close();
}
}
If I start my eclipse as an Administrator then this works fine. Also if I run start and stop commands on command prompt (which is opened as an Administrator i.e. right click on command prompt icon and click 'run as Administrator') then they execute successfully. But if I run the commands on normal command prompt (which is not opened as a administrator) then I get the same error there as well.
Please advise if there is any solution or any approach to solve this problem.
In java there is a option to run windows cmd as administrator
replace your code "commands.add("cmd.exe");" with below code and try
commands.add("runas /profile /user:ADMINUSERNAME \"cmd.exe");
I'm trying toopen/execute another program, which is a .jar file, but I'm getting the following error:
it is not a windows application
(java.io.IOException: CreateProcess error=193)
Here is my code:
import java.io.IOException;
public class Test8 {
public static void main(String[] args) {
try {
String filepath = "C://Users//Alex//Desktop//Speedtest.jar";
Process p = Runtime.getRuntime().exec(filepath);
} catch (IOException e) {
e.printStackTrace();
}
}
}
At the command-line, JARs are executed with java -jar. Try passing a String array:
String[] args = new String[] {"java", "-jar", "/path/to/myJar.jar"};
Process p = Runtime.getRuntime().exec(args);
I have been creating a program that writes and run java classes. So far I have been able to write a "Runable.java" class but not able to run it. I have tried to run a "runjava.bat" and get the .bat to run the "Runable.java" class but I keep getting a "Error: Could not find or load main class application.Runable.class". I was wondering what I am doing wrong or if there is a better way to go about running a java class from within a java program?
Here is my code(Simplify Slightly):
Main.java:
package application;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Platform;
import javafx.stage.FileChooser;
public class Main {
final static String Program =
"package application;\n"
+ "public class Runable {\n"
+ "public static void main(String[] args) {\n"
+ "System.out.println(\"Hello\");\n"
+ "}\n"
+ "}\n";
public static void main(String[] args) throws IOException {
Scanner s = new Scanner(System.in);
while(true){
System.out.println("State a comand.");
String Command = s.nextLine();
if (Command.equalsIgnoreCase("Write") || Command.equalsIgnoreCase("Save")){
FileChooser fileChooser = new FileChooser();
//Set extension filter
FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("TXT files (*.txt)", "*.txt");
fileChooser.getExtensionFilters().add(extFilter);
//Show save file dialog
File file = new File("src/application/Runable.class");
if(file != null){
SaveFile(Program, file);
}
}
else if (Command.equalsIgnoreCase("Run") || Command.equalsIgnoreCase("Play")){
ProcessBuilder builder = new ProcessBuilder(
"src/runjava.bat");
builder.redirectErrorStream(true);
Process p = builder.start();
BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while (true) {
line = r.readLine();
if (line == null) { break; }
System.out.println(line);
}
}
else if (Command.equalsIgnoreCase("End") || Command.equalsIgnoreCase("Exit")){
Platform.exit();
}
else{
System.err.println("Command not recognized.");
System.err.println("Please try again.");
}
}
}
private static void SaveFile(String content, File file){
try {
FileWriter fileWriter = null;
fileWriter = new FileWriter(file);
fileWriter.write(content);
fileWriter.close();
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
runjava.bat:
javac "src\application\Runable.java"
java application.Runable.class
and Runable.java if you didn't get it from the Main.java:
package application;
public class Runable {
public static void main(String[] args) {
System.out.println("Hello");
}
}
The java command expects a class name, not a filename. Unless your class is called "class" in the package "application.Runable" (which it isn't) you probably wanted to use:
java application.Runable
Because you can't execute a .java file like that. You must first compile it to get a .class file, and change the code that executes the class to point to Runable.class
The reason it is not running, is because the .java file is the code you type, and the .class file is the compiled version of the code that Java Virtual Machine executes.
Another solution to compile and run the program compared to executing the .bat file is to use the javax.tools API or another library based off of it. I have found InMemoryJavaCompiler library that makes it easy to compile and run the programs. This approach means that the program will run on the same JVM as your UI which may be helpful.
The following code shows how you might invoke the program using the library.
try{
Class<?> clazz = InMemoryJavaCompiler.compile("apllication.Runable", Program);
clazz.getMethod("main", String[].class).invoke(null, new String[0]);
}catch(Exception e){
e.printStackTrace();
}
In your Main.java's "Run" block, you should have
ProcessBuilder builder = new ProcessBuilder("runjava.bat");
In your runjava.bat, you should have (as immibis said)
javac -d . src/application/Runable.java
java application.Runable
** not Runable.class in the second line.
And runjava.bat should be placed in parallel with the parent folder of application\ but not the src\application folder. In other words, you should have something like classes\runjava.bat, classes\application\Main.class and classes\application\Runable.class. Hope it helps.
I have the following code segment to run a bat file:
String workingDir = System.getProperty("user.dir");
ProcessBuilder pb = new ProcessBuilder("cmd", "/c",
"\"" + workingDir + File.separator + "midl.bat\"");
Process ddsBuildProc = pb.start();
ddsBuildProc.waitFor();
The workingDir includes spaces in the path. Eventhough I use quotes to enclose the workingDir+fileName string, the shell still splits the workingDir and doesn't run the bat file. If a try and copy-paste-execute the bat file path string in the Windows command window manually, it works as expected. What can be the problem here?
Also, please do not close this question as duplicate because I tried all the solutions in the other questions with no success.
Don't quote commands in a command list, unless the command been executed expects it, this will just stuff things up
user.dir is your programs current executing context...so it actually makes no sense to include it, you could just use midl.bat by itself (assuming the command exists within the current execution context)
I wrote a really simple batch file...
#echo off
dir
Which I put in my "C:\Program Files" directory, as I need a path with spaces and used....
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
public class RunBatch {
public static void main(String[] args) {
ProcessBuilder pb = new ProcessBuilder(
"cmd", "/c", "listme.bat"
);
pb.directory(new File("C:/Program Files"));
pb.redirectError();
try {
Process process = pb.start();
InputStreamConsumer.consume(process.getInputStream());
System.out.println("Exited with " + process.waitFor());
} catch (IOException | InterruptedException ex) {
ex.printStackTrace();
}
}
public static class InputStreamConsumer implements Runnable {
private InputStream is;
public InputStreamConsumer(InputStream is) {
this.is = is;
}
public static void consume(InputStream inputStream) {
new Thread(new InputStreamConsumer(inputStream)).start();
}
#Override
public void run() {
int in = -1;
try {
while ((in = is.read()) != -1) {
System.out.print((char) in);
}
} catch (IOException exp) {
exp.printStackTrace();
}
}
}
}
To run it without any issues...