Explorar o código

Code simplification

Sebastian Stenzel %!s(int64=9) %!d(string=hai) anos
pai
achega
c41225eab6

+ 0 - 3
main/filesystem-api/src/main/java/org/cryptomator/io/ByteBuffers.java

@@ -10,9 +10,6 @@ package org.cryptomator.io;
 
 import java.nio.ByteBuffer;
 
-/**
- * TODO this probably doesn't belong into this maven module, but it is used by various filesystem layers.
- */
 public final class ByteBuffers {
 
 	private ByteBuffers() {

+ 56 - 0
main/filesystem-api/src/main/java/org/cryptomator/io/FileContents.java

@@ -0,0 +1,56 @@
+package org.cryptomator.io;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.UncheckedIOException;
+import java.nio.channels.Channels;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.commons.io.IOUtils;
+import org.cryptomator.filesystem.File;
+import org.cryptomator.filesystem.WritableFile;
+
+public final class FileContents {
+
+	public static final FileContents UTF_8 = FileContents.withCharset(StandardCharsets.UTF_8);
+
+	private final Charset charset;
+
+	private FileContents(Charset charset) {
+		this.charset = charset;
+	}
+
+	/**
+	 * Reads the whole content from the given file.
+	 * 
+	 * @param file File whose content should be read.
+	 * @return The file's content interpreted in this FileContents' charset.
+	 */
+	public String readContents(File file) {
+		try (Reader reader = Channels.newReader(file.openReadable(), charset.newDecoder(), -1)) {
+			return IOUtils.toString(reader);
+		} catch (IOException e) {
+			throw new UncheckedIOException(e);
+		}
+	}
+
+	/**
+	 * Writes the string into the file encoded with this FileContents' charset.
+	 * This methods replaces any previously existing content, i.e. the string will be the sole content.
+	 * 
+	 * @param file File whose content should be written.
+	 * @param content The new content.
+	 */
+	public void writeContents(File file, String content) {
+		try (WritableFile writable = file.openWritable()) {
+			writable.truncate();
+			writable.write(charset.encode(content));
+		}
+	}
+
+	public static FileContents withCharset(Charset charset) {
+		return new FileContents(charset);
+	}
+
+}

+ 103 - 0
main/filesystem-api/src/test/java/org/cryptomator/io/FileContentsTest.java

@@ -0,0 +1,103 @@
+package org.cryptomator.io;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+
+import org.cryptomator.filesystem.File;
+import org.cryptomator.filesystem.ReadableFile;
+import org.cryptomator.filesystem.WritableFile;
+import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.experimental.theories.DataPoints;
+import org.junit.experimental.theories.Theories;
+import org.junit.experimental.theories.Theory;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+
+@RunWith(Theories.class)
+public class FileContentsTest {
+
+	@DataPoints
+	public static final Iterable<Charset> CHARSETS = Arrays.asList(StandardCharsets.UTF_8, StandardCharsets.US_ASCII, StandardCharsets.UTF_16);
+
+	@DataPoints
+	public static final Iterable<String> TEST_CONTENTS = Arrays.asList("hello world", "hellö wörld", "");
+
+	@Theory
+	public void testReadAll(Charset charset, String testString) {
+		Assume.assumeTrue(charset.newEncoder().canEncode(testString));
+
+		ByteBuffer testContent = ByteBuffer.wrap(testString.getBytes(charset));
+		File file = Mockito.mock(File.class);
+		ReadableFile readable = Mockito.mock(ReadableFile.class);
+		Mockito.when(file.openReadable()).thenReturn(readable);
+		Mockito.when(readable.read(Mockito.any(ByteBuffer.class))).then(invocation -> {
+			ByteBuffer target = invocation.getArgumentAt(0, ByteBuffer.class);
+			if (testContent.hasRemaining()) {
+				return ByteBuffers.copy(testContent, target);
+			} else {
+				return -1;
+			}
+		});
+
+		String contentsRead = FileContents.withCharset(charset).readContents(file);
+		Assert.assertEquals(testString, contentsRead);
+	}
+
+	@Theory
+	public void testWriteAll(Charset charset, String testString) {
+		Assume.assumeTrue(charset.newEncoder().canEncode(testString));
+
+		ByteBuffer testContent = ByteBuffer.allocate(100);
+		File file = Mockito.mock(File.class);
+		WritableFile writable = Mockito.mock(WritableFile.class);
+		Mockito.when(file.openWritable()).thenReturn(writable);
+		Mockito.doAnswer(invocation -> {
+			testContent.clear();
+			return null;
+		}).when(writable).truncate();
+		Mockito.when(writable.write(Mockito.any(ByteBuffer.class))).then(invocation -> {
+			ByteBuffer source = invocation.getArgumentAt(0, ByteBuffer.class);
+			if (testContent.hasRemaining()) {
+				return ByteBuffers.copy(source, testContent);
+			} else {
+				return -1;
+			}
+		});
+
+		FileContents.withCharset(charset).writeContents(file, testString);
+		Assert.assertArrayEquals(testString.getBytes(charset), Arrays.copyOf(testContent.array(), testContent.position()));
+	}
+
+	@Test(expected = UncheckedIOException.class)
+	public void testIOExceptionDuringRead() {
+		File file = Mockito.mock(File.class);
+		Mockito.when(file.openReadable()).thenAnswer(invocation -> {
+			throw new IOException("failed");
+		});
+
+		FileContents.UTF_8.readContents(file);
+	}
+
+	@Test(expected = UncheckedIOException.class)
+	public void testUncheckedIOExceptionDuringRead() {
+		File file = Mockito.mock(File.class);
+		Mockito.when(file.openReadable()).thenThrow(new UncheckedIOException(new IOException("failed")));
+
+		FileContents.UTF_8.readContents(file);
+	}
+
+	@Test(expected = UncheckedIOException.class)
+	public void testUncheckedIOExceptionDuringWrite() {
+		File file = Mockito.mock(File.class);
+		Mockito.when(file.openWritable()).thenThrow(new UncheckedIOException(new IOException("failed")));
+
+		FileContents.UTF_8.writeContents(file, "hello world");
+	}
+
+}

+ 4 - 20
main/filesystem-crypto/src/main/java/org/cryptomator/filesystem/crypto/CryptoFolder.java

@@ -71,21 +71,9 @@ class CryptoFolder extends CryptoNode implements Folder {
 	}
 
 	protected Optional<String> getDirectoryId() {
-		if (directoryId.get() != null) {
-			return Optional.of(directoryId.get());
-		}
-		if (physicalFile().isPresent()) {
-			File dirFile = physicalFile().get();
-			if (dirFile.exists()) {
-				try (Reader reader = Channels.newReader(dirFile.openReadable(), UTF_8.newDecoder(), -1)) {
-					directoryId.set(IOUtils.toString(reader));
-					return Optional.of(directoryId.get());
-				} catch (IOException e) {
-					throw new UncheckedIOException(e);
-				}
-			}
-		}
-		return Optional.empty();
+		return Optional.ofNullable(LazyInitializer.initializeLazily(directoryId, () -> {
+			return physicalFile().filter(File::exists).map(FileContents.UTF_8::readContents).orElse(null);
+		}));
 	}
 
 	@Override
@@ -156,11 +144,7 @@ class CryptoFolder extends CryptoNode implements Folder {
 		if (parent.file(name).exists()) {
 			throw new UncheckedIOException(new FileAlreadyExistsException(toString()));
 		}
-		try (Writer writer = Channels.newWriter(dirFile.openWritable(), UTF_8.newEncoder(), -1)) {
-			writer.write(directoryId.get());
-		} catch (IOException e) {
-			throw new UncheckedIOException(e);
-		}
+		FileContents.UTF_8.writeContents(dirFile, directoryId.get());
 		dir.create();
 	}
 

+ 3 - 17
main/filesystem-nameshortening/src/main/java/org/cryptomator/filesystem/shortening/FilenameShortener.java

@@ -8,22 +8,16 @@
  *******************************************************************************/
 package org.cryptomator.filesystem.shortening;
 
-import static java.nio.charset.StandardCharsets.UTF_8;
-
 import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.Reader;
 import java.io.UncheckedIOException;
-import java.io.Writer;
-import java.nio.channels.Channels;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 
 import org.apache.commons.codec.binary.Base32;
 import org.apache.commons.codec.binary.BaseNCodec;
-import org.apache.commons.io.IOUtils;
 import org.cryptomator.filesystem.File;
 import org.cryptomator.filesystem.Folder;
+import org.cryptomator.io.FileContents;
 
 class FilenameShortener {
 
@@ -64,11 +58,7 @@ class FilenameShortener {
 		final File mappingFile = mappingFile(shortName);
 		if (!mappingFile.exists()) {
 			mappingFile.parent().get().create();
-			try (Writer writer = Channels.newWriter(mappingFile.openWritable(), UTF_8.newEncoder(), -1)) {
-				writer.write(longName);
-			} catch (IOException e) {
-				throw new UncheckedIOException(e);
-			}
+			FileContents.UTF_8.writeContents(mappingFile, longName);
 		}
 	}
 
@@ -82,11 +72,7 @@ class FilenameShortener {
 		if (!mappingFile.exists()) {
 			throw new UncheckedIOException(new FileNotFoundException("Mapping file not found " + mappingFile));
 		} else {
-			try (Reader reader = Channels.newReader(mappingFile.openReadable(), UTF_8.newDecoder(), -1)) {
-				return IOUtils.toString(reader);
-			} catch (IOException e) {
-				throw new UncheckedIOException(e);
-			}
+			return FileContents.UTF_8.readContents(mappingFile);
 		}
 	}