I have, a game bot which runs through console. I don't think i'm going to code a gui for it but i would like to have the possibility to close the program without CTRL+C cause this just interrupts my program instead of properly cleaning up the code and ensure that theres no leaks.
Should i use som kind of Key Bindings or am i bound to, make a GUI ?
Or how could i go about this ?
I think thats what a shutdown hook is for.
Runtime.getRuntime().addShutdownHook( new Thread() {
#Override
public void run() {
System.out.println("Application shutdown");
}
});
David's answer is good. It may well work for you.
I generally prefer not to deliberately abort a process and then detect that it's coming down to avoid dangling operations. So I'd probably do more like:
Are you processing console inputs as they are entered? IF so, you could just have a console command that tells the app to shut down, and check for this in whatever your process is of handling console inputs. Or if you mean that the app just runs with no user input, you could just periodically check if the console buffer is empty (Console.reader().ready()), and if not, read the console and see if it's the quit command.
Related
Situation
I've been creating a program to exchange messages between two computers in the LAN. One computer identifies itself as the server while the other is a client. Upon startup, the user has to enter the Host and the Port of another computer, should he wish to connect as a client to that machine.
The setup of how it works is very basic: You type your message, hit enter and it shows up on your own screen. After that your conversation partner has to click a button to retrieve the latest messages and it should show up on his screen. This goes on untill someone leaves.
Problem
The program launches correctly and asks for the connection settings. After that I initiate the connection on both computers and things seem to go fine (after the connection is established, a label shows you what your status, e.g. Client or Server, is (1)). Things continue looking fine when I enter a message and send it, the output gets written to the sender's screen and no unexpected behaviour occurs.
When I want to retrieve the messages on the other computer, the program completely freezes. No objects in the GUI are clickable and no output is shown.
Code
Assuming the connection is correctly established (see (1)), I will outline the process of sending a message below while leaving out the non-essential parts.
GuiApplication.java
private void sendMessage() {
connection.sendMessage(message);
showMessage(message);
}
Connection.java
public void sendMessage(String message) {
if (isClient()) {
client.sendMessage(message);
} else if (isServer()) {
server.sendMessage(message);
}
}
Client.java
public void sendMessage(String message) {
outbound = new PrintWriter(socket.getOutputStream(), true); // Defined outside this method
outbound.println(message);
}
The process of sending a message is pretty straightforward, but I wanted to include it just in case I've overlooked something.
What follows is the code I've created to retrieve the new messages. The concept is simple: I check if there are any new messages and if there are, I retrieve them.
GuiApplication.java
if (connection.hasNewMessage()) {
message = connection.retrieveMessage();
}
showMessage(message);
The first part (connection.hasNewMessage()) will check whether or not the program is either running the client or the server and call the appropriate retrieveMessage().
Client.java
public String retrieveMessage() throws IOException {
inbound = socket.getInputStream(); // Defined outside this method
return IOUtils.toString(inbound, "UTF-8");
}
At first I've tried this with a BufferedReader using an InputStreamReader and calling the readLine() method, but decided to try out the commons.io method once I noticed it didn't work (the same problem as I am currently facing).
Question
It's been made pretty clear by now: why does my program hang the moment I click a button which retrieves new messages?
External
I'm not sure if it's frowned upon, but here's the github repository in case you wanted a better overview, although I believe the necessary code snippers are there.
I did look at your code, and as I suspected, your problem has absolutely nothing to do with the code you've posted. Your GUI completely ignores Swing threading rules, and calls long-running tasks on the main Swing event thread known as the Event Dispatch Thread or EDT. Since this thread is responsible for all Swing drawing and user interaction, your GUI is prevented from doing this and becomes completely frozen.
Please read Concurrency in Swing for the details on this.
And next time, please post an sscce so we don't have to dive into a huge amount of your source code! The key to the SSCCE is to eliminate all code not essential to your problem at hand. This is not easy to do and will require a lot of work from you to create, so that it has enough code to run, but not too much as to drown us in code, but then you are asking volunteers to help you on their free time, so it's not asking too much.
Best of luck!
Without reading all your explanations and all code attachments I can assume that you are reading from or writing to stream into UI thread (e.g. call IO operation from Action or ActionListener directly and you are blocked on read/write.
Please examine your code. I believe you will find point where you call to in.read() or out.write(). Add print just before and just after the line. You will see that you never exit read or write.
This is because the other side does not perform opposite operation. So, you have to:
decouple UI from IO. IO must be done in separate thread.
check why other side blocks your flow.
I have a java app which has a menu. One of the menu items is Exit. Which is defined as follows:
item_exit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
System.exit(0);
}
});
Another menu item is New, which makes another instance (?) of the same program run in parallel. It is defined as follows:
item_new.addActionListener(new ActionListener() {
MyApp app = new MyApp();
app.start();
}
});
It works as desired except for one problem. It's that when I close one of them, both of them close. The entire app is built on one JFrame object. I don't think changing the default close operation of it will help. I think the issue is with system.exit(0). But, what is the alternative to fix this? I only want the thread I closed to close, not all of them. Thanks.
Creating an object and callings its start() method doesn't make another program run in parallel. It only creates an object, in the same JVM, and executes its start() method, in the same JVM.
System.exit() exits the JVM, so everything running in this JVM stops running.
To make a JFrame invisible, you call setVisible(false) on it. That won't stop the JVM.
System.exit(0); makes the entire Java machine to quit, with everything that is running within. Try not to use this, unless you really need this to happen.
For quitting, perhaps try checking this How to close a Java Swing application from the code
System.exit(0) quits the complete program, not only the current thread. If you want to quit a thread, you have two options: a thread automatically quits as soon as the corresponding Runnables run() method finishes, or you can kill the thread using thread.stop() (just for completeness, shouldn't be used).
Please read the documentation for System.exit(). It specifically states:
Terminates the currently running Java Virtual Machine.
This means the JVM will terminate, and all of your threads with it.
System.exit(0) shuts the whole JVM down.
Your two instances run on the same JVM : you don't fork a process, you just create another instance of your MyApp class. So it is obvious that both "applications" will be killed.
Instead of calling System.exit(0), you should send a termination signal to the JFrame you want to close
frame.dispatchEvent(new WindowEvent(frame, WindowEvent.WINDOW_CLOSING));
This way, only that JFrame (or "application") will be killed.
Another option would be to fork a whole new process. For that, I recommend you take a look at the Process class.
Basically, you'll need to change the action of "Exit" so that it's able to detect when there's another "app" currently running ... and to do something plausible in that case. Maybe you alert the user that the other activity hasn't finished yet, and warn him that if he really wants to exit now, the other activity will be abandoned. Maybe you launch the other activity in such a way that it is altogether separate and therefore doesn't care. There are several good alternatives, so this really becomes a design decision on your part: what strategy makes the most intuitive sense for you, and for your users?
I have a program which bruteforces an AES256 encryption, how would I pause the program when the computer goes into shutdown/or reboot and continue at the same point until the next boot of the system?
A sort of hibernate of the program.
I would agree with part 2 and 3 of #Thufir's answer, but regarding part 1 it assumes that you are running a GUI.
Instead of this I would add a shutdown hook into the JVM and write the state of my program at that point. You can do this using the following:
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
// your serialization code goes here
}
});
You asked three things here.
1- How can I check when the OS goes reboot/shutdown
Solution:
You can make an empty invisible window, and add WindowListener to it. It will receive windowClosing event on windows.
You can find an example HERE
2- How can I save the state of my BruteForce process and pause to start again when system goes up.
Solution:
Here is easy, you must serialize. These will save the state of your class/classes to deserialize when system goes UP again. You can study HERE
3- How know when startup the programm again when OS goes UP?
Solution:
You can put your program in initialization process of your OS. When it starts, you check if there is anything to deserialize and do it, restoring the process of the BruteForce.
I've come to the conclusion after reading from many sources that using printStackTrace for error handling is bad practice. Here's one.
Now I'm struck curious: in what cases is printing the stacktrace a valid solution? For the sake of the argument, let's assume we aren't working on a system such as a microwave or a banana, but a basic out-of-the-shelf PC.
The reason I'm asking this could be seen as a question in itself, but I'll tell you about it anyhoo:
I'm developing a snake-like game that can be played with AIs, and is intended for that purpose. All such AIs should extend an abstract class called SnakeLogic. All such AIs should also reside in their standalone .jar archives in a specific folder, from where the main program can find them and list them using classloaders.
The user can then choose one of his/her AIs from a list, should all stars fall in line, and play a game with this AI.
Now, I have a method in my main program that gets the next move from the AI like so:
public void startGame(int speed) {
gameInterface.showWindow();
Runnable moveCmd = () -> {
try {
for (Player player : snakeGame.getPlayers()) {
if (player.isDead()) {
continue;
}
String move = player.getLogicHandler().getMove();
Direction direction = Direction.directionFromString(move);
snakeGame.makeMove(player, direction);
}
gameInterface.getFrame().repaint();
snakeGame.wait(speed);
if (snakeGame.gameOver()) {
stopGame();
}
} catch (Exception ex) {
ex.printStackTrace();
stopGame();
}
};
/* moveSchedule is an instance of ScheduledExecutorService */
moveSchedule.scheduleAtFixedRate(moveCmd, 1000, speed, TimeUnit.MILLISECONDS);
}
I'm not going to get too involved with the code above. I'd like to draw your attention to the try-catch statement, however. As you can see I print the stacktrace and end the game, should an exception occur somewhere during the execution of the moveCmd runnable. This is the source of my curiosity: If I don't print the stacktrace like this, or if I remove the try-catch entirely, I never get any errors in the case of a runtime exception during the execution of that block. Why? Is it because it's wrapped inside the runnable? Note also that the line snakeGame.makeMove(player, direction); doesn't call any code in the main program; snakeGame is an instance of a SnakeLogic, which resides in an external .jar.
Why don't I get any errors if I remove the try-catch? Also, in this case, is printing the stacktrace a good idea?
I understand this imposes two questions for you: the topic and the above. I want to emphasize the topic, so don't get too sidetracked with the second question; though insight is duly noted, there's nothing broken in my code.
You need to shift your thought process a bit when dealing with error and exceptions. It is always a good practice to print the error trace. Now the question is where to print. by default printStackTrace prints to your standard console. of course you can redirect that output to a log file like Tomcat does but that is a work around, if you ask me.
In production and pre-prod systems and even in distributable spftware where you distribute a desktop application to users for running on PCs you may or may not have dedicated access to console. Further more what prints on console is lost once the console is closed or app finishes. You need to persist the errors somewhere for analysis later. Normally folks design the app to zip and send error logs periodically to developers for analysis.
Now if you think about the whole scenarios the bottom line is to preserve the errors somewhere for analysis later. So usually do it in a rotating log file or in DB. Console wont suffice. Thus incidentally the catch block should have a log statement to log the exception.
The problem with Exception.printStackTrace() is that it writes to your console (most probably) which is a synchronous operation. Not to mention that writing to console is slow in most platforms. You dont want to hold off your execution thread until the full stack trace is written. So its better to hand it over to a log framework like log4j which has the ability to write the complete stack trace into to file asynchronously (other appenders are available), so that the execution thread returns immediately to the callee and yet the log contains necessary details.
So its a question of synchronous write or asynchronous write. As Nazgul pointed out, you have to log exceptions in a system for later analysis where ever applicable.
NotE: A problem with asynchronous logging is that if the process dies abruptly, like in kill -9 or system powered down, you may loose the buffered content before OS has chance to write it to disk
What is the best way to have a (Java) program recognize it crashed last time it ran and show a message along the lines of "it looks like this program crashed on you last time. Report this problem here: bla#foo.com ...."
Is there a recommended way of doing this? (Bad?) ideas I had would be:
Have the program store a temporary key file at startup and then delete it when closing regularly. If the file exists at startup, show the message.
Recognize deadlocks and store an "error file" in this case. If an "error file" exists at startup, show the error message and move the file into an archive or something similar.
There are three reasons why a Java program can crash:
Unhandled RuntimeException. This is easy to solve with a try-catch in main.
Unhandled Errors. These are rare but can be caught in main also. I usually catch Throwable in main. See below for a template.
If you use threads, then look at Thread.setDefaultUncaughtExceptionHandler().
Bugs in the VM, or program killed by the user, or hardware violent shutdown. These will lead to a crash which can't be caught. Here, your best option is to create a flag file somewhere with new File(...).deleteOnExit(). Java will clean it up for you if it gets a chance.
The problem with deadlocks is how to detect that you have a deadlock. I haven't seen a consistent way to do that, yet.
import org.apache.commons.lang.exception.ExceptionUtils;
public class Demo
{
public static void main (String[] args)
{
try
{
Demo obj = new Demo ();
obj.run (args);
System.out.println ("Done.");
}
catch (Throwable t)
{
ExceptionUtils.printRootCauseStackTrace (t);
}
}
}
Crash as in an uncaught exception? The use a Thread.setDefaultUncaughtExceptionHandler, and display the message as part of the crash.
On the first idea, how do you handle multiply instances of the applications running at the same time? (Also think about multi-user environments).
Recognize deadlocks - How often are deadlocks the problem? I guess you could monitor the thread states on all the "key" threads.
You then have external forces killing the application, should they be considered a problem that you should report? After all your application was not at fault in this case.
Finally, always store an "error file" in the form of a log. Use a proper logging framework (i.e. Java Logging or Log4J). You could check the last lines of this for a signal that the application exited normally but again you will need to be careful in multi-instance environments.
A variant of the first solution you propose is common enough on Un*x for processes: store the pid file of a running process in a file at startup. When the program is launched again you can check if this file still exists (and even if the process with this pid is running).
With Java you could probably adapt this idea using Threadid defined in ThreadMXBean. But any file would do. A file that contains a key as you propose seems a good enough way. You could also put some usefull information in it like last execution time. If it's still there at startup the program didn't stopped cleanly.
It could also become something like a launch log file that trace program events including startup and clean stops, and maybe locks.
What I do is redirect System.err to a file, so that any error message (like crashes) end up in a file I can later process...
The code to do this is quite simple...
String errLog = "c:\\myLog";
try
{
java.io.PrintStream err = new java.io.PrintStream(new java.io.FileOutputStream(errLog));
System.setErr(err);
}
catch (java.io.FileNotFoundException fnfe) {}
I'm going to mimic Marcos here. Create a configuration or log file that will host the last error message and last run date of the program. Then read that file during program load.
Many of these answers are about tracking exceptions that caused your app to quit working.
Another possibility is that the application just quit (i.e. user killed it, computer shutdown, power outage, etc.). I think your temporary key idea will work for that. It's similar to how text editing programs, such as vi or Word, automatically create a special copy of the file being edited. Upon opening it checks to see if the special copy exists and asks if you want to recover the file.