package net.sf.cotta.memory;
import net.sf.cotta.system.FileSystem;
import net.sf.cotta.PathContent;
import net.sf.cotta.PathSeparator;
import net.sf.cotta.TFileNotFoundException;
import net.sf.cotta.TIoException;
import net.sf.cotta.TPath;
import net.sf.cotta.io.OutputMode;
import net.sf.cotta.system.ContentManager;
import net.sf.cotta.system.DirectoryIndex;
import net.sf.cotta.system.FileContent;
import net.sf.cotta.system.HashBasedDirectoryIndex;
import net.sf.cotta.system.TreeBasedDirectoryIndex;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.channels.FileChannel;
/**
* A file system whose directory structure and file contents are stored in memory.
* It can be backed by a hash-based directory index or a tree-based one, with hash-based
* being the default.
*
* @see net.sf.cotta.memory.InMemoryFileSystemBuilder for more flexibility in building an instance.
*/
public class InMemoryFileSystem implements FileSystem, ContentManager<InMemoryFileContent> {
public enum IndexType { HASH_BASED, TREE_BASED }
static final PathSeparator DEFAULT_PATH_SEPARATOR = PathSeparator.Unix;
static final ListingOrder DEFAULT_LISTING_ORDER = ListingOrder.NULL;
static final IndexType DEFAULT_INDEX_TYPE = IndexType.HASH_BASED;
private int fileInitialCapacity = 0;
private int fileSizeIncrement = 16;
private final DirectoryIndex<InMemoryFileContent> dirIndex;
public InMemoryFileSystem() {
this(DEFAULT_PATH_SEPARATOR);
}
public InMemoryFileSystem(ListingOrder order) {
this(DEFAULT_PATH_SEPARATOR, order);
}
public InMemoryFileSystem(PathSeparator separator) {
this(separator, DEFAULT_LISTING_ORDER);
}
public InMemoryFileSystem(PathSeparator separator, ListingOrder order) {
this(separator, order, DEFAULT_INDEX_TYPE);
}
/**
* Constructor used by the other constructors or by {@link net.sf.cotta.memory.InMemoryFileSystemBuilder}
* @param separator the desired path separator
* @param order the desired listing order
* @param index the desired directory index type
*/
InMemoryFileSystem(PathSeparator separator, ListingOrder order, IndexType index) {
if (index == IndexType.HASH_BASED) {
this.dirIndex = new HashBasedDirectoryIndex<InMemoryFileContent>(separator, order, this);
}
else if (index == IndexType.TREE_BASED) {
this.dirIndex = new TreeBasedDirectoryIndex<InMemoryFileContent>(separator, order, this);
}
else {
throw new IllegalArgumentException("unrecognized index type: " + index);
}
}
public void setFileInitialCapacity(int value) {
this.fileInitialCapacity = value;
}
public void setFileSizeIncrement(int value) {
this.fileSizeIncrement = value;
}
public InMemoryFileContent createFileContent() {
return new InMemoryFileContent(fileInitialCapacity, fileSizeIncrement);
}
public boolean fileExists(TPath path) {
return dirIndex.fileExists(path);
}
public void createFile(TPath path) throws TIoException {
dirIndex.createFile(path).setContent("");
}
public void createDir(TPath path) throws TIoException {
dirIndex.createDir(path);
}
public void deleteFile(TPath path) throws TFileNotFoundException {
dirIndex.deleteFile(path);
}
public boolean dirExists(TPath path) {
return dirIndex.dirExists(path);
}
public PathContent list(TPath path) {
return dirIndex.list(path);
}
public InputStream createInputStream(TPath path) throws TIoException {
return retrieveFileContent(path).inputStream();
}
private FileContent retrieveFileContent(TPath path) throws TFileNotFoundException {
FileContent content = dirIndex.fileContent(path);
if (content == null) {
throw new TFileNotFoundException(path);
}
return content;
}
public OutputStream createOutputStream(TPath path, OutputMode mode) throws TIoException {
InMemoryFileContent content = dirIndex.fileContent(path);
if (content == null) {
content = dirIndex.createFile(path);
}
if (mode.isOverwrite()) {
content.setContent("");
}
return content.outputStream();
}
public FileChannel createOutputChannel(TPath path, OutputStream outputStream) throws TIoException {
return null;
}
public void deleteDirectory(TPath path) throws TIoException {
dirIndex.deleteDir(path);
}
public void moveFile(TPath source, TPath destination) throws TIoException {
dirIndex.moveFile(source, destination);
}
public void moveDirectory(TPath source, TPath destination) throws TIoException {
dirIndex.moveDir(source, destination);
}
public String pathString(TPath path) {
return dirIndex.pathString(path);
}
public long fileLength(TPath path) {
return dirIndex.fileContent(path).getContentBuffer().size();
}
public long fileLastModified(TPath path) {
return dirIndex.fileContent(path).lastModified();
}
public int compare(TPath path1, TPath path2) {
return dirIndex.compare(path1, path2);
}
public boolean equals(TPath path1, TPath path2) {
return dirIndex.equals(path1, path2);
}
public int hashCode(TPath path) {
return dirIndex.hashCode(path);
}
public URI toUri(TPath path) {
try {
return new URI("memory", null, path.toPathString(), null);
} catch (URISyntaxException e) {
throw new Error(e.getMessage(), e);
}
}
public File toJavaFile(TPath path) {
throw new UnsupportedOperationException("InMemoryFileSystem");
}
public String toCanonicalPath(TPath path) {
return "memory://" + pathString(path);
}
public FileChannel createInputChannel(TPath path) throws TFileNotFoundException {
return retrieveFileContent(path).inputChannel();
}
}