package com.constellio.data.io.services.facades; import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.Closeable; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.Reader; import java.util.Collection; import java.util.List; import java.util.Scanner; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.io.filefilter.IOFileFilter; import com.constellio.data.dao.services.idGenerator.UUIDV1Generator; import com.constellio.data.io.streamFactories.CloseableStreamFactory; import com.constellio.data.io.streamFactories.StreamFactory; import com.constellio.data.io.streamFactories.impl.CopyInputStreamFactory; import com.constellio.data.io.streamFactories.impl.CopyInputStreamFactoryRuntimeException; import com.constellio.data.io.streamFactories.services.StreamFactoriesServices; import com.constellio.data.io.streamFactories.services.one.StreamOperation; import com.constellio.data.io.streamFactories.services.one.StreamOperationReturningValue; import com.constellio.data.io.streamFactories.services.one.StreamOperationReturningValueOrThrowingException; import com.constellio.data.io.streamFactories.services.one.StreamOperationThrowingException; import com.constellio.data.io.streamFactories.services.two.TwoStreamsOperation; import com.constellio.data.io.streamFactories.services.two.TwoStreamsOperationReturningValue; import com.constellio.data.io.streamFactories.services.two.TwoStreamsOperationReturningValueOrThrowingException; import com.constellio.data.io.streamFactories.services.two.TwoStreamsOperationThrowingException; import com.constellio.data.io.streams.factories.StreamsServices; import com.constellio.data.utils.ImpossibleRuntimeException; import com.constellio.data.utils.Octets; public class IOServices { private static final String REPLACE_FILE_CONTENT_TEMP_FILE = "IOServices-replaceFileContentTempFile"; private final File tempFolder; private final FileService fileServices; private final StreamsServices streamsServices; private final StreamFactoriesServices streamFactoriesServices; public IOServices(File tempFolder) { super(); this.tempFolder = tempFolder; this.fileServices = new FileService(tempFolder); this.streamsServices = new StreamsServices(fileServices); this.streamFactoriesServices = new StreamFactoriesServices(streamsServices); } public byte[] readBytes(InputStream inputStream) throws IOException { return streamsServices.readBytes(inputStream); } public void copyAndClose(InputStream inputStream, OutputStream outputStream) throws IOException { try { copy(inputStream, outputStream); } finally { closeQuietly(inputStream); closeQuietly(outputStream); } } public void copy(InputStream inputStream, OutputStream outputStream) throws IOException { streamsServices.copy(inputStream, outputStream); } public void copyLarge(InputStream inputStream, OutputStream outputStream) throws IOException { streamsServices.copyLarge(inputStream, outputStream); } public void deleteQuietly(File file) { fileServices.deleteQuietly(file); } public void closeQuietly(Closeable closeable) { streamsServices.closeQuietly(closeable); } public InputStream newByteInputStream(byte[] theContentBytes, String name) { return streamsServices.newByteArrayInputStream(theContentBytes, uniqueIdWith(name)); } public InputStream newBufferedInputStream(InputStream inputStream, String name) { return streamsServices.newBufferedInputStream(inputStream, uniqueIdWith(name)); } public BufferedReader newBufferedReader(Reader reader, String name) { return streamsServices.newBufferedReader(reader, uniqueIdWith(name)); } public BufferedReader newBufferedFileReader(File file, String name) { return streamsServices.newFileReader(file, uniqueIdWith(name)); } public BufferedReader newFileReader(File file, String name) { return streamsServices.newFileReader(file, uniqueIdWith(name)); } public StreamFactory<Reader> newFileReaderFactory(File file) throws FileNotFoundException { return streamsServices.newFileReaderFactory(file); } public Scanner newFileScanner(File file) { return streamsServices.newFileScanner(file); } public InputStream newFileInputStream(File file, String name) throws FileNotFoundException { return streamsServices.newFileInputStream(file, uniqueIdWith(name)); } public InputStream newBufferedByteArrayInputStream(byte[] byteArray, String name) { return streamsServices.newBufferedByteArrayInputStream(byteArray, uniqueIdWith(name)); } public InputStream newBufferedFileInputStream(File file, String name) throws FileNotFoundException { return streamsServices.newBufferedFileInputStream(file, uniqueIdWith(name)); } public InputStream newBufferedFileInputStreamWithFileDeleteOnClose(File file, String name) throws FileNotFoundException { return streamsServices.newBufferedFileInputStreamWithFileDeleteOnClose(file, uniqueIdWith(name)); } public BufferedInputStream newBufferedFileInputStreamWithoutExpectableFileNotFoundException(File file, String name) { try { return streamsServices.newBufferedFileInputStream(file, uniqueIdWith(name)); } catch (FileNotFoundException e) { throw new ImpossibleRuntimeException("File does not exist: " + file.getAbsolutePath(), e); } } public ByteArrayInputStream newByteArrayInputStream(byte[] byteArray, String name) { return streamsServices.newByteArrayInputStream(byteArray, uniqueIdWith(name)); } public OutputStream newBufferedOutputStream(OutputStream outputStream, String name) { return streamsServices.newBufferedOutputStream(outputStream, uniqueIdWith(name)); } public OutputStream newBufferedFileOutputStream(File file, String name) throws FileNotFoundException { return streamsServices.newBufferedFileOutputStream(file, uniqueIdWith(name)); } public OutputStream newBufferedFileOutputStreamWithoutExpectableFileNotFoundException(File file, String name) { try { return streamsServices.newBufferedFileOutputStream(file, uniqueIdWith(name)); } catch (FileNotFoundException e) { throw new ImpossibleRuntimeException(e); } } public OutputStream newFileOutputStream(File file, String name) throws FileNotFoundException { return streamsServices.newFileOutputStream(file, uniqueIdWith(name)); } public ByteArrayOutputStream newByteArrayOutputStream(String name) { return streamsServices.newByteArrayOutputStream(uniqueIdWith(name)); } public StreamFactory<InputStream> newByteArrayStreamFactory(final byte[] bytes, String name) { return streamsServices.newByteArrayStreamFactory(bytes, uniqueIdWith(name)); } public <F extends Closeable> void execute(StreamOperation<F> operation, StreamFactory<F> closeableStreamFactory) throws IOException { streamFactoriesServices.execute(operation, closeableStreamFactory); } public <F extends Closeable, R> R execute(StreamOperationReturningValue<F, R> operation, StreamFactory<F> closeableStreamFactory) throws IOException { return streamFactoriesServices.execute(operation, closeableStreamFactory); } public <F extends Closeable, R, E extends Exception> R execute( StreamOperationReturningValueOrThrowingException<F, R, E> operation, StreamFactory<F> closeableStreamFactory) throws E, IOException { return streamFactoriesServices.execute(operation, closeableStreamFactory); } public <F extends Closeable, E extends Exception> void execute(StreamOperationThrowingException<F, E> operation, StreamFactory<F> closeableStreamFactory) throws E, IOException { streamFactoriesServices.execute(operation, closeableStreamFactory); } public <F extends Closeable, S extends Closeable> void execute(TwoStreamsOperation<F, S> operation, StreamFactory<F> firstCloseableStreamFactory, StreamFactory<S> secondCloseableStreamFactory) throws IOException { streamFactoriesServices.execute(operation, firstCloseableStreamFactory, secondCloseableStreamFactory); } public <F extends Closeable, S extends Closeable, R> R execute(TwoStreamsOperationReturningValue<F, S, R> operation, StreamFactory<F> firstCloseableStreamFactory, StreamFactory<S> secondCloseableStreamFactory) throws IOException { return streamFactoriesServices.execute(operation, firstCloseableStreamFactory, secondCloseableStreamFactory); } public <F extends Closeable, S extends Closeable, R, E extends Exception> R execute( TwoStreamsOperationReturningValueOrThrowingException<F, S, R, E> operation, StreamFactory<F> firstCloseableStreamFactory, StreamFactory<S> secondCloseableStreamFactory) throws E, IOException { return streamFactoriesServices.execute(operation, firstCloseableStreamFactory, secondCloseableStreamFactory); } public <F extends Closeable, S extends Closeable, E extends Exception> void execute( TwoStreamsOperationThrowingException<F, S, E> operation, StreamFactory<F> firstCloseableStreamFactory, StreamFactory<S> secondCloseableStreamFactory) throws E, IOException { streamFactoriesServices.execute(operation, firstCloseableStreamFactory, secondCloseableStreamFactory); } public void closeQuietly(CloseableStreamFactory<InputStream> inputStreamFactory) { streamFactoriesServices.closeQuietly(inputStreamFactory); } public CopyInputStreamFactory copyToReusableStreamFactory(InputStream inputStream, String filename) throws CopyInputStreamFactoryRuntimeException { CopyInputStreamFactory copyInputStreamFactory = new CopyInputStreamFactory(this, Octets.megaoctets(10)); try { copyInputStreamFactory.saveInputStreamContent(inputStream, filename); } finally { IOUtils.closeQuietly(inputStream); } return copyInputStreamFactory; } public void copyDirectory(File srcDir, File destDir) throws IOException { fileServices.copyDirectory(srcDir, destDir); } public void copyDirectoryWithoutExpectableIOException(File srcDir, File destDir) { fileServices.copyDirectoryWithoutExpectableIOException(srcDir, destDir); } public void copyFile(File srcFile, File destFile) throws IOException { fileServices.copyFile(srcFile, destFile); } public void copyFileWithoutExpectableIOException(File srcFile, File destFile) { fileServices.copyFileWithoutExpectableIOException(srcFile, destFile); } public String readFileToString(File file) throws IOException { return fileServices.readFileToString(file); } public String readFileToStringWithoutExpectableIOException(File file) { return fileServices.readFileToStringWithoutExpectableIOException(file); } public List<String> readFileToLinesWithoutExpectableIOException(File file) { return fileServices.readFileToLinesWithoutExpectableIOException(file); } public void replaceFileContent(File file, String data) throws IOException { fileServices.replaceFileContent(file, data); } public void appendFileContent(File file, String data) throws IOException { fileServices.appendFileContent(file, data); } public void ensureWritePermissions(File file) throws IOException { fileServices.ensureWritePermissions(file); } public Collection<File> listFiles(File directory, IOFileFilter fileFilter, IOFileFilter dirFilter) { return fileServices.listFiles(directory, fileFilter, dirFilter); } public Collection<File> listRecursiveFiles(File directory) { return fileServices.listRecursiveFiles(directory); } public Collection<File> listRecursiveFiles(File directory, IOFileFilter fileFilter) { return fileServices.listRecursiveFiles(directory, fileFilter); } public Collection<File> listRecursiveFilesWithName(File directory, String name) { return fileServices.listRecursiveFilesWithName(directory, name); } public void deleteDirectory(File directory) throws IOException { fileServices.deleteDirectory(directory); } public void deleteDirectoryWithoutExpectableIOException(File directory) { fileServices.deleteDirectoryWithoutExpectableIOException(directory); } public File newTemporaryFolder(String resourceName) { return fileServices.newTemporaryFolder(resourceName); } public File newTemporaryFolderWithoutExpectableIOException(String resourceName) { return fileServices.newTemporaryFolder(resourceName); } public String readStreamToStringWithoutExpectableIOException(InputStream inputStream) { return fileServices.readStreamToStringWithoutExpectableIOException(inputStream); } public String readStreamToString(InputStream inputStream) throws IOException { return fileServices.readStreamToString(inputStream); } public List<String> readStreamToLines(InputStream inputStream) throws IOException { return fileServices.readStreamToLines(inputStream); } public StreamFactory<InputStream> newInputStreamFactory(File file, String name) { return streamsServices.newInputStreamFactory(file, uniqueIdWith(name)); } public StreamFactory<OutputStream> newOutputStreamFactory(File file, String name) { return streamsServices.newOutputStreamFactory(file, uniqueIdWith(name)); } public StreamFactory<InputStream> newInputStreamFactory(String string) { return streamsServices.newInputStreamFactory(string); } private String uniqueIdWith(String name) { return name + "-" + UUIDV1Generator.newRandomId(); } public File newTemporaryFile(String resourceName) { return fileServices.newTemporaryFile(resourceName); } public File newTemporaryFile(String resourceName, String extension) { return fileServices.newTemporaryFile(resourceName, extension); } public void touch(File file) { try { FileUtils.touch(file); } catch (IOException e) { throw new RuntimeException(e); } } public File getAtomicWriteTempFileFor(File propertiesFile) { return fileServices.getAtomicWriteTempFileFor(propertiesFile); } public void moveFolder(File src, File dest) { fileServices.moveFolder(src, dest); } public void moveFile(File src, File dest) { fileServices.moveFile(src, dest); } public void replaceFileContent(File file, byte[] bytes) throws IOException { InputStream byteArrayInputStream = new ByteArrayInputStream(bytes); try { replaceFileContent(file, byteArrayInputStream); } finally { byteArrayInputStream.close(); } } public void replaceFileContent(File file, InputStream inputStream) throws IOException { File tempFile = getAtomicWriteTempFileFor(file); OutputStream outputStream = newFileOutputStream(tempFile, REPLACE_FILE_CONTENT_TEMP_FILE); try { copy(inputStream, outputStream); } catch (IOException e) { tempFile.delete(); throw e; } finally { closeQuietly(outputStream); } moveFile(tempFile, file); } public void deleteEmptyDirectoriesExceptThisOneIn(File folder) { deleteEmptyDirectoriesIn(folder, true); } public void deleteEmptyDirectoriesIn(File folder, boolean exceptThisDirectory) { boolean hasFile = false; File[] files = folder.listFiles(); if (files != null) { for (File file : files) { if (file.isDirectory()) { deleteEmptyDirectoriesIn(file, false); if (file.exists()) { hasFile = true; } } else { hasFile = true; } } } if (!hasFile && !exceptThisDirectory) { try { deleteDirectory(folder); } catch (IOException e) { throw new RuntimeException(e); } } } }