Is it possible to check if a Java application is already running and if it is, get an instance of it?
Say i have a jar that the first time it's clicked it opens a frame, and every time after that (until it's closed), it gets that frame and adds an object to it. This also needs to work without the main application having a close() method so the application will work again when reopened if it stops responding or it has been closed with task manager.
Java applications works on different process.
So is not so easy to interact between two different process (already running application and the new one).
What you can do is find a inter process communication mechanism and use it.
Typical inter process communications use files or a common database.
You can store the id of the current main thread executing your java app.
If a new process starts check if there is an already running application.
If yes, you can use the same (or a new one) inter process communication system to send information that the main process should update. Then the secondary process kill itself.
I know this is an old question, but I recently had to get count and PID of running instance in JAVA on Linux. Just thought I would post my solution in case it could help someone in the future. (I have been helped so much in the past, I figured I should pay back a little).
Switch return to lngPidOfrunning for PID of other instance rather than count.
public long checkIsAlreadyRunning(){
//Check if app is already running
long lngCountOfInstances = 0; //Use this to hold how many already running
String strProcessName = "appNameToCheckFor";
//If it is required to also capture app running from within NetBeans, remove the .jar
System.out.println("ps -ef|grep " + strProcessName);
try{
long lngPid = ProcessHandle.current().pid();//PID of this instance of the application
long lngPidOfRunning = 0; //Holder for PID of already running instance
System.out.println(lngPid+""); //Only for verification
Runtime rt = Runtime.getRuntime();
String[] cmd = {"/bin/sh", "-c", "ps -ef|grep " + strProcessName };
Process proc = rt.exec(cmd);
delay_ms(2);//found I needed small delay to ensure buffer was ready
BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
String strLineIn;
StringBuilder strOutput = new StringBuilder();
String strProcessId = "";
while ((strLineIn = reader.readLine()) != null) {
if(!strLineIn.contains("grep") && !strLineIn.contains(String.valueOf(lngPid))) {//ignore is PID is current, or line contais grep
strOutput.append(strLineIn + "\r\n");//Only here for debuging
lngCountOfInstances++;
}
}
reader.close(); //always close the reader
String strReturn = removeDuplicates(strOutput.toString()," "); // remove duplicate spaces frm reteun
String[] strArray = strReturn.split(" ");
if(strArray.length>2){lngPidOfRunning = isLong(strArray[1]);}//Aray index 1 will be PID, isLong checks if valid long and if yes, retunrs long, esle 0;
System.out.println(lngPidOfRunning + " --> " + strReturn); //Only here for debuging
}
catch(Exception ex){
ex.printStackTrace();
err(ex.getMessage(), ex); //remove this, I use funtion to log messages and stacktraces to file
}
//return lngPidOfrunning; //Use this is you would like to use the PID to bring running instance to front
return lngCountOfInstances; //use this if you just want to get count of running instances
}
private long isLong(String strValue){
if(NumberUtils.isParsable(strValue)){
return Long.parseLong(strValue);
}
return 0;
}
Related
I have n Netbeans Java project that connects to the MYSQL, to read data from my database.
But the MYSQL services is not running, and I have to manually start it.
Can I start this service in my code?
Windows Services
This solution is specific to Windows and assumes that the MySQL service name is MySQL80 (as shown in your screenshot). To start the MySQL service if it is not running from Java in Windows:
Create a BAT file containing nothing but NET START MySQL80
Create a shortcut to that BAT file. In Windows File Explorer display the properties of that shortcut, click the Shortcut tab, click the Advanced... button, and check the Run as administrator box:
Run the Java application shown below which will:
Check the status of the MySQL80 service by parsing the output returned by the command sc query MySQL80. See method getServiceState() in the code below.
If the service is not running (because getServiceState() returned "STOPPED"), run the shortcut to the BAT file (as an administrator) to start the service. See method startService() in the code below, and set your value of String shortcut as appropriate.
If the service is already running (getServiceState() returned "RUNNING"), or the service name is not recognized, the code does nothing.
If there is a problem starting the service the error stream is displayed.
This is the code:
package servicestarter;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class ServiceStarter {
public static void main(String[] args) {
try {
ServiceStarter ss = new ServiceStarter();
String serviceName = "MySQL80";
String serviceStatus = ss.getServiceState(serviceName);
if ("STOPPED".equals(serviceStatus)) {
System.out.println("Service " + serviceName + " is stopped. Starting the service...");
String shortcut = "D:\\temp\\netstartmysql80.bat.lnk";
Process process = ss.startService(shortcut);
// Display any error output. Should be nothing there if all goes well...
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
reader.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
private String getServiceState(String serviceName) throws IOException {
String state = "";
Process process = Runtime.getRuntime().exec("cmd.exe /c sc query " + serviceName);
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
if (line.contains("STATE")) {
String[] tokens = line.split("\\s+");
state = tokens[tokens.length - 1];
break;
}
}
reader.close();
return state; // Returns "STOPPED" or "RUNNING", or empty string for invalid service name.
}
private Process startService(String shortcut) throws IOException {
return Runtime.getRuntime().exec("cmd.exe /c " + shortcut);
}
}
Method getServiceState() just parses the content produced by sc query MySQL80 to determine the status ("STATE") of the service:
C:\WINDOWS\system32>sc query MySQL80
SERVICE_NAME: MySQL80
TYPE : 10 WIN32_OWN_PROCESS
STATE : 1 STOPPED
WIN32_EXIT_CODE : 0 (0x0)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x0
WAIT_HINT : 0x0
Notes:
The above code works for me on Windows 10 starting a MySQL 8.0 service named "MySQL80", though it should start any STOPPED service by changing the value of String serviceName, and the name and content of the shortcut that is run.
This approach has a problem which may be a deal breaker: because the service must be started as an administrator you will normally get that familiar prompt from User Account Control when the shortcut to the BAT file is run, asking "Do you want to allow this app to make changes to your device?". You can easily avoid that prompt by running the application from a Command Prompt window that was Run as administrator, but that may not necessarily be a viable approach for you.
This is not a robust solution. If the output generated by SC QUERY {service name} changes this code may break, but I don't know of a Java API to query Windows services directly.
I have a Hadoop YARN cluster set up on some machines at my university (all machines running Linux Fedora 25). When running a mapreduce job in YARN, I am unable to receive the output from a call I make to a separate program. Interestingly, if I run my job locally (configured in mapred-site.xml), my method for calling the program and receiving its output works just fine. Below is my executeShellCommand class, which is instantiated and used in my first map task.
public class ExecuteShellCommand {
public String executeCommand(String command) {
StringBuffer output = new StringBuffer();
Process p;
try {
String [] args = command.split(" ");
String cmd = args[0];
ProcessBuilder pb = new ProcessBuilder().command(cmd, args[1], args[2], args[3], args[4], args[5], args[6], args[7]).directory(new File("path to executable"));
p = pb.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
p.waitFor();
String line = "";
while ((line = reader.readLine())!= null) {
output.append(line + "\n");
}
} catch (Exception e) {
e.printStackTrace();
return e.toString();
}
return output.toString();
}
}
Things I have made sure to check:
1) Permissions are appropriately set for all files/directories needed
2) Map tasks are run as current user (me), so no issues with illegal access
3) I am not receiving a file not found exception, so the path to the program I'm calling is correct
4) Checked the input/output stream for Process p (input stream set as java.lang.UNIXProcess$ProcessPipeInputStream#1000e80, output stream is null)
5) Instead of calling the program I need to use, I have tried a simple "echo" command, and could not receive that output either.
6) I have also tried using
p = Runtime.getRuntime().exec("myCommand")
but the results are the same (no output received)
As I already mentioned, when I run a job locally, my executeCommand method functions perfectly, and returns the output from the program I call. Only in YARN do the issues occur. I have a feeling that the problem caused by either not reading from the correct buffer, or the command issued to ProcessBuilder is never actually executed. I am quite stumped as to how to debug what is going on here, and any tips would be greatly appreciated!
After hours of trying all sorts of solutions, I figured out how to get the error stream from the process spawned with ProcessBuilder. Turns out when I set the working directory for the process, I forgot to update the path to one of the arguments I was passing it. D'oh!!!
This question already has an answer here:
JavaFX 2 StringProperty does not update field until enclosing method returns
(1 answer)
Closed 7 years ago.
I am currently learning JavaFX. I am building an app that takes a file as input, connects to an external server, and returns the parsed results to a MySQL database. The core functionality is working fine, but I would like to have JavaFX update to the user, so that they know they are waiting to connect to the server etc. However, when the method is invoked, the text updates are not visible until the method has completed execution - I would like the updates to occur in real time. The offending method is below:
public void doBlast(){
//this line is not updated until completion of the program - not straight away
status.setText("Connecting to NCBI servers..NCBI" + "\n");
//Biojava API details extracted as it is not relevant
BufferedReader bufferedFileReader = null;
Scanner bufferedScanner = null;
BufferedWriter bufferedWriterXML = null;
String rid = null;
int count = 0;
try {
//this.getFasta() represents the input file
bufferedScanner
= new Scanner(new BufferedReader(new FileReader (this.getFasta())));
//this.getTempXML() is a temporary file for temporary storage of xml output from the server
bufferedWriterXML
= new BufferedWriter (new FileWriter (this.getTempXML(), true));
String line, nextline, query, xmlLine;
//Loops for a specified number of times
while (count < alignmentLimit) {
this.setSequence_id(bufferedScanner.nextLine());
//newline here
bufferedScanner.nextLine();
//this line from the file is used to search a database in the server
query = bufferedScanner.nextLine();
//this line is not updated until completion of the program - not straight away
status.setText("Connecting to NCBI servers.." + "\n");
//below service connects to server
rid = service.sendAlignmentRequest(query, props);
//results
InputStream in = service.getAlignmentResults(rid, outputProps);
//this line is not updated until completion of the program - not straight away
status.setText("Connected to NCBI." + "\n");
bufferedFileReader = new BufferedReader(new InputStreamReader(in));
xmlLine = bufferedFileReader.readLine();
while (xmlLine != null) {
bufferedWriterXML.write("\n" + xmlLine);
xmlLine = bufferedFileReader.readLine();
// have to flush here so that it prints to file;
// the file can then be deleted each loop
bufferedWriterXML.flush();
}
count++;
//this method removes specific strings
this.removeAll("<?xml", "<!DOCTYPE", this.getTempXML(), this.getXML());
//this method fills a database with the data from server
this.xml2mysql();
//file cleaning
this.eraseData(this.getTempXML());
this.eraseData(this.getXML());
bufferedScanner.nextLine();
//this line is not updated until completion of the program - not straight away
numberOfRecords.setText(Integer.toString(count));
}
}
catch (Exception anException){
anException.printStackTrace();
}
finally {
try {
bufferedWriterXML.close();
bufferedScanner.close();
bufferedFileReader.close();
}
catch (Exception anException){
System.out.println("Error: " + anException);
}
}
}
The setText() methods use a FXML-defined fx:id variable and the above method is in a controller.
Much appreciated if anyone can help me out. I have searched everywhere for a solution.
Thanks.
You should look at using a task or service which will place the loading of the file on a background thread.
You can hook into the methods called during the execution:
From Oracle documentation:
Inside the call method, you can use the updateProgress, updateMessage,
updateTitle methods, which update the values of the corresponding
properties on the JavaFX Application thread. However, if the task was
canceled, a return value from the call method is ignored
If you perform the long process on the JavaFX Thread, the UI will be blocked and appear frozen.
I have an executable jar that runs a Java Swing application with an internal SqlLite db.
Users (by mistake) do more than a click on the jar, causing the db lock.
I'd like to prevent this behavior.
What can I do?
thank you very much
You need some kind of synchronization mechanism.
Either you need to code it yourself, or you can create a Java WebStart configuration for your application, where Java WebStart can handle the "only one invocation" through the Single Instance Service (which you must call explicitly in your code).
See http://docs.oracle.com/javase/6/docs/technotes/guides/javaws/developersguide/examples.html#SingleInstanceService for an example.
The first instances accessing the db should acquire a lock of some sort on the db and all further instances should first check if there is already such a lock. If there is one -> "I am not the first, show warning/error, quit.", if there is none "I am the first, get a lock, proceed."
You can use JPS or JNI (need to implement on different platform). The attached is the JPS code to check the Java application instance. You can modify it to more OO.
Using File, Socket or Registry as a lock is not perfect, since there are a lot of chance that a mis-operation can make your application can not start any more (for example, another program occupe the same port)
import java.io.*;
public class TestRun {
public TestRun() {}
public static void main(String args[]) {
String jpsApp = "jps -mlvV";
int count = 0;
try {
Process p = Runtime.getRuntime().exec(jpsApp);
//parser the result to check if TestAPP is running
InputStream is = p.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line = null;
while ((line = reader.readLine()) != null) {
System.out.println();
System.out.println(line);
String[] pair = line.split(" ");
if (pair.length >= 2) {
System.out.println("name is " + pair[1]);
if (pair[1].trim().indexOf("TestRun") > -1) {
count++;
System.out.println("count is " + count);
}
}
}
//it is running, just exit the second instance
if(count>1){
System.out.println("Has run a application!");
return;
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
I have developed a exe of my Java application, and run it from a thumb drive. It will take some time to execute. But my end user thinks it is not running and clicks for the second time. I need to stop this. I need to stop continuous click on the exe, while it is running. I used the shell script to check whether the exe is running or not. And displays the message, that the exe is already running. And stops the further process. I need this to be happened while exe is running for the second time. I couldn't figure this out. Is there any way to disable the exe from click, while it is running. Or how can I use the check whether it is running or not.
import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.InputStreamReader;
public class VBSUtils {
private VBSUtils() { }
public static boolean isRunning(String process) {
boolean found = false;
try {
File file = File.createTempFile("realhowto",".vbs");
file.deleteOnExit();
FileWriter fw = new java.io.FileWriter(file);
String vbs = "Set WshShell = WScript.CreateObject(\"WScript.Shell\")\n"
+ "Set locator = CreateObject(\"WbemScripting.SWbemLocator\")\n"
+ "Set service = locator.ConnectServer()\n"
+ "Set processes = service.ExecQuery _\n"
+ " (\"select * from Win32_Process where name='" + process +"'\")\n"
+ "For Each process in processes\n"
+ "wscript.echo process.Name \n"
+ "Next\n"
+ "Set WSHShell = Nothing\n";
fw.write(vbs);
fw.close();
Process p = Runtime.getRuntime().exec("cscript //NoLogo " + file.getPath());
BufferedReader input =
new BufferedReader
(new InputStreamReader(p.getInputStream()));
String line;
line = input.readLine();
if (line != null) {
if (line.equals(process)) {
found = true;
}
}
input.close();
}
catch(Exception e){
e.printStackTrace();
}
return found;
}
}
And In my main class, I called VBUtils.
boolean result = VBSUtils.isRunning("myexe.exe");
if(result)
{
msgBox("myexe is running. Please wait");
}
else
{
// my part of execution.
}
If I call like this, the exe got terminated. Both the first and second execution.
The easiest way would be to present the user with some kind of visual feedback, so he knows that the application is running. (e.g. a console window with messages, a wait dialog, ...)
You need to use some sort of flag to indicate that your app is running. Many apps use a temp .pid file. When your app starts it checks for a .pid file, if there is one then it exits with an error message. If there is no .pid file then it creates one and runs as normal.
First of all java has a provision for a very early splash screen:
http://download.oracle.com/javase/6/docs/api/java/awt/SplashScreen.html
Furthermore per RMI you can on startup connect to any possibly running instance and stop and transmit command line ("open files ..."). RMI allows you to play remote server.