From fa95d578f58c3db6839287e1499306b92c9534da Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Thu, 15 Nov 2018 21:04:25 +0100 Subject: [PATCH] Implement HTML table renderer and export --- .../vanitasvitae/imi/codes/CodeGenerator.java | 47 +++++++++++++++ .../imi/codes/HtmlTableStringBuilder.java | 52 +++++++++++++++++ .../java/de/vanitasvitae/imi/codes/Main.java | 57 +++++++++++-------- .../imi/codes/input/InputValidator.java | 18 +++++- 4 files changed, 149 insertions(+), 25 deletions(-) create mode 100644 src/main/java/de/vanitasvitae/imi/codes/CodeGenerator.java create mode 100644 src/main/java/de/vanitasvitae/imi/codes/HtmlTableStringBuilder.java diff --git a/src/main/java/de/vanitasvitae/imi/codes/CodeGenerator.java b/src/main/java/de/vanitasvitae/imi/codes/CodeGenerator.java new file mode 100644 index 0000000..8a48c53 --- /dev/null +++ b/src/main/java/de/vanitasvitae/imi/codes/CodeGenerator.java @@ -0,0 +1,47 @@ +package de.vanitasvitae.imi.codes; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import de.vanitasvitae.imi.codes.input.InvalidOptionException; +import de.vanitasvitae.imi.codes.persistence.FileRepository; +import de.vanitasvitae.imi.codes.types.SampleTubeCode; +import de.vanitasvitae.imi.codes.types.SampleType; +import de.vanitasvitae.imi.codes.types.StudyNumber; + +public class CodeGenerator { + + private final FileRepository repository = new FileRepository(new File(".imicodes")); + + public CodeGenerator() { + + } + + public List generateCodes(StudyNumber studyNumber, SampleType sampleType, int numberOfCodes) + throws InvalidOptionException, IOException { + List codes = new ArrayList<>(); + + // Read the next sample code from file + int nextSampleCode = repository.nextSampleCode(studyNumber); + + int nextTotal = nextSampleCode + numberOfCodes; + // Check, if we'd have an overflow of sample numbers + // We check like this to prevent integer overflows + if (nextSampleCode > 9999 || numberOfCodes > 9999 || nextTotal - 1 > 9999) { + throw new InvalidOptionException("Study " + studyNumber + "would have too many sample tubes" + + " (" + (nextTotal - 1) + "). Aborting."); + } + + // Write back the number of the next sample number that should be generated next time + repository.writeNextSampleCode(studyNumber, nextSampleCode + numberOfCodes); + + // Generate codes + for (int i = 0; i < numberOfCodes; i++) { + codes.add(new SampleTubeCode(studyNumber, sampleType, nextSampleCode + i)); + } + + return codes; + } +} diff --git a/src/main/java/de/vanitasvitae/imi/codes/HtmlTableStringBuilder.java b/src/main/java/de/vanitasvitae/imi/codes/HtmlTableStringBuilder.java new file mode 100644 index 0000000..748651a --- /dev/null +++ b/src/main/java/de/vanitasvitae/imi/codes/HtmlTableStringBuilder.java @@ -0,0 +1,52 @@ +package de.vanitasvitae.imi.codes; + +import java.util.List; + +import de.vanitasvitae.imi.codes.types.SampleTubeCode; + +public class HtmlTableStringBuilder { + + private StringBuilder html; + + public HtmlTableStringBuilder(String title, List codes) { + html = new StringBuilder("\n") + .append("\n") + .append("\n") + .append("\n") + .append("") + .append("") + .append("\n"); + + // Add title + html.append("

").append(title).append("

\n"); + + // Open table + html.append("\n") + .append("\n") + .append("\n") + .append("\n"); + + // Append table entries + for (SampleTubeCode c : codes) { + html.append("\n") + .append("\n") + .append("\n"); + } + + // Close table + html.append("
Code
").append(c.toString()).append("
\n"); + + // Close body and html + html.append("\n"); + html.append(""); + } + + @Override + public String toString() { + return html.toString(); + } +} diff --git a/src/main/java/de/vanitasvitae/imi/codes/Main.java b/src/main/java/de/vanitasvitae/imi/codes/Main.java index 93bef80..c0087c2 100644 --- a/src/main/java/de/vanitasvitae/imi/codes/Main.java +++ b/src/main/java/de/vanitasvitae/imi/codes/Main.java @@ -1,12 +1,14 @@ package de.vanitasvitae.imi.codes; import java.io.File; +import java.io.FileWriter; import java.io.IOException; +import java.io.Writer; +import java.util.List; import de.vanitasvitae.imi.codes.input.Arguments; import de.vanitasvitae.imi.codes.input.InputValidator; import de.vanitasvitae.imi.codes.input.InvalidOptionException; -import de.vanitasvitae.imi.codes.persistence.FileRepository; import de.vanitasvitae.imi.codes.types.SampleTubeCode; import de.vanitasvitae.imi.codes.types.SampleType; import de.vanitasvitae.imi.codes.types.StudyNumber; @@ -19,10 +21,17 @@ import org.apache.commons.cli.ParseException; public class Main { - private static final String NAME_JAR = "imicodes"; + private static final String NAME_JAR = "java -jar imicodes.jar"; private static final String HELP_HEADER = "Generate ID codes for sample tubes."; private static final String HELP_FOOTER = "\nAuthor: Paul Schaub "; + /** + * Entry point to the program. + * Any provided arguments are parsed and the behaviour of the program is modified respectively. + * A list of available options can be displayed using "-h". + * + * @param args arguments + */ public static void main(String[] args) { Options options = Arguments.getCommandLineOptions(); CommandLineParser parser = new DefaultParser(); @@ -42,18 +51,24 @@ public class Main { return; } - // Parse arguments StudyNumber studyNumber; SampleType sampleType; int numberOfCodes; File outputPath; boolean externalBrowser; + // Parse arguments try { studyNumber = InputValidator.validateStudyNumber(arguments.getOptionValue(Arguments.STUDY_NUMBER)); sampleType = InputValidator.validateSampleType(arguments.getOptionValue(Arguments.SAMPLE_TYPE)); numberOfCodes = InputValidator.validateNumberOfCodes(arguments.getOptionValue(Arguments.NUMBER_CODES)); - outputPath = InputValidator.validateOutputPath(arguments.getOptionValue(Arguments.OUTPUT_DESTINATION)); + + if (arguments.hasOption(Arguments.OUTPUT_DESTINATION)) { + outputPath = InputValidator.validateOutputPath(arguments.getOptionValue(Arguments.OUTPUT_DESTINATION)); + } else { + outputPath = InputValidator.validateOutputPath("./out.html"); + } + externalBrowser = arguments.hasOption(Arguments.EXTERNAL_BROWSER); } catch (InvalidOptionException e) { // Something is wrong with the users input, so exit. @@ -61,32 +76,28 @@ public class Main { return; } - FileRepository repository = new FileRepository(new File(".imicodes")); + CodeGenerator generator = new CodeGenerator(); - // Read the next sample code from file - int nextSampleCode = repository.nextSampleCode(studyNumber); - - int nextTotal = nextSampleCode + numberOfCodes; - // Check, if we'd have an overflow of sample numbers - // We check like this to prevent integer overflows - if (nextSampleCode > 9999 || numberOfCodes > 9999 || nextTotal - 1 > 9999) { - System.out.println("Study " + studyNumber + "would have too many sample tubes" + - " (" + (nextTotal - 1) + "). Aborting."); - return; - } - - // Write back the number of the next sample number that should be generated next time + List codes; try { - repository.writeNextSampleCode(studyNumber, nextSampleCode + numberOfCodes); + codes = generator.generateCodes(studyNumber, sampleType, numberOfCodes); + } catch (InvalidOptionException e) { + System.out.println(e.getMessage()); + return; } catch (IOException e) { e.printStackTrace(); return; } - // Now we are finished with dangerous IO... - // Generate codes - for (int i = 0; i < numberOfCodes; i++) { - System.out.println(new SampleTubeCode(studyNumber, sampleType, nextSampleCode + i)); + String html = new HtmlTableStringBuilder("IMI Sample Tube Code Generator", codes).toString(); + writeHtml(html, outputPath); + } + + private static void writeHtml(String html, File destination) { + try(Writer writer = new FileWriter(destination)) { + writer.write(html); + } catch (IOException e) { + e.printStackTrace(); } } diff --git a/src/main/java/de/vanitasvitae/imi/codes/input/InputValidator.java b/src/main/java/de/vanitasvitae/imi/codes/input/InputValidator.java index ed0cd16..49f3150 100644 --- a/src/main/java/de/vanitasvitae/imi/codes/input/InputValidator.java +++ b/src/main/java/de/vanitasvitae/imi/codes/input/InputValidator.java @@ -1,6 +1,7 @@ package de.vanitasvitae.imi.codes.input; import java.io.File; +import java.io.IOException; import de.vanitasvitae.imi.codes.types.SampleType; import de.vanitasvitae.imi.codes.types.StudyNumber; @@ -70,7 +71,20 @@ public class InputValidator { * destination is not writable. */ public static File validateOutputPath(String path) throws InvalidOptionException { - // TODO - return null; + File file = new File(path); + File parent = file.getParentFile(); + if (!parent.exists() || parent.isFile()) { + throw new InvalidOptionException("Invalid directory " + parent.getAbsolutePath()); + } + + if (!file.exists()) { + try { + file.createNewFile(); + } catch (IOException e) { + throw new InvalidOptionException("Cannot write file " + file.getAbsolutePath(), e); + } + } + + return file; } }