Java wait for variable to change - java

I am sitting with a little problem here, and i has been searching for hours for any soultion now, but cant seem to find any, and i hope you can help me.
I have these methods:
public String getInput(){
//Wait here somehow
return "Whatever to return";
}
public void keyTrigger(KeyEvent event){
if(event.getCode().equals(KeyCode.ENTER)){
String[] getInput = gameLog.getText().split("\n");
input = getInput[getInput.length - 1]; //Input is a variable in the class
//Tell the getInput() to continue from where i waited
}
}
So if anyone can tell me how the make the first method wait for a response from the other method, i woul be very happy, because none i have tried so far has worked
EDIT...
Sorry guys, i have missed out on some details.
1st: I am developing a GUI in JavaFX, and the gameLog variable is a textarea, and thats why im splitting the String on linebreaks.
2nd: when i call getInput() i want it to wait for the user to press enter, then get the input variable

Your immediate request would be satisfied by a CompletableFuture:
public String getInput(){
final CompletableFuture<String> fut = new CompletableFuture<>();
commonFuture = fut;
return fut.join();
}
In the above, you need to provide a variable commonFuture which is accessible both from the above code and from your KeyEvent listener, and will serve as the point of contact between these two pieces of code. In the listener you would say
commonFuture.complete(getInput[getInput.length - 1]);
and at that point the join call in getInput() would complete, returning this value.
However, I urge you to seriously think through your current design, which demands such synchronous blocking. You may be able to rework so that getInput is replaced by a callback method which gets invoked when the input value is available.

I don't really understand your issue here, from common logic I guess your getInput() should read from command line and return the value as String. You don't need to write any special code for it, for reading from command line you should use BufferedReader, see the example below.
public String getInput(){
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line;
try{
line = reader.readLine();
}catch(IOException e){
e.printStackTrace();
}
return line;
}
Also this part of your code, input = getInput[getInput.length - 1]; I don't see a point of getInput.length - 1 because getInput() will return a whole string so you don't need to trim it unless you explicitly want to do it. So you can just write input = getInput();, with assumption that variable input is of type String.

Instead of trying to block until the variable changes, you should use a StringProperty and register listeners with it.
Here's some skeleton code:
private final StringProperty input = new SimpleStringProperty();
public StringProperty inputProperty() {
return input ;
}
public final String getInput() {
return inputProperty().get();
}
public final void setInput(String input) {
inputProperty().set(input);
}
// event handler (I'm assuming):
public void keyTrigger(KeyEvent event){
if(event.getCode().equals(KeyCode.ENTER)){
String[] getInput = gameLog.getText().split("\n");
inputProperty().set(getInput[getInput.length - 1]);
}
}
Now you can have code execute when the input is changed:
inputProperty().addListener((obs, oldInput, newInput) -> {
// newInput contains the new value set to the input property....
});
The Properties and Bindings tutorial has more details on using JavaFX properties.

Related

How to return out of command pattern in controller so that application stops running (Java)?

I am designing a controller using the command pattern.
The controller has a while loop inside that is scanning for user input. If user input matches a specific String, then a command class is executed. Here is a code snippit:
public Controller(Readable in, Appendable out) {
this.out = out;
this.scan = new Scanner(in);
this.commandMap = this.generateCommands();
}
public void go(Model m) {
while (scan.hasNext()) {
String input = scan.next();
Command command = this.commandMap.get(input);
command.do(m);
}
}
I usually use return to stop the application. However, when I use return inside one of the Command classes, the application keeps running. I think it just goes back to this upper loop.
By the way, all my commands are public void.
Is there a way to exit/close the application from within the command classes? Like a "super" return? Or do I need to no longer make them void and if/else the return in the controller.
EDIT: system.exit(0) doesn't seem like the right solution for me because it doesn't preserve the appendable log? My JUnit tests no longer print out everything I have appended once system.exit(0) is called.
Use this to terminate the entire program:
System.exit(0);

Handling Errors with try and catch blocks

I Have a question abouth the code for handling erros made by the user.
So the thing is, I need my user to add a name of a program, to add the memory that program takes in the RAM and to add the time he will have that program open.
I need to add in my code defensive programming, so I thought maybe I could do it by checking if the user actually add the type of the variables that the program need, or if it didn't.
Either way I am confused on how to use the try and catch blocks, for now this is what I have...
System.out.println("add program Id");
String programID = scan.next();
try{
String check;
check = programID;
}catch(Exception e){
System.out.println("add a value of String type");
}
That doesn't work.
anything you can type is a string. I can type '5'. That's a string. You may think it is a number, but this entire block of text is a String, and '5' is in it.
No text is a string too. String x = ""; compiles fine.
Thus, no exception would ever occur here, and it's not clear what scenario you are trying to detect.
Perhaps a programID is of the form: "one capital letter (and only english capitals, not Ü for example), and then up to 3 different digits". For example, 'Z5' or 'Y495'.
You'd need to write code to detect this, no need for try/catch. For example, regular expressions:
private static final Pattern PROGRAM_ID_PATTERN = Pattern.compile("^[A-Z]\\d{1,3}$");
public static void main(String[] args) {
....
String programId;
do {
programId = scanner.next();
if (!PROGRAM_ID_PATTERN.matcher(programId).matches()) {
System.err.println("Enter a valid program ID, e.g. A123");
} else {
break;
}
} while (true);
}
Exceptions are for when a method has multiple different ways to exit.
For example, imagine this method:
byte[] contentsOfFile = Files.readFileFully("myfile.txt");
The readFileFully method seems simple: You provide the name of a file, and it returns a byte array with its contents.
However, that's just one way that could go. What if the file doesn't exist? What if the file exists, but your process doesn't have read access rights? What if the disk is failing or it's a removable drive and it's yanked out halfway through reading it?
These somewhat predictable potential alternate ways out are generally done by exceptions. That method would be throwing FileNotFoundException, noReadAccessException, and more generally IOException, for example.
There's no 'that is not a string' variant of scanner.next().
There is scanner.next(Pattern) which you could use:
private static final Pattern PROGRAM_ID_PATTERN = Pattern.compile("^[A-Z]\\d{1,3}$");
public static void main(String[] args) {
....
String programId;
do {
try {
programId = scanner.next(PROGRAM_ID_PATTERN);
break;
} catch (NoSuchElementException e) {
System.err.println("Enter a valid program ID, e.g. A123");
}
} while (true);
}
The javadoc generally explains what exceptions can occur; if a method doesn't mention any, you're not supposed to try/catch there.

Java Loop InputStream until boolean = false

I have this input stream that checks if I have a certain CAD file open or not. I am doing this by using an input stream to run a tasklist command with the name I want to check. I currently have a boolean that returns true if the specific CAD file isn't open. If the CAD file is open, it returns false. However, I want it to be able to loop this until the CAD file is open because as of right now I have to keep running it in order for it to work. I also need to be able to check this boolean from a separate class. I have it in my main right now so i could test it. My code looks like this...
public class AutoCadCheck {
public static void main(String[] argv) throws Exception {
String notOpen = "INFO: No tasks are running which match the specified criteria";
StringBuilder textBuilder = new StringBuilder();
String command = "tasklist /fi \"windowtitle eq Autodesk AutoCAD 2017 - [123-4567.dwg]";
int i;
InputStream myStream = Runtime.getRuntime().exec(command).getInputStream();
while ((i = myStream.read()) != -1) {
textBuilder.append((char) i);
}
String output = textBuilder.toString();
boolean logical = output.contains(notOpen);
if (logical) {
System.out.println("DWG Not Open");
} else {
System.out.print(output);
}
myStream.close();
}
}
My other class is going to have an 'if statement' that checks whether my boolean "logical" is false, and if so, print something. I have tried every possible method I could think of, but I cannot get it to function the way I want it to. Every other thing I found involving looping an inputstream didn't really apply to my situation. So hopefully someone can help me out in achieving what I want to do.
I would start by moving everything out of main and into a different class. This will make retrieving values and calling specific functions easier. Then create an object of that class in main. Once that is done, I'd create a get method for the boolean variable. Now to focus on the loop. Once the object is created in main, create a conditional loop inside of main which calls the function you need until a different condition is met. This condition might be met once the file is open. After the condition is met, it exits to another loop that relies on another conditional, such as user input.
public class AutoCadCheck {
public static void main(String[] argv) throws Exception {
AutoCadFile file = new AutoCadFile();
//loop 1
//Some conditional so the program will
//continue to run after the file has been found.
// while(){
//loop 2
//check to see if the file is open or not
//while(logical){
//}
//}
}
}
Other class
import java.io.IOException;
import java.io.InputStream;
public class AutoCadFile {
private String notOpen;
private StringBuilder textBuilder;
private String command;
private int i;
private InputStream myStream;
private String output;
private boolean logical;
public AutoCadFile() {
notOpen = "INFO: No tasks are running which match the specified criteria";
textBuilder = new StringBuilder();
command = "tasklist /fi \"windowtitle eq Autodesk AutoCAD 2017 - [123-4567.dwg]";
output = textBuilder.toString();
logical = output.contains(notOpen);
try {
myStream = Runtime.getRuntime().exec(command).getInputStream();
} catch (IOException e) {
e.printStackTrace();
}
}
public void checkForFileOpen() {
try {
while ((i = myStream.read()) != -1) {
textBuilder.append((char) i);
}
if (logical) {
System.out.println("DWG Not Open");
} else {
System.out.print(output);
}
myStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public boolean getFileBoolean() {
return logical;
}
}
My other class is going to have an if statement that checks whether my boolean logical is false ...
Well, logical is a local variable within a method. So no code in another class is going to be able to see it.
There are two common approaches to this kind of thing:
Make the variable (i.e. logical) a field of the relevant class. (Preferably NOT a static field because that leads to other problems.)
Put your code into a method that returns the value you are assigning to logical as a result.
From a design perspective the second approach is preferable ... because it reduces coupling relative to the first. But if your application is tiny, that hardly matters.
I can see a couple of other significant problems with your code.
When you use exec(String), you are relying on the exec method to split the command string into a command name and arguments. Unfortunately, exec does not understand the (OS / shell / whatever specific) rules for quoting, etcetera in commands. So it will make a mess of your quoted string. You need to do the splitting yourself; i.e something like this:
String[] command = new String{} {
"tasklist",
"/fi",
"windowtitle eq Autodesk AutoCAD 2017 - [123-4567.dwg]"
};
Your code potentially leaks an input stream. You should use a "try with resource" to avoid that; e.g.
try (InputStream myStream = Runtime.getRuntime().exec(command).getInputStream()) {
// do stuff
} // the stream is closed automatically ... always

Cannot add new object to a set, values come from a file

I am trying to create a public instance method that takes no arguments and returns no values. It is required to get an input from a user to select a file, this part I have no issues with. The method needs to make use of the BufferReader and Scanner Objects. So that it can read the file selected. For each line that is read, a new object should be created and its instance variables set using the values found in the file.
That object that is created should then be added to a list. This is where I am having issues, it won't let me add the new object to the list. Below is my code:
public void readInEntrants()
{
String pathname = OUFileChooser.getFilename();
File aFile = new File(pathname);
Scanner bufferedScanner = null;
Set<Entrant> entrantSet = new HashSet<>();
try
{
String currentEntrantLine;
Scanner lineScanner;
bufferedScanner = new Scanner(new BufferedReader(new FileReader(aFile)));
while (bufferedScanner.hasNextLine())
{
currentEntrantLine = bufferedScanner.nextLine();
lineScanner = new Scanner(currentEntrantLine);
lineScanner.useDelimiter(" ");
currentEntrantLine = lineScanner.next();
entrantSet.add(new Entrant(currentEntrantLine)); // <----- Here is where I am having trouble. It won't let me add the new object to the class Entrant
}
}
catch (Exception anException)
{
System.out.println("Error: " + anException);
}
finally
{
try
{
bufferedScanner.close();
}
catch (Exception anException)
{
System.out.println("Error: " + anException);
}
}
return entrantSet;
}
I'm not sure what to do. Could anyone see what I am doing wrong?
Sorry for got to add that it is a compilation issue, it will not compile properly.
Use an IDE ,I bet you dont (otherwise it would mark compilation error immediatly with red -> you use return in void method ) and in this case you would see other errors.
(off: this would go to comment section however under 50reputation I am not allowed to do that. Stackoverflow should change this imo. )
First of all:
You marked function readInEntrants as public void so you can't use return inside.
You could either remove return entrantSet; instruction or change function definition to public Set<Entrant> readInEntrants.
Concerning problem you have:
Basing on comment you left on beatrice answer I think you have only parameterless constructor for 'Entrant' class, while you try to create it passing string as parameter.
new Entrant(currentEntrantLine)
What you need to do is define Entrant class constructor that accept String as it's argument. For example:
public Entrant(String dataToParse)
{
// here you parse data from string to entrant fields
}
On the side:
You use bufferedReader to read entire file line at once and that's ok, but then you define Scanner lineScanner to iterate through line elements and then use it only once.
This way for file... let's say:
One Two Three
Four Five Six
Your while loop would work like this:
Store "One Two Three" inside currentEntrantLine.
Create scanner that'll work on "One Two Three", and set it to use space as delimiter.
Use .next to "Finds and returns the next complete token" (see documentation) and then store value inside currentEntrantLine. This way contents of currentEntrantLine is "One". Not entire line.
In next iteration you would have scanner working on "Four Five Six" and "Four" as currentEntranceLine content.
It seems the constructor of entrant class does not have any argument. Pass String as an argument type in the constructor to set the String field inside the Entrant class .

Why won't my Export button display the output from my fields

New to asking questions here on stack overflow. I have a program that has me stumped. I have been able to get it to work but just not in the manner I would prefer and I was wondering if some of you could take a look at it and help me figure out what I am doing wrong. Please see below:
For the beginning, the program doesnt compile in class Output at
String ageStr = Input.getAge().toString();
int ageInt = Integer.parseInt(ageStr);
because getAge() returns the address, not the Text of JTextField. Integer can't parse that, as it inhabits not only integers.
And so does all your static getters only return not intended data.
Try to change those in class Input after this sample:
public static String getAge() {
return age.getText();
}
and don't forget to add the outputPanel in class Output
add(outputPanel, BorderLayout.CENTER);
Additionally,
make those methods non-static as stated by others
separate / encapsulate code into fitting methods and improve your API
keep an overall persistent code appearance.
One option is to define an object variable and change your Output-Constructor:
Input input; // keeps a ref to input
public Output(Input input) {
super("Output", 300, 300);
this.input = input;
String ageStr = input.getAge();
...
And the call to:
public void actionPerformed(ActionEvent e){
output = new Output(Input.this);
output.display();
...
Hope it helps you.
Ok here is what I changed, like I said I'm still getting an error. So far all I have tried to fix is the code associated with the age. I will work the rest when i figure out how to make this work. See new code below. I can get it to work if I leave everything static but I know that's not the appropriate method. Tried to fix the formatting as well.

Categories