Skip to content

Commit

Permalink
Better Exception handling and messages
Browse files Browse the repository at this point in the history
  • Loading branch information
[email protected] committed Jan 7, 2024
1 parent 7e38b18 commit bdfdb26
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 121 deletions.
12 changes: 6 additions & 6 deletions src/main/java/de/nqueensfaf/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ public Config() {

public void validate() {
if (updateInterval < 0)
throw new IllegalArgumentException("invalid value for updateInterval: only numbers >0 or 0 (no updates) are allowed");
throw new IllegalArgumentException("invalid value for updateInterval: must be a number >=0 (0 means disabling updates)");

if (autoSaveEnabled) {
if (autoSavePercentageStep <= 0 || autoSavePercentageStep >= 100)
throw new IllegalArgumentException(
"invalid value for autoSavePercentageStep: only numbers >0 and <100 are allowed");
"invalid value for autoSavePercentageStep: must be a number >0 and <100");
if (autoSavePath != null && autoSavePath.length() > 0) {
File file = new File(autoSavePath);
try {
Expand All @@ -44,18 +44,18 @@ public void validate() {
file.createNewFile();
file.delete();
}
} catch (Exception e) {
} catch (IOException e) {
// if something goes wrong, the path is invalid
throw new IllegalArgumentException("invalid value for autoSavePath: " + e.getMessage());
throw new IllegalArgumentException("invalid value for autoSavePath: invalid path or filename");
}
} else {
throw new IllegalArgumentException(
"invalid value for autoSavePath: must not be null or empty when autoSaveEnabled is true");
"invalid value for autoSavePath: must be specified when autoSaveEnabled is true");
}
} else { // auto save is disabled
if (autoDeleteEnabled)
throw new IllegalArgumentException(
"invalid value for autoDeleteEnabled: must not be true when autoSaveEnabled is true");
"invalid value for autoDeleteEnabled: must be false when autoSaveEnabled is false");
}
}

Expand Down
57 changes: 24 additions & 33 deletions src/main/java/de/nqueensfaf/Solver.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ protected Solver() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
System.err.println("could not wait for auto save to finish: " + e.getMessage());
break;
}
}
}));
Expand All @@ -35,7 +36,7 @@ protected Solver() {

protected abstract void run();
protected abstract void save_(String filepath) throws IOException;
protected abstract void load_(String filepath) throws IOException, ClassNotFoundException, ClassCastException;
protected abstract void load_(String filepath) throws IOException;

@SuppressWarnings("unchecked")
public final <T extends Solver> T solve() {
Expand All @@ -60,15 +61,15 @@ public final <T extends Solver> T solve() {
run();
} catch (Exception e) {
state = Status.TERMINATING;
throw e;
throw new RuntimeException("error while running solver: " + e.getMessage());
}

state = Status.TERMINATING;
if(config().updateInterval > 0) {
try {
bgThread.join();
} catch (InterruptedException e) {
throw new RuntimeException("unexpected error while waiting for background thread to die: " + e.getMessage());
throw new RuntimeException("could not wait for background thread to terminate: " + e.getMessage());
}
}
if (finishCb != null)
Expand All @@ -88,27 +89,27 @@ public final <T extends Solver> T solveAsync() {
@SuppressWarnings("unchecked")
public final <T extends Solver> T waitFor() {
if(asyncSolverThread == null || !asyncSolverThread.isAlive())
throw new IllegalStateException("waitFor() can not be called: solver is not running asynchronous at the moment");
throw new IllegalStateException("could not wait for solver thread to terminate: solver is not running asynchronous");
try {
asyncSolverThread.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException("could not wait for solver thread to terminate: " + e.getMessage());
}
return (T) this;
}

private void preconditions() {
if (n == 0) {
state = Status.IDLE;
throw new IllegalStateException("board size was not set");
throw new IllegalStateException("starting conditions not fullfilled: board size was not set");
}
if (!isIdle()) {
state = Status.IDLE;
throw new IllegalStateException("solver is already started");
throw new IllegalStateException("starting conditions not fullfilled: solver is already started");
}
if (getProgress() == 1.0f) {
state = Status.IDLE;
throw new IllegalStateException("solver is already done, nothing to do here");
throw new IllegalStateException("starting conditions not fullfilled: solver is already done, nothing to do here");
}
}

Expand All @@ -132,34 +133,20 @@ else if (progress >= tmpProgress + config().autoSavePercentageStep) {
new Thread(() -> {
try {
save(filePath);
} catch (IllegalArgumentException | IOException e) {
System.err.println("error in autosaver thread: " + e.getMessage());
} catch (IOException e) {
System.err.println("could not save solver state: " + e.getMessage());
}
}).start();
tmpProgress = progress;
}
}

try {
Thread.sleep(config().updateInterval);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}

if(updateConsumer) {
onUpdateConsumer.accept(this, getProgress(), getSolutions(), getDuration());
}

if(autoSaver) {
progress = getProgress() * 100;
if (progress >= 100) {
if (config().autoDeleteEnabled) {
try {
new File(filePath).delete();
} catch (SecurityException e) {
throw new SecurityException("unable to delete autosave file", e);
}
new File(filePath).delete();
}
}
}
Expand Down Expand Up @@ -192,16 +179,20 @@ private void smallBoardNQ(int ld, int rd, int col, int row, int free, int mask)
}
}

public final void save(String filepath) throws IOException, IllegalArgumentException {
public final void save(String filepath) throws IOException {
if(isSaving)
return;
if(isIdle())
throw new IllegalStateException("could not save solver state: solver is idle");
isSaving = true;
save_(filepath);
isSaving = false;
}

public final synchronized void load(File file)
throws IOException, ClassNotFoundException, ClassCastException, IllegalArgumentException {
public final synchronized void load(File file) throws IOException{
if(!isIdle())
throw new IllegalStateException("could not load solver state: solver already running");

load_(file.getAbsolutePath());
config().autoSavePath = file.getAbsolutePath();
solve();
Expand All @@ -210,7 +201,7 @@ public final synchronized void load(File file)
@SuppressWarnings("unchecked")
public final <T extends Solver> T onInit(Consumer<Solver> c) {
if (c == null) {
throw new IllegalArgumentException("argument must not be null");
throw new IllegalArgumentException("could not set initialization callback: callback must not be null");
}
initCb = c;
return (T) this;
Expand All @@ -219,7 +210,7 @@ public final <T extends Solver> T onInit(Consumer<Solver> c) {
@SuppressWarnings("unchecked")
public final <T extends Solver> T onFinish(Consumer<Solver> c) {
if (c == null) {
throw new IllegalArgumentException("argument must not be null");
throw new IllegalArgumentException("could not set finish callback: callback must not be null");
}
finishCb = c;
return (T) this;
Expand All @@ -238,10 +229,10 @@ public final <T extends Solver> T onUpdate(OnUpdateConsumer onUpdateConsumer) {
@SuppressWarnings("unchecked")
public final <T extends Solver> T setN(int n) {
if (!isIdle()) {
throw new IllegalStateException("cannot set board size while solving");
throw new IllegalStateException("could not set board size: solver already running");
}
if (n <= 0 || n > 31) {
throw new IllegalArgumentException("board size must be a number between 0 and 32 (not inclusive)");
throw new IllegalArgumentException("could not set board size: must be a number between >0 and <32");
}
this.n = n;
return (T) this;
Expand Down
14 changes: 0 additions & 14 deletions src/main/java/de/nqueensfaf/SolverException.java

This file was deleted.

24 changes: 9 additions & 15 deletions src/main/java/de/nqueensfaf/cli/CLI.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import picocli.CommandLine.Option;
import picocli.CommandLine.ParameterException;
import picocli.CommandLine.Spec;
import picocli.CommandLine.TypeConversionException;

@Command(name = "nqueensfaf")
public class CLI implements Runnable {
Expand All @@ -38,8 +39,7 @@ public class CLI implements Runnable {
"--config" }, paramLabel = "FILE", required = false, description = "absolute path to the configuration file")
public void setConfigFile(File configFile) {
if (!configFile.exists()) {
throw new ParameterException(spec.commandLine(),
"Invalid value '" + configFile.getAbsolutePath() + "' for option '--config-file': file not found");
throw new ParameterException(spec.commandLine(), "invalid config file: file not found");
}
this.configFile = configFile;
}
Expand All @@ -50,8 +50,7 @@ public void setConfigFile(File configFile) {
"--task" }, paramLabel = "FILE", required = false, description = "absolute path to the file containing the task")
public void setTaskFile(File taskFile) {
if (!taskFile.exists()) {
throw new ParameterException(spec.commandLine(),
"Invalid value '" + taskFile.getAbsolutePath() + "' for option '--task-file': file not found");
throw new ParameterException(spec.commandLine(), "invalid task file: file not found");
}
this.taskFile = taskFile;
}
Expand Down Expand Up @@ -91,8 +90,7 @@ public void run() {
return;
}
if (n <= 0 || n >= 32) {
System.err.println("Invalid board size! Must be a number with > 0 and < 32.");
return;
throw new TypeConversionException("invalid board size: " + n + " is not >0 and <32");
}
}

Expand All @@ -104,9 +102,8 @@ public void run() {
if (configFile != null) {
try {
cpuSolver.config().load(configFile);
} catch (IllegalArgumentException | IllegalAccessException | IOException e) {
System.err.println("Could not apply config: " + e.getMessage());
System.exit(0);
} catch (IllegalAccessException | IOException e) {
throw new IOException("could not apply config: " + e.getMessage());
}
} else {
System.out.println("no config file provided, using default config...");
Expand All @@ -118,8 +115,7 @@ public void run() {
try {
gpuSolver.config().load(configFile);
} catch (IllegalArgumentException | IllegalAccessException | IOException e) {
System.err.println("Could not apply config: " + e.getMessage());
System.exit(0);
throw new IOException("could not apply config: " + e.getMessage());
}
} else {
System.out.println("no config file provided, using default config...");
Expand Down Expand Up @@ -187,10 +183,8 @@ public void run() {
* utils.getj(key), utils.getk(key), utils.getl(key), solPerIjkl.get(key));
* }
*/
} catch (IOException | ClassNotFoundException | ClassCastException | IllegalArgumentException
| IllegalStateException e) {
System.err.println("Unexpected error: " + e.getMessage());
// e.printStackTrace();
} catch (Exception e) {
System.err.println("could not create or execute solver: " + e.getMessage());
}
}

Expand Down
18 changes: 5 additions & 13 deletions src/main/java/de/nqueensfaf/impl/CPUSolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,8 @@ protected void run() {
}
progress = (float) solvedConstellations / constellations.size();
}
} catch (InterruptedException e1) {
// e.printStackTrace();
Thread.currentThread().interrupt();
} catch (InterruptedException e) {
throw new RuntimeException("could not wait for solver cpu threads to terminate: " + e.getMessage());
}
loaded = false;
}
Expand All @@ -117,10 +116,6 @@ public CPUSolverConfig config() {

@Override
protected void save_(String filepath) throws IOException {
// if Solver was not even started yet, throw exception
if (constellations.size() == 0) {
throw new IllegalStateException("Nothing to be saved");
}
try (Output output = new Output(new GZIPOutputStream(new FileOutputStream(filepath)))) {
kryo.writeObject(output,
new SolverState(n, System.currentTimeMillis() - start + storedDuration, constellations));
Expand All @@ -129,10 +124,7 @@ protected void save_(String filepath) throws IOException {
}

@Override
protected void load_(String filepath) throws IOException, ClassNotFoundException, ClassCastException {
if (!isIdle()) {
throw new IllegalStateException("Cannot load a state while the Solver is running");
}
protected void load_(String filepath) throws IOException {
try (Input input = new Input(new GZIPInputStream(new FileInputStream(filepath)))) {
SolverState state = kryo.readObject(input, SolverState.class);
setN(state.getN());
Expand Down Expand Up @@ -204,9 +196,9 @@ public CPUSolverConfig() {
public void validate() {
super.validate();
if (threadcount < 1)
throw new IllegalArgumentException("invalid value for threadcount: only numbers >0 are allowed");
throw new IllegalArgumentException("invalid value for threadcount: not a number >0");
if (presetQueens < 4)
throw new IllegalArgumentException("invalid value for presetQueens: only numbers >=4 are allowed");
throw new IllegalArgumentException("invalid value for presetQueens: not a number >= 4");
}
}
}
Loading

0 comments on commit bdfdb26

Please sign in to comment.