How can you detect a unique value in an exe using Java? - java

I've got this going at the moment;
public class ProcessKill {
private static final String TASKLIST = "tasklist";
private static final String KILL = "taskkill /IM ";
public static boolean isProcessRunging(String serviceName) throws Exception {
Process p = Runtime.getRuntime().exec(TASKLIST);
BufferedReader reader = new BufferedReader(new InputStreamReader(
p.getInputStream()));
String line;
while ((line = reader.readLine()) != null){
System.out.println(line);
if (line.contains(serviceName)){
return true;
}
}
return false;
}
public static void killProcess(String serviceName) throws Exception {
Runtime.getRuntime().exec(KILL + serviceName);
}
}
public static void main(String args[]) throws Exception{
ProcessKill pkill = new ProcessKill();
String processName = "wmplayer.exe";
if (pkill.isProcessRunging(processName)){
pkill.killProcess(processName);
}
}
Only problem is, what if the name is changed? I don't want to keep updating the code. Is there a way to grab a hex value of an .exe file and read it into Java for it to detect that instead?
Thanks

well, you can first check if the process you want to kill is running by executing wmic.exe PROCESS where name='"+processName+"' - although WMIC provides a PROCESS DELETE option, the java-process blocks when calling this. wmic PROCESS (without any specifig process name) returns a list (and description) of all currently running processes on a windows machine which you can read in using an InputSreamReader() and then iterate through all running processes and check which of these might be your target process. Moreover the line of your target process contains arguments passed to your process which you can either use to distinguish processes in case you have multiple processes running or need to delete some resource files your application used.
While debugging our application which uses an embedded mongodb for unit-tests, after debugging the embedded mongod process kept running and refused to work on the next unit-test (as the unit-test cleanup was not executed properly) - furthermore it created a local datastore which could not be overridden by a new embedded mongod process - so it needed to get deleted manually. I therefore extracted the file from the line returned by WMIC and deleted the files after killing the process automatically.

As far as I understand you do not want to hold the process name hard-coded. In this case just pass it through command line parameters:
public static void main(String args[]) throws Exception{
ProcessKill pkill = new ProcessKill();
String processName = args[0];
if (pkill.isProcessRunging(processName)){
pkill.killProcess(processName);
}
}
Now your user has to provide the process name to kill in command line:
:> ProcessKill notepad.exe
However IMHO I do not understand why do you need your utility at all? Indeed you just run processkill, so user can use it directly. Your utility does not provide any additional functionality.

Related

Opening new process in Java and keeping current one open

Got a task to make new version of our software to new client, and I need to make application behave so, that originally started application starts another and stays open at the back. At the moment original one is closed when new starts. Original application is kind of a loader, it's whole purpose is to download other applications from server and run one of them. That's why FileLock is used and that is probably the reason why I can't figure out how to keep the original open at the back and succesfully open the new one. I managed to make that work in Linux, but unfortunately our client uses Windows 10...
Some variables:
private final List<FileLock> locks = new ArrayList<FileLock>();
private final File applicationPath;
private final String application;
Loader constructor
public Loader(String[] args) throws IOException {
this.args = args;
applicationPath = new File(THIS_DIRECTORY, application + ".jar");
tryLock("loader");
tryLock(application);
}
load() is called in main after the constructor is made, nothing fancy there.
private void load() throws Exception
checkAndDownloadUpdate(application, applicationPath);
String javaBin = getJavaBinary();
List<String> command = new ArrayList<String>();
command.addAll(Arrays.asList(javaBin, THIS_FILE.getAbsolutePath(), "-jar", applicationPath.getAbsolutePath()));
command.addAll(Arrays.asList(args));
new ProcessBuilder(command).start();
}
TryLock:
private void tryLock(String name) {
File path = new File(THIS_DIRECTORY, name + "_lock");
long waitUntil = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(10);
while (System.currentTimeMillis() < waitUntil) {
try {
FileLock fileLock = tryLock(path);
if (fileLock != null) {
locks.add(fileLock);
return;
}
}
}
In Linux I was able to make application work as I wanted by replacing content of tryLock() with just return and adding waitFor() to Processbuilder's command. In windows new application doesn't start until first one is killed.
Problem seems to occur when new process is launched, in Windows 10 Java calls Unsafe.park() method and it halts until original process is closed.
I think it's because of the file handle in Windows which will prevent the second process to get a lock to the file.
Only when the first process release its lock the second will be able to get it.
I would try to avoid the file locks and only monitor the child process
ProcessBuilder builder = new ProcessBuilder("comman.exe");
Process process = builder.start();
if (process.isAlive()) {
//wait
}
So I had to ProcessBuilder's inheritIO method be able to open new process. Now it works as intended. Also added waitFor() for process:
ProcessBuilder builder = new ProcessBuilder(command);
builder.directory(new File(workingDir.toString()));
builder.inheritIO();
Process p = builder.start();
p.waitFor();

Java - run Python script and monitor continuous output

I'm using a Raspberry Pi to receive the UID of some RFID cards from a RC522 reader. The python script I'm running is here: https://github.com/mxgxw/MFRC522-python
For various reasons I won't go into, I have to process these IDs in Java.
It seems the most viable solution is to run the python script and read in the result into Java. The problem is, the Python code gives continuous output, i.e. it will print the ID of the card into the console window as and when a card is tapped onto the reader, and will only terminate on a user's command.
I'm currently using a ProcessBuilder to execute the script, however it seems like it's more suited to run the program and read in the immediate result back to Java (which of course is null if I haven't tapped a card onto the reader). I've tried executing the code in a while(true) loop to continuously start the process - but this doesn't work:
import java.io.*;
public class PythonCaller {
/**
* #param args
* #throws IOException
*/
public static void main(String[] args) throws IOException {
// set up the command and parameter
String pythonScriptPath = "/home/pi/MFRC522-python/Read.py";
String[] cmd = new String[3];
cmd[0] = "sudo";
cmd[1] = "python"; // check version of installed python: python -V
cmd[2] = pythonScriptPath;
// create runtime to execute external command
ProcessBuilder pb = new ProcessBuilder(cmd);
// retrieve output from python script
pb.redirectError();
while(true){
Process p = pb.start();
System.out.println("Process Started...");
BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
int ret = new Integer(in.readLine()).intValue();
System.out.println("value is : "+ret);
}
}
}
The output on the console window is blank - no exceptions thrown or println's.
Any help would be massively appreciated!!
Thanks
EDIT - I've surrounded my code in a try/catch to see if there's anything at all being thrown, and it doesn't seem to be the case
I use the following programs to try to reproduce the problem
PythonCaller.java
import java.io.*;
public class PythonCaller {
public static void main(String[] args) throws IOException {
// set up the command and parameter
String pythonScriptPath = "/home/pi/test.py";
String[] cmd = { "python", pythonScriptPath };
// create runtime to execute external command
ProcessBuilder pb = new ProcessBuilder(cmd);
// retrieve output from python script
pb.redirectError();
while(true){
Process p = pb.start();
System.out.println("Process Started...");
BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
int ret = new Integer(in.readLine()).intValue();
System.out.println("value is : "+ret);
}
}
}
test.py
uid =(123,456,789,999)
print "Card read UID: "+str(uid[0])+","+str(uid[1])+","+str(uid[2])+","+str(uid[3])
The method pb.redirectError() doesn't modify anything. It returns a value, your codes does nothing with it. (see http://docs.oracle.com/javase/7/docs/api/java/lang/ProcessBuilder.html#redirectError%28%29). What you want is probably redirectErrorStream(boolean redirectErrorStream)
The second line of the python test program is taken directly from "Read.py" (line 44). It causes an error with the java intValue() method. If I replace it with String ret = in.readLine();, the program seems to work.
Since the Process p = pb.start(); is inside the loop, the python subprogram is called repeatedly.
The next step should be to try running the python program manually in a console, see what it does.
(n.b. I had to remove "sudo" and change paths to be able to test on my system, you should have no problems replacing things for your setup).
I've managed to get around it by editing my Python script - it returns null if there's no card on the reader, and the UID if there is.
I'll probably use observer pattern or similar on the Java end to detect when there's a card. Very resource intensive but it'll have to do for now!

Closing a Thread's GUI after using Runtime.exec()

I am making a game with LibGDX, now I am trying to restart the game by re-running the jar, for that I am using the jar's path, finding it by using:
String location = new File(DesktopLauncher.class
.getProtectionDomain().getCodeSource().getLocation()
.getPath()).toString().replace("%20", " ");
After using that I attempt to restart using a Process and the Runtime.getRuntime().exec("java -jar " + location + "\\Test.jar");
Now that far it works, but the problem is that the first instance of the game from which I create the new instance (from which I restart), remains on the screen and won't close until the second instance closes.
This is my code for the restart:
public static void restart() {
Gdx.app.exit();
try {
String location = new File(DesktopLauncher.class
.getProtectionDomain().getCodeSource().getLocation()
.getPath()).toString().replace("%20", " ");
System.out.println(location);
Process pro = Runtime.getRuntime().exec(
"java -jar " + location + "\\Test.jar");
BufferedWriter writer = new BufferedWriter(new FileWriter(new File(
"reprot.txt")));
InputStream stream = pro.getErrorStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(
stream));
String line = "";
writer.write(location);
while ((line = reader.readLine()) != null) {
writer.write(line);
}
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Am I doing something wrong? How can I close the first instance of the game after starting the second instance?
I tried doing it using a different thread, having this code:
public static void main(String[] args) {
try {
String location = new File(DesktopLauncher.class
.getProtectionDomain().getCodeSource().getLocation()
.getPath()).toString();
System.out.println(location);
Process pro = Runtime.getRuntime().exec(
"java -jar " + location + "\\Test.jar");
BufferedWriter writer = new BufferedWriter(new FileWriter(new File(
"report.txt")));
InputStream stream = pro.getErrorStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(
stream));
String line = "";
writer.write(location);
while ((line = reader.readLine()) != null) {
writer.write(line);
}
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
But it still has the same problem.
EDIT: I tried to used System.exit(0);, and try to use the LwjglApplication to close it but it remains the same, however I have made some progress:
When creating this new process, the second instance of the game, the first instance's UI freezes, causing the game not to respond. I thought, well if it doesn't respond I should just find a way to kill it off and leave the other instance, but that can't be accomplished due to the fact that when closing once instance of the game (by forcing a close on it), you close both instances.
I think I figured out a piece of this annoying puzzle:
Let's say our main instance of the game is called 'Game_1', and the instance that we're creating is 'Game_2'.
After looking at the code and thinking about what happens (with testing of small classes and not the large game), I think that that the 'Game_1' isn't closing because 'Game_2' isn't closing.
In more complex terms, the instance of 'Game_1' won't close because it is somehow attached to 'Game_2' and thus is waiting for 'Game_2' to close before it itself will close.
So if that correct, the way to close 'Game_1' would to make 'Game_2' run simultaneously to 'Game_1' making it independent and thus allowing 'Game_1' to continue with the current progress of the code, which will be the implementation of Gdx.app.exit(); method.
So now the question remains, how do I make the instance of 'Game_2' run independently from 'Game_1'? Or how would I make 'Game_1' continue the code or, not to wait till an exit value will be received from 'Game_2'.
EDIT2: MASSIVE PROGRESS After adding a line of code System.exit(0); in the restart class, 'Game_1' continued not to respond, BUT after terminating 'Game_1', 'Game_2' did not get turned off, I'll continue to play around with it until I figure out what to do.
EDIT3: I continue to try and fix it so it'll work, but have ran into another problem. I figured out that if I can simulate an exit value for the process of 'Game_2' without actually exiting, I can terminate 'Game_1' 's UI, while keeping game 2 still alive, if anyone has any ideas please share them with me.
EDIT4: I continue my attempts to do this, but I can't follow what's going on, I'm trying to pass a PID to the restart class by writing
"java -cp " + location + "\\Test.jar Restart " + PID but it doesn't seem to work, or I don't seem to receive any information (syso for example) from the Restart class. On top of that I have found a memory leak inside my game that I will address once I finish working this out.
Please, if you have any idea how to help me, even just a theory, please share it.
EDIT5: I have established the efficiency of the termination of a given process using this LINK
Here is the solution, since I can't answer my problem until tomorrow:
Alright, finally, I finished solving it, it has a few problems, only two of them I will mention since it concerns the code in general and not how I'm using it. 'Game_1' will be the game that was started first, and 'Game_2' will be the instance of the restarted game. This is it:
First off I got the PID of the current process that is currently running, 'Game_1', from which I will create 'Game_2'. The problem with this is that Java applications all have the same name, 'Java.exe', and what that causes is a bunch of applications of the same name, so for now I add a message saying that the game should be the only java instance on the computer, not eclipse, or anything like that.
The code for the PID retrieval is this:
private static String getPID() {
try {
String line;
Process p = Runtime.getRuntime().exec(
System.getenv("windir") + "\\system32\\" + "tasklist.exe");
BufferedReader input = new BufferedReader(new InputStreamReader(
p.getInputStream()));
while ((line = input.readLine()) != null) {
System.out.println(line);
if (line.contains("java")) {
String data = line.subSequence(27, 35).toString();
data = data.trim();
return data;
}
}
input.close();
} catch (IOException e) {
e.printStackTrace();
}
return "-1";
}
Now, later on, I will look for a way to name the process that is currently running, so that you won't have to use line.contains("java") since it might give more than one instance, but for now it's as good as it gets.
This code uses an exe file inside of windows that basically gives all the current processes running on the computer, so you can find your.
The returned list is given in this format:
Image Name PID Session Name Session# Mem Usage
========================= ======== ================ =========== ============
All the processes will be located here.
The PID is located between the 27th character to the 35th, and that's why I added
String data = line.subSequence(27, 35).toString();
so that it returns the PID of the process.
After doing that I prepared a cmd with an execution command as follows:
String jarLocation = new File(YourClass.class.getProtectedDomain().getCodeSource().getLocation().getPath()).toString();
String command = "java -cp " + jarLocation + " your.Package.here.Restart \""+PID+"\"";
Runtime.getRuntime().exec("cmd /C start cmd.exe /C \"" + command + "\"");
Now first off I got the location of the .jar file. It is returned in the following format:
C:\A%20Folder\To%20YourJar\YourJar.jar
So there needs to be the following formatting to the location
jarLocation = jarLocation.replace("%20", " ");
Just to turn all the %20's to white spaces.
Note If you do not have spaces in your directory the previous step of formatting is not required.
After that I had prepared the actual command, which is as follows (this is for me, but you can change it to fit your needs).
java - calling the java program in cmd.
-cp - execute a class located inside of a jar file. Then I added the jar location, then added the package and added an argument (for the String[] args in the main method) of the PID to be terminated.
Now the following line of code represents a OS dependency, so if you want to add multiple OS support, I would recommend finding the equivalent to cmd in the other OS and figuring out how to use it.
The last line of code is the execution, where we get the runtime, start a cmd and execute a single command before closing the cmd.
You can find details about it in the following issue: LINK
#Vincent Ramdhanie also gives a link to commands you can run using runtime when activating cmd.
After that I had a class that was actually restarting the game itself, which is named Restart.
Like the last line of code, a line of code there represents OS dependency, so if you want to support multiple OS's, find the equivalent to taskkil in other OS's. According to #erhun it's pkill for Linux or something, sorry I don't exactly remember.
This is the code for that class:
public static void main(String[] args) {
try {
String location = new File(DesktopLauncher.class
.getProtectionDomain().getCodeSource().getLocation()
.getPath()).toString();
location = "\"" + location.replaceAll("%20", " ");
Runtime.getRuntime().exec("taskkill /F /PID " + args[0]);
Runtime.getRuntime().exec("java -jar " + location);
} catch (IOException e) {
e.printStackTrace();
}
}
Like with the previous line, location here means the same thing as before, and you have to format it if you have spaces in the directory.
After that you need to terminate the previous process, that is where taskkill /F /PID + args[0] comes in. If you run that you will terminate the task with the id of args[0], which was 'Game_1' 's PID.
After that I just run the jar file and you're good to go.
I would like to note something, I tried running it so that the main class (DesktopLauncher) would use the Restart class through an exec command in runtime, but the problem presisted, and I found that the only way to fix this, was to work around it, and use cmd. (This was after using cmd to debug the location string).
That's it, I worked a whole week, trying to fix this problem, and as crude as this is, it's a solution, for the mean time. If I have a problem somewhere in this code please tell me.
There is a much 'easier' method to do what you want. You will of course have to adapt to your own application as what you are trying to do is completely outside of libgdx's scope. It is a cross-platform library and the idea update/restart is very different with mobile.
An actual desktop cross-platform solution can be found here, I would highly suggest you not use your method as it is not a reliable solution and very platform specific.
Below is an example of how you would do it in libgdx. You need two things, code to launch the application and code to restart it.
Launcher:
public class TestLauncher {
public static void main(final String[] args) {
final LwjglApplicationConfiguration cfg = new LwjglApplicationConfiguration();
cfg.title = "Game";
cfg.width = 1280;
cfg.height = 720;
cfg.backgroundFPS = 12;
cfg.foregroundFPS = 60;
final Runnable rebootable = new Runnable() {
#Override public void run() {
if (Gdx.app != null) {
Gdx.app.exit();
}
TestLauncher.restart();
}
};
new LwjglApplication(new RebootTest(rebootable), cfg);
}
public static void restart() {
final StringBuilder cmd = new StringBuilder();
cmd.append(System.getProperty("java.home") + File.separator + "bin" + File.separator + "java ");
for (final String jvmArg : ManagementFactory.getRuntimeMXBean().getInputArguments()) {
cmd.append(jvmArg + " ");
}
cmd.append("-cp ").append(ManagementFactory.getRuntimeMXBean().getClassPath()).append(" ");
cmd.append(TestLauncher.class.getName()).append(" ");
try {
Runtime.getRuntime().exec(cmd.toString());
} catch (final IOException e) {
e.printStackTrace();
}
}
}
Sample Game Code:
public class RebootTest implements ApplicationListener {
private final Runnable rebootHook;
private Stage stage;
private Skin skin;
public RebootTest(final Runnable rebootHook) {
this.rebootHook = rebootHook;
}
#Override public void create() {
this.stage = new Stage();
this.skin = new Skin(Gdx.files.internal("skin/uiskin.json"));
final Table table = new Table();
table.setFillParent(true);
final TextButton button = new TextButton("Reboot", this.skin);
button.addListener(new ClickListener() {
#Override public void clicked(final InputEvent event, final float x, final float y) {
Gdx.app.postRunnable(RebootTest.this.rebootHook);
}
});
table.add(button).expand().size(120, 40);
this.stage.addActor(table);
Gdx.input.setInputProcessor(this.stage);
}
#Override public void resize(final int width, final int height) {}
#Override public void render() {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
this.stage.act();
this.stage.draw();
}
#Override public void pause() {}
#Override public void resume() {}
#Override public void dispose() {
if (this.stage != null) {
this.stage.dispose();
}
if (this.skin != null) {
this.skin.dispose();
}
}
}

How to run command line within java using thread async

I am new to java. I am tasked to write java program to run the command lines. I tested the command line under the DOS prompt since i do not have have access to Linux box yet. it worked fine. See the PROGRAM below for full command line syntax. the job will take 6 input files and generate some output files. Next i tried to create a class to and using getruntime and process to process this job. Even it compiled without error but when i run it just show the cursor blinking... i thought i need to use Thread async technique. please provide some advices since i do not have enough time for the projects. I also would like to implement a call back or return values when the job is done. an example would be greatly appreciated. Thanks
import java.io.*;
public class RunJob {
// public static final String PROGRAM = "c:\\wrk\\java.exe Hello";
//one command line below
public static final String PROGRAM = "c:/java.exe -cp \"wrk/jmp.jar;wrk/colt.jar\" gov.lanl.yadas.reliability.UltimateMissileReliabilityModel 10000 \"wrk/\" x1.dat x2c.dat x3.dat x4.dat x5.dat x6.dat true";
// Set to true to end the loop
static boolean done = false;
public static void main(String argv[]) throws IOException {
BufferedReader is;
String line;
String returnMsg = "Start ";
final Process p = Runtime.getRuntime().exec(PROGRAM);
System.out.println("start");
Thread waiter = new Thread() {
public void run() {
try {
p.waitFor();
} catch (InterruptedException ex) {
System.out.println("InterruptedException");
return;
}
System.out.println("Program terminated!");
done = true;
}
};
waiter.start();
is = new BufferedReader(new InputStreamReader(p.getInputStream()));
while (!done && ((line = is.readLine()) != null))
{
System.out.println(line);
returnMsg = returnMsg + line;
}
System.out.println(returnMsg);
System.out.println("End");
return;
}// main
}
I assume that there is a good reason why you want to run a java program from another java program and not just from a shell script, or by invoking an API - but if not - please reconsider.
As to your problem - if your application produces a lot of output (the one you are running as a process) - your application will hang. The p.waitFor() will halt until the process ends. But if you don't read the information from the InputStream - it will overflow and hang!
Advice #1: put the p.waitFor() at the end.
Advice #2: read this article. If I remember correctly it is the one I read when I had a similar problem. You can also google for "StreamGobbler" - it is a common name for a separate thread that "gobbles" your streams.
Advice #3: Don't forget the ErrorStream - if your application will produce too many errors - that stream will cause the process to hang as well.

How to get the hard disk serial number using Java?

How can I get the serial number of the hard disk with Java?
Java runs on a virtual machine which doesn't have hard drives only files and filesystems. You should be able to get this information by running the approriate command line utility from Java.
One Linux you can do
hdparm -i /dev/hda
Good news there is a volume:vsn attribute for the FileStore object.
for (FileStore store: FileSystems.getDefault().getFileStores()) {
System.out.format("%-20s vsn:%s\n", store, store.getAttribute("volume:vsn"));
}
The output looks like an int (e.g. -1037833820, 194154)
Bad news it is windows specific for testing purposes as they say in WindowsFileStore jdk8u source. Might work in other platforms and in the future, or not.
Other options (JNI, executing and parsing CLI) are also system dependent. Are more ellaborate but might not suddenly break up when you change the runtime. But I think the attribute solution is much simpler and I am totally going with it until I have something better.
If you are using a Windows OS which is Win7 SP1 or higher, you can simply get it by executing the following cmd command in your java program, via wmic.
wmic diskdrive get serialnumber
If this command returns "Invalid XML content." you may wanna apply the hotfix file as described in here.
on windows machine you can use
public static String getSerialKey(Character letter) throws Exception{
String line = null;
String serial = null;
Process process = Runtime.getRuntime().exec("cmd /c vol "+letter+":");
BufferedReader in = new BufferedReader(
new InputStreamReader(process.getInputStream()) );
while ((line = in.readLine()) != null) {
if(line.toLowerCase().contains("serial number")){
String[] strings = line.split(" ");
serial = strings[strings.length-1];
}
}
in.close();
return serial;
}
Windows: This is a windows dependent solution using Java which invokes VBS.
Linux: try this c program and use JNI for Java.
I would imagine you'd have to implement that feature in C or C++ and use JNI to access it from Java.
For a Windows machine you can execute wmic with parameters and than parse the result like is done in the following snippet:
public static String getNumeroDisq() throws IOException {
Runtime runtime = Runtime.getRuntime();
String[] commands = {"wmic", "diskdrive", "get", "SerialNumber"};
Process process = runtime.exec(commands);
String chain = null;
try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
String serialNumber= null;
while ((serialNumber = bufferedReader.readLine()) != null) {
if (serialNumber.trim().length() > 0) {
chain = serialNumber;
}
}
return chain.trim();
}
}

Categories