package org.apache.commons.vfs2.provider.ram;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.apache.commons.vfs2.Capability;
import org.apache.commons.vfs2.FileName;
import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSystemException;
import org.apache.commons.vfs2.FileSystemOptions;
import org.apache.commons.vfs2.FileType;
import org.apache.commons.vfs2.provider.AbstractFileName;
import org.apache.commons.vfs2.provider.AbstractFileSystem;
public class RamFileSystem extends AbstractFileSystem implements Serializable {
private static final int BUFFER_SIZE = 512;
private static final long serialVersionUID = 20101208L;
private final Map<FileName, RamFileData> cache;
protected RamFileSystem(final FileName rootName, final FileSystemOptions fileSystemOptions) {
super(rootName, null, fileSystemOptions);
this.cache = Collections.synchronizedMap(new HashMap<FileName, RamFileData>());
final RamFileData rootData = new RamFileData(rootName);
rootData.setType(FileType.FOLDER);
rootData.setLastModified(System.currentTimeMillis());
this.cache.put(rootName, rootData);
}
@Override
protected FileObject createFile(final AbstractFileName name) throws Exception {
return new RamFileObject(name, this);
}
@Override
protected void addCapabilities(final Collection<Capability> caps) {
caps.addAll(RamFileProvider.capabilities);
}
String[] listChildren(final FileName name) {
final RamFileData data = this.cache.get(name);
if (data == null || !data.getType().hasChildren()) {
return null;
}
final Collection<RamFileData> children = data.getChildren();
String[] names;
synchronized (children) {
names = new String[children.size()];
int pos = 0;
final Iterator<RamFileData> iter = children.iterator();
while (iter.hasNext()) {
final RamFileData childData = iter.next();
names[pos] = childData.getName().getBaseName();
pos++;
}
}
return names;
}
void delete(final RamFileObject file) throws FileSystemException {
FileSystemException.requireNonNull(file.getParent(), "unable to delete root");
this.cache.remove(file.getName());
final RamFileObject parent = (RamFileObject) this.resolveFile(file.getParent().getName());
parent.getData().removeChild(file.getData());
parent.close();
file.getData().clear();
file.close();
}
void save(final RamFileObject file) throws FileSystemException {
if (file.getData().getName() == null) {
throw new FileSystemException(new IllegalStateException("The data has no name. " + file));
}
if (file.getName().getDepth() > 0) {
final RamFileData parentData = this.cache.get(file.getParent().getName());
if (!parentData.hasChildren(file.getData())) {
final RamFileObject parent = (RamFileObject) file.getParent();
parent.getData().addChild(file.getData());
parent.close();
}
}
cache.put(file.getName(), file.getData());
file.getData().updateLastModified();
file.close();
}
void rename(final RamFileObject from, final RamFileObject to) throws FileSystemException {
if (!this.cache.containsKey(from.getName())) {
throw new FileSystemException("File does not exist: " + from.getName());
}
to.getData().setContent(from.getData().getContent());
to.getData().setLastModified(from.getData().getLastModified());
to.getData().setType(from.getData().getType());
this.save(to);
this.delete(from);
}
public void attach(final RamFileObject fo) {
if (fo.getName() == null) {
throw new IllegalArgumentException("Null argument");
}
RamFileData data = this.cache.get(fo.getName());
if (data == null) {
data = new RamFileData(fo.getName());
}
fo.setData(data);
}
public void importTree(final File file) throws FileSystemException {
final FileObject fileFo = getFileSystemManager().toFileObject(file);
this.toRamFileObject(fileFo, fileFo);
}
void toRamFileObject(final FileObject fo, final FileObject root) throws FileSystemException {
final RamFileObject memFo = (RamFileObject) this
.resolveFile(fo.getName().getPath().substring(root.getName().getPath().length()));
if (fo.getType().hasChildren()) {
memFo.createFolder();
final FileObject[] fos = fo.getChildren();
for (final FileObject child : fos) {
this.toRamFileObject(child, root);
}
} else if (fo.isFile()) {
try {
final InputStream is = fo.getContent().getInputStream();
try {
final OutputStream os = new BufferedOutputStream(memFo.getOutputStream(), BUFFER_SIZE);
int i;
while ((i = is.read()) != -1) {
os.write(i);
}
os.close();
} finally {
try {
is.close();
} catch (final IOException ignored) {
}
}
} catch (final IOException e) {
throw new FileSystemException(e.getClass().getName() + " " + e.getMessage());
}
} else {
throw new FileSystemException("File is not a folder nor a file " + memFo);
}
}
long size() {
long size = 0;
synchronized (cache) {
final Iterator<RamFileData> iter = cache.values().iterator();
while (iter.hasNext()) {
final RamFileData data = iter.next();
size += data.size();
}
}
return size;
}
@Override
public void close() {
this.cache.clear();
super.close();
}
}