package co.paralleluniverse.fuse;
import java.nio.ByteBuffer;
import java.nio.file.Path;
import java.util.logging.Level;
import java.util.logging.Logger;
import jnr.ffi.Pointer;
final class LoggedFuseFilesystem extends FuseFilesystem {
private static interface LoggedMethod<T> {
public T invoke();
}
private static interface LoggedVoidMethod {
public void invoke();
}
private static final String methodSuccess = "Method succeeded.";
private static final String methodFailure = "Exception thrown: ";
private static final String methodResult = " Result: ";
private final String className;
private final Logger logger;
private final FuseFilesystem filesystem;
LoggedFuseFilesystem(FuseFilesystem filesystem, Logger logger) {
this.filesystem = filesystem;
this.logger = logger;
className = filesystem.getClass().getName();
}
private void log(final String methodName, final LoggedVoidMethod method) {
log(methodName, method, null, (Object[]) null);
}
private void log(final String methodName, final LoggedVoidMethod method, final String path, final Object... args) {
try {
logger.entering(className, methodName, args);
method.invoke();
logger.logp(Level.INFO, className, methodName, (path == null ? "" : "[" + path + "] ") + methodSuccess, args);
logger.exiting(className, methodName, args);
} catch (Throwable e) {
logException(e, methodName, null, args);
}
}
private <T> T log(String methodName, T defaultValue, LoggedMethod<T> method) {
return log(methodName, defaultValue, method, null, (Object[]) null);
}
private <T> T log(String methodName, T defaultValue, LoggedMethod<T> method, String path, Object... args) {
try {
logger.entering(className, methodName, args);
final T result = method.invoke();
logger.logp(Level.INFO, className, methodName, (path == null ? "" : "[" + path + "] ") + methodSuccess + methodResult + result, args);
logger.exiting(className, methodName, args);
return result;
} catch (Throwable e) {
return logException(e, methodName, defaultValue, args);
}
}
private <T> T logException(Throwable e, String methodName, T defaultValue, Object... args) {
final StackTraceElement[] stack = e.getStackTrace();
final StringBuilder builder = new StringBuilder();
for (StackTraceElement element : stack)
builder.append('\n').append(element);
logger.logp(Level.SEVERE, className, methodName, methodFailure + e + builder.toString(), args);
return defaultValue;
}
@Override
public final void _destroy() {
destroy();
_destroy(this, filesystem);
}
@Override
public int access(final String path, final int access) {
return log("access", 0, new LoggedMethod<Integer>() {
@Override
public Integer invoke() {
return filesystem.access(path, access);
}
}, path, access);
}
@Override
public void afterUnmount(final Path mountPoint) {
log("afterUnmount", new LoggedVoidMethod() {
@Override
public void invoke() {
filesystem.afterUnmount(mountPoint);
}
}, mountPoint.toString());
}
@Override
public void beforeMount(final Path mountPoint) {
log("beforeMount", new LoggedVoidMethod() {
@Override
public void invoke() {
filesystem.beforeMount(mountPoint);
}
}, mountPoint.toString());
}
@Override
public int bmap(final String path, final StructFuseFileInfo info) {
return log("bmap", 0, new LoggedMethod<Integer>() {
@Override
public Integer invoke() {
return filesystem.bmap(path, info);
}
}, path, info);
}
@Override
public int chmod(final String path, final long mode) {
return log("chmod", 0, new LoggedMethod<Integer>() {
@Override
public Integer invoke() {
return filesystem.chmod(path, mode);
}
}, path, mode);
}
@Override
public int chown(final String path, final long uid, final long gid) {
return log("chown", 0, new LoggedMethod<Integer>() {
@Override
public Integer invoke() {
return filesystem.chown(path, uid, gid);
}
}, path, uid, gid);
}
@Override
public int create(final String path, final long mode, final StructFuseFileInfo info) {
return log("create", 0, new LoggedMethod<Integer>() {
@Override
public Integer invoke() {
return filesystem.create(path, mode, info);
}
}, path, mode, info);
}
@Override
public void destroy() {
log("destroy", new LoggedVoidMethod() {
@Override
public void invoke() {
filesystem.destroy();
}
});
}
@Override
public int fgetattr(final String path, final StructStat stat, final StructFuseFileInfo info) {
return log("fgetattr", 0, new LoggedMethod<Integer>() {
@Override
public Integer invoke() {
return filesystem.fgetattr(path, stat, info);
}
}, path, stat);
}
@Override
public int flush(final String path, final StructFuseFileInfo info) {
return log("flush", 0, new LoggedMethod<Integer>() {
@Override
public Integer invoke() {
return filesystem.flush(path, info);
}
}, path, info);
}
@Override
public int fsync(final String path, final int datasync, final StructFuseFileInfo info) {
return log("fsync", 0, new LoggedMethod<Integer>() {
@Override
public Integer invoke() {
return filesystem.fsync(path, datasync, info);
}
}, path, info);
}
@Override
public int fsyncdir(final String path, final int datasync, final StructFuseFileInfo info) {
return log("fsyncdir", 0, new LoggedMethod<Integer>() {
@Override
public Integer invoke() {
return filesystem.fsyncdir(path, datasync, info);
}
}, path, info);
}
@Override
public int ftruncate(final String path, final long offset, final StructFuseFileInfo info) {
return log("ftruncate", 0, new LoggedMethod<Integer>() {
@Override
public Integer invoke() {
return filesystem.ftruncate(path, offset, info);
}
}, path, offset, info);
}
@Override
public int getattr(final String path, final StructStat stat) {
return log("getattr", 0, new LoggedMethod<Integer>() {
@Override
public Integer invoke() {
return filesystem.getattr(path, stat);
}
}, path, stat);
}
@Override
protected String getName() {
return log("getName", null, new LoggedMethod<String>() {
@Override
public String invoke() {
return filesystem.getName();
}
});
}
@Override
protected String[] getOptions() {
return log("getOptions", null, new LoggedMethod<String[]>() {
@Override
public String[] invoke() {
return filesystem.getOptions();
}
});
}
@Override
public int getxattr(final String path, final String xattr, final XattrFiller filler, final long size, final long position) {
return log("getxattr", 0, new LoggedMethod<Integer>() {
@Override
public Integer invoke() {
return filesystem.getxattr(path, xattr, filler, size, position);
}
}, path, xattr, filler, size, position);
}
@Override
public void init() {
log("init", new LoggedVoidMethod() {
@Override
public void invoke() {
filesystem.init();
}
});
}
@Override
public int link(final String path, final String target) {
return log("link", 0, new LoggedMethod<Integer>() {
@Override
public Integer invoke() {
return filesystem.link(path, target);
}
}, path, target);
}
@Override
public int listxattr(final String path, final XattrListFiller filler) {
return log("listxattr", 0, new LoggedMethod<Integer>() {
@Override
public Integer invoke() {
return filesystem.listxattr(path, filler);
}
}, path, filler);
}
@Override
public int lock(final String path, final StructFuseFileInfo info, final int command, final StructFlock flock) {
return log("lock", 0, new LoggedMethod<Integer>() {
@Override
public Integer invoke() {
return filesystem.lock(path, info, command, flock);
}
}, path, info, command, flock);
}
@Override
public int mkdir(final String path, final long mode) {
return log("mkdir", 0, new LoggedMethod<Integer>() {
@Override
public Integer invoke() {
return filesystem.mkdir(path, mode);
}
}, path, mode);
}
@Override
public int mknod(final String path, final long mode, final long dev) {
return log("mknod", 0, new LoggedMethod<Integer>() {
@Override
public Integer invoke() {
return filesystem.mknod(path, mode, dev);
}
}, path, mode, dev);
}
@Override
public int open(final String path, final StructFuseFileInfo info) {
return log("open", 0, new LoggedMethod<Integer>() {
@Override
public Integer invoke() {
return filesystem.open(path, info);
}
}, path, info);
}
@Override
public int opendir(final String path, final StructFuseFileInfo info) {
return log("opendir", 0, new LoggedMethod<Integer>() {
@Override
public Integer invoke() {
return filesystem.opendir(path, info);
}
}, path, info);
}
@Override
public int read(final String path, final ByteBuffer buffer, final long size, final long offset, final StructFuseFileInfo info) {
return log("read", 0, new LoggedMethod<Integer>() {
@Override
public Integer invoke() {
return filesystem.read(path, buffer, size, offset, info);
}
}, path, buffer, size, offset, info);
}
@Override
public int readdir(final String path, final StructFuseFileInfo info, final DirectoryFiller filler) {
return log("readdir", 0, new LoggedMethod<Integer>() {
@Override
public Integer invoke() {
return filesystem.readdir(path, info, filler);
}
}, path, filler);
}
@Override
public int readlink(final String path, final ByteBuffer buffer, final long size) {
return log("readlink", 0, new LoggedMethod<Integer>() {
@Override
public Integer invoke() {
return filesystem.readlink(path, buffer, size);
}
}, path, buffer, size);
}
@Override
public int release(final String path, final StructFuseFileInfo info) {
return log("release", 0, new LoggedMethod<Integer>() {
@Override
public Integer invoke() {
return filesystem.release(path, info);
}
}, path, info);
}
@Override
public int releasedir(final String path, final StructFuseFileInfo info) {
return log("releasedir", 0, new LoggedMethod<Integer>() {
@Override
public Integer invoke() {
return filesystem.releasedir(path, info);
}
}, path, info);
}
@Override
public int removexattr(final String path, final String xattr) {
return log("removexattr", 0, new LoggedMethod<Integer>() {
@Override
public Integer invoke() {
return filesystem.removexattr(path, xattr);
}
}, path, xattr);
}
@Override
public int rename(final String path, final String newName) {
return log("rename", 0, new LoggedMethod<Integer>() {
@Override
public Integer invoke() {
return filesystem.rename(path, newName);
}
});
}
@Override
public int rmdir(final String path) {
return log("rmdir", 0, new LoggedMethod<Integer>() {
@Override
public Integer invoke() {
return filesystem.rmdir(path);
}
}, path);
}
@Override
public int setxattr(final String path, final String name, final ByteBuffer buf, final long size, final int flags, final int position) {
return log("setxattr", 0, new LoggedMethod<Integer>() {
@Override
public Integer invoke() {
return filesystem.setxattr(path, name, buf, size, flags, position);
}
}, path, name, buf, size, flags, position);
}
@Override
public int statfs(final String path, final StructStatvfs statvfs) {
return log("statfs", 0, new LoggedMethod<Integer>() {
@Override
public Integer invoke() {
return filesystem.statfs(path, statvfs);
}
}, path, statvfs);
}
@Override
public int symlink(final String path, final String target) {
return log("symlink", 0, new LoggedMethod<Integer>() {
@Override
public Integer invoke() {
return filesystem.symlink(path, target);
}
}, path, target);
}
@Override
public int truncate(final String path, final long offset) {
return log("truncate", 0, new LoggedMethod<Integer>() {
@Override
public Integer invoke() {
return filesystem.truncate(path, offset);
}
}, path, offset);
}
@Override
public int unlink(final String path) {
return log("unlink", 0, new LoggedMethod<Integer>() {
@Override
public Integer invoke() {
return filesystem.unlink(path);
}
}, path);
}
@Override
public int utimens(final String path, final StructTimeBuffer timeBuffer) {
return log("utimens", 0, new LoggedMethod<Integer>() {
@Override
public Integer invoke() {
return filesystem.utimens(path, timeBuffer);
}
}, path, timeBuffer);
}
@Override
public int write(final String path, final ByteBuffer buf, final long bufSize, final long writeOffset, final StructFuseFileInfo wrapper) {
return log("write", 0, new LoggedMethod<Integer>() {
@Override
public Integer invoke() {
return filesystem.write(path, buf, bufSize, writeOffset, wrapper);
}
}, path, buf, bufSize, writeOffset, wrapper);
}
@Override
protected int ioctl(final String path, final int cmd, final Pointer arg, final StructFuseFileInfo fi, final long flags, final Pointer data) {
return log("ioctl", 0, new LoggedMethod<Integer>() {
@Override
public Integer invoke() {
return filesystem.ioctl(path, cmd, arg, fi, flags, data);
}
}, path, cmd, arg, fi, flags, data);
}
@Override
protected int poll(final String path, final StructFuseFileInfo fi, final StructFusePollHandle ph, final Pointer reventsp) {
return log("poll", 0, new LoggedMethod<Integer>() {
@Override
public Integer invoke() {
return filesystem.poll(path, fi, ph, reventsp);
}
}, path, fi, ph, reventsp);
}
@Override
protected int write_buf(final String path, final StructFuseBufvec buf, final long off, final StructFuseFileInfo fi) {
return log("write_buf", 0, new LoggedMethod<Integer>() {
@Override
public Integer invoke() {
return filesystem.write_buf(path, buf, off, fi);
}
}, path, buf, off, fi);
}
@Override
protected int read_buf(final String path, final Pointer bufp, final long size, final long off, final StructFuseFileInfo fi) {
return log("read_buf", 0, new LoggedMethod<Integer>() {
@Override
public Integer invoke() {
return filesystem.read_buf(path, bufp, size, off, fi);
}
}, path, bufp, size, off, fi);
}
@Override
protected int flock(final String path, final StructFuseFileInfo fi, final int op) {
return log("flock", 0, new LoggedMethod<Integer>() {
@Override
public Integer invoke() {
return filesystem.flock(path, fi, op);
}
}, path, fi, op);
}
@Override
protected int fallocate(final String path, final int mode, final long off, final long length, final StructFuseFileInfo fi) {
return log("fallocate", 0, new LoggedMethod<Integer>() {
@Override
public Integer invoke() {
return filesystem.fallocate(path, mode, off, length, fi);
}
}, path, mode, off, length, fi);
}
}