From ea3e2bf07939926e43c7abe3fd13a7c4e93f69d1 Mon Sep 17 00:00:00 2001 From: Adrien Hopkins Date: Thu, 22 Aug 2024 11:41:04 -0500 Subject: Show unit/dim file errors as popup Previously, any error in the unit or dimension file(s) crashes the program. Instead, 7Units now ignores any invalid lines, still parsing the correct ones, and shows a popup in case any errors happen. --- .../java/sevenUnits/unit/LoadingException.java | 96 ++++++++++++++ src/main/java/sevenUnits/unit/UnitDatabase.java | 138 ++++++++++----------- 2 files changed, 165 insertions(+), 69 deletions(-) create mode 100644 src/main/java/sevenUnits/unit/LoadingException.java (limited to 'src/main/java/sevenUnits/unit') diff --git a/src/main/java/sevenUnits/unit/LoadingException.java b/src/main/java/sevenUnits/unit/LoadingException.java new file mode 100644 index 0000000..9376ed7 --- /dev/null +++ b/src/main/java/sevenUnits/unit/LoadingException.java @@ -0,0 +1,96 @@ +/** + * Copyright (C) 2024 Adrien Hopkins + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package sevenUnits.unit; + +import java.nio.file.Path; +import java.util.Optional; + +/** + * An exception that occurred when loading a file. This wrapper class adds more + * info about the error. + * + * @author Adrien Hopkins + * @since 2024-08-22 + */ +public final class LoadingException extends RuntimeException { + public static enum FileType { + UNIT, DIMENSION + } + + private static final long serialVersionUID = -8167971828216907607L; + + private final long lineNumber; + private final String line; + private final Optional file; + + private final FileType fileType; + + private final RuntimeException problem; + + public LoadingException(long lineNumber, String line, FileType fileType, + RuntimeException problem) { + super(problem); + this.lineNumber = lineNumber; + this.line = line; + this.file = Optional.empty(); + this.fileType = fileType; + this.problem = problem; + } + + public LoadingException(long lineNumber, String line, Path file, + FileType fileType, RuntimeException problem) { + super(problem); + this.lineNumber = lineNumber; + this.line = line; + this.file = Optional.of(file); + this.fileType = fileType; + this.problem = problem; + } + + public Optional file() { + return this.file; + } + + public FileType fileType() { + return this.fileType; + } + + @Override + public String getMessage() { + return this.file + .map(f -> String.format( + "Error parsing line %d of %s file '%s' (\"%s\"): %s", + this.lineNumber, this.fileType.toString().toLowerCase(), f, + this.line, this.problem)) + .orElse(String.format( + "Error parsing line %d of %s stream (\"%s\"): %s", + this.lineNumber, this.fileType.toString().toLowerCase(), + this.line, this.problem)); + } + + public String line() { + return this.line; + } + + public long lineNumber() { + return this.lineNumber; + } + + public RuntimeException problem() { + return this.problem; + } +} diff --git a/src/main/java/sevenUnits/unit/UnitDatabase.java b/src/main/java/sevenUnits/unit/UnitDatabase.java index 514b27d..dc81aca 100644 --- a/src/main/java/sevenUnits/unit/UnitDatabase.java +++ b/src/main/java/sevenUnits/unit/UnitDatabase.java @@ -1364,16 +1364,7 @@ public final class UnitDatabase { throw new IllegalArgumentException(String.format( "! used but no dimension found (line %d).", lineCounter)); } else { - // it's a unit, get the unit - final ObjectProduct dimension; - try { - dimension = this.getDimensionFromExpression(expression); - } catch (final IllegalArgumentException | NoSuchElementException e) { - System.err.printf("Parsing error on line %d:%n", lineCounter); - throw e; - } - - this.addDimension(name, dimension); + this.addDimension(name, this.getDimensionFromExpression(expression)); } } @@ -1454,56 +1445,15 @@ public final class UnitDatabase { .format("! used but no unit found (line %d).", lineCounter)); } else { if (name.endsWith("-")) { - final UnitPrefix prefix; - try { - prefix = this.getPrefixFromExpression(expression); - } catch (final IllegalArgumentException - | NoSuchElementException e) { - System.err.printf("Parsing error on line %d:%n", lineCounter); - throw e; - } final String prefixName = name.substring(0, name.length() - 1); - this.addPrefix(prefixName, prefix); + this.addPrefix(prefixName, + this.getPrefixFromExpression(expression)); } else if (expression.contains(";")) { // it's a multi-unit - final String[] parts = expression.split(";"); - final List units = new ArrayList<>(parts.length); - for (final String unitName : parts) { - final Unit unit; - try { - unit = this.getUnitFromExpression(unitName.trim()); - } catch (final NoSuchElementException e) { - System.err.printf("Parsing error on line %d:%n", lineCounter); - throw e; - } - - if (unit instanceof LinearUnit) { - units.add((LinearUnit) unit); - } else { - System.err.printf("Parsing error on line %d:%n", lineCounter); - throw new IllegalArgumentException(String.format( - "Unit '%s' is in a unit-set expression, but is not linear.", - unitName)); - } - } - - try { - this.addUnitSet(name, units); - } catch (final IllegalArgumentException e) { - System.err.printf("Parsing error on line %d:%n", lineCounter); - throw e; - } + this.addUnitSet(name, this.getUnitSetFromExpression(expression)); } else { // it's a unit, get the unit - final Unit unit; - try { - unit = this.getUnitFromExpression(expression); - } catch (final IllegalArgumentException - | NoSuchElementException e) { - System.err.printf("Parsing error on line %d:%n", lineCounter); - throw e; - } - this.addUnit(name, unit); + this.addUnit(name, this.getUnitFromExpression(expression)); } } } @@ -1950,6 +1900,27 @@ public final class UnitDatabase { return unitSet; } + /** + * Parses a semicolon-separated expression to get the unit set being used. + * + * @since 2024-08-22 + */ + private List getUnitSetFromExpression(String expression) { + final String[] parts = expression.split(";"); + final List units = new ArrayList<>(parts.length); + for (final String unitName : parts) { + final Unit unit = this.getUnitFromExpression(unitName.trim()); + + if (unit instanceof LinearUnit) { + units.add((LinearUnit) unit); + } else + throw new IllegalArgumentException(String.format( + "Unit '%s' is in a unit-set expression, but is not linear.", + unitName)); + } + return units; + } + /** * Adds all dimensions from a file, using data from the database to parse * them. @@ -1970,24 +1941,30 @@ public final class UnitDatabase { * * * @param file file to read - * @throws IllegalArgumentException if the file cannot be parsed, found or - * read - * @throws NullPointerException if file is null + * @throws NullPointerException if file is null + * @returns list of errors that happened when loading file * @since 2019-01-13 * @since v0.1.0 */ - public void loadDimensionFile(final Path file) { + public List loadDimensionFile(final Path file) { Objects.requireNonNull(file, "file must not be null."); + final List errors = new ArrayList<>(); try { long lineCounter = 0; for (final String line : Files.readAllLines(file)) { - this.addDimensionFromLine(line, ++lineCounter); + try { + this.addDimensionFromLine(line, ++lineCounter); + } catch (IllegalArgumentException | NoSuchElementException e) { + errors.add(new LoadingException(lineCounter, line, file, + LoadingException.FileType.DIMENSION, e)); + } } } catch (final FileNotFoundException e) { throw new IllegalArgumentException("Could not find file " + file, e); } catch (final IOException e) { throw new IllegalArgumentException("Could not read file " + file, e); } + return errors; } /** @@ -1997,13 +1974,22 @@ public final class UnitDatabase { * @param stream stream to load from * @since 2021-03-27 */ - public void loadDimensionsFromStream(final InputStream stream) { + public List loadDimensionsFromStream( + final InputStream stream) { + final List errors = new ArrayList<>(); try (final Scanner scanner = new Scanner(stream)) { long lineCounter = 0; while (scanner.hasNextLine()) { - this.addDimensionFromLine(scanner.nextLine(), ++lineCounter); + final String line = scanner.nextLine(); + try { + this.addDimensionFromLine(line, ++lineCounter); + } catch (IllegalArgumentException | NoSuchElementException e) { + errors.add(new LoadingException(lineCounter, line, + LoadingException.FileType.DIMENSION, e)); + } } } + return errors; } /** @@ -2025,24 +2011,30 @@ public final class UnitDatabase { * * * @param file file to read - * @throws IllegalArgumentException if the file cannot be parsed, found or - * read - * @throws NullPointerException if file is null + * @throws NullPointerException if file is null + * @returns list of errors that happened when loading file * @since 2019-01-13 * @since v0.1.0 */ - public void loadUnitsFile(final Path file) { + public List loadUnitsFile(final Path file) { Objects.requireNonNull(file, "file must not be null."); + final List errors = new ArrayList<>(); try { long lineCounter = 0; for (final String line : Files.readAllLines(file)) { - this.addUnitOrPrefixFromLine(line, ++lineCounter); + try { + this.addUnitOrPrefixFromLine(line, ++lineCounter); + } catch (IllegalArgumentException | NoSuchElementException e) { + errors.add(new LoadingException(lineCounter, line, file, + LoadingException.FileType.UNIT, e)); + } } } catch (final FileNotFoundException e) { throw new IllegalArgumentException("Could not find file " + file, e); } catch (final IOException e) { throw new IllegalArgumentException("Could not read file " + file, e); } + return errors; } /** @@ -2052,13 +2044,21 @@ public final class UnitDatabase { * @param stream stream to load from * @since 2021-03-27 */ - public void loadUnitsFromStream(InputStream stream) { + public List loadUnitsFromStream(InputStream stream) { + final List errors = new ArrayList<>(); try (final Scanner scanner = new Scanner(stream)) { long lineCounter = 0; while (scanner.hasNextLine()) { - this.addUnitOrPrefixFromLine(scanner.nextLine(), ++lineCounter); + final String line = scanner.nextLine(); + try { + this.addUnitOrPrefixFromLine(line, ++lineCounter); + } catch (IllegalArgumentException | NoSuchElementException e) { + errors.add(new LoadingException(lineCounter, line, + LoadingException.FileType.UNIT, e)); + } } } + return errors; } /** -- cgit v1.2.3