Code simplification

This commit is contained in:
Sebastian Stenzel
2016-02-15 22:34:11 +01:00
parent 2725b6b920
commit c41225eab6
5 changed files with 166 additions and 40 deletions

View File

@@ -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() {

View File

@@ -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);
}
}

View File

@@ -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");
}
}

View File

@@ -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();
}

View File

@@ -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);
}
}