diff --git a/pom.xml b/pom.xml index fd7a6c9..029d0b5 100644 --- a/pom.xml +++ b/pom.xml @@ -14,7 +14,9 @@ 0.0.2-SNAPSHOT + 1.2.10 2.0.25 + 1.7.35 @@ -35,10 +37,19 @@ pdfbox ${pdfbox.version} + + org.slf4j + slf4j-api + ${slf4j.version} + + + ch.qos.logback + logback-classic + ${logback.version} + org.junit.jupiter junit-jupiter-api - test diff --git a/src/main/java/ch/fritteli/labyrinth/generator/Main.java b/src/main/java/ch/fritteli/labyrinth/generator/Main.java index 1acf787..df3ebef 100644 --- a/src/main/java/ch/fritteli/labyrinth/generator/Main.java +++ b/src/main/java/ch/fritteli/labyrinth/generator/Main.java @@ -7,10 +7,12 @@ import ch.fritteli.labyrinth.generator.renderer.pdffile.PDFFileRenderer; import ch.fritteli.labyrinth.generator.renderer.text.TextRenderer; import ch.fritteli.labyrinth.generator.renderer.textfile.TextFileRenderer; import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; import java.nio.file.Path; import java.nio.file.Paths; +@Slf4j public class Main { public static void main(@NonNull final String[] args) { int width = 100; @@ -28,19 +30,19 @@ public class Main { final PDFFileRenderer pdfFileRenderer = PDFFileRenderer.newInstance() .setTargetFile(userHome.resolve(baseFilename + ".pdf")); - System.out.println("Labyrinth-ID: " + labyrinth.getRandomSeed()); + log.info("Labyrinth-ID: {}", labyrinth.getRandomSeed()); // Render Labyrinth to stdout - System.out.println(textRenderer.render(labyrinth)); + log.info("Text rendering:\n{}", textRenderer.render(labyrinth)); // Render Labyrinth solution to stdout - System.out.println(textRenderer.setRenderSolution(true).render(labyrinth)); + log.info("Text rendering with solution:\n{}", textRenderer.setRenderSolution(true).render(labyrinth)); // Render HTML to stdout - System.out.println(htmlRenderer.render(labyrinth)); + log.info("HTML rendering:\n{}", htmlRenderer.render(labyrinth)); // Render Labyrinth and solution to (separate) files - System.out.println(textFileRenderer.render(labyrinth)); + log.info("Text rendering to file:\n{}", textFileRenderer.render(labyrinth)); // Render HTML to file - System.out.println(htmlFileRenderer.render(labyrinth)); + log.info("HTML rendering to file:\n{}", htmlFileRenderer.render(labyrinth)); // Render PDF to file - System.out.println(pdfFileRenderer.render(labyrinth)); + log.info("PDF rendering to file:\n{}", pdfFileRenderer.render(labyrinth)); } private static String getBaseFilename(@NonNull final Labyrinth labyrinth) { diff --git a/src/main/java/ch/fritteli/labyrinth/generator/renderer/html/HTMLRenderer.java b/src/main/java/ch/fritteli/labyrinth/generator/renderer/html/HTMLRenderer.java index 03666a7..fc03f38 100644 --- a/src/main/java/ch/fritteli/labyrinth/generator/renderer/html/HTMLRenderer.java +++ b/src/main/java/ch/fritteli/labyrinth/generator/renderer/html/HTMLRenderer.java @@ -16,6 +16,7 @@ public class HTMLRenderer implements Renderer { } @NonNull + @Override public String render(@NonNull final Labyrinth labyrinth) { if (labyrinth.getWidth() == 0 || labyrinth.getHeight() == 0) { return this.getPreamble(labyrinth) + POSTAMBLE; diff --git a/src/main/java/ch/fritteli/labyrinth/generator/renderer/htmlfile/HTMLFileRenderer.java b/src/main/java/ch/fritteli/labyrinth/generator/renderer/htmlfile/HTMLFileRenderer.java index 3407537..db829bc 100644 --- a/src/main/java/ch/fritteli/labyrinth/generator/renderer/htmlfile/HTMLFileRenderer.java +++ b/src/main/java/ch/fritteli/labyrinth/generator/renderer/htmlfile/HTMLFileRenderer.java @@ -3,25 +3,30 @@ package ch.fritteli.labyrinth.generator.renderer.htmlfile; import ch.fritteli.labyrinth.generator.model.Labyrinth; import ch.fritteli.labyrinth.generator.renderer.Renderer; import ch.fritteli.labyrinth.generator.renderer.html.HTMLRenderer; +import io.vavr.control.Option; +import io.vavr.control.Try; import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; +import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; +import java.util.NoSuchElementException; +@Slf4j public class HTMLFileRenderer implements Renderer { @NonNull private static final HTMLRenderer HTML_RENDERER = HTMLRenderer.newInstance(); - private Path targetFile; + @NonNull + private Option targetFile; private HTMLFileRenderer() { - try { - this.targetFile = Files.createTempFile("labyrinth_", ".html"); - } catch (IOException e) { - System.err.println("Unable to set default target file."); - e.printStackTrace(); - } + this.targetFile = Try + .of(() -> Files.createTempFile("labyrinth_", ".html")) + .onFailure(ex -> log.error("Unable to set default target file.", ex)) + .toOption(); } @NonNull @@ -30,30 +35,33 @@ public class HTMLFileRenderer implements Renderer { } public boolean isTargetFileDefinedAndWritable() { - return this.targetFile != null && this.targetFile.toFile().canWrite(); + return this.targetFile + .map(Path::toFile) + .exists(File::canWrite); } @NonNull public HTMLFileRenderer setTargetFile(@NonNull final Path targetFile) { - this.targetFile = targetFile; + this.targetFile = Option.of(targetFile); return this; } + @NonNull @Override public Path render(@NonNull final Labyrinth labyrinth) { if (!this.isTargetFileDefinedAndWritable()) { try { - Files.createFile(this.targetFile); - } catch (IOException e) { + Files.createFile(this.targetFile.get()); + } catch (IOException | NoSuchElementException e) { throw new IllegalArgumentException("Cannot write to target file.", e); } } final String html = HTML_RENDERER.render(labyrinth); + final Path targetFile = this.targetFile.get(); try { - Files.writeString(this.targetFile, html, StandardCharsets.UTF_8); + Files.writeString(targetFile, html, StandardCharsets.UTF_8); } catch (IOException e) { - System.err.println("Failed writing to file " + this.targetFile.normalize().toString()); - e.printStackTrace(); + log.error("Failed writing to file " + targetFile.normalize(), e); } return targetFile; } diff --git a/src/main/java/ch/fritteli/labyrinth/generator/renderer/pdf/Generator.java b/src/main/java/ch/fritteli/labyrinth/generator/renderer/pdf/Generator.java index 7f15ba1..971fed2 100644 --- a/src/main/java/ch/fritteli/labyrinth/generator/renderer/pdf/Generator.java +++ b/src/main/java/ch/fritteli/labyrinth/generator/renderer/pdf/Generator.java @@ -8,6 +8,7 @@ import io.vavr.control.Option; import lombok.NonNull; import lombok.RequiredArgsConstructor; import lombok.Value; +import lombok.extern.slf4j.Slf4j; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocumentInformation; import org.apache.pdfbox.pdmodel.PDPage; @@ -20,14 +21,12 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; @RequiredArgsConstructor +@Slf4j class Generator { @NonNull private final Labyrinth labyrinth; - private static boolean isValid(@NonNull final Position position) { - return position.getX() >= 0 && position.getY() >= 0; - } - + @NonNull public byte[] generate() { final float pageWidth = this.labyrinth.getWidth() * PDFRenderer.SCALE + 2 * PDFRenderer.MARGIN; final float pageHeight = this.labyrinth.getHeight() * PDFRenderer.SCALE + 2 * PDFRenderer.MARGIN; @@ -48,14 +47,14 @@ class Generator { this.drawVerticalLines(puzzlePageContentStream, solutionPageContentStream); this.drawSolution(solutionPageContentStream); } catch (IOException e) { - e.printStackTrace(); + log.error("Error while rendering PDF document", e); } final ByteArrayOutputStream output = new ByteArrayOutputStream(); try { pdDocument.save(output); pdDocument.close(); } catch (IOException e) { - e.printStackTrace(); + log.error("Error while writing PDF data", e); } return output.toByteArray(); } diff --git a/src/main/java/ch/fritteli/labyrinth/generator/renderer/pdf/PDFRenderer.java b/src/main/java/ch/fritteli/labyrinth/generator/renderer/pdf/PDFRenderer.java index dd4183c..c9ff88a 100644 --- a/src/main/java/ch/fritteli/labyrinth/generator/renderer/pdf/PDFRenderer.java +++ b/src/main/java/ch/fritteli/labyrinth/generator/renderer/pdf/PDFRenderer.java @@ -16,8 +16,8 @@ public class PDFRenderer implements Renderer { return new PDFRenderer(); } - @Override @NonNull + @Override public byte[] render(@NonNull final Labyrinth labyrinth) { final Generator generator = new Generator(labyrinth); return generator.generate(); diff --git a/src/main/java/ch/fritteli/labyrinth/generator/renderer/pdffile/PDFFileRenderer.java b/src/main/java/ch/fritteli/labyrinth/generator/renderer/pdffile/PDFFileRenderer.java index 781d33f..a6753e0 100644 --- a/src/main/java/ch/fritteli/labyrinth/generator/renderer/pdffile/PDFFileRenderer.java +++ b/src/main/java/ch/fritteli/labyrinth/generator/renderer/pdffile/PDFFileRenderer.java @@ -6,6 +6,7 @@ import ch.fritteli.labyrinth.generator.renderer.pdf.PDFRenderer; import io.vavr.control.Option; import io.vavr.control.Try; import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; import java.io.File; import java.io.IOException; @@ -13,6 +14,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.NoSuchElementException; +@Slf4j public class PDFFileRenderer implements Renderer { @NonNull private static final PDFRenderer PDF_RENDERER = PDFRenderer.newInstance(); @@ -22,10 +24,7 @@ public class PDFFileRenderer implements Renderer { private PDFFileRenderer() { this.targetFile = Try .of(() -> Files.createTempFile("labyrinth_", ".pdf")) - .onFailure(ex -> { - System.err.println("Unable to set default target file."); - ex.printStackTrace(); - }) + .onFailure(ex -> log.error("Unable to set default target file.", ex)) .toOption(); } @@ -37,8 +36,7 @@ public class PDFFileRenderer implements Renderer { public boolean isTargetFileDefinedAndWritable() { return this.targetFile .map(Path::toFile) - .map(File::canWrite) - .getOrElse(false); + .exists(File::canWrite); } @NonNull @@ -47,6 +45,7 @@ public class PDFFileRenderer implements Renderer { return this; } + @NonNull @Override public Path render(@NonNull final Labyrinth labyrinth) { if (!this.isTargetFileDefinedAndWritable()) { @@ -61,8 +60,7 @@ public class PDFFileRenderer implements Renderer { try { Files.write(targetFile, bytes); } catch (IOException e) { - System.err.println("Failed writing to file " + targetFile.normalize().toString()); - e.printStackTrace(); + log.error("Failed writing to file " + targetFile.normalize(), e); } return targetFile; } diff --git a/src/main/java/ch/fritteli/labyrinth/generator/renderer/text/TextRenderer.java b/src/main/java/ch/fritteli/labyrinth/generator/renderer/text/TextRenderer.java index ecb605f..b7ce398 100644 --- a/src/main/java/ch/fritteli/labyrinth/generator/renderer/text/TextRenderer.java +++ b/src/main/java/ch/fritteli/labyrinth/generator/renderer/text/TextRenderer.java @@ -23,6 +23,7 @@ public class TextRenderer implements Renderer { } @NonNull + @Override public String render(@NonNull final Labyrinth labyrinth) { if (labyrinth.getWidth() == 0 || labyrinth.getHeight() == 0) { return ""; diff --git a/src/main/java/ch/fritteli/labyrinth/generator/renderer/textfile/TextFileRenderer.java b/src/main/java/ch/fritteli/labyrinth/generator/renderer/textfile/TextFileRenderer.java index 9f0d959..d274f37 100644 --- a/src/main/java/ch/fritteli/labyrinth/generator/renderer/textfile/TextFileRenderer.java +++ b/src/main/java/ch/fritteli/labyrinth/generator/renderer/textfile/TextFileRenderer.java @@ -4,29 +4,42 @@ import ch.fritteli.labyrinth.generator.model.Labyrinth; import ch.fritteli.labyrinth.generator.renderer.Renderer; import ch.fritteli.labyrinth.generator.renderer.text.TextRenderer; import io.vavr.collection.List; +import io.vavr.control.Option; +import io.vavr.control.Try; import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; +import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; +import java.util.NoSuchElementException; +@Slf4j public class TextFileRenderer implements Renderer> { @NonNull private static final TextRenderer TEXT_RENDERER = TextRenderer.newInstance(); - private Path targetLabyrinthFile; - private Path targetSolutionFile; + @NonNull + private Option targetLabyrinthFile; + @NonNull + private Option targetSolutionFile; private TextFileRenderer() { - try { - this.targetLabyrinthFile = Files.createTempFile("labyrinth_", ".txt"); - this.targetSolutionFile = this.targetLabyrinthFile.getParent().resolve( - this.targetLabyrinthFile.getFileName().toString().replace(".txt", "-solution.txt") - ); - } catch (IOException e) { - System.err.println("Unable to set default target file."); - e.printStackTrace(); - } + this.targetLabyrinthFile = Try + .of(() -> Files.createTempFile("labyrinth_", ".txt")) + .onFailure(ex -> log.error("Unable to set default target file", ex)) + .toOption(); + + this.targetSolutionFile = this.targetLabyrinthFile.toTry() + .map(Path::getParent) + .flatMap(parent -> this.targetLabyrinthFile.toTry() + .map(Path::getFileName) + .map(Path::toString) + .map(a -> a.replace(".txt", "-solution.txt")) + .map(parent::resolve)) + .onFailure(ex -> log.error("Unable to set default solution target file", ex)) + .toOption(); } @NonNull @@ -35,38 +48,44 @@ public class TextFileRenderer implements Renderer> { } public boolean isTargetLabyrinthFileDefinedAndWritable() { - return this.targetLabyrinthFile != null && this.targetLabyrinthFile.toFile().canWrite(); + return this.targetLabyrinthFile + .map(Path::toFile) + .exists(File::canWrite); } public boolean isTargetSolutionFileDefinedAndWritable() { - return this.targetSolutionFile != null && this.targetSolutionFile.toFile().canWrite(); + return this.targetSolutionFile + .map(Path::toFile) + .exists(File::canWrite); } @NonNull public TextFileRenderer setTargetLabyrinthFile(@NonNull final Path targetLabyrinthFile) { - this.targetLabyrinthFile = targetLabyrinthFile; + this.targetLabyrinthFile = Option.of(targetLabyrinthFile); return this; } @NonNull public TextFileRenderer setTargetSolutionFile(@NonNull final Path targetSolutionFile) { - this.targetSolutionFile = targetSolutionFile; + this.targetSolutionFile = Option.of(targetSolutionFile); return this; } + @NonNull @Override public List render(@NonNull final Labyrinth labyrinth) { if (!this.isTargetLabyrinthFileDefinedAndWritable()) { try { - Files.createFile(this.targetLabyrinthFile); - } catch (IOException e) { + Files.createFile(this.targetLabyrinthFile.get()); + } catch (IOException | NoSuchElementException e) { + log.error("Cannot write to target labyrinth file.", e); throw new IllegalArgumentException("Cannot write to target labyrinth file.", e); } } if (!this.isTargetSolutionFileDefinedAndWritable()) { try { - Files.createFile(this.targetSolutionFile); - } catch (IOException e) { + Files.createFile(this.targetSolutionFile.get()); + } catch (IOException | NoSuchElementException e) { throw new IllegalArgumentException("Cannot write to target solution file.", e); } } @@ -76,13 +95,18 @@ public class TextFileRenderer implements Renderer> { text = TEXT_RENDERER.setRenderSolution(false).render(labyrinth).strip(); solution = TEXT_RENDERER.setRenderSolution(true).render(labyrinth).strip(); } + final Path targetLabyrinthFile = this.targetLabyrinthFile.get(); + final Path targetSolutionFile = this.targetSolutionFile.get(); try { - Files.write(this.targetLabyrinthFile, text.getBytes(StandardCharsets.UTF_8)); - Files.write(this.targetSolutionFile, solution.getBytes(StandardCharsets.UTF_8)); + Files.write(targetLabyrinthFile, text.getBytes(StandardCharsets.UTF_8)); } catch (IOException e) { - System.err.println("Failed writing to file " + this.targetLabyrinthFile.normalize().toString()); - e.printStackTrace(); + log.error("Failed writing to file " + targetLabyrinthFile.normalize(), e); } - return List.of(this.targetLabyrinthFile, this.targetSolutionFile); + try { + Files.write(targetSolutionFile, solution.getBytes(StandardCharsets.UTF_8)); + } catch (IOException e) { + log.error("Failed writing to file " + targetSolutionFile.normalize()); + } + return List.of(targetLabyrinthFile, targetSolutionFile); } } diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml new file mode 100644 index 0000000..fd7cd55 --- /dev/null +++ b/src/main/resources/logback.xml @@ -0,0 +1,16 @@ + + + + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + +