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();
}
}
}
Related
I'm a small java developer currently working on a discord bot that I made in Java. one of the features of my bot is to simply have a leveling system whenever anyone sends a message (and other conditions but this is irrelevant for the problem I'm encountering).
Whenever someone sends a message an event is fired and a thread is created to compute how much exp the user should gain. and eventually, the function to edit the storage file is called.
which works fine when called sparsely. but if two threads try to write on the file at once, the file usually gets deleted or truncated. either of these two cases being undesired behavior
I then tried to make a queuing system that worked for over 24h but still failed once so it is more stable in a way. I only know the basics of how threads work so I may've skipped over an important thing that causes the problem
the function looks like this
Thread editingThread = null;
public boolean editThreadStarted = false;
HashMap<String, String> queue = new HashMap<>();
public final boolean editParameter(String key, String value) {
queue.put(key, value);
if(!editThreadStarted) {
editingThread = new Thread(new Runnable() {
#Override
public void run() {
while(queue.keySet().size() > 0) {
String key = (String) queue.keySet().toArray()[0];
String value = queue.get(key);
File inputFile = getFile();
File tempFile = new File(getFile().getName() + ".temp");
try {
tempFile.createNewFile();
} catch (IOException e) {
DemiConsole.error("Failed to create temp file");
handleTrace(e);
continue;
}
//System.out.println("tempFile.isFile = " + tempFile.isFile());
try (BufferedReader reader = new BufferedReader(new FileReader(inputFile)); BufferedWriter writer = new BufferedWriter(new FileWriter(tempFile))){
String currentLine;
while((currentLine = reader.readLine()) != null) {
String trimmedLine = currentLine.trim();
if(trimmedLine.startsWith(key)) {
writer.write(key + ":" + value + System.getProperty("line.separator"));
continue;
}
writer.write(currentLine + System.getProperty("line.separator"));
}
writer.close();
reader.close();
inputFile.delete();
tempFile.renameTo(inputFile);
} catch (IOException e) {
DemiConsole.error("Caught an IO exception while attempting to edit parameter ("+key+") in file ("+getFile().getName()+"), returning false");
handleTrace(e);
continue;
}
queue.remove(key);
}
editThreadStarted = false;
}
});
editThreadStarted = true;
editingThread.start();
}
return true;
}
getFile() returns the file the function is meant to write to
the file format is
memberid1:expamount
memberid2:expamount
memberid3:expamount
memberid4:expamount
the way the editing works is by creating a temporary file to which i will write all of the original file's data line by line, checking if the memberid matches with what i want to edit, if it does, then instead of writing the original file's line, i will write the new edited line with the new expamount instead, before continuing on with the rest of the lines. Once that is done, the original file is deleted and the temporary file is renamed to the original file, replacing it.
This function will always be called asynchronously so making the whole thing synchronous is not an option.
Thanks in advance
Edit(1) :
I've been suggested to use semaphores and after digging a little into it (i never heard of semaphores before) it seems to be a really good option and would remove the need for a queue, simply aquire in the beginning and release at the end, nothing more required!
I ended up using semaphores as per user207421's suggestions and it seems to work perfectly
I simply put delays between each line write to artificially make the task longer and make it easier to have multiple threads trying to write at once, and they all wait for their turns!
Thanks
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;
}
I'm working on a project for school. We are are making a harbour where you can load and unload ships. The control part is made in Netbeans and the simulation in JME.
We send data from Netbeans to JME via a socket. JME is running a serversocket who is liseting to the input from Netbeans.
For example Netbeans sends an ID of a container and the crane in JME gets that container and puts it on the shore so a verhicle can pick it up.
We change a count in the main (Main.count = 2) so the SimpleUpdate can call a method. The problem is that sometimes stuff is getting skipped. Also I think it's getting worse when we send more information for instance a vehicle that's getting the container. How can I fix this? And are there other ways to get a good connection?
The code:
Netbeans
Send client
public static void run() throws Exception
{
Socket socket = new Socket("Localhost", 4321);
out = new ObjectOutputStream(socket.getOutputStream());
}
//Sent arraystring to Simulation
public void sent(String sentString){
try {
out.writeObject(sentString);
} catch (IOException ex) {
Logger.getLogger(CommunicationWithSimulatoin.class.getName()).log(Level.SEVERE, null, ex);
}
}
Main send some stuff example
for(int i = Calculator.getContainersFromMaritime(); i > 1; i--)
{
Thread.sleep(50);
sim.sent("craneCon;" + i + ";");
System.out.println(i);
}
JME
Listener
public static void Listener() throws Exception {
boolean isRunning = true;
//Creates the server socket
ServerSocket sSocket = new ServerSocket(4321);
//Acception a connection from the client
Socket socket = sSocket.accept();
ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
//Get the input from the client
while (isRunning) {
//Reads and prints the input
test = (String) in.readObject();
System.out.println(test);
String[] parts = receivedString.split(";");
if(parts[0].equals("ContainerPositionsMaritime"))
{
Maritime.ContainersOnBoard = receivedString.split(";");
Main.count = 0;
}
if(parts[0].equals("craneCon"))
{
int containerId = Integer.parseInt(parts[1]);
SeagoingCranes.idContainer = containerId;
Main.count = 2;
}
}
}
Main simpleupdate
public void simpleUpdate(float tpf) {
if(count == 0)
{
InitContainers();
//martime.setLocalTranslation(0, 500.0f, 0);
count = 999;
}
if(count == 2)
{
InitCrane(SeagoingCranes.idContainer);
count = 999;
}
if(martime != null)
{
martime.move(0,0,0.25f*tpf);
}
}
There are a number of problems with your program.
Firstly - you have potential race and thread contention issues as you have "count" which I assume is an integer value inside the SimpleApplication is being modified from one thread and read from another. Unless the value is declared as volatile this can cause all sorts of unexpected problems and odd behaviour and even declaring it as volatile is not recommended.
Your main issue though (even leaving aside the subtle problems) is being caused by the fact that in simpleUpdate() you are scanning count and then taking an action based on count. simpleUpdate() is called once for each frame as your jME3 application is running.
If you receive more than one message in a frame then only the last one will be acted on as the count will be modified again before the next simpleUpdate() runs.
The best way to do this is to use app.enqueue().
if(parts[0].equals("ContainerPositionsMaritime"))
{
final ContainersOnBoard containers = receivedString.split(";");
mainApp.enqueue(new Callable<Spatial>() {
public Spatial call() throws Exception {
mainApp.InitContainers(containers);
return null;
}
});
}
}
You can remove all the existing code from your simpleUpdate().
The Callable you enqueue will be called back from the JME3 thread in the next update and process the addition of the containers. By doing a similar thing for every different commands it will enqueue and process all the commands as the time comes. You can enqueue as many commands as you like and they will all be processed.
In general you should read up on AppStates, Controls and the threading model as they will allow you to make your code much more structured and organised.
http://hub.jmonkeyengine.org/wiki/doku.php/jme3:advanced:multithreading
http://hub.jmonkeyengine.org/wiki/doku.php/jme3:advanced:application_states
http://hub.jmonkeyengine.org/wiki/doku.php/jme3:advanced:custom_controls
P.S. You should try and follow Java style/coding conventions - for example methods should begin with lowercase. initContainers not InitContainers.
I want to output the result of the "dir" command to the java console. I have already looked on Google and here, but none of the examples work for me, thus making me rite this post.
My code is as follows:
try
{
System.out.println("Thread started..");
String line = "";
String cmd = "dir";
Process child = Runtime.getRuntime().exec(cmd);
//Read output
BufferedReader dis = new BufferedReader( new InputStreamReader(child.getInputStream() ));
while ((line = dis.readLine()) != null)
{
System.out.println("Line: " + line);
}
dis.close();
}catch (IOException e){
}
What am I doing wrong?
Any help would be very nice.
Thanks in advance,
Darryl
You cannot run "dir" as a process, you need to change it to String cmd = "cmd dir";.
You don't handle the exception at all. adding the line e.printStackTrace()); in the catch block would tell you what I wrote in (1). Never ignore exceptions!
You don't handle error stream. This might cause your program to hang, handle error stream and read from both streams (error and input) in parallel using different streams.
The best way is to use commons exec http://commons.apache.org/exec/
This has things that catch quirks that can really drive you up the wall, such as the whole process blocking if you didn't clear its output stream, escaping quotes in commands, etc.
Here is a method that will run the del command in windows successfully. Note the use of cmd since del is not a standalone executable:
private void deleteWithCmd(File toDelete) throws IOException {
CommandLine cmdLine = new CommandLine("cmd.exe");
cmdLine.addArgument("/C");
cmdLine.addArgument("del");
cmdLine.addArgument(toDelete.getAbsolutePath());
DefaultExecutor executor = new DefaultExecutor();
int exitValue = executor.execute(cmdLine);
}
a) What is the java console?
b) You should use javas File.listFiles () instead of Runtime.exec, which isn't portable, and makes Name splitting neccessary - a hard thing, for filenames which contain spaces, blanks, newlines and so on.
c) Whats wrong with your code?
d) Why don't you do anything in the case of Exception?
Here is a more thorough example that accounts for OS versions and error conditions ( as stated by MByD above)
http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html?page=4
Remember that using "exec" means that your application is no longer cross-platform and loses one of the main advantages of Java.
A better approach is to use java.io package.
http://download.oracle.com/javase/tutorial/essential/io/dirs.html
You can also do something like that in java 6 :
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
public class ListFilesFromRegExp {
public static void main(String[] args) throws IOException {
File dir = new File("files/");
File[] files = dir.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.matches("File[0-9].c");
}
});
for (int i = 0; i < files.length; i++) {
System.out.println(files[i].getAbsolutePath());
}
}
}
I'm trying to create a Thread that keeps netsh windows command-line tool open so I can execute netsh commands without open it every single time.
The thing is, once I've created the Thread, just the first command call works... the subsequent calls seems to have no effect.
Here is my code:
public class NetshThread implements Runnable{
private static Process netshProcess = null;
private static BufferedInputStream netshInStream = null;
private static BufferedOutputStream netshOutStream = null;
public BufferedReader inPipe = null;
public void run(){
startNetsh();
}
public void startNetsh(){
try {
netshProcess = Runtime.getRuntime().exec("netsh");
netshInStream = new BufferedInputStream(netshProcess.getInputStream());
netshOutStream = new BufferedOutputStream(netshProcess.getOutputStream());
inPipe = new BufferedReader(new InputStreamReader(netshInStream));
} catch (IOException e) {
e.printStackTrace();
}
}
public void executeCommand(String command){
System.out.println("Executing: " + command);
try {
String str = "";
netshOutStream.write(command.getBytes());
netshOutStream.close();
while ((str = inPipe.readLine()) != null) {
System.out.println(str);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void closeNetsh(){
executeCommand("exit");
}
public static void main(String[] args){
NetshThread nthread = new NetshThread();
nthread.run();
String command = "int ip set address " +
"\"Local Area Connection 6\" static .69.69.69 255.255.255.0";
nthread.executeCommand(command);
command = "int ip set address " +
"\"Local Area Connection 6\" static 69.69.69.69 255.255.255.0";
nthread.executeCommand(command);
System.out.println("*** DONE ***");
}
}
Thank you!!! =)
Update 1:
Ok... I'm now using a PrintWriter instead... so I think I don't need to flush anything anymore, since the constructor is:
new PrintWriter(netshOutStream, true); (just like Mr. Shiny told me)...
Suppose I decide to break the while loop when the first output line is available... I doesn't work either... the next command wont be executed.... My code now looks like:
import java.io.*;
public class NetshThread implements Runnable{
private static Process netshProcess = null;
private static BufferedInputStream netshInStream = null;
private static BufferedOutputStream netshOutStream = null;
public BufferedReader inPipe = null;
private PrintWriter netshWriter = null;
public void run(){
startNetsh();
}
public void startNetsh(){
try {
netshProcess = Runtime.getRuntime().exec("netsh");
netshInStream = new BufferedInputStream(netshProcess.getInputStream());
netshOutStream = new BufferedOutputStream(netshProcess.getOutputStream());
netshWriter = new PrintWriter(netshOutStream, true);
inPipe = new BufferedReader(new InputStreamReader(netshInStream));
} catch (IOException e) {
e.printStackTrace();
}
}
public void executeCommand(String command){
System.out.println("Executing: " + command);
try {
String str = "";
netshWriter.println(command);
while ((str = inPipe.readLine()) != null) {
System.out.println(str);
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void closeNetsh(){
executeCommand("exit");
}
public static void main(String[] args){
NetshThread nthread = new NetshThread();
Thread xs = new Thread(nthread);
xs.run();
String command = "int ip set address " +
"\"Local Area Connection 6\" static .69.69.69 255.255.255.0";
nthread.executeCommand(command);
command = "int ip set address " +
"\"Local Area Connection 6\" static 69.69.69.69 255.255.255.0";
nthread.executeCommand(command);
System.out.println("*** DONE ***");
}
}
and the output I get:
Executing: int ip set address "Local
Area Connection 6" static .69.69.69
255.255.255.0 netsh>.69.69.69 is not an acceptable value for addr.
Executing: int ip set address "Local
Area Connection 6" static 69.69.69.69
Why the second command is not executed???
255.255.255.0
* DONE *
Update 2:
Everything seemed to work just fine until a teacher tried my app in a spanish-windows enviroment....
my code looks like this:
Scanner fi = new Scanner(netshProcess.getInputStream());
public void executeCommand(String command) {
System.out.println("Executing: " + command);
String str = "";
netshWriter.println(command);
fi.skip("\\s*");
str = fi.nextLine();
System.out.println(str);
}
and what i need is to somehow set the netshWriter encoding to the windows default.
Can anyone know who to do this?
You are closing the output stream.
You need to move the stream processing into separate threads. What's happening is that inPipe.readLine() is blocking waiting for netsh to return data. Apache has a package that deals with process handling. I'd look at using that instead of rolling your own (http://commons.apache.org/exec/)
This seems wrong in many ways.
First, why a Runnable object? This isn't ever passed to a Thread anywhere. The only thread you're creating isn't a java thread, it is an OS process created by exec().
Second, you need a way to know when netsh is done. Your loop that reads the output of netsh will just run forever because readLine will only return null when netsh closes its standard out (which is never, in your case). You need to look for some standard thing that netsh prints when it is done processing your request.
And as others mentioned, close is bad. Use a flush. And hope netsh uses a flush back to you...
I'd try:
PrintWriter netshWriter = new PrintWriter(netshOutputStream, true); // auto-flush writer
netshWriter.println(command);
No close()ing the stream, flush the stream automatically, and uses a writer to send character data rather than relying on the platforms "native character set".
You do definitely need to remove the close, else you'll never be able to execute another command. When you say "it won't work" once the close() call removed, do you mean no commands are processed?
Chances are that after you send the bytes for the command, you need to send some kind of confirmation key for the process to start, well, processing it. If you'd normally enter this from the keyboard it might be as simple as a carriage return, otherwise it might need to be a Ctrl-D or similar.
I'd try replacing the close() line with
netshOutStream.write('\n');
and see if that works. Depending on the software you might need to change the character(s) you send to signify the end of the command, but this general approach should see you through.
EDIT:
It would also be prudent to call
netshOutStream.flush();
after the above lines; without the flush there's no guarantee that your data will be written and in fact, since you're using a BufferedInputStream I'm 99% sure that nothing will be written until the stream is flushed. Hence why the code afterwards blocks, as you're waiting for a response while the process has not seen any input yet either and is waiting for you to send it some.
I've used scanner instead of BufferedReader, just because I like it. So this code works:
Scanner fi = new Scanner(netshProcess.getInputStream());
public void executeCommand(String command) {
System.out.println("Executing: " + command);
String str = "";
netshWriter.println(command);
fi.skip("\\s*");
str = fi.nextLine();
System.out.println(str);
}
It executes both commands.