Make TextRenderer and HTMLRenderer thread-safe (or so I think ...)
This commit is contained in:
		
							parent
							
								
									8774324b65
								
							
						
					
					
						commit
						cf96949f8e
					
				
					 5 changed files with 292 additions and 294 deletions
				
			
		|  | @ -9,6 +9,8 @@ import java.nio.file.Path; | |||
| import java.nio.file.StandardOpenOption; | ||||
| 
 | ||||
| public class HTMLFileRenderer implements Renderer<Path> { | ||||
|     @NonNull | ||||
|     private static final HTMLRenderer HTML_RENDERER = HTMLRenderer.newInstance(); | ||||
|     @Setter | ||||
|     private Path targetFile; | ||||
| 
 | ||||
|  | @ -35,7 +37,7 @@ public class HTMLFileRenderer implements Renderer<Path> { | |||
|         if (!this.isTargetFileDefinedAndWritable()) { | ||||
|             throw new IllegalArgumentException("Cannot write to target file. See previous log messages for details."); | ||||
|         } | ||||
|         final String html = HTMLRenderer.newInstance().render(labyrinth); | ||||
|         final String html = HTML_RENDERER.render(labyrinth); | ||||
|         try { | ||||
|             Files.writeString(this.targetFile, html, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE); | ||||
|         } catch (IOException e) { | ||||
|  |  | |||
|  | @ -3,6 +3,7 @@ package ch.fritteli.labyrinth; | |||
| import io.vavr.collection.HashSet; | ||||
| import io.vavr.collection.Set; | ||||
| import lombok.NonNull; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| 
 | ||||
| public class HTMLRenderer implements Renderer<String> { | ||||
|     private static final String PREAMBLE = "<!DOCTYPE html><html lang=\"en\">" + | ||||
|  | @ -33,11 +34,6 @@ public class HTMLRenderer implements Renderer<String> { | |||
|             "<body>" + | ||||
|             "<input type=\"checkbox\" onclick=\"toggleSolution()\">show solution</input>"; | ||||
|     private static final String POSTAMBLE = "</body></html>"; | ||||
|     private Labyrinth labyrinth; | ||||
|     private int width; | ||||
|     private int height; | ||||
|     // row counter | ||||
|     private int y = 0; | ||||
| 
 | ||||
|     private HTMLRenderer() { | ||||
|     } | ||||
|  | @ -49,29 +45,32 @@ public class HTMLRenderer implements Renderer<String> { | |||
| 
 | ||||
|     @NonNull | ||||
|     public String render(@NonNull final Labyrinth labyrinth) { | ||||
|         this.labyrinth = labyrinth; | ||||
|         this.width = labyrinth.getWidth(); | ||||
|         this.height = labyrinth.getHeight(); | ||||
|         if (this.width == 0 || this.height == 0) { | ||||
|         if (labyrinth.getWidth() == 0 || labyrinth.getHeight() == 0) { | ||||
|             return PREAMBLE + POSTAMBLE; | ||||
|         } | ||||
|         final Generator generator = new Generator(labyrinth); | ||||
|         final StringBuilder sb = new StringBuilder(PREAMBLE); | ||||
|         sb.append("<table>"); | ||||
|         while (this.hasNext()) { | ||||
|             sb.append(this.next()); | ||||
|         while (generator.hasNext()) { | ||||
|             sb.append(generator.next()); | ||||
|         } | ||||
|         sb.append("</table>"); | ||||
|         sb.append(POSTAMBLE); | ||||
|         return sb.toString(); | ||||
|     } | ||||
| 
 | ||||
|     @RequiredArgsConstructor | ||||
|     private static class Generator { | ||||
|         private final Labyrinth labyrinth; | ||||
|         private int y = 0; | ||||
| 
 | ||||
|         private boolean hasNext() { | ||||
|         return this.y < this.height; | ||||
|             return this.y < this.labyrinth.getHeight(); | ||||
|         } | ||||
| 
 | ||||
|         private String next() { | ||||
|             StringBuilder sb = new StringBuilder("<tr>"); | ||||
|         for (int x = 0; x < this.width; x++) { | ||||
|             for (int x = 0; x < this.labyrinth.getWidth(); x++) { | ||||
|                 final Tile currentTile = this.labyrinth.getTileAt(x, this.y); | ||||
|                 sb.append("<td class=\""); | ||||
|                 sb.append(this.getClasses(currentTile).mkString(" ")); | ||||
|  | @ -102,3 +101,4 @@ public class HTMLRenderer implements Renderer<String> { | |||
|             return result; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -9,7 +9,7 @@ public class Main { | |||
|         final Labyrinth labyrinth = new Labyrinth(width, height); | ||||
|         final TextRenderer textRenderer = TextRenderer.newInstance(); | ||||
|         System.out.println(textRenderer.render(labyrinth)); | ||||
|         System.out.println(textRenderer.setRenderingSolution(true).render(labyrinth)); | ||||
|         System.out.println(textRenderer.setRenderSolution(true).render(labyrinth)); | ||||
|         final HTMLRenderer htmlRenderer = HTMLRenderer.newInstance(); | ||||
|         System.out.println(htmlRenderer.render(labyrinth)); | ||||
|         System.out.println(HTMLFileRenderer.newInstance().render(labyrinth)); | ||||
|  |  | |||
|  | @ -4,20 +4,12 @@ import lombok.AccessLevel; | |||
| import lombok.AllArgsConstructor; | ||||
| import lombok.NoArgsConstructor; | ||||
| import lombok.NonNull; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import lombok.experimental.FieldDefaults; | ||||
| import org.jetbrains.annotations.Nullable; | ||||
| 
 | ||||
| public class TextRenderer implements Renderer<String> { | ||||
|     private Labyrinth labyrinth; | ||||
|     private int width; | ||||
|     private int height; | ||||
|     private boolean renderSolution; | ||||
|     // column counter | ||||
|     private int x; | ||||
|     // row counter | ||||
|     private int y; | ||||
|     // line counter (top-, center- or bottom line of a row) | ||||
|     private int line; | ||||
| 
 | ||||
|     private TextRenderer() { | ||||
|         this.renderSolution = false; | ||||
|  | @ -29,31 +21,35 @@ public class TextRenderer implements Renderer<String> { | |||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     public TextRenderer setRenderingSolution(final boolean renderSolution) { | ||||
|     public TextRenderer setRenderSolution(final boolean renderSolution) { | ||||
|         this.renderSolution = renderSolution; | ||||
|         return this; | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     public String render(@NonNull final Labyrinth labyrinth) { | ||||
|         this.labyrinth = labyrinth; | ||||
|         this.width = labyrinth.getWidth(); | ||||
|         this.height = labyrinth.getHeight(); | ||||
|         if (this.width == 0 || this.height == 0) { | ||||
|         if (labyrinth.getWidth() == 0 || labyrinth.getHeight() == 0) { | ||||
|             return ""; | ||||
|         } | ||||
|         this.x = 0; | ||||
|         this.y = 0; | ||||
|         this.line = 0; | ||||
|         final Generator generator = new Generator(labyrinth, this.renderSolution); | ||||
|         final StringBuilder sb = new StringBuilder(); | ||||
|         while (this.hasNext()) { | ||||
|             sb.append(this.next()); | ||||
|         while (generator.hasNext()) { | ||||
|             sb.append(generator.next()); | ||||
|         } | ||||
|         return sb.toString(); | ||||
|     } | ||||
| 
 | ||||
|     @RequiredArgsConstructor(access = AccessLevel.PRIVATE) | ||||
|     static class Generator { | ||||
|         @NonNull | ||||
|         private final Labyrinth labyrinth; | ||||
|         private final boolean renderSolution; | ||||
|         private int x = 0; | ||||
|         private int y = 0; | ||||
|         private int line = 0; | ||||
| 
 | ||||
|         private boolean hasNext() { | ||||
|         return this.y < this.height; | ||||
|             return this.y < this.labyrinth.getHeight(); | ||||
|         } | ||||
| 
 | ||||
|         private String next() { | ||||
|  | @ -82,13 +78,13 @@ public class TextRenderer implements Renderer<String> { | |||
|         private void prepareNextStep() { | ||||
|             // do some magic ... | ||||
|             this.x++; | ||||
|         if (this.x == this.width) { | ||||
|             if (this.x == this.labyrinth.getWidth()) { | ||||
|                 // Reached the end of the row? | ||||
|                 // On to the next line then! | ||||
|                 this.x = 0; | ||||
|                 this.line++; | ||||
|             } | ||||
|         if (this.line == 2 && this.y < this.height - 1) { | ||||
|             if (this.line == 2 && this.y < this.labyrinth.getHeight() - 1) { | ||||
|                 // Finished rendering the center line, and more rows available? | ||||
|                 // On to the next row then! | ||||
|                 this.line = 0; | ||||
|  | @ -103,7 +99,7 @@ public class TextRenderer implements Renderer<String> { | |||
|         } | ||||
| 
 | ||||
|         private Tile getTileOrNull(final int x, final int y) { | ||||
|         if (x < 0 || y < 0 || x >= this.width || y >= this.height) { | ||||
|             if (x < 0 || y < 0 || x >= this.labyrinth.getWidth() || y >= this.labyrinth.getHeight()) { | ||||
|                 return null; | ||||
|             } | ||||
|             return this.labyrinth.getTileAt(x, y); | ||||
|  | @ -137,7 +133,7 @@ public class TextRenderer implements Renderer<String> { | |||
|                 } | ||||
|             } | ||||
|             result = charDef1.toString() + charDef2; | ||||
|         if (this.x == this.width - 1) { | ||||
|             if (this.x == this.labyrinth.getWidth() - 1) { | ||||
|                 result += charDef3 + "\n"; | ||||
|             } | ||||
|             return result; | ||||
|  | @ -156,7 +152,7 @@ public class TextRenderer implements Renderer<String> { | |||
| 
 | ||||
|             result = charDef1 + (currentTile.isSolution() && this.renderSolution ? "x" : " "); | ||||
| 
 | ||||
|         if (this.x == this.width - 1) { | ||||
|             if (this.x == this.labyrinth.getWidth() - 1) { | ||||
|                 result += charDef2 + "\n"; | ||||
|             } | ||||
| 
 | ||||
|  | @ -186,7 +182,7 @@ public class TextRenderer implements Renderer<String> { | |||
| 
 | ||||
|             result = charDef1.toString() + charDef2; | ||||
| 
 | ||||
|         if (this.x == this.width - 1) { | ||||
|             if (this.x == this.labyrinth.getWidth() - 1) { | ||||
|                 result += charDef3; | ||||
|             } | ||||
|             return result; | ||||
|  | @ -255,7 +251,6 @@ public class TextRenderer implements Renderer<String> { | |||
|                 return this; | ||||
|             } | ||||
| 
 | ||||
| 
 | ||||
|             CharDefinition horizontal() { | ||||
|                 return this.left().right(); | ||||
|             } | ||||
|  | @ -325,3 +320,4 @@ public class TextRenderer implements Renderer<String> { | |||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| package ch.fritteli.labyrinth; | ||||
| 
 | ||||
| import ch.fritteli.labyrinth.TextRenderer.CharDefinition; | ||||
| import ch.fritteli.labyrinth.TextRenderer.Generator.CharDefinition; | ||||
| import org.junit.jupiter.api.Nested; | ||||
| import org.junit.jupiter.api.Test; | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue