diff --git a/LabJavaIO/src/main/java/ch/heigvd/res/labio/impl/Application.java b/LabJavaIO/src/main/java/ch/heigvd/res/labio/impl/Application.java index 25e835c4..dee7b96a 100644 --- a/LabJavaIO/src/main/java/ch/heigvd/res/labio/impl/Application.java +++ b/LabJavaIO/src/main/java/ch/heigvd/res/labio/impl/Application.java @@ -9,11 +9,10 @@ import ch.heigvd.res.labio.quotes.QuoteClient; import org.apache.commons.io.FileUtils; -import java.io.File; -import java.io.IOException; -import java.io.StringWriter; -import java.io.Writer; +import java.io.*; import java.net.URISyntaxException; +import java.nio.charset.StandardCharsets; +import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; @@ -92,12 +91,7 @@ public void fetchAndStoreQuotes(int numberOfQuotes) throws IOException { e.printStackTrace(); } if (quote != null) { - /* There is a missing piece here! - * As you can see, this method handles the first part of the lab. It uses the web service - * client to fetch quotes. We have removed a single line from this method. It is a call to - * one method provided by this class, which is responsible for storing the content of the - * quote in a text file (and for generating the directories based on the tags). - */ + storeQuote(quote, "quote-" + (i + 1) + ".utf8"); LOG.info("Received a new joke with " + quote.getTags().size() + " tags."); for (String tag : quote.getTags()) { LOG.info("> " + tag); @@ -133,7 +127,23 @@ void clearOutputDirectory() throws IOException { * @throws IOException */ void storeQuote(Quote quote, String filename) throws IOException { - throw new UnsupportedOperationException("The student has not implemented this method yet."); + + // Getting the filepath + String filepath = WORKSPACE_DIRECTORY + "/"; + List quotesTags = quote.getTags(); + for (String tag : quotesTags) + filepath += tag + "/"; + + // Create needed directories and new file + File newFile = new File(filepath + filename); + newFile.getParentFile().mkdirs(); + newFile.createNewFile(); + + // Write + FileWriter fw = new FileWriter(newFile, StandardCharsets.UTF_8); + fw.write(quote.getQuote()); + fw.flush(); + fw.close(); } /** @@ -145,11 +155,11 @@ void printFileNames(final Writer writer) { explorer.explore(new File(WORKSPACE_DIRECTORY), new IFileVisitor() { @Override public void visit(File file) { - /* - * There is a missing piece here. Notice how we use an anonymous class here. We provide the implementation - * of the the IFileVisitor interface inline. You just have to add the body of the visit method, which should - * be pretty easy (we want to write the filename, including the path, to the writer passed in argument). - */ + try{ + writer.write(file.getPath() + "\n"); + }catch(IOException e){ + LOG.log(Level.SEVERE, "Could not write the filename", e.getMessage()); + } } }); } diff --git a/LabJavaIO/src/main/java/ch/heigvd/res/labio/impl/Utils.java b/LabJavaIO/src/main/java/ch/heigvd/res/labio/impl/Utils.java index c8a3a5ad..8c428434 100644 --- a/LabJavaIO/src/main/java/ch/heigvd/res/labio/impl/Utils.java +++ b/LabJavaIO/src/main/java/ch/heigvd/res/labio/impl/Utils.java @@ -20,7 +20,38 @@ public class Utils { * contain any line separator, then the first element is an empty string. */ public static String[] getNextLine(String lines) { - throw new UnsupportedOperationException("The student has not implemented this method yet."); + String[] resullt; + + // Line with separator "\r\n" + if (lines.contains("\r\n")) + resullt = split("\r\n", lines); + + // Line with separator "\r" + else if (lines.contains("\r")) + resullt = split("\r", lines); + + // Line with separator "\n" + else if (lines.contains("\n")) + resullt = split("\n", lines); + + // No line separator + else + resullt = new String[] {"", lines}; + return resullt; + } + + /** + * This method splits the string according to the Separator into two strings; + * the nextLine and the rest. + * + * @param separator + * @return an array with 2 elements; the first element is the next line with + * the line separator, the second element is the remaining text. + */ + private static String[] split(String separator, String lines) { + String[] nextLine = lines.split(separator, 2); + nextLine[0] += separator; + return nextLine; } } diff --git a/LabJavaIO/src/main/java/ch/heigvd/res/labio/impl/explorers/DFSFileExplorer.java b/LabJavaIO/src/main/java/ch/heigvd/res/labio/impl/explorers/DFSFileExplorer.java index b97c4a72..dca04ca1 100644 --- a/LabJavaIO/src/main/java/ch/heigvd/res/labio/impl/explorers/DFSFileExplorer.java +++ b/LabJavaIO/src/main/java/ch/heigvd/res/labio/impl/explorers/DFSFileExplorer.java @@ -4,6 +4,7 @@ import ch.heigvd.res.labio.interfaces.IFileVisitor; import java.io.File; +import java.util.Arrays; /** * This implementation of the IFileExplorer interface performs a depth-first @@ -17,7 +18,28 @@ public class DFSFileExplorer implements IFileExplorer { @Override public void explore(File rootDirectory, IFileVisitor vistor) { - throw new UnsupportedOperationException("The student has not implemented this method yet."); + // Check if the File exists + if (rootDirectory == null) + return; + + // Visit the node + vistor.visit(rootDirectory); + + // Visit the directories recursively (sorted) + File[] directories = rootDirectory.listFiles(File::isDirectory); + if (directories != null) { + Arrays.sort(directories); + for (File currentDirectory : directories) + explore(currentDirectory, vistor); + } + + // Visit The files (sorted) + File[] files = rootDirectory.listFiles(File::isFile); + if (files != null) { + Arrays.sort(files); + for (File currentFile : files) + vistor.visit(currentFile); + } } } diff --git a/LabJavaIO/src/main/java/ch/heigvd/res/labio/impl/filters/FileNumberingFilterWriter.java b/LabJavaIO/src/main/java/ch/heigvd/res/labio/impl/filters/FileNumberingFilterWriter.java index 976c9462..43371d89 100644 --- a/LabJavaIO/src/main/java/ch/heigvd/res/labio/impl/filters/FileNumberingFilterWriter.java +++ b/LabJavaIO/src/main/java/ch/heigvd/res/labio/impl/filters/FileNumberingFilterWriter.java @@ -10,32 +10,64 @@ * When filter encounters a line separator, it sends it to the decorated writer. * It then sends the line number and a tab character, before resuming the write * process. - * + *

* Hello\n\World -> 1\Hello\n2\tWorld * * @author Olivier Liechti */ public class FileNumberingFilterWriter extends FilterWriter { - private static final Logger LOG = Logger.getLogger(FileNumberingFilterWriter.class.getName()); + private final char TAB_CHAR = '\t'; + + private int lineNumber = 1; + private boolean backslashR = false; + + private static final Logger LOG = Logger.getLogger(FileNumberingFilterWriter.class.getName()); - public FileNumberingFilterWriter(Writer out) { - super(out); - } + public FileNumberingFilterWriter(Writer out) { + super(out); + } - @Override - public void write(String str, int off, int len) throws IOException { - throw new UnsupportedOperationException("The student has not implemented this method yet."); - } + @Override + public void write(String str, int off, int len) throws IOException { + write(str.toCharArray(), off, len); + } - @Override - public void write(char[] cbuf, int off, int len) throws IOException { - throw new UnsupportedOperationException("The student has not implemented this method yet."); - } + @Override + public void write(char[] cbuf, int off, int len) throws IOException { + for (int i = off; i < off + len; ++i) + write(cbuf[i]); + } - @Override - public void write(int c) throws IOException { - throw new UnsupportedOperationException("The student has not implemented this method yet."); - } + @Override + public void write(int c) throws IOException { + // First line + if (lineNumber == 1) { + super.write(String.valueOf(lineNumber++) + TAB_CHAR); + super.write(c); + } + // '/r' case + else if ((char) c == '\r') { + backslashR = true; + super.write(c); + } + // Line break with '\n' or "\r\n" + else if ((char) c == '\n') { + backslashR = false; + super.write(c); + super.write(String.valueOf(lineNumber++) + TAB_CHAR); + } + // Line break with '\r' + else if (backslashR) { + backslashR = false; + super.write(String.valueOf(lineNumber++) + TAB_CHAR); + super.write(c); + } + // Other character + else + super.write(c); + } } + + diff --git a/LabJavaIO/src/main/java/ch/heigvd/res/labio/impl/filters/UpperCaseFilterWriter.java b/LabJavaIO/src/main/java/ch/heigvd/res/labio/impl/filters/UpperCaseFilterWriter.java index 0f41a5dd..14dbed04 100644 --- a/LabJavaIO/src/main/java/ch/heigvd/res/labio/impl/filters/UpperCaseFilterWriter.java +++ b/LabJavaIO/src/main/java/ch/heigvd/res/labio/impl/filters/UpperCaseFilterWriter.java @@ -16,17 +16,18 @@ public UpperCaseFilterWriter(Writer wrappedWriter) { @Override public void write(String str, int off, int len) throws IOException { - throw new UnsupportedOperationException("The student has not implemented this method yet."); + write(str.toCharArray(), off, len); } @Override public void write(char[] cbuf, int off, int len) throws IOException { - throw new UnsupportedOperationException("The student has not implemented this method yet."); + for(int i = off; i < (len + off); ++i) + write(cbuf[i]); } @Override public void write(int c) throws IOException { - throw new UnsupportedOperationException("The student has not implemented this method yet."); + super.write(Character.toUpperCase(c)); } } diff --git a/LabJavaIO/src/main/java/ch/heigvd/res/labio/impl/transformers/CompleteFileTransformer.java b/LabJavaIO/src/main/java/ch/heigvd/res/labio/impl/transformers/CompleteFileTransformer.java index 4beca482..a7c8ff7d 100644 --- a/LabJavaIO/src/main/java/ch/heigvd/res/labio/impl/transformers/CompleteFileTransformer.java +++ b/LabJavaIO/src/main/java/ch/heigvd/res/labio/impl/transformers/CompleteFileTransformer.java @@ -1,5 +1,8 @@ package ch.heigvd.res.labio.impl.transformers; +import ch.heigvd.res.labio.impl.filters.FileNumberingFilterWriter; +import ch.heigvd.res.labio.impl.filters.UpperCaseFilterWriter; + import java.io.Writer; /** @@ -15,16 +18,7 @@ public class CompleteFileTransformer extends FileTransformer { @Override public Writer decorateWithFilters(Writer writer) { - if (true) { - throw new UnsupportedOperationException("The student has not implemented this method yet."); - } - /* - * If you uncomment the following line (and get rid of th 3 previous lines...), you will restore the decoration - * of the writer (connected to the file. You can see that you first decorate the writer with an UpperCaseFilterWriter, which you then - * decorate with a FileNumberingFilterWriter. The resulting writer is used by the abstract class to write the characters read from the - * input files. So, the input is first prefixed with line numbers, then transformed to uppercase, then sent to the output file.f - */ - //writer = new FileNumberingFilterWriter(new UpperCaseFilterWriter(writer)); + writer = new FileNumberingFilterWriter(new UpperCaseFilterWriter(writer)); return writer; } diff --git a/LabJavaIO/src/main/java/ch/heigvd/res/labio/impl/transformers/FileTransformer.java b/LabJavaIO/src/main/java/ch/heigvd/res/labio/impl/transformers/FileTransformer.java index bde833e8..132106ac 100644 --- a/LabJavaIO/src/main/java/ch/heigvd/res/labio/impl/transformers/FileTransformer.java +++ b/LabJavaIO/src/main/java/ch/heigvd/res/labio/impl/transformers/FileTransformer.java @@ -13,52 +13,53 @@ * This abstract class implements the IFileVisitor interface and has the responsibility * to open an input text file, to read its content, to apply a number of transformations * (via filters) and to write the result in an output text file. - * + *

* The subclasses have to implement the decorateWithFilters method, which instantiates * a list of filters and decorates the output writer with them. - * + * * @author Olivier Liechti */ public abstract class FileTransformer implements IFileVisitor { - private static final Logger LOG = Logger.getLogger(FileTransformer.class.getName()); - private final List filters = new ArrayList<>(); - - /** - * The subclasses implement this method to define what transformation(s) are - * applied when writing characters to the output writer. The visit(File file) - * method creates an output file and creates a corresponding writer. It then - * calls decorateWithFilters and passes the writer as argument. The method - * wraps 0, 1 or more filter writers around the original writer and returns - * the result. - * - * @param writer the writer connected to the output file - * @return the writer decorated by 0, 1 or more filter writers - */ - public abstract Writer decorateWithFilters(Writer writer); + private static final Logger LOG = Logger.getLogger(FileTransformer.class.getName()); + private final List filters = new ArrayList<>(); + + /** + * The subclasses implement this method to define what transformation(s) are + * applied when writing characters to the output writer. The visit(File file) + * method creates an output file and creates a corresponding writer. It then + * calls decorateWithFilters and passes the writer as argument. The method + * wraps 0, 1 or more filter writers around the original writer and returns + * the result. + * + * @param writer the writer connected to the output file + * @return the writer decorated by 0, 1 or more filter writers + */ + public abstract Writer decorateWithFilters(Writer writer); + + @Override + public void visit(File file) { + if (!file.isFile()) { + return; + } + try { + Reader reader = new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8); + Writer writer = new OutputStreamWriter(new FileOutputStream(file.getPath() + ".out"), StandardCharsets.UTF_8); // the bug fix by teacher + writer = decorateWithFilters(writer); + + + int c; + while ((c = reader.read()) != -1) { + writer.write(c); + } - @Override - public void visit(File file) { - if (!file.isFile()) { - return; - } - try { - Reader reader = new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8); - Writer writer = new OutputStreamWriter(new FileOutputStream(file.getPath()+ ".out"), StandardCharsets.UTF_8); // the bug fix by teacher - writer = decorateWithFilters(writer); - /* - * There is a missing piece here: you have an input reader and an ouput writer (notice how the - * writer has been decorated by the concrete subclass!). You need to write a loop to read the - * characters and write them to the writer. - */ - - reader.close(); - writer.flush(); - writer.close(); - } catch (IOException ex) { - LOG.log(Level.SEVERE, null, ex); + reader.close(); + writer.flush(); + writer.close(); + } catch (IOException ex) { + LOG.log(Level.SEVERE, null, ex); + } } - } } diff --git a/LabJavaIO/src/main/java/ch/heigvd/res/labio/impl/transformers/NoOpFileTransformer.java b/LabJavaIO/src/main/java/ch/heigvd/res/labio/impl/transformers/NoOpFileTransformer.java index 5971a302..880c065b 100644 --- a/LabJavaIO/src/main/java/ch/heigvd/res/labio/impl/transformers/NoOpFileTransformer.java +++ b/LabJavaIO/src/main/java/ch/heigvd/res/labio/impl/transformers/NoOpFileTransformer.java @@ -13,14 +13,7 @@ public class NoOpFileTransformer extends FileTransformer { @Override public Writer decorateWithFilters(Writer writer) { - throw new UnsupportedOperationException("The student has not implemented this method yet."); - /* - * The NoOpFileTransformer does not apply any transformation of the character stream - * (no uppercase, no line number, etc.). So, we don't need to decorate the writer connected to - * the output file at all. Just uncomment the following line and get rid of the UnsupportedOperationException and - * you will be all set. - */ - //return writer; + return writer; } }