Improved error handling

* Created AsyncTaskService to build async UI operations which always log
uncaught exceptions
* Changed all executor service invocations in the UI to invocations of
AsyncTaskService
* Improved error handling in some other places, especially
try-with-resources
* Unlocking read/write locks in NioFile when opening of a channel fails
This commit is contained in:
Markus Kreusch
2016-07-14 13:58:17 +02:00
parent 9a2f602d6c
commit 7022a80c95
15 changed files with 351 additions and 107 deletions
@@ -30,13 +30,21 @@ class NioFile extends NioNode implements File {
@Override
public ReadableFile openReadable() throws UncheckedIOException {
if (lock.getWriteHoldCount() > 0) {
throw new IllegalStateException("Current thread is currently writing this file");
throw new IllegalStateException("Current thread is currently writing " + path);
}
if (lock.getReadHoldCount() > 0) {
throw new IllegalStateException("Current thread is already reading this file");
throw new IllegalStateException("Current thread is already reading " + path);
}
lock.readLock().lock();
return instanceFactory.readableNioFile(path, sharedChannel, this::unlockReadLock);
ReadableFile result = null;
try {
result = instanceFactory.readableNioFile(path, sharedChannel, this::unlockReadLock);
} finally {
if (result == null) {
unlockReadLock();
}
}
return result;
}
private void unlockReadLock() {
@@ -46,13 +54,21 @@ class NioFile extends NioNode implements File {
@Override
public WritableFile openWritable() throws UncheckedIOException {
if (lock.getWriteHoldCount() > 0) {
throw new IllegalStateException("Current thread is already writing this file");
throw new IllegalStateException("Current thread is already writing " + path);
}
if (lock.getReadHoldCount() > 0) {
throw new IllegalStateException("Current thread is currently reading this file");
throw new IllegalStateException("Current thread is currently reading " + path);
}
lockWriteLock();
return instanceFactory.writableNioFile(fileSystem(), path, sharedChannel, this::unlockWriteLock);
WritableFile result = null;
try {
result = instanceFactory.writableNioFile(fileSystem(), path, sharedChannel, this::unlockWriteLock);
} finally {
if (result == null) {
unlockWriteLock();
}
}
return result;
}
// visible for testing
@@ -99,10 +99,11 @@ public class NioFileTest {
@Test
public void testOpenReadableInvokedBeforeInvokingAfterCloseOperationThrowsIllegalStateException() {
when(instanceFactory.readableNioFile(same(path), same(channel), any())).thenReturn(mock(ReadableNioFile.class));
inTest.openReadable();
thrown.expect(IllegalStateException.class);
thrown.expectMessage("already reading this file");
thrown.expectMessage("already reading " + path);
inTest.openReadable();
}
@@ -111,7 +112,7 @@ public class NioFileTest {
public void testOpenReadableInvokedAfterAfterCloseOperationCreatesNewReadableFile() {
ReadableNioFile readableNioFile = mock(ReadableNioFile.class);
ArgumentCaptor<Runnable> captor = ArgumentCaptor.forClass(Runnable.class);
when(instanceFactory.readableNioFile(same(path), same(channel), captor.capture())).thenReturn(null, readableNioFile);
when(instanceFactory.readableNioFile(same(path), same(channel), captor.capture())).thenReturn(mock(ReadableNioFile.class), readableNioFile);
inTest.openReadable();
captor.getValue().run();
@@ -122,10 +123,11 @@ public class NioFileTest {
@Test
public void testOpenReadableInvokedBeforeInvokingAfterCloseOperationOfOpenWritableThrowsIllegalStateException() {
when(instanceFactory.writableNioFile(same(fileSystem), same(path), same(channel), any())).thenReturn(mock(WritableNioFile.class));
inTest.openWritable();
thrown.expect(IllegalStateException.class);
thrown.expectMessage("currently writing this file");
thrown.expectMessage("currently writing " + path);
inTest.openReadable();
}
@@ -133,7 +135,7 @@ public class NioFileTest {
@Test
public void testOpenReadableInvokedAfterInvokingAfterCloseOperationWorks() {
ArgumentCaptor<Runnable> captor = ArgumentCaptor.forClass(Runnable.class);
when(instanceFactory.writableNioFile(same(fileSystem), same(path), same(channel), captor.capture())).thenReturn(null);
when(instanceFactory.writableNioFile(same(fileSystem), same(path), same(channel), captor.capture())).thenReturn(mock(WritableNioFile.class));
inTest.openWritable();
captor.getValue().run();
@@ -154,7 +156,7 @@ public class NioFileTest {
public void testOpenWritableInvokedAfterAfterCloseOperationCreatesNewWritableFile() {
WritableNioFile writableNioFile = mock(WritableNioFile.class);
ArgumentCaptor<Runnable> captor = ArgumentCaptor.forClass(Runnable.class);
when(instanceFactory.writableNioFile(same(fileSystem), same(path), same(channel), captor.capture())).thenReturn(null, writableNioFile);
when(instanceFactory.writableNioFile(same(fileSystem), same(path), same(channel), captor.capture())).thenReturn(mock(WritableNioFile.class), writableNioFile);
inTest.openWritable();
captor.getValue().run();
@@ -165,28 +167,31 @@ public class NioFileTest {
@Test
public void testOpenWritableInvokedBeforeInvokingAfterCloseOperationThrowsIllegalStateException() {
when(instanceFactory.writableNioFile(same(fileSystem), same(path), same(channel), any())).thenReturn(mock(WritableNioFile.class));
inTest.openWritable();
thrown.expect(IllegalStateException.class);
thrown.expectMessage("already writing this file");
thrown.expectMessage("already writing " + path);
inTest.openWritable();
}
@Test
public void testOpenWritableInvokedBeforeInvokingAfterCloseOperationFromOpenReadableThrowsIllegalStateException() {
when(instanceFactory.readableNioFile(same(path), same(channel), any())).thenReturn(mock(ReadableNioFile.class));
inTest.openReadable();
thrown.expect(IllegalStateException.class);
thrown.expectMessage("currently reading this file");
thrown.expectMessage("currently reading " + path);
inTest.openWritable();
}
@Test
public void testOpenWritableInvokedAfterInvokingAfterCloseOperationWorks() {
ReadableNioFile readableNioFile = mock(ReadableNioFile.class);
ArgumentCaptor<Runnable> captor = ArgumentCaptor.forClass(Runnable.class);
when(instanceFactory.readableNioFile(same(path), same(channel), captor.capture())).thenReturn(null);
when(instanceFactory.readableNioFile(same(path), same(channel), captor.capture())).thenReturn(readableNioFile);
inTest.openReadable();
captor.getValue().run();