package com.github.marschall.memoryfilesystem; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousFileChannel; import java.nio.channels.CompletionHandler; import java.nio.channels.FileLock; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; final class AsynchronousBlockChannel extends AsynchronousFileChannel { private final BlockChannel delegate; private final ExecutorService workExecutor; private final ExecutorService callbackExecutor; AsynchronousBlockChannel(BlockChannel delegate, ExecutorService workExecutor, ExecutorService callbackExecutor) { this.delegate = delegate; this.workExecutor = workExecutor; this.callbackExecutor = callbackExecutor; } private <A> void failed(final Throwable exception, final A attachment, final CompletionHandler<?, ? super A> handler) { this.callbackExecutor.submit(new Runnable() { @Override public void run() { handler.failed(exception, attachment); } }); } private <V, A> void completed(final V result, final A attachment, final CompletionHandler<V, ? super A> handler) { this.callbackExecutor.submit(new Runnable() { @Override public void run() { handler.completed(result, attachment); } }); } @Override public void close() throws IOException { this.delegate.close(); } @Override public boolean isOpen() { return this.delegate.isOpen(); } @Override public long size() throws IOException { return this.delegate.size(); } @Override public AsynchronousFileChannel truncate(long size) throws IOException { this.delegate.truncate(size); return this; } @Override public void force(boolean metaData) throws IOException { this.delegate.force(metaData); } @Override public <A> void lock(final long position, final long size, final boolean shared, final A attachment, final CompletionHandler<FileLock, ? super A> handler) { this.workExecutor.submit(new Runnable() { @Override public void run() { try { MemoryFileLock l = new MemoryFileLock(AsynchronousBlockChannel.this, position, size, shared); FileLock lock = AsynchronousBlockChannel.this.delegate.lock(l); AsynchronousBlockChannel.this.completed(lock, attachment, handler); } catch (IOException | RuntimeException e) { AsynchronousBlockChannel.this.failed(e, attachment, handler); } } }); } @Override public Future<FileLock> lock(final long position, final long size, final boolean shared) { return this.workExecutor.submit(new Callable<FileLock>() { @Override public FileLock call() throws Exception { MemoryFileLock l = new MemoryFileLock(AsynchronousBlockChannel.this, position, size, shared); return AsynchronousBlockChannel.this.delegate.lock(l); } }); } @Override public FileLock tryLock(long position, long size, boolean shared) throws IOException { return this.delegate.tryLock(position, size, shared); } @Override public <A> void read(final ByteBuffer dst, final long position, final A attachment, final CompletionHandler<Integer, ? super A> handler) { this.workExecutor.submit(new Runnable() { @Override public void run() { try { final int read = AsynchronousBlockChannel.this.delegate.read(dst, position); AsynchronousBlockChannel.this.completed(read, attachment, handler); } catch (IOException | RuntimeException e) { AsynchronousBlockChannel.this.failed(e, attachment, handler); } } }); } @Override public Future<Integer> read(final ByteBuffer dst, final long position) { return this.workExecutor.submit(new Callable<Integer>() { @Override public Integer call() throws Exception { return AsynchronousBlockChannel.this.delegate.read(dst, position); } }); } @Override public <A> void write(final ByteBuffer src, final long position, final A attachment, final CompletionHandler<Integer, ? super A> handler) { this.workExecutor.submit(new Runnable() { @Override public void run() { try { final int written = AsynchronousBlockChannel.this.delegate.write(src, position); AsynchronousBlockChannel.this.completed(written, attachment, handler); } catch (IOException | RuntimeException e) { AsynchronousBlockChannel.this.failed(e, attachment, handler); } } }); } @Override public Future<Integer> write(final ByteBuffer src, final long position) { return this.workExecutor.submit(new Callable<Integer>() { @Override public Integer call() throws Exception { return AsynchronousBlockChannel.this.delegate.write(src, position); } }); } }