package net.sf.cotta.system; import net.sf.cotta.PathContent; import net.sf.cotta.PathSeparator; import net.sf.cotta.TDirectoryNotFoundException; import net.sf.cotta.TFileNotFoundException; import net.sf.cotta.TIoException; import net.sf.cotta.TPath; import net.sf.cotta.memory.ListingOrder; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; public class TreeBasedDirectoryIndex<F extends FileContent> extends AbstractDirectoryIndex<F> { private Map<String, DirTreeNode> roots = new HashMap<String, DirTreeNode>(); public TreeBasedDirectoryIndex(ContentManager<F> contentManager) { super(contentManager); init(); } public TreeBasedDirectoryIndex(PathSeparator separator, ListingOrder order, ContentManager<F> contentManager) { super(separator, order, contentManager); init(); } private void init() { roots.put("", new DirTreeNode()); roots.put(".", new DirTreeNode()); } public boolean fileExists(TPath path) { return findFile(path) != null; } public boolean dirExists(TPath path) { return findDir(path) != null; } public PathContent list(TPath path) { DirTreeNode dir = findDir(path); List<TPath> dirs = new ArrayList<TPath>(dir.dirs().size()); for (String dirName : dir.dirs()) { dirs.add(path.join(dirName)); } List<TPath> files = new ArrayList<TPath>(dir.files().size()); for (String fileName : dir.files()) { files.add(path.join(fileName)); } sort(dirs); sort(files); return new PathContent(dirs, files); } public F fileContent(TPath path) { return findFile(path); } public F createFile(TPath path) throws TIoException { validateBeforeCreateFile(path); DirTreeNode parentDir = findDir(path.parent()); if (parentDir == null) { throw new TIoException(path, "parent needs to be created first"); } F f = contentManager.createFileContent(); parentDir.addFile(path.lastElementName(), f); return f; } public void deleteFile(TPath path) throws TFileNotFoundException { DirTreeNode parent = findDir(path.parent()); if (parent == null || parent.getFile(path.lastElementName()) == null) { throw new TFileNotFoundException(path); } parent.removeFile(path.lastElementName()); } public void moveFile(TPath source, TPath dest) throws TIoException { F f = findFile(source); DirTreeNode destParent = findDir(dest.parent()); destParent.addFile(dest.lastElementName(), f); findDir(source.parent()).removeFile(source.lastElementName()); } public void createDir(TPath path) throws TIoException { validateBeforeCreateDir(path); DirTreeNode current = roots.get(path.headElement()); for (int i = 0; i < path.length(); i++) { DirTreeNode child = current.getDir(path.elementAt(i)); if (child == null) { child = current.addDir(path.elementAt(i)); } current = child; } } public void deleteDir(TPath path) throws TIoException { DirTreeNode parent = findDir(path.parent()); if (parent == null || parent.getDir(path.lastElementName()) == null) { throw new TDirectoryNotFoundException(path); } if (!findDir(path).isEmpty()) { throw new TIoException(path, "Directory not empty"); } parent.removeDir(path.lastElementName()); } public void moveDir(TPath source, TPath dest) throws TIoException { DirTreeNode sourceDir = findDir(source.parent()).removeDir(source.lastElementName()); DirTreeNode destParent = findDir(dest.parent()); destParent.addDir(dest.lastElementName(), sourceDir); } private F findFile(TPath path) { TPath parent = path.parent(); DirTreeNode dir = parent != null ? findDir(parent) : roots.get(path.headElement()); F file = dir != null ? dir.getFile(path.lastElementName()) : null; return file; } private DirTreeNode findDir(TPath path) { DirTreeNode current = roots.get(path.headElement()); for (int i = 0; i < path.length() && current != null; i++) { current = current.getDir(path.elementAt(i)); } return current; } private class DirTreeNode { private Map<String, F> files = new HashMap<String, F>(); private Map<String, DirTreeNode> dirs = new HashMap<String, DirTreeNode>(); DirTreeNode addDir(String name) { DirTreeNode d = new DirTreeNode(); addDir(name, d); return d; } void addDir(String name, DirTreeNode d) { dirs.put(name, d); } void addFile(String name, F file) { files.put(name, file); } DirTreeNode removeDir(String name) { return dirs.remove(name); } void removeFile(String name) { files.remove(name); } DirTreeNode getDir(String name) { return dirs.get(name); } F getFile(String name) { return files.get(name); } Collection<String> dirs() { return dirs.keySet(); } Collection<String> files() { return files.keySet(); } boolean isEmpty() { return dirs.isEmpty() && files.isEmpty(); } } }