Skip to content

Commit

Permalink
Created the File Tool for common file handling
Browse files Browse the repository at this point in the history
  • Loading branch information
AdamCarroll committed Jan 4, 2017
1 parent 16faaba commit 9f6804d
Show file tree
Hide file tree
Showing 7 changed files with 265 additions and 64 deletions.
@@ -0,0 +1,63 @@
/*
* Open Source Software published under the Apache Licence, Version 2.0.
*/

package io.github.vocabhunter.analysis.core;

import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;

public final class FileTool {
private static final ObjectMapper MAPPER = new ObjectMapper();

private static final List<String> MINIMAL_JSON = Collections.singletonList("{}");

private FileTool() {
// Prevent instantiation - all methods are static
}

public static void ensureDirectoryExists(final Path file, final String errorTemplate) {
Path parent = file.getParent();

try {
if (parent != null) {
Files.createDirectories(parent);
}
} catch (final IOException e) {
throw buildError(parent, errorTemplate, e);
}
}

public static void writeMinimalJson(final Path file, final String errorTemplate) {
try {
Files.write(file, MINIMAL_JSON);
} catch (final IOException e) {
throw buildError(file, errorTemplate, e);
}
}

public static void writeAsJson(final Path file, final Object v, final String errorTemplate) {
try {
MAPPER.writeValue(file.toFile(), v);
} catch (final IOException e) {
throw buildError(file, errorTemplate, e);
}
}

public static <T> T readFromJson(final Class<T> beanClass, final Path file, final String errorTemplate) {
try {
return MAPPER.readValue(file.toFile(), beanClass);
} catch (final IOException e) {
throw buildError(file, errorTemplate, e);
}
}

private static VocabHunterException buildError(final Path file, final String errorTemplate, final Throwable e) {
return new VocabHunterException(String.format(errorTemplate, file), e);
}
}
Expand Up @@ -4,31 +4,24 @@

package io.github.vocabhunter.analysis.session;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.github.vocabhunter.analysis.core.FileTool;
import io.github.vocabhunter.analysis.core.VocabHunterException;
import io.github.vocabhunter.analysis.marked.MarkedWord;
import io.github.vocabhunter.analysis.simple.WordStreamTool;

import java.io.IOException;
import java.nio.file.Path;
import java.util.List;

import static io.github.vocabhunter.analysis.session.SessionFormatVersion.*;
import static java.util.stream.Collectors.toList;

public final class SessionSerialiser {
private static final ObjectMapper MAPPER = new ObjectMapper();

private SessionSerialiser() {
// Prevent instantiation - all methods are static
}

public static void write(final Path file, final SessionState state) {
try {
MAPPER.writeValue(file.toFile(), state);
} catch (final IOException e) {
throw new VocabHunterException(String.format("Unable to save file '%s'", file), e);
}
FileTool.writeAsJson(file, state, "Unable to save file '%s'");
}

public static List<? extends MarkedWord> readMarkedWords(final Path file) {
Expand All @@ -44,17 +37,13 @@ private static SessionState readInternal(final Path file) {
}

private static SessionState readForMarkedWords(final Path file) {
try {
SessionState state = MAPPER.readValue(file.toFile(), SessionState.class);
int formatVersion = state.getFormatVersion();

if (formatVersion < 1 || formatVersion > LATEST_VERSION) {
throw new VocabHunterException("This file was created with a newer version of VocabHunter. Please upgrade and try again.");
} else {
return upgradeForMarkedWords(state);
}
} catch (final IOException e) {
throw new VocabHunterException(String.format("Unable to load file '%s'", file), e);
SessionState state = FileTool.readFromJson(SessionState.class, file, "Unable to load file '%s'");
int formatVersion = state.getFormatVersion();

if (formatVersion < 1 || formatVersion > LATEST_VERSION) {
throw new VocabHunterException("This file was created with a newer version of VocabHunter. Please upgrade and try again.");
} else {
return upgradeForMarkedWords(state);
}
}

Expand Down
Expand Up @@ -4,24 +4,16 @@

package io.github.vocabhunter.analysis.settings;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.github.vocabhunter.analysis.core.VocabHunterException;
import io.github.vocabhunter.analysis.core.FileTool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;

public class BaseSettingsManager<T> {
private static final Logger LOG = LoggerFactory.getLogger(BaseSettingsManager.class);

private static final ObjectMapper MAPPER = new ObjectMapper();

private static final List<String> MINIMAL_JSON = Collections.singletonList("{}");

private final Path settingsFile;

private final Class<T> beanClass;
Expand All @@ -33,59 +25,35 @@ protected BaseSettingsManager(final String filename, final Class<T> beanClass) {
protected BaseSettingsManager(final Path settingsFile, final Class<T> beanClass) {
this.settingsFile = settingsFile;
this.beanClass = beanClass;
ensureDirectoryExists(settingsFile);
}

private void ensureDirectoryExists(final Path settingsFile) {
Path parent = settingsFile.getParent();

try {
if (parent != null) {
Files.createDirectories(parent);
}
} catch (final IOException e) {
throw new VocabHunterException(String.format("Unable to create directory %s", parent), e);
}
FileTool.ensureDirectoryExists(settingsFile, "Unable to create directory %s");
}

protected T readSettings() {
try {
T result = readSettingsIfAvailable();

if (result == null) {
Files.write(settingsFile, MINIMAL_JSON);
result = readSettingsIfAvailable();
}
T result = readSettingsIfAvailable();

return result;
} catch (final IOException e) {
throw new VocabHunterException(String.format("Unable to load settings file '%s'", settingsFile), e);
if (result == null) {
FileTool.writeMinimalJson(settingsFile, "Unable to save settings file '%s'");
result = readSettingsIfAvailable();
}

return result;
}

private T readSettingsIfAvailable() {
try {
if (Files.isRegularFile(settingsFile)) {
return readSettingsInternal();
return FileTool.readFromJson(beanClass, settingsFile, "Unable to load settings file '%s'");
} else {
return null;
}
} catch (final Exception e) {
LOG.error("Unable to load settings file '{}'", settingsFile, e);
LOG.error("Discarding unreadable settings file '{}'", settingsFile, e);

return null;
}
}

private T readSettingsInternal() throws IOException {
return MAPPER.readValue(settingsFile.toFile(), beanClass);
}

protected void writeSettings(final T settings) {
try {
MAPPER.writeValue(settingsFile.toFile(), settings);
} catch (final IOException e) {
throw new VocabHunterException(String.format("Unable to save settings file '%s'", settingsFile), e);
}
FileTool.writeAsJson(settingsFile, settings, "Unable to save settings file '%s'");
}
}
@@ -0,0 +1,103 @@
/*
* Open Source Software published under the Apache Licence, Version 2.0.
*/

package io.github.vocabhunter.analysis.core;

import io.github.vocabhunter.test.utils.TestFileManager;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.List;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

public class FileToolTest {
private static final String ERROR_TEMPLATE = "Error %s";
private TestFileManager manager;

private Path base;

private Path existingFile;

private Path newFile;

private Path subDirectory;

@Before
public void setUp() throws Exception {
manager = new TestFileManager(getClass());
base = manager.getDirectory();
existingFile = manager.addFile("existingFile");
Files.createFile(existingFile);
newFile = manager.addFile("newFile");
subDirectory = manager.addFile("directory");
Files.createDirectories(subDirectory);
}

@After
public void tearDown() throws Exception {
manager.cleanup();
}

@Test
public void testEnsureDirectoryExistsWithDirectory() {
FileTool.ensureDirectoryExists(existingFile, ERROR_TEMPLATE);

assertTrue(Files.isDirectory(base));
}

@Test(expected = VocabHunterException.class)
public void testEnsureDirectoryExistsWithError() {
Path impossible = existingFile.resolve("file");

FileTool.ensureDirectoryExists(impossible, ERROR_TEMPLATE);
}

@Test
public void testEnsureDirectoryExistsWithoutBase() {
Path file = Paths.get("file");
FileTool.ensureDirectoryExists(file, ERROR_TEMPLATE);
}

@Test
public void testWriteMinimalJsonSuccess() throws Exception {
FileTool.writeMinimalJson(newFile, ERROR_TEMPLATE);

List<String> result = Files.readAllLines(newFile);
List<String> expected = Collections.singletonList("{}");

assertEquals(expected, result);
}

@Test(expected = VocabHunterException.class)
public void testWriteMinimalJsonFailure() throws Exception {
FileTool.writeMinimalJson(subDirectory, ERROR_TEMPLATE);
}

@Test
public void testReadThenWriteJson() {
FileToolTestBean bean = new FileToolTestBean("left", "right");

FileTool.writeAsJson(newFile, bean, ERROR_TEMPLATE);
FileToolTestBean result = FileTool.readFromJson(FileToolTestBean.class, newFile, ERROR_TEMPLATE);

assertEquals(bean, result);
}

@Test(expected = VocabHunterException.class)
public void testWriteAsJsonWithError() {
FileTool.writeAsJson(subDirectory, new FileToolTestBean(), ERROR_TEMPLATE);
}

@Test(expected = VocabHunterException.class)
public void testReadFromJsonWithError() {
FileTool.readFromJson(FileToolTestBean.class, subDirectory, ERROR_TEMPLATE);
}
}
@@ -0,0 +1,74 @@
/*
* Open Source Software published under the Apache Licence, Version 2.0.
*/

package io.github.vocabhunter.analysis.core;

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;

public class FileToolTestBean {
private String left;

private String right;

public FileToolTestBean() {
// No argument constructor to allow use as standard Java Bean
}

public FileToolTestBean(final String left, final String right) {
this.left = left;
this.right = right;
}

public String getLeft() {
return left;
}

public void setLeft(final String left) {
this.left = left;
}

public String getRight() {
return right;
}

public void setRight(final String right) {
this.right = right;
}

@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}

if (o == null || getClass() != o.getClass()) {
return false;
}

FileToolTestBean that = (FileToolTestBean) o;

return new EqualsBuilder()
.append(left, that.left)
.append(right, that.right)
.isEquals();
}

@Override
public int hashCode() {
return new HashCodeBuilder()
.append(left)
.append(right)
.toHashCode();
}

@Override
public String toString() {
return new ToStringBuilder(this)
.append("left", left)
.append("right", right)
.toString();
}
}

0 comments on commit 9f6804d

Please sign in to comment.