Why jTextArea.setText() method works after it should? - java

Sorry guys maybe it can be a silly question but really i couldn't find any similar situation like this.
Here is my code:
private void startHashingButtonActionPerformed(java.awt.event.ActionEvent evt) {
consoleArea.setText( myFile.getName() + " started to be hashing! It can take few minutes, please wait.."); //20:05
try {
BufferedReader reader = new BufferedReader(new FileReader(myFile));
myHash = new HashOA(300000);
try {
while(reader.readLine() != null){
myHash.hash(reader.readLine());
}
consoleArea.append("\n" + myFile.getName() + " is successfully hashed!!");
} catch (IOException ex) {
Logger.getLogger(MainScreen.class.getName()).log(Level.SEVERE, null, ex);
}
} catch (FileNotFoundException ex) {
Logger.getLogger(MainScreen.class.getName()).log(Level.SEVERE, null, ex);
}
}
I expect that in consoleArea(TextArea) there should be "file.txt started to be hashing! It can take few minutes, please wait.." written and after that the hashing process(that while(reader.readLine() != null) loop) should be started. But when i run the program and click on "startHashingButton" it first finishes hashing process and later it writes on console(jTextArea) --> "file.txt started to be hashing! It can take few minutes, please wait..", "file.txt is successfully hashed!!"
I'm working on a large text file and it takes a while to hash it. That's why i want to tell user he/she should wait a bit.
Why the working queue differs from my code order ?
Note: The only thing that came to my mind is to use thread, could it solve the problem?

Note: The only thing that came to my mind is to use thread, could it solve the problem?
Yes, that is correct. Code executed in an event listener is invoked on the Event Dispatch Thread. The GUI can't be repainted until all the code is finished executing. So a long running task prevents the GUI from repainting itself.
Read the section from the Swing tutorial on Concurrency in Swing for more information. Maybe a SwingWorker will be a better solution than creating your own Thread.

Use SwingWorker to implement a worker thread.
Do all the processing in doInBackground method, you can add your following code in doInBackground. Before that you can you will set the text in your console area. And once your file is hashed, you can implement done() method and set the appropriate message in your console area. To give you an idea, it will look something like this
#Override
protected Integer doInBackground() throws Exception {
try {
BufferedReader reader = new BufferedReader(new FileReader(myFile));
myHash = new HashOA(300000);
try {
while(reader.readLine() != null){
myHash.hash(reader.readLine());
}
return null;
} catch (IOException ex) {
Logger.getLogger(MainScreen.class.getName()).log(Level.SEVERE, null, ex);
}
} catch (FileNotFoundException ex) {
Logger.getLogger(MainScreen.class.getName()).log(Level.SEVERE, null, ex);
}
}
#Override
protected void done() {
consoleArea.append("\n" + myFile.getName() + " is successfully hashed!!");
}
Refer this for more clarity : How do I make my SwingWorker example work properly?

Related

How to use console view in Eclipse RCP Application

I just started using RCP to write Java-based applications. I am trying to add a console view in my app, and output info of log4j to the console. Now it works. But there is a problem, it cannot perform as eclipse witch output once per line, but output all info after the method finish.
Object[] elements = tableViewer.getCheckedElements();
if(elements.length > 0){
for(Object ele : elements){
File file = (File) ele;
logger.info("log4j处理目录" + file.getAbsolutePath());
MessageConsoleStream stream = ConsoleFactory.getConsole().newMessageStream();
stream.println("println处理目录" + file.getAbsolutePath());
try {
stream.flush();
stream.close();
} catch (IOException e1) {
e1.printStackTrace();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
I tried use stream.println() stream.flush(), but it does not work.
It is my first time questing on stackoverflow. Sorry for my english.
Calling Thread.sleep(1000) in the User Interface Thread will block the entire UI and nothing will happen. Never do this.
If you want to do something once a second use the timerExec method of Display to run code.
Something like:
Display.getDefault().timerExec(1000, new Runnable() {
#Override
public void run()
{
// TODO output one item to the log
// TODO if need to run again call
Display.getDefault().timerExec(1000, this);
}
});
The JavaDoc for MessageConsoleStream says:
Clients should avoid writing large amounts of output to this stream in
the UI thread. The console needs to process the output in the UI
thread and if the client hogs the UI thread writing output to the
console, the console will not be able to process the output.
So you must not loop constantly outputting to the stream without letting other code in the UI thread run.

Dialog with changing text in swing

I am developing a swing application in which I am running a cmd command using Runtime.getRuntime.execute(); and reading the output of command using BufferReader. Now what I want is I want to show the output in dialog with changing the text(Using JTextPane) inside it or appended strings in a textarea with the output of command like we can see while starting Eclipse of any other IDE for loading prerequisites.
I tried making subclass of JDialog class but it is not doing what i want.
My Code :
Process p = Runtime.getRuntime().exec(commandToBeExecuted);
BufferedReader in = new BufferedReader(newInputStreamReader(p.getInputStream()));
String line = null;
MessageDialog myDialog=new MessageDialog(UserInterface.this);
while ((line = in.readLine()) != null) {
System.out.println(line);
myDialog.setText(line);
myDialog.setVisible(true);
myDialog.setLocationRelativeTo(UserInterface.this);
}
} catch (Exception ex) {
Logger.getLogger(UserInterface.class.getName()).log(Level.SEVERE, null, ex);
errorGlobal.setText("Some Exception Occured in update "+ex.getMessage());
System.out.println("Exception occured " + ex.getMessage());
}
Is it possible to do what I want and what will be the best way to achieve this ?
Your problem is in the loop. Use JTextArea.append and put the rest outside the loop,

Socket read() and ready() interlock, client disconnect detection

Ok my issue is simple. I am trying to make simple chat but i feel that detection of disconnected client from server is mandatory. Chat works fine (without such detection) when i use simple:
if (this.in.ready()) //preinitialized buffered reader
this.dataIn=this.in.readLine();
I have browsed lots of websites/questions posted here and i read that ready() should be ommited since it blocks everything, that may be true since when i delete this ready() my chat no longer works, however it enables client disconnected detection.
In order to reach my goal i need to test if BufferedReader recieves null through readLine() but this does not work as it should either.
if (this.in.readLine()!=null){ //1. check if client disconnected
if (this.in.ready()) //2/
this.dataIn=this.in.readLine(); //3.
}
else
this.notice="Client disconnected!";
Now what happens when i apply code presented above. Initial if (1) is blocking the inner ready() (line 2) which is required to read actual message send over socket (3).
The other "order" does not work:
if (this.in.ready()){
this.dataIn=this.in.readLine();
}
else if (this.in.readLine()!=null)
this.notice="Client disconnected!";
This one also does not allow to send messages through socket.
*Yes, sending/recieving is realized in separate thread
*BufferedReader is initialized only once
Thread source code (if any1 would need it in order to take a look):
#Override
public void run() {
try {
if (this.isServer){
this.initServer();
this.initProcessData(sSocket);
}
else if (!this.isServer){
this.initClient();
this.initProcessData(clientSocket);
}
this.initDone=true;
} catch (IOException ex) {
Logger.getLogger(NetClass.class.getName()).log(Level.SEVERE, null, ex);
}
while(this.initDone){
try {
Thread.sleep(100);
if ((!this.dataOut.isEmpty())&&(this.dataOut!="")){
this.out.println(this.dataOut);
this.out.flush();
this.dataOut = "";
}
if (this.in.ready())
this.dataIn=this.in.readLine();
}
catch (IOException ex) {
Logger.getLogger(NetClass.class.getName()).log(Level.SEVERE, null, ex);
}
catch (InterruptedException ex) {
this.initDone=false;
Logger.getLogger(NetClass.class.getName()).log(Level.SEVERE, null, ex);
}
//System.out.println(this.notice);
}
}
The worst thing is that i have either proper detection of client disconnected or i have working chat.
Can anyone enlight me what should i do in order to combine those two together? Any help greatly appreciated.
Consider using java.io.ObjectInputStream and java.io.ObjectOutputStream. Use the blocking read() method in a separate worker thread, and loop until it returns -1 or throws an exception. Send String objects back and forth. In that way, you can also send messages with line feeds.

Webapp that runs process won't complete

So I've got a couple of shell scripts that run on a server. They do some time intensive data gathering and then complete. They seem to work fine when I run them from the server. I'm now trying to automate these with a Spring webapp. Everything is running and I can run the scripts through ProcessBuilder, but for some reason, when the scripts are run through ProcessBuilder they only get about halfway and then just stop responding.
I'm really hoping someone will have some thoughts on why this might be. Unfortunately due to the work I can't really post much in the way of code. I can post the webapp code that runs the processes, which I'll do down below, but I can't post the scripts. If anyone has some thoughts please chime in. Thanks.
#Entity
public class Job implements Runnable {
#Id #GeneratedValue
private Long id;
//getters and setters
#Override
public void run() {
Process p = null;
try {
BufferedWriter bw = new BufferedWriter(new FileWriter("/opt/condor/bin/datafile"));
bw.write(this.getName());
bw.close();
p = new ProcessBuilder("/opt/condor/bin/scripts/create-filter.sh").start();
jobHelper(p);
List<String> dates = datesBetween();
status = "Running Master";
for(String temp : dates) {
String[] splitDate = temp.split("-");
String tmpYear = splitDate[0];
String tmpMonth = splitDate[1];
String tmpDay = splitDate[2];
log.info("Running Master script: master.sh " + this.getCustomer() + ", " + this.getProject() + ", " + tmpYear + ", " + tmpMonth + ", " + tmpDay);
p = new ProcessBuilder("/opt/condor/bin/scripts/master.sh", this.getCustomer(), this.getProject(), tmpYear, tmpMonth, tmpDay).start();
log.info("Entering job helper");
jobHelper(p);
log.info("exited job helper");
}
status = "Finished Master";
log.info("Finished Master");
} catch (IOException ioe) {
log.error("IO Error: " , ioe);
ioe.printStackTrace();
}
log.info("Done running script");
endTime = Long.toString(System.currentTimeMillis());
status = "Ended";
JobManager.FinishJob(this);
}
private boolean jobHelper(Process p) {
log.info("inside job helper");
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
try {
while ((line = br.readLine()) != null) {
log.info(line);
if(line.contains("Uh oh!"))
return true;
}
boolean running = true;
while(running) {
log.info("waiting...");
p.waitFor();
log.info("done waiting");
running = false;
}
} catch (IOException e) {
log.error("IO Error: " , e);
e.printStackTrace();
} catch (InterruptedException e) {
log.error("Interrupted Exception: ", e);
e.printStackTrace();
p.destroy();
}
return false;
}
}
I apologize for any syntactical errors you see, the code does compile and run so please just ignore them. I was copying and pasting the relevant bits of code and may have messed up something in that regard.
EDIT
I added some log statements in different places and can see that the code is entering my helper, which is why it is displaying output, but at some point it just stops. it doesn't ever seem to hit the log statements surrounding the p.waitFor() method. Clearly I'm not doing something right, which is understandable since threads are a huge weakpoint of mine. I'm guessing maybe it is getting hung up displaying stuff and I'm then getting a deadlock situation but I really don't understand where or how to fix it. Can anyone let me know what I'm screwing up and what I need to do to fix it? I could really use an example as well, thanks.
I can not help much without more context on why your process is hanging. However, your entity should not be runable. Extract this to a service, you can store your process id in you entity if you need to map it back to a process.
Well after more research it seems that the problem was related to me not properly getting all the data from the input and error streams. I guess you're supposed to have multiple threads for each stream, which I still don't understand. I added a line that called the redirectErrorStream() method on the processbuilder object and that seems to have helped. I'm still not sure it won't hang again when processing greater amounts of data as I've seen a bunch of talk about all the streams needing to be in their own threads as I mentioned, but I'm not really sure how I'm supposed to do that. It's very hard to find a good concise example of how to use ProcessBuilder. However, this seems to have fixed the problem I was having.

Java Gridgain application starts to fail after 1 day of stress testing

So I have a an application which is running on top of gridgain and does so quite successfully for about 12-24 hours of stress testing before it starts to act funny. After this period of time the application will suddenly start replying to all queries with the exception java.nio.channels.ClosedByInterruptException (full stack trace is at http://pastie.org/664717
The method that is failing from is (edited to use #stephenc feedback)
public static com.vlc.edge.FileChannel createChannel(final File file) {
FileChannel channel = null;
try {
channel = new FileInputStream(file).getChannel();
channel.position(0);
final com.vlc.edge.FileChannel fileChannel = new FileChannelImpl(channel);
channel = null;
return fileChannel;
} catch (FileNotFoundException e) {
throw new VlcRuntimeException("Failed to open file: " + file, e);
} catch (IOException e) {
throw new VlcRuntimeException(e);
} finally {
if (channel != null) {
try {
channel.close();
} catch (IOException e){
// noop
LOGGER.error("There was a problem closing the file: " + file);
}
}
}
}
and the calling function correctly closes the object
private void fillContactBuffer(final File signFile) {
contactBuffer = ByteBuffer.allocate((int) signFile.length());
final FileChannel channel = FileUtils.createChannel(signFile);
try {
channel.read(contactBuffer);
} finally {
channel.close();
}
contactBuffer.rewind();
}
The application basically serves as a distributed file parser so it does a lot of these types of operations (will typically open about 10 such channels per query per node). It seems that after a certain period it stops being able to open files and I'm at a loss to explain why this could be happening and would greatly appreciate any one who can tell me what could be causing this and how I could go about tracking it down and fixing it. If it is possibly related to file handle exhaustion, I'd love to hear any tips for finding out for sure... i.e. querying the JVM while it's running or using linux command line tools to find out more information about what handles are currently open.
update: I've been using command line tools to interrogate the output of lsof and haven't been able to see any evidence that file handles are being held open... each node in the grid has a very stable profile of openned files which I can see changing as the above code is executed... but it always returns to a stable number of open files.
Related to this question: Freeing java file handles
There are a couple of scenarios where file handles might not be being closed:
There might be some other code that opens files.
There might be some other bit of code that calls createChannel(...) and doesn't call fillContactBuffer(...)
If channel.position(0) throws an exception, the channel won't be closed. The fix is to rearrange the code so that the following statements are inside the try block.
channel.position(0);
return new FileChannelImpl(channel);
EDIT: Looking at the stack trace, it seems that the two methods are in different code-bases. I'd point the finger of blame at the createChannel method. It is potentially leaky, even if it is not the source of your problems. It needs an in internal finally clause to make sure that the channel is closed in the event of an exception.
Something like this should do the trick. Note that you need to make sure that the finally block does not closes the channel on success!
public static com.vlc.edge.FileChannel createChannel(final File file) {
final FileChannel channel = null;
try {
channel = new FileInputStream(file).getChannel();
channel.position(0);
FileChannel res = new FileChannelImpl(channel);
channel = null;
return res;
} catch (FileNotFoundException e) {
throw new VlcRuntimeException("Failed to open file: " + file, e);
} catch (IOException e) {
throw new VlcRuntimeException(e);
} finally {
if (channel != null) {
try {
channel.close();
} catch (...) {
...
}
}
}
}
FOLLOWUP much later
Given that file handle leakage has been eliminated as a possible cause, my next theory would be that the server side is actually interrupting its own threads using Thread.interrupt(). Some low-level I/O calls respond to an interrupt by throwing an exception, and the root exception being thrown here looks like one such exception.
This doesn't explain why this is happening, but at a wild guess I'd say that it was the server-side framework trying to resolve an overload or deadlock problem.

Categories

Resources