package org.codefx.mvn.jdeps.tool; import com.google.common.collect.ImmutableList; import java.io.BufferedWriter; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardOpenOption; import java.util.stream.Stream; import static java.lang.String.format; import static java.nio.file.StandardOpenOption.CREATE; import static java.nio.file.StandardOpenOption.WRITE; import static java.util.Objects.requireNonNull; /** * Writes a stream of lines to a file. */ public class LineWriter { private final Path outputFile; private final IfFileExists ifFileExists; private final StaticContent staticContent; /** * Creates a new writer. * * @param outputFile * the file to write to * @param ifFileExists * what to do if the file already exists * @param staticContent * the content to wrap the written lines in */ public LineWriter(Path outputFile, IfFileExists ifFileExists, StaticContent staticContent) { this.outputFile = requireNonNull(outputFile, "The argument 'outputFile' must not be null."); this.ifFileExists = requireNonNull(ifFileExists, "The argument 'ifFileExists' must not be null."); this.staticContent = requireNonNull(staticContent, "The argument 'staticContent' must not be null."); } /** * Writes the specified lines to the file. * * @param lines * the lines to write * * @throws IOException * if writing fails */ public void write(Stream<String> lines) throws IOException { try (BufferedWriter writer = openFile()) { staticContent.prolog.forEach(line -> writeToFile(writer, line)); lines.forEachOrdered(line -> writeToFile(writer, staticContent.indent + line)); staticContent.epilog.forEach(line -> writeToFile(writer, line)); } catch (IllegalStateException ex) { // 'IOException's are rethrown as 'IllegalStateExceptions' if (ex.getCause() instanceof IOException) throwWriteFailedException((IOException) ex.getCause()); } catch (IOException ex) { throwWriteFailedException(ex); } } private BufferedWriter openFile() throws IOException { // create a new file or append the existing file; open with write access return Files.newBufferedWriter(outputFile, CREATE, ifFileExists.openOption(), WRITE); } private void writeToFile(BufferedWriter writer, String line) { try { writer.append(line); writer.newLine(); } catch (IOException ex) { throw new IllegalStateException(ex); } } private void throwWriteFailedException(IOException ex) throws IOException { String message = format("Writing to '%s' failed.", outputFile); throw new IOException(message, ex); } /** * Defines some static content the writer will write to the file. */ public static class StaticContent { public final ImmutableList<String> prolog; public final ImmutableList<String> epilog; public final String indent; /** * @param prolog * the written lines must start with these lines * @param epilog * the written lines must end with these lines * @param indent * this indent is to be added before each line from the stream; it must only consist of whitespace */ public StaticContent(ImmutableList<String> prolog, ImmutableList<String> epilog, String indent) { this.prolog = requireNonNull(prolog, "The argument 'prolog' must not be null."); this.epilog = requireNonNull(epilog, "The argument 'epilog' must not be null."); this.indent = requireNonNull(indent, "The argument 'indent' must not be null."); if (!indent.trim().isEmpty()) throw new IllegalArgumentException("The argument 'indent' must only consist of whitespace."); } } /** * Defines the writers behavior if the file already exists. */ public enum IfFileExists { /** * Remove all existing content. */ REMOVE_EXISTING_CONTENT, /** * Append the new content. */ APPEND_NEW_CONTENT; public StandardOpenOption openOption() { switch (this) { case REMOVE_EXISTING_CONTENT: return StandardOpenOption.TRUNCATE_EXISTING; case APPEND_NEW_CONTENT: return StandardOpenOption.APPEND; default: throw new IllegalArgumentException(format("Unknown IfFileExists.%s.", this)); } } } }