How to exit 2D game simulation (only) without exiting the Java code? - java

I (new to Java) am working on a decades old Java project built using Golden T Studios Game dev jdk. I have a game in the project which runs a 2D simulation. The code structure in a nutshell is as follows:
package game;
import java.io.*;
import java.lang.reflect.Field;
import javax.swing.JFrame;
import com.golden.gamedev.GameLoader;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import sometcpimports.*;
public class MainGAME extends JFrame implements Runnable {
public static void main(String[] args) { //call new MainGAME;
}
public MainGAME() {//initiate game parameters;
//start new THREAD;
}
#Override
public void run() { //initiate new game and environment;
game = new GameLoader();
gameenv = new GameEnvironment(params); //This class is in another file "public class GameEnvironment extends Game {}"
//I don't clearly undertsand what the following lines do, so I'm mentioning them as is;
game.setup(gameenv, dimensions);
this.setVisible(false);
gameenv.setVisible(false);
game.start();
game.setVisible(true);
//tbd (code reaches this step)
}
}
My goal is to run the above simulation multiple times (with different inputs each time) and extract information after each run in a new main class as follows.
public class gamedriver {
public static void main(String[] args) {
MainGAME.params = some params;
MainGAME.main(); // runs the simulation;
//tbd1 (code doesn't reach this step)
}
}
The issue is that, on running the simulation from a different file (new main class), I am unable to exit 2D simulator after one run. The code doesn't reach //tbd1 in the new main class which has some output print statements. Essentially I want to simply exit simulator and not the whole JVM. So far I've tried:
game.stop() & gameenv.finish() at //tbd which does nothing.
System.exit(0) at //tbd which exits game after simulation but also exits jvm and doesnt reach the other main class.
finish() at both //tbd and GameEnvironment class which behaves exactly like point 2.
Additionally, I am unable to run the above (MainGAME in gamedriver class) in a for loop. This throws Game.Exception error. I understand it has something to do with threads but I'm not sure how to run them.
Thank you for your time. Appreciate your help!

I found a method to solve the above problem. I'm posting my workaround as a reference for someone who encounters a similar issue. Please note that there might be other (better) solutions out there.
I disabled all (any) threads implementation in the MainGAME (by simply commenting it out).
I added System.out.println() in MainGAME to print all my outputs at the end of simulation.
My second script uses Runtime processes to execute MainGAME:
public class gamedriver {
public static void main(String[] args) {
try {
String separator = System.getProperty("file.separator");
String classpath = System.getProperty("java.class.path");
String path = System.getProperty("java.home") + separator + "bin" + separator + "java";
String[] command = new String[]{path, "-cp", classpath, gamedriver.GAME.class.getName(), "output.csv"};
Process process = Runtime.getRuntime().exec(command);
process.waitFor();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
static class GAME {
public static void main(String args[]) {
PrintStream out = null;
try {
out = new PrintStream(args[1]);
} catch (FileNotFoundException p) {
p.printStackTrace();
}
System.setOut(out);// this catches all output from the game to a csv file (output.csv)
MainGAME temp = new MainGame(some params); // initiate the simulation
temp.run()
out.close();
System.exit(0); // force close the simulator
}
}
}
I parse output.csv to get the solution.
This might be a sloppy way to solve the issue, but it worked for me, especially because none of the other methods provided by GTGE worked.

Related

IllegalThreadStateException Error on Simple Chat Application using Socket Programmin, Code bellow

Client code:
import java.io.BufferedReader;
import java.io.IOError;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.*;
import java.util.Scanner;
import javax.swing.*;
import java.io.*;
public class messages_client
{
static BufferedReader in;
static Scanner sc;
static PrintWriter out;
public static void main(String args[])
{
try{
JFrame frame=new JFrame();
Socket client=new Socket("localhost",59001);
in=new BufferedReader(new InputStreamReader(client.getInputStream()));
out=new PrintWriter(client.getOutputStream(),true);
sc=new Scanner(System.in);
boolean running=false;
String input=in.readLine();
System.out.println(input);
String name=sc.next();
out.println(name);
running=true;
Thread send=new Thread(new send());
Thread recieve=new Thread(new recieve());
if(running == true)
{
while(true)
{
send.start();
recieve.start();
}
}
} catch(IOException e){}
}
public static class send implements Runnable
{
#Override
public void run()
{
String message=sc.nextLine();
out.println(message);
}
}
public static class recieve implements Runnable
{
#Override
public void run()
{
try {
String input=in.readLine();
System.out.println(input);
} catch (IOException e) {
}
}
}
}
Server code:
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.concurrent.Executors;
public class messages_server
{
private static ServerSocket server;
private static Set<PrintWriter> printwriters=new HashSet<>();
public static void main(String args[])
{
try{
server=new ServerSocket(59001);
var pool=Executors.newFixedThreadPool(5);
System.out.println("Server is running");
while(true)
{
pool.execute(new ClientHandler(server.accept()));
}
} catch(IOException e)
{
} finally
{
try{
server.close();
} catch(IOException e){}
}
}
private static class ClientHandler implements Runnable
{
private Socket client;
private static PrintWriter out;
private static BufferedReader in;
private static String message;
private static String name;
ClientHandler(Socket client)
{
this.client=client;
}
#Override
public void run()
{
try{
out=new PrintWriter(client.getOutputStream(),true);
in=new BufferedReader(new InputStreamReader(client.getInputStream()));
send("Name: ");
name=in.readLine();
System.out.println(name);
out.println("1");
broadcast(name+" has joined the chat");
while(true)
{
message=in.readLine();
broadcast(name+":"+message);
}
} catch(IOException e){}finally
{
if(in != null)
{
printwriters.remove(out);
broadcast(name+" has left the chat");
}
try{
client.close();
}catch(IOException e){}
}
}
public void broadcast(String message)
{
for(PrintWriter printwriter:printwriters)
{
printwriter.println(message);
}
}
public void send(String message)
{
out.println(message);
}
}
}
I have created this simple Chat Application where multiple users can join a common chat.The Server creates a different thread for each client and continuously recieves and broadcasts data.The client to has two threads: "send" "recieve" which send and recieve data continuosly.
The Server works fine but when I run the client after typing in my name there shows IllegalThreadStateException.
Please help and suggest if there is anyway I can improve this code too.
I think you're confused about what Thread's start() method does.
In your code:
Thread send = new Thread(new send());
Thread recieve = new Thread(new recieve());
You create exactly one thread (send) for sending, and exactly one (recieve - note you have a typo, it's "receive". English is weird) for receiving.
You then:
while(true)
{
send.start();
recieve.start();
}
repeatedly (while loop) invoke .start() on these single threads.
That's not how it works: You can only start a Thread object once, ever. If you invoke .start() the second time, you get IllegalThreadStateException, because the state is 'STARTED' and you can't call .start() on such a thread.
What's not quite clear is your intent. Were you intending to continually start threads? Then you'd have to create a new thread object every time and then start it, i.e. move the Thread send = ...; code inside the while loop. However, I can't imagine you want that: If you stick that in a while(true) the system will create an infinite amount of threads, starts them, and, naturally, crashes very very quickly and very definitely if you try that.
If your intent is simply to keep that one send and one receive thread from continuing to run - there is no need to repeatedly invoke .start() or do anything else from the main method - your receive and send runnables already have loops (they both have a while(true) loop of their own).
If you intent is to restart any thread that somehow stopped itself, 'just in case' - that's not how it works. Once a thread ends you can't start it again - you'd have to make a new one. And as discussed before, just making an endless amount of threads is just going to lead to a swift crash. You CAN ask a thread if it is no longer running, and then create a new thread and start the new one, but you shouldn't defensively program.
Let me clarify that, because the term 'defensive programming' is overloaded: You should not write code to deal with situations that are not understood. In this case, the situation is: "I dont quite know how, but lets just imagine the send thread is somehow stopped. I want to restart it if this happens". The reason that kind of defensive programming is bad, is: By definition you don't really know what happened (after all, you have no idea how some state COULD happen, therefore it is likely that you're missing rather crucial understanding about what's going on when the to you impossible situation does evidently occur), so the odds that you're doing the right thing (that 'just restart it' is the right answer to 'huh, weird, that thread stopped and I do not understand why') are low.
Most likely, the situation you can't fathom happening can, in fact, never happen, so you wrote a bunch of code that never ever runs. This leads to the biggest problem of defensive programming: The code is untestable, and rarely (often never) runs, which means any bugs in it go completely unnoticed. So you now have useless code that if it ever becomes useful, doesn't work at all.
It is FAR better to just hard-crash out with an exception in such impossible cases. At least then, if it does occur, you have a lead on investigating. Only after you understand can you write code that deals with the situation.

how to test this class with JUnit testing?

I have TicTacToe game in java language and I have to do Junit test cases for this Game class, because I need to apply mutation testing for this application. can anyone help me to write good test cases.
public class Game {
private Board board;
private Queue<Player> players;
public Game() {
board = new Board();
players = new LinkedList<>();
addPlayers();
}
private void addPlayers() {
players.add(new Player("X"));
players.add(new Player("O"));
}
private void startGame() throws IOException {
do {
Player currentPlayer = players.remove();
System.out.println("Enter position for Player "+currentPlayer.toString());
java.io.BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
board.placeMarker(currentPlayer,new Position(Integer.parseInt(in.readLine()),Integer.parseInt(in.readLine())));
players.add(currentPlayer);
System.out.println(board.toString());
if(board.hasWon(currentPlayer)){
break;
}
}while (board.hasEmptyPosition());
}
public void main(String[] args) {
Game game= new Game();
try {
game.startGame();
} catch (IOException e) {
e.printStackTrace();
}
}
}
this is a very simple application, so there aren't a lot of possible tests to do.
first you should focus on testing the public API of a class, but in your case you only have main. Secondly, you depend on external input, which makes it harder to test your code...
I recommend you to read some articles on how to make your code more testable. For instance:
https://medium.com/feedzaitech/writing-testable-code-b3201d4538eb
https://www.toptal.com/qa/how-to-write-testable-code-and-why-it-matters
A few starters:
Create a class responsible for starting the app (having the main method): let's call it class Application
Make Game startGame() method receive as input a function that returns the input (in your PROD code you'll use the BufferedReader, in test code you could use a stream for instance
same idea for the addPlayers method
Extract a method for each play (basically the code inside the do...while) so that you can test it as well
and maybe you can find a few more tasks
ps: but in the end, with such a basic codebase, this is kinda overkill...

How To Allow Only One .Jar Instance, And To Let It Use Args From Other Attempted Instances?

I've got a tough question, for which I will first sketch a background to make things more understandable.
Background
I have made an audioplayer in Java which can be launched with command line args, and also without. The application's .jar (made with Netbeans) is wrapped in a .exe file (made with Launch4j) so that you can open for example a mp3 file with the .exe, and then the .jar inside adopts the filepath in it's String[] args.
The problem with this approach (for now) is that if you select multiple mp3 files at once and you open them at the same time, they all get opened in seperate windows of the audioplayer. What I want however, is that all the files get opened in one single instance of the application.
What I then attempted is to let Launch4j allow only one instance of the .jar/.exe in the hopes that all the selected files would be opened in one application, this did unfortinately not work.
What I see as a solution
So I want to be able to select multiple .mp3 files in windows, and that all their filepaths get passed on as a command line arg to one single instance of the application. Or a different approach that has the same result. Does anyone know how to realize this in the actual application?
Many thanks in advance. I will try to keep looking for potential solutions/ideas as well.
--Edits--
The main method is ready to receive multiple files. I have implemented a piece of code that saves all the command line args of the application to a .txt file, and when I allow only one single instance with the Launch4j .exe file, there only appears to be one single argument in the .txt file when I try to open multiple mp3 files.
If I allow the .exe to have multiple instances, then I simply have the .jar application being launched multiple times (one time for each file I try to open).
I used java RMI (Remote Method Invokation) to make a single-instance application.
An RMI attempts to listen on a socket with a user-defined port number.
When starting the jar.
If noone serves that port, then this instance is the RMI server. Establish a GUI Window. Call an open with the main's args.
If there is already a serving application, send by RMI an open with the main's args. Then exit normally, return from main.
Code: Untested as you probably want to arrange things differently.
public interface OpenRMI extends Remote {
void open(String[] args) throws RemoteException;
}
public class SingleInstanceApp implements OpenRMI {
private static final String RMI_ENTRY = "ImJustACowLolAudioPlayer";
public static void main(String[] args) throws RemoteException,
AccessException, NotBoundException {
System.out.println("main " + Arrays.toString(args));
if (System.getSecurityManager() == null) {
System.setSecurityManager(new SecurityManager());
}
Registry registry = LocateRegistry.getRegistry();
OpenRMI openRMI;
try {
System.out.println("bind with new OpenRMI");
SingleInstanceApp app = new SingleInstanceApp();
openRMI = (OpenRMI) UnicastRemoteObject.exportObject(app, 0);
registry.bind(RMI_ENTRY, openRMI);
System.out.println("Player bound");
app.create(); // Server.
} catch (AlreadyBoundException e2) {
System.out.println("lookup as someone else bound before us");
openRMI = (OpenRMI) registry.lookup(RMI_ENTRY); // Client.
}
openRMI.open(args);
}
private void create() {
new Thread(true) { // Daemon thread, or start GUI
#Override
public void run() {
System.out.println("create " + this);
for (int i = 0; i < 10; ++i) {
Thread.sleep(1000L);
}
shutdown();
}
}
}
private void shutdown() throws RemoteException,
NotBoundException, AccessException {
System.out.println("close " + this);
Registry registry = LocateRegistry.getRegistry();
registry.unbind(RMI_ENTRY);
}
#Override
public void open(String[] args) throws RemoteException {
System.out.println("open " + this + ": " + Arrays.toString(args));
}
}
I would expect some more decent classes.
I fixed it, after some hours of programming and taking breaks inbetween
package argsbuilder;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
public class ArgsBuilder
{
public static void main(String[] args)
{
checkIfRunning(args);
}
private static void checkIfRunning(String[] args)
{
buildFile(args);
ProcessBuilder pb = new ProcessBuilder("core.exe"); //core.exe is a .exe wrapper with the .jar audioplayer in it
try
{
Process p = pb.start();
}catch (IOException f){System.out.println(f);}
}
private static void buildFile(String[] args)
{
try
{
boolean notdone = true;
int i=0;
File f;
while(notdone)
{
f = new File("arg" + i + ".txt");
if(f.exists())
{
i++;
}
else
{
PrintStream out = new PrintStream(new FileOutputStream(new File("Folder Location" + "arg" + i + ".txt")));
System.setOut(out);
System.out.println(args[0]);
notdone = false;
}
}
}catch(Exception g){System.out.println(g);}
}}
What the above does
The above application checks if there are other argument files, and if there are it will keep generating a new name untill the name is free. It then prints the argument to that file. After it has printed the argument, it launches the audioplayer. In the audioplayer the following happens:
import javafx.embed.swing.JFXPanel;
import java.net.InetAddress;
import java.net.ServerSocket;
public class YourApp {
public static void main(String[] args)
{
try
{
socket = new ServerSocket(PORT,0,InetAddress.getByAddress(new byte[] {127,0,0,1}));
//Everything you need to launch the application in the try
}catch(Exception g){//Nothing in the catch}
}}
What the above does
It tries to claim a serversocket for itself. If there already is one then it does not proceed to launch the application. That way only one instance will be running at a time. (at PORT you just fill in a random integer).
Combining those 2, you can read the textfiles created by the first application and interpret them as arguments in the second application.
So how does it interpret them as arguments?
Well, I already had a timer fixed into the program, and I tell the audioplayer to look for the very first arg file (arg0.txt) in a specified folder. If it finds it it adds it to an arraylist, along with all arg+i.txt files.
It might not be the fastest way, but it surely works well.

timing an operation in java

I want to run my program in eclipse but I want to see how long it takes to run the program. In other words I want to time my program. I know that in UNIX I can time any operation by placing the word “time” before the command on the command line. But I dont know how I might be able to time my operation in Eclipse. Just to make everything a bit more clear, I want to avoid writing new methods. Is there a way that I could add sth to my configuration path? Does anyone have an idea of how I can do so?
If you don't mind adding two lines of code, you can do this purely in Java:
public class Foo {
public static void main(String[] args) {
long ms = System.currentTimeMillis();
// do whatever
System.out.println(System.currentTimeMillis() - ms);
}
}
You could also use nanoTime if you need it.
Add a system.out.println at the end of your app to indicate how long it ran.
Put this class somewhere in your code:
package your.package.name.common;
import org.apache.log4j.Logger;
import java.util.concurrent.TimeUnit;
public class CProfile {
/**
* Logger for this class
*/
private static final Logger logger = Logger.getLogger(CProfile.class);
public static final int SECONDS_TO_ALERT = 2;
public static void slownessAlert(long startTime, String name) {
long seconds = TimeUnit.SECONDS.convert(System.nanoTime() - startTime, TimeUnit.NANOSECONDS);
if (seconds>SECONDS_TO_ALERT){
logger.warn("slow method detected: "+name+" "+seconds+"s");
}
}
}
Then use this snippet in your code in following way:
public void something() {
long startTime = System.nanoTime();
//SOME HEAVY COMPUTATIONS
CProfile.slownessAlert(startTime, "something");
}
It will inform you about slowness when it happens (SECONDS_TO_ALERT>2s).
Add the speed-tracer plugin to eclipse if it is a web application.It will help u find out the time for everything.
A simple way to do this and guarantee you will get results is to add the following to the top of your main class. This code will save the app start time and then add JVM shutdown hook that will fire and print the duration when the JVM shutsdown.
final static long startTime = System.currentTimeMillis();
static {
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
try {
System.out.println("My program ran for "+( System.currentTimeMillis()-startTime )+" seconds.");
} catch (Exception e) {
e.printStackTrace();
}
}
});
}

IDE-Style program running

My Goal
I am attempting to make a Java program in which a user can select any .class or .jar file from their computer. My program will then pop up a JInternalFrame with a JEditorPane in it as the console, capturing any console output from the user's program. When the user's program closes (calls System.exit(int status);), my program must not close along with it. My program might also have such features as a button to immediately stop the user's program and others an IDE would. My program need not compile Java code, only run .class and .jar files.
My Experience
I have made a small test version of this program wherein I got two specific files from a package and had the user click one of two buttons, each representing one of the two programs. A press of a button calls the following method:
private void run(Class runnable)
{
java.lang.reflect.Method[] m = runnable.getMethods();
boolean hasMain = false;
for (int i = 0; i < m.length; i++)
{
if (m[i].getName().equals("main") && m[i].getParameterTypes()[0].isArray() && m[i].getParameterTypes()[0].getName().contains("java.lang.String"))
try
{
Object invoke = m[i].invoke(null, (Object)globalArgs);
hasMain = true;
hub.setExtendedState(Hub.ICONIFIED);
numPrograms++;
}
catch (Throwable t)
{
java.util.logging.Logger.getLogger(Hub.class.getName()).log(java.util.logging.Level.SEVERE, null, t);
javax.swing.JOptionPane.showMessageDialog(null, "Could not run " + runnable.getName(), "Error in invocation", javax.swing.JOptionPane.ERROR_MESSAGE);
}
finally
{
break;
}
}
if (!hasMain)
javax.swing.JOptionPane.showMessageDialog(null, runnable.getName()
+ " does not have a public static main method that\nreturns void and takes in an array of Strings",
"No main method", javax.swing.JOptionPane.ERROR_MESSAGE);
}
This method successfully calls either program's main method and runs a copy of said program. However, when any of the programs this hub has started calls the System.exit(int status) command, the hub closes, too. Also, I haven't the slightest clue as to how to capture console output.
My Questions
Does anyone have any experience or advice they would be willing to share to help me make a fully-functional program that can...
Open and run a compiled Java file (remember that .jar files may have more than one class with main(String[] args) method)
Catch System.exit(int status); so that the hub program handles the internal program's exiting
Catch new java.io.PrintStream().println(Object o) and similar calls and place their output in a JEditorPane
Make a button that, when pressed, stops the internal program from running
Possibly make all JFrames the internal program uses into JInternalFrames and place them in a JDesktopPane
If you don't want the other program (which you call through it's main method) to be able to shut down the JVM you're running in, you have, as I see it, three options:
1. Using a SecurityManager
Set up the SecurityManager so that it prevents the System.exit call:
public class Test {
public static void main(String args[]) {
SecurityManager sm = System.getSecurityManager();
System.setSecurityManager(new SecurityManager() {
#Override
public void checkExit(int status) {
throw new SecurityException("Client program exited.");
}
});
try {
System.out.println("hello");
System.exit(0);
System.out.println("world");
} catch (SecurityException se) {
System.out.println(se.getMessage());
}
}
}
Prints:
hello
Client program exited.
This is probably the nicest solution. This is the way application servers prevent an arbitrary servlet from terminating the entire server.
2. Separate JVM
Run the other program in a separate JVM, using for instance ProcessBuilder
import java.io.*;
public class Test {
public static void main(String args[]) throws IOException {
ProcessBuilder pb = new ProcessBuilder("java", "other.Program");
pb.redirectErrorStream();
Process p = pb.start();
InputStream is = p.getInputStream();
int ch;
while ((ch = is.read()) != -1)
System.out.print((char) ch);
is.close();
System.out.println("Client program done.");
}
}
3. Use shutdown hooks instead
Don't disallow the termination of the JVM, but instead add shutdown-hooks that cleans up the "hub" and exits gracefully. (This option probably only makes sense if your running one "external" program at a time.)
import java.io.*;
public class Test {
public static void main(String args[]) throws IOException {
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
System.out.println("Uninitializing hub...");
System.out.println("Exiting gracefully.");
}
});
// Run client program
System.out.println("Running... running... running...");
System.exit(0);
}
}
Prints:
Running... running... running...
Uninitializing hub...
Exiting gracefully.

Categories