feature/serialize #1

Merged
manuel merged 7 commits from feature/serialize into master 2022-02-02 01:15:21 +01:00
10 changed files with 121 additions and 61 deletions
Showing only changes of commit 28c78325fe - Show all commits

13
pom.xml
View file

@ -14,7 +14,9 @@
<version>0.0.2-SNAPSHOT</version> <version>0.0.2-SNAPSHOT</version>
<properties> <properties>
<logback.version>1.2.10</logback.version>
<pdfbox.version>2.0.25</pdfbox.version> <pdfbox.version>2.0.25</pdfbox.version>
<slf4j.version>1.7.35</slf4j.version>
</properties> </properties>
<dependencies> <dependencies>
@ -35,10 +37,19 @@
<artifactId>pdfbox</artifactId> <artifactId>pdfbox</artifactId>
<version>${pdfbox.version}</version> <version>${pdfbox.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.junit.jupiter</groupId> <groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId> <artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>
<build> <build>

View file

@ -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.text.TextRenderer;
import ch.fritteli.labyrinth.generator.renderer.textfile.TextFileRenderer; import ch.fritteli.labyrinth.generator.renderer.textfile.TextFileRenderer;
import lombok.NonNull; import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
@Slf4j
public class Main { public class Main {
public static void main(@NonNull final String[] args) { public static void main(@NonNull final String[] args) {
int width = 100; int width = 100;
@ -28,19 +30,19 @@ public class Main {
final PDFFileRenderer pdfFileRenderer = PDFFileRenderer.newInstance() final PDFFileRenderer pdfFileRenderer = PDFFileRenderer.newInstance()
.setTargetFile(userHome.resolve(baseFilename + ".pdf")); .setTargetFile(userHome.resolve(baseFilename + ".pdf"));
System.out.println("Labyrinth-ID: " + labyrinth.getRandomSeed()); log.info("Labyrinth-ID: {}", labyrinth.getRandomSeed());
// Render Labyrinth to stdout // Render Labyrinth to stdout
System.out.println(textRenderer.render(labyrinth)); log.info("Text rendering:\n{}", textRenderer.render(labyrinth));
// Render Labyrinth solution to stdout // 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 // 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 // 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 // Render HTML to file
System.out.println(htmlFileRenderer.render(labyrinth)); log.info("HTML rendering to file:\n{}", htmlFileRenderer.render(labyrinth));
// Render PDF to file // 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) { private static String getBaseFilename(@NonNull final Labyrinth labyrinth) {

View file

@ -16,6 +16,7 @@ public class HTMLRenderer implements Renderer<String> {
} }
@NonNull @NonNull
@Override
public String render(@NonNull final Labyrinth labyrinth) { public String render(@NonNull final Labyrinth labyrinth) {
if (labyrinth.getWidth() == 0 || labyrinth.getHeight() == 0) { if (labyrinth.getWidth() == 0 || labyrinth.getHeight() == 0) {
return this.getPreamble(labyrinth) + POSTAMBLE; return this.getPreamble(labyrinth) + POSTAMBLE;

View file

@ -3,25 +3,30 @@ package ch.fritteli.labyrinth.generator.renderer.htmlfile;
import ch.fritteli.labyrinth.generator.model.Labyrinth; import ch.fritteli.labyrinth.generator.model.Labyrinth;
import ch.fritteli.labyrinth.generator.renderer.Renderer; import ch.fritteli.labyrinth.generator.renderer.Renderer;
import ch.fritteli.labyrinth.generator.renderer.html.HTMLRenderer; import ch.fritteli.labyrinth.generator.renderer.html.HTMLRenderer;
import io.vavr.control.Option;
import io.vavr.control.Try;
import lombok.NonNull; import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.NoSuchElementException;
@Slf4j
public class HTMLFileRenderer implements Renderer<Path> { public class HTMLFileRenderer implements Renderer<Path> {
@NonNull @NonNull
private static final HTMLRenderer HTML_RENDERER = HTMLRenderer.newInstance(); private static final HTMLRenderer HTML_RENDERER = HTMLRenderer.newInstance();
private Path targetFile; @NonNull
private Option<Path> targetFile;
private HTMLFileRenderer() { private HTMLFileRenderer() {
try { this.targetFile = Try
this.targetFile = Files.createTempFile("labyrinth_", ".html"); .of(() -> Files.createTempFile("labyrinth_", ".html"))
} catch (IOException e) { .onFailure(ex -> log.error("Unable to set default target file.", ex))
System.err.println("Unable to set default target file."); .toOption();
e.printStackTrace();
}
} }
@NonNull @NonNull
@ -30,30 +35,33 @@ public class HTMLFileRenderer implements Renderer<Path> {
} }
public boolean isTargetFileDefinedAndWritable() { public boolean isTargetFileDefinedAndWritable() {
return this.targetFile != null && this.targetFile.toFile().canWrite(); return this.targetFile
.map(Path::toFile)
.exists(File::canWrite);
} }
@NonNull @NonNull
public HTMLFileRenderer setTargetFile(@NonNull final Path targetFile) { public HTMLFileRenderer setTargetFile(@NonNull final Path targetFile) {
this.targetFile = targetFile; this.targetFile = Option.of(targetFile);
return this; return this;
} }
@NonNull
@Override @Override
public Path render(@NonNull final Labyrinth labyrinth) { public Path render(@NonNull final Labyrinth labyrinth) {
if (!this.isTargetFileDefinedAndWritable()) { if (!this.isTargetFileDefinedAndWritable()) {
try { try {
Files.createFile(this.targetFile); Files.createFile(this.targetFile.get());
} catch (IOException e) { } catch (IOException | NoSuchElementException e) {
throw new IllegalArgumentException("Cannot write to target file.", e); throw new IllegalArgumentException("Cannot write to target file.", e);
} }
} }
final String html = HTML_RENDERER.render(labyrinth); final String html = HTML_RENDERER.render(labyrinth);
final Path targetFile = this.targetFile.get();
try { try {
Files.writeString(this.targetFile, html, StandardCharsets.UTF_8); Files.writeString(targetFile, html, StandardCharsets.UTF_8);
} catch (IOException e) { } catch (IOException e) {
System.err.println("Failed writing to file " + this.targetFile.normalize().toString()); log.error("Failed writing to file " + targetFile.normalize(), e);
e.printStackTrace();
} }
return targetFile; return targetFile;
} }

View file

@ -8,6 +8,7 @@ import io.vavr.control.Option;
import lombok.NonNull; import lombok.NonNull;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.Value; import lombok.Value;
import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentInformation; import org.apache.pdfbox.pdmodel.PDDocumentInformation;
import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDPage;
@ -20,14 +21,12 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
@RequiredArgsConstructor @RequiredArgsConstructor
@Slf4j
class Generator { class Generator {
@NonNull @NonNull
private final Labyrinth labyrinth; private final Labyrinth labyrinth;
private static boolean isValid(@NonNull final Position position) { @NonNull
return position.getX() >= 0 && position.getY() >= 0;
}
public byte[] generate() { public byte[] generate() {
final float pageWidth = this.labyrinth.getWidth() * PDFRenderer.SCALE + 2 * PDFRenderer.MARGIN; final float pageWidth = this.labyrinth.getWidth() * PDFRenderer.SCALE + 2 * PDFRenderer.MARGIN;
final float pageHeight = this.labyrinth.getHeight() * 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.drawVerticalLines(puzzlePageContentStream, solutionPageContentStream);
this.drawSolution(solutionPageContentStream); this.drawSolution(solutionPageContentStream);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); log.error("Error while rendering PDF document", e);
} }
final ByteArrayOutputStream output = new ByteArrayOutputStream(); final ByteArrayOutputStream output = new ByteArrayOutputStream();
try { try {
pdDocument.save(output); pdDocument.save(output);
pdDocument.close(); pdDocument.close();
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); log.error("Error while writing PDF data", e);
} }
return output.toByteArray(); return output.toByteArray();
} }

View file

@ -16,8 +16,8 @@ public class PDFRenderer implements Renderer<byte[]> {
return new PDFRenderer(); return new PDFRenderer();
} }
@Override
@NonNull @NonNull
@Override
public byte[] render(@NonNull final Labyrinth labyrinth) { public byte[] render(@NonNull final Labyrinth labyrinth) {
final Generator generator = new Generator(labyrinth); final Generator generator = new Generator(labyrinth);
return generator.generate(); return generator.generate();

View file

@ -6,6 +6,7 @@ import ch.fritteli.labyrinth.generator.renderer.pdf.PDFRenderer;
import io.vavr.control.Option; import io.vavr.control.Option;
import io.vavr.control.Try; import io.vavr.control.Try;
import lombok.NonNull; import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -13,6 +14,7 @@ import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
@Slf4j
public class PDFFileRenderer implements Renderer<Path> { public class PDFFileRenderer implements Renderer<Path> {
@NonNull @NonNull
private static final PDFRenderer PDF_RENDERER = PDFRenderer.newInstance(); private static final PDFRenderer PDF_RENDERER = PDFRenderer.newInstance();
@ -22,10 +24,7 @@ public class PDFFileRenderer implements Renderer<Path> {
private PDFFileRenderer() { private PDFFileRenderer() {
this.targetFile = Try this.targetFile = Try
.of(() -> Files.createTempFile("labyrinth_", ".pdf")) .of(() -> Files.createTempFile("labyrinth_", ".pdf"))
.onFailure(ex -> { .onFailure(ex -> log.error("Unable to set default target file.", ex))
System.err.println("Unable to set default target file.");
ex.printStackTrace();
})
.toOption(); .toOption();
} }
@ -37,8 +36,7 @@ public class PDFFileRenderer implements Renderer<Path> {
public boolean isTargetFileDefinedAndWritable() { public boolean isTargetFileDefinedAndWritable() {
return this.targetFile return this.targetFile
.map(Path::toFile) .map(Path::toFile)
.map(File::canWrite) .exists(File::canWrite);
.getOrElse(false);
} }
@NonNull @NonNull
@ -47,6 +45,7 @@ public class PDFFileRenderer implements Renderer<Path> {
return this; return this;
} }
@NonNull
@Override @Override
public Path render(@NonNull final Labyrinth labyrinth) { public Path render(@NonNull final Labyrinth labyrinth) {
if (!this.isTargetFileDefinedAndWritable()) { if (!this.isTargetFileDefinedAndWritable()) {
@ -61,8 +60,7 @@ public class PDFFileRenderer implements Renderer<Path> {
try { try {
Files.write(targetFile, bytes); Files.write(targetFile, bytes);
} catch (IOException e) { } catch (IOException e) {
System.err.println("Failed writing to file " + targetFile.normalize().toString()); log.error("Failed writing to file " + targetFile.normalize(), e);
e.printStackTrace();
} }
return targetFile; return targetFile;
} }

View file

@ -23,6 +23,7 @@ public class TextRenderer implements Renderer<String> {
} }
@NonNull @NonNull
@Override
public String render(@NonNull final Labyrinth labyrinth) { public String render(@NonNull final Labyrinth labyrinth) {
if (labyrinth.getWidth() == 0 || labyrinth.getHeight() == 0) { if (labyrinth.getWidth() == 0 || labyrinth.getHeight() == 0) {
return ""; return "";

View file

@ -4,29 +4,42 @@ import ch.fritteli.labyrinth.generator.model.Labyrinth;
import ch.fritteli.labyrinth.generator.renderer.Renderer; import ch.fritteli.labyrinth.generator.renderer.Renderer;
import ch.fritteli.labyrinth.generator.renderer.text.TextRenderer; import ch.fritteli.labyrinth.generator.renderer.text.TextRenderer;
import io.vavr.collection.List; import io.vavr.collection.List;
import io.vavr.control.Option;
import io.vavr.control.Try;
import lombok.NonNull; import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.NoSuchElementException;
@Slf4j
public class TextFileRenderer implements Renderer<List<Path>> { public class TextFileRenderer implements Renderer<List<Path>> {
@NonNull @NonNull
private static final TextRenderer TEXT_RENDERER = TextRenderer.newInstance(); private static final TextRenderer TEXT_RENDERER = TextRenderer.newInstance();
private Path targetLabyrinthFile; @NonNull
private Path targetSolutionFile; private Option<Path> targetLabyrinthFile;
@NonNull
private Option<Path> targetSolutionFile;
private TextFileRenderer() { private TextFileRenderer() {
try { this.targetLabyrinthFile = Try
this.targetLabyrinthFile = Files.createTempFile("labyrinth_", ".txt"); .of(() -> Files.createTempFile("labyrinth_", ".txt"))
this.targetSolutionFile = this.targetLabyrinthFile.getParent().resolve( .onFailure(ex -> log.error("Unable to set default target file", ex))
this.targetLabyrinthFile.getFileName().toString().replace(".txt", "-solution.txt") .toOption();
);
} catch (IOException e) { this.targetSolutionFile = this.targetLabyrinthFile.toTry()
System.err.println("Unable to set default target file."); .map(Path::getParent)
e.printStackTrace(); .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 @NonNull
@ -35,38 +48,44 @@ public class TextFileRenderer implements Renderer<List<Path>> {
} }
public boolean isTargetLabyrinthFileDefinedAndWritable() { public boolean isTargetLabyrinthFileDefinedAndWritable() {
return this.targetLabyrinthFile != null && this.targetLabyrinthFile.toFile().canWrite(); return this.targetLabyrinthFile
.map(Path::toFile)
.exists(File::canWrite);
} }
public boolean isTargetSolutionFileDefinedAndWritable() { public boolean isTargetSolutionFileDefinedAndWritable() {
return this.targetSolutionFile != null && this.targetSolutionFile.toFile().canWrite(); return this.targetSolutionFile
.map(Path::toFile)
.exists(File::canWrite);
} }
@NonNull @NonNull
public TextFileRenderer setTargetLabyrinthFile(@NonNull final Path targetLabyrinthFile) { public TextFileRenderer setTargetLabyrinthFile(@NonNull final Path targetLabyrinthFile) {
this.targetLabyrinthFile = targetLabyrinthFile; this.targetLabyrinthFile = Option.of(targetLabyrinthFile);
return this; return this;
} }
@NonNull @NonNull
public TextFileRenderer setTargetSolutionFile(@NonNull final Path targetSolutionFile) { public TextFileRenderer setTargetSolutionFile(@NonNull final Path targetSolutionFile) {
this.targetSolutionFile = targetSolutionFile; this.targetSolutionFile = Option.of(targetSolutionFile);
return this; return this;
} }
@NonNull
@Override @Override
public List<Path> render(@NonNull final Labyrinth labyrinth) { public List<Path> render(@NonNull final Labyrinth labyrinth) {
if (!this.isTargetLabyrinthFileDefinedAndWritable()) { if (!this.isTargetLabyrinthFileDefinedAndWritable()) {
try { try {
Files.createFile(this.targetLabyrinthFile); Files.createFile(this.targetLabyrinthFile.get());
} catch (IOException e) { } catch (IOException | NoSuchElementException e) {
log.error("Cannot write to target labyrinth file.", e);
throw new IllegalArgumentException("Cannot write to target labyrinth file.", e); throw new IllegalArgumentException("Cannot write to target labyrinth file.", e);
} }
} }
if (!this.isTargetSolutionFileDefinedAndWritable()) { if (!this.isTargetSolutionFileDefinedAndWritable()) {
try { try {
Files.createFile(this.targetSolutionFile); Files.createFile(this.targetSolutionFile.get());
} catch (IOException e) { } catch (IOException | NoSuchElementException e) {
throw new IllegalArgumentException("Cannot write to target solution file.", e); throw new IllegalArgumentException("Cannot write to target solution file.", e);
} }
} }
@ -76,13 +95,18 @@ public class TextFileRenderer implements Renderer<List<Path>> {
text = TEXT_RENDERER.setRenderSolution(false).render(labyrinth).strip(); text = TEXT_RENDERER.setRenderSolution(false).render(labyrinth).strip();
solution = TEXT_RENDERER.setRenderSolution(true).render(labyrinth).strip(); solution = TEXT_RENDERER.setRenderSolution(true).render(labyrinth).strip();
} }
final Path targetLabyrinthFile = this.targetLabyrinthFile.get();
final Path targetSolutionFile = this.targetSolutionFile.get();
try { try {
Files.write(this.targetLabyrinthFile, text.getBytes(StandardCharsets.UTF_8)); Files.write(targetLabyrinthFile, text.getBytes(StandardCharsets.UTF_8));
Files.write(this.targetSolutionFile, solution.getBytes(StandardCharsets.UTF_8));
} catch (IOException e) { } catch (IOException e) {
System.err.println("Failed writing to file " + this.targetLabyrinthFile.normalize().toString()); log.error("Failed writing to file " + targetLabyrinthFile.normalize(), e);
e.printStackTrace();
} }
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);
} }
} }

View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<shutdownHook class="ch.qos.logback.core.hook.DelayingShutdownHook"/>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoders are by default assigned the type
ch.qos.logback.classic.encoder.PatternLayoutEncoder -->
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="info">
<appender-ref ref="STDOUT"/>
</root>
</configuration>