package de.vanitasvitae.imi.codes.persistence; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.Writer; import java.util.HashMap; import de.vanitasvitae.imi.codes.input.InvalidOptionException; import de.vanitasvitae.imi.codes.types.StudyNumber; /** * Repository, that stores generated sample codes per study to files on disk. * The repository stores the next sample code which would be generated for any {@link StudyNumber} {@code stn} to * the directory {@code /stn}. * If no sample number record has been found for a {@link StudyNumber}, 0 is returned. * * Additionally, the repository is initialized with some hard-coded values for studies "AAA" and "BBB". * If the user tries to generate codes for those studies, the generated codes start at the hard coded values instead * of 0. */ public class FileRepository implements Repository { private final File base; private final HashMap hardCoded = new HashMap<>(); /** * Create a new file-based repository which stores files in the given directory {@code base}. * * @param base base directory. */ public FileRepository(File base) { this.base = base; // Populate the repository with some hard coded values try { hardCoded.put(new StudyNumber("AAA"), 35); hardCoded.put(new StudyNumber("BBB"), 42); } catch (InvalidOptionException e) { // It should never happen here, that the hard coded study numbers are invalid. throw new AssertionError(e); } } /** * Return the base directory of the repository. * @return base directory */ public File getBaseDirectory() { return base; } // Returns a hard coded value, or 0 if absent. private int getHardCodedOrZero(StudyNumber studyNumber) { Integer i = hardCoded.get(studyNumber); return (i != null ? i : 0); } /** * Return the sample number of the next code which will be generated for the given {@link StudyNumber}. * * @param study code for the study * @return sample number */ @Override public int getNextSampleCode(StudyNumber study) { File studyNumberFile = new File(base, study.toString()); int next; // Check, if we have hard-coded values available if (!studyNumberFile.exists()) { next = getHardCodedOrZero(study); } // Otherwise read from file else { next = readInt(studyNumberFile); } return next; } /** * Write the next sample code number, which should be generated to file. * The next sample code number should be the last generated sample code number + 1. * * @param study study number * @param nextSampleCode next sample code to be generated. * * @throws IOException in case the file cannot be written */ @Override public void setNextSampleCode(StudyNumber study, int nextSampleCode) throws IOException { writeInt(new File(base, study.toString()), nextSampleCode); } /** * Reads an integer from the first line inside a file. If the file does not exist or is not readable, 0 is returned. * * @param file file to read from * @return integer or 0 */ private int readInt(File file) { try(BufferedReader in = new BufferedReader(new FileReader(file))) { return Integer.parseInt(in.readLine()); } catch (FileNotFoundException e) { System.out.println("File " + file.getAbsolutePath() + " does not exist."); return 0; } catch (IOException e) { e.printStackTrace(); return 0; } } /** * Write an integer to a destination file. * This method throws an {@link IOException} in case the parent directories or the file * cannot be created or written to. * * @param file destination * @param integer integer to be written */ private void writeInt(File file, int integer) throws IOException { // Check if destination is directory, which would be illegal if (file.isDirectory()) { throw new IOException("Provided output directory points to a directory, which is not allowed."); } // Make sure, the parent folder exists File parent = file.getParentFile(); if (!parent.exists() && !parent.mkdirs()) { throw new IOException("Cannot create parent directory " + parent.getAbsolutePath()); } // Check if destination file exists and if not, try to create it if (!file.exists()) { try { if (!file.createNewFile()) { throw new IOException("Output file " +file.getAbsolutePath() + " cannot be created."); } } catch (IOException e) { throw new IOException("Output file " + file.getAbsolutePath() + " cannot be created." , e); } } try(Writer wr = new FileWriter(file)) { wr.write(Integer.toString(integer)); } catch (FileNotFoundException e) { // Must not happen throw new AssertionError(e); } catch (IOException e) { throw new IOException("Cannot write to output file " + file.getAbsolutePath(), e); } } }