Java console log simultaneously to readLine without collisions - java

I'm currently dealing with the following problem:
I try to make a console input for a java application
that works with multiple threads. So while running the
software it happens sometimes, that a new line of log is
appearing while I'm writing to the readLine with a promt..
When that happens it looks like the following:
Image of the Console
so it does stack the messages like in the image.. so here is the question:
How can I keep the line and text I am writing to and log the text above it like in the example below?
Gif of the input
(Sorry for low quallity but you can guess what I mean)
As you can see my input stays at the bottom, is still editable and the lines do not stack
Thank you for some help, I am struggeling so much after trying Log4j, System.console, BufferedReaders and Scanner

Solved. It was horrible complicated..
But here for the future:
class ConsoleThread implements Runnable {
private ConsoleReader reader;
private OutputStream output;
public ConsoleThread(OutputStream output, ConsoleReader reader) {
this.output = output;
this.reader = reader;
}
#Override
public void run() {
try {
String message;
while (true) {
message = LoggingQueue.getNextLogEvent();
if(message == null) continue;
reader.print(Ansi.ansi().eraseLine(Ansi.Erase.ALL).toString() + ConsoleReader.RESET_LINE);
reader.flush();
output.write((message + System.lineSeparator()).getBytes());
output.flush();
try {
reader.drawLine();
} catch (Throwable ex) {
reader.getCursorBuffer().clear();
}
reader.flush();
}
} catch (IOException e) {
Controller.handleException(Thread.currentThread(), e);
}
}
Using the ConsoleReader of jLine2 and jAnsi. The output stream is just System.out.
You just need a second thread which reads and you are done :)

You need to handle the threads competing for stdin/stdout.
In theory, that would imply some kind of mutex but, since you're using external libraries, it seems like too much trouble...
From your images, it seems that you're running a sort of server application that takes commands.
If that's the case, I recommend re-architecting to use two separate processes: one for the server part and one for the command prompt.
The two processes then communicate through a socket.
This allows you to make the command prompt single threaded or, at least, behave like a single threaded application, since it is only reacting to user commands.
This is what lots of applications, like Docker, Kubernetes or MySQL do.
In the case of Docker and Kubernetes, they expose full REST APIs on that socket so you can leverage libraries for that.

Related

Open file from file browser in already running application [duplicate]

I need to prevent users from starting my Java application (WebStart Swing app) multiple times. So if the application is already running it shouldn't be possible to start it again or show a warning / be closed again.
Is there some convenient way to achieve this? I thought about blocking a port or write sth to a file. But hopefully you can access some system properties or the JVM?
btw. target platform is Windows XP with Java 1.5
I think your suggestion of opening a port to listen when you start your application is the best idea.
It's very easy to do and you don't need to worry about cleaning it up when you close your application. For example, if you write to a file but someone then kills the processes using Task Manager the file won't get deleted.
Also, if I remember correctly there is no easy way of getting the PID of a Java process from inside the JVM so don't try and formulate a solution using PIDs.
Something like this should do the trick:
private static final int PORT = 9999;
private static ServerSocket socket;
private static void checkIfRunning() {
try {
//Bind to localhost adapter with a zero connection queue
socket = new ServerSocket(PORT,0,InetAddress.getByAddress(new byte[] {127,0,0,1}));
}
catch (BindException e) {
System.err.println("Already running.");
System.exit(1);
}
catch (IOException e) {
System.err.println("Unexpected error.");
e.printStackTrace();
System.exit(2);
}
}
This sample code explicitly binds to 127.0.0.1 which should avoid any firewall warnings, as any traffic on this address must be from the local system.
When picking a port try to avoid one mentioned in the list of Well Known Ports. You should ideally make the port used configurable in a file or via a command line switch in case of conflicts.
As the question states that WebStart is being used, the obvious solution is to use javax.jnlp.SingleInstanceService.
This service is available in 1.5. Note that 1.5 is currently most of the way through its End Of Service Life period. Get with Java SE 6!
I think that the better idea would be to use file lock (quite an old idea :) ). Since Java 1.4 a new I/O library was introduced, that allows file locking.
Once the application starts it tries to acquire lock on a file (or create it if does not exist), when the application exits the lock is relased. If application cannot acquire a lock, it quits.
The example how to do file locking is for example in Java Developers Almanac.
If you want to use file locking in Java Web Start application or an applet you need to sing the application or the applet.
You can use JUnique library. It provides support for running single-instance java application and is open-source.
http://www.sauronsoftware.it/projects/junique/
See also my full answer at How to implement a single instance Java application?
We do the same in C++ by creating a kernal mutex object and looking for it at start up. The advantages are the same as using a socket, ie when the process dies/crashes/exits/is killed, the mutex object is cleaned up by the kernel.
I'm not a Java programmer, so I am not sure whether you can do the same kind of thing in Java?
I've create the cross platform AppLock class.
http://mixeddev.info/articles/2015/02/01/run-single-jvm-app-instance.html
It is using file lock technique.
Update. At 2016-10-14 I've created package compatible with maven/gradle https://github.com/jneat/jneat and explained it here http://mixeddev.info/articles/2015/06/01/synchronize-different-jvm-instances.html
You could use the registry, although this halfheartedly defeats the purpose of using a high-level language like java. At least your target platform is windows =D
Try JUnique:
String appId = "com.example.win.run.main";
boolean alreadyRunning;
try {
JUnique.acquireLock(appId);
alreadyRunning = false;
} catch (AlreadyLockedException e) {
alreadyRunning = true;
}
if (alreadyRunning) {
Sysout("An Instance of this app is already running");
System.exit(1);
}
I've seen so many of this questions and I was looking to solve the same problem in a platform independent way that doesn't take the chance to collide with firewalls or get into socket stuff.
So, here's what I did:
import java.io.File;
import java.io.IOException;
/**
* This static class is in charge of file-locking the program
* so no more than one instance can be run at the same time.
* #author nirei
*/
public class SingleInstanceLock {
private static final String LOCK_FILEPATH = System.getProperty("java.io.tmpdir") + File.separator + "lector.lock";
private static final File lock = new File(LOCK_FILEPATH);
private static boolean locked = false;
private SingleInstanceLock() {}
/**
* Creates the lock file if it's not present and requests its deletion on
* program termination or informs that the program is already running if
* that's the case.
* #return true - if the operation was succesful or if the program already has the lock.<br>
* false - if the program is already running
* #throws IOException if the lock file cannot be created.
*/
public static boolean lock() throws IOException {
if(locked) return true;
if(lock.exists()) return false;
lock.createNewFile();
lock.deleteOnExit();
locked = true;
return true;
}
}
Using System.getProperty("java.io.tmpdir") for the lockfile path makes sure that you will always create your lock on the same place.
Then, from your program you just call something like:
blah blah main(blah blah blah) {
try() {
if(!SingleInstanceLock.lock()) {
System.out.println("The program is already running");
System.exit(0);
}
} catch (IOException e) {
System.err.println("Couldn't create lock file or w/e");
System.exit(1);
}
}
And that does it for me. Now, if you kill the program it won't delete the lock file but you can solve this by writing the program's PID into the lockfile and making the lock() method check if that process is already running. This is left as an assingment for anyone interested. :)

Java application sometimes hangs at start

It's a really weird issue:
Sometimes when I try to start my app, the process creates himself but doesn't do anything.
And sometimes it starts.
I tried to look on the web but I didn't find anything helpful for now. So I was wondering if any of you had the same problem and how did you solved it.
PS:I tried to see the console and show printStackTrace but, there wasn't anything. Just the regulars logs until it hangs (before showing any GUI).
Edit:
Here is the cmd with java -jar when it happens
And Task manager stuck at 30 000k memory
My program is just calling : read("MaxAttempts")
public String read(String NomFonction) {
String ConfigFile = cfgfile.getPath();
try{
InputStream flux=new FileInputStream(ConfigFile);
InputStreamReader lecture=new InputStreamReader(flux);
BufferedReader buff=new BufferedReader(lecture);
String ligne;
String Fonction = null;
while ((ligne=buff.readLine())!=null){
if(ligne.contains(NomFonction + "=")) {
Fonction = ligne.split("=")[1];
}
}
buff.close();
if(!Fonction.equals(null)) {
return Fonction;
}
} catch(Exception e1) {
e1.printStackTrace();
}
return "Error";
}
Try to reproduce it in the debug mode.
Keep starting the process in the debug mode until it is reproduced. When the program hangs, see the list of your threads. If the configuration reading happens in the main thread (and it looks so. If not, pick up the required thread), depending on your IDE, right click on the tread and select "suspend" (then again, depending on your IDE).
It will show where your thread hung.

Efficient execution and output stream redirection of process spawned with Runtime.exec()

I have a script which executes a program several times, producing about 350 lines of output to both STDERR and STDOUT. Now, I need to execute the script in Java, thereby printing the output streams to their original destinations. So, basically, I execute the script from inside a Java class, maintaining the original behavior for the user.
The way I do this is inspired from suggestions like Reading streams from java Runtime.exec and, functionally, works fine.
Process p = Runtime.getRuntime().exec(cmdarray);
new Thread(new ProcessInputStreamHandler(p.getInputStream(), System.out)).start();
new Thread(new ProcessInputStreamHandler(p.getErrorStream(), System.err)).start();
return p.waitFor();
And the class ProcessInputStreamHandler:
class ProcessInputStreamHandler implements Runnable {
private BufferedReader in_reader;
private PrintStream out_stream;
public ProcessInputStreamHandler(final InputStream in_stream, final PrintStream out_stream) {
this.in_reader = new BufferedReader(new InputStreamReader(in_stream));
this.out_stream = out_stream;
}
#Override public void run() {
String line;
try {
while ((line = in_reader.readLine()) != null) {
out_stream.println(line);
}
} catch (Exception e) {throw new Error(e);}
out_stream.flush();
}
}
Now regarding my problem statement: While the execution of the script takes about 17 seconds, the "encapsulated" execution takes at least 21 seconds. Where do I lose these 4 or more seconds?
I already tried using a ProcessBuilder with redirection of STDERR to STDOUT, using POSIX vfork with libraries like https://github.com/axiak/java_posix_spawn, using a byte buffer instead of a BufferedReader... everything with no positive result at all.
Are there any suggestings? I understand that there will be some performance loss, but 4 seconds seem to be a bit much to me...
Appreciate any suggestions!
Best Regards and Thanks in Advance.
The fastest way for your task is to use Java 7 and
return new ProcessBuilder(cmdarray).inheritIO().start().waitFor();
If that doesn’t help, I think there’s nothing you can do as every other approach would add even more code to your runtime environment that has to be processed.
Don't know if it will improve performance or not, but you can try the NuProcess library which while also providing non-blocking (asynchronous) I/O will also use vfork on Linux, which does decrease process launch times (and memory overhead) quite a bit.

Running a command line program multiple times in Java - is this correct?

I have a program (in Java) that needs to use another program multiple times, with different arguments, during it's execution. It is multi-threaded, and also needs to do other things besides calling that program during it's execution, so I need to use Java to do that.
The problem is, all Runtime.exec() calls seem to be done in a synchronized way by Java, such that threads get bottlenecked not around the functions themselves, but in the Java call. Thus, we have a very slow running program, but that does not bottleneck at any system resource.
In order to fix that problem, I decided to not close the Process, and make all calls using this script:
#!/bin/bash
read choice
while [ "$choice" != "end" ]
do
$choice
read choice
done
And all the previous exec calls are substituted by this:
private Process ntpProc;
Initializer(){
try {
ntpProc = Runtime.getRuntime().exec("./runscript.sh");
} catch (Exception ex) {
//Error Processing
}
}
public String callFunction(String function) throws Exception e{
OutputStream os = ntpProc.getOutputStream();
String result = "";
os.write((function + "\n").getBytes());
os.flush();
BufferedReader bis = new BufferedReader(new InputStreamReader(ntpProc.getInputStream()));
int timeout = 5;
while(!bis.ready() && timeout > 0){
try{
sleep(1000);
timeout--;
}
catch (InterruptedException e) {}
}
if(bis.ready()){
while(bis.ready()) result += bis.readLine() + "\n";
String errorStream = "";
BufferedReader bes = new BufferedReader(new InputStreamReader(ntpProc.getErrorStream()));
while(bes.ready()) errorStream += bes.readLine() + "\n";
}
return result;
}
public void Destroyer() throws exception{
BufferedOutputStream os = (BufferedOutputStream) ntpProc.getOutputStream();
os.write(("end\n").getBytes());
os.close();
ntpProc.destroy();
}
That works very well, and actually managed to improve my program performance tenfold. SO, my question is: Is this correct? Or am I missing somethings about doing things this way that will make everything go terribly wrong eventually?
If you want to read from the process Error and Input streams ( aka stderr and stdout ), you need to do this job on dedicated threads.
The main problem is that you need to empty the buffers as they become filled up, and you can only do this on a separate thread.
What you did, you've managed to shorten the output, so it does not overflow these buffers, but the underlying problem is still there.
Also, from the past experience, calling external process from Java is extremely slow, so your approach may be better after all.
As long as you not calling Proccess.waitFor(), execution of process will not block. As Alex said - blocking in your case caused by those loops to read the output.
You can use commons-exec package, as it provides a nice way of running processes (sync or async), handling output, setting timeouts, etc.
Here is a link to a project:
http://commons.apache.org/exec/
The best example of using the api is test class they have:
http://svn.apache.org/viewvc/commons/proper/exec/trunk/src/test/java/org/apache/commons/exec/DefaultExecutorTest.java?view=markup

java process is frozen(?) on linux

This is my first question on S.O.
I have a very odd problem.
Below is my problem...
I write very simple method that write some text to a file.
Of course it works well my machine(XP, 4CPU, jdk1.5.0_17[SUN])
But it somtimes freezes on operating server
(Linux Accounting240 2.4.20-8smp, 4CPU, jdk1.5.0_22[SUN]).
kill -3 doesn't work.
ctrl + \ doesn't work.
So, I can't show you the thread dump.
It freezes well..
When I just write some Thread.sleep(XX) at this method, the problem is gone well(?)...
sleep(XX) break... it happened again today with Thread.sleep(XX)...
Do you know this problem?
Do you have the some solution about that?
Thanks. :-)
P.S.
linux distribution: Red Hat Linux 3.2.2-5
command: java -cp . T
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
public class T {
private BufferedWriter writer = null;
private void log(String log) {
try {
if (writer == null) {
File logFile = new File("test.log");
writer = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(logFile, true)));
}
writer.write(new SimpleDateFormat("[yyyy-MM-dd HH:mm:ss] ")
.format(new Date()));
writer.write("[" + log + "]" + "\n");
writer.flush();
/*
* this is ad hoc solution ???
*/
//Thread.sleep(10);
} catch (Exception e) {
e.printStackTrace();
} finally {
}
}
public void test() {
long startTime = System.currentTimeMillis();
while (true) {
log(String.valueOf(System.currentTimeMillis()));
System.out.println(System.currentTimeMillis());
try {
//Thread.sleep((int) (Math.random() * 100));
} catch (Exception e) {
break;
}
if (System.currentTimeMillis() - startTime > 1000 * 5) {
break;
}
}
if (writer != null) {
try {
writer.close();
} catch (Exception e) {
}
}
System.out.println("OK");
}
public static void main(String[] args) {
new T().test();
}
}
If the JVM does not respond to kill -3 then it is not your program but the JVM that is failing which is bad and would require a bug report to Sun.
I noticed you are running a 2.4.20-8smp kernel. This is not a typical kernel for a current open source Linux distribution, so I would suggest you have a look at http://java.sun.com/j2se/1.5.0/system-configurations.html to see if you are deploying to a supported configuration. If not, you should let the responsible people know this!
The first step is to get a thread dump of where the program is when it "freezes". If this were on Java 6, you could connect JVisualVM or JConsole to it by default, and get the stacktraces of all the threads from there. Since it's Java 5, you should be able to use the jstack command to get a thread dump (or you could enable JMX with a command-line option to attach the aforementioned tools, but I don't think it's worth it in this case). In all cases, pressing Ctrl-Break from the console that launched the application may also produce a thread dump, depending on the environment.
Do this several times a few seconds apart and then compare the thread dumps. If they're always identical, then it looks like your application is deadlocked; and the top line of the dump will show exactly where the threads are blocking (which will give a very good clue, when you look at that line of the code, which resources they're blocked on).
On the other hand if the thread dumps change from time to time, the program is not strictly deadlocked but looks like it's running in an infinite loop - perhaps one of your loop conditions is not declared properly so the threads never exit or something of that sort. Again, look at the set of thread dumps to see what area of code each thread is looping around in, which will give you an idea of the loop condition that is never evaluating to an exit condition.
If the issue isn't obvious from this analysis, post back the dumps as it will help people debug your above code.
I think this is a race condition. The while(true) will force the VM on linux to write and flush continuously, and the linux kernel VM will try to intercept those calls and buffer the writing. This will make the process spinloop while waiting for the syscall to be completed; at the same time, it will be picked up by the scheduler and assigned to another CPU (I might be wrong here, tho). The new CPU will try to acquire a lock on the resource, and everything will result in a deadlock.
This might be a sign of other issues to come. I suggest:
first of all, for clarity's sake: move the file creation outside of the log() method. That's what constructors are for.
secondly, why are you trying to write to a file like that? Are you sure your program logic makes sense in the first place? Would you not rather write your log messages to a container (say, an ArrayList) and every XX seconds dump that to disk in a separate thread? Right now you're limiting your logging ability to your disk speed: something you might want to avoid.

Categories