Index: src/main/java/org/apache/jackrabbit/core/fs/mem/MemoryFile.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/fs/mem/MemoryFile.java +++ src/main/java/org/apache/jackrabbit/core/fs/mem/MemoryFile.java @@ -0,0 +1,19 @@ +package org.apache.jackrabbit.core.fs.mem; + +public class MemoryFile extends MemoryFileSystemEntry { + + private byte[] data = new byte[0]; + + public boolean isFolder() { + return false; + } + + protected byte[] getData() { + return data; + } + + protected void setData(byte[] data) { + this.data = data; + } + +} Index: src/main/java/org/apache/jackrabbit/core/fs/mem/MemoryFileSystem.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/fs/mem/MemoryFileSystem.java +++ src/main/java/org/apache/jackrabbit/core/fs/mem/MemoryFileSystem.java @@ -0,0 +1,228 @@ +package org.apache.jackrabbit.core.fs.mem; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import org.apache.jackrabbit.core.fs.FileSystem; +import org.apache.jackrabbit.core.fs.FileSystemException; +import org.apache.jackrabbit.core.fs.RandomAccessOutputStream; + +public class MemoryFileSystem implements FileSystem { + + private Map entries = new HashMap(); + + public void close() { + } + + public void copy(String srcPath, String destPath) + throws FileSystemException { + assertExistence(srcPath); + MemoryFile srcFile = getFile(srcPath); + OutputStream destinationOutputStream = getOutputStream(destPath); + try { + destinationOutputStream.write(srcFile.getData()); + } catch (IOException e) { + throw new FileSystemException(e.getMessage(), e); + } finally { + try { + destinationOutputStream.close(); + } catch (IOException e) { + // ignore + } + } + } + + private MemoryFile getFile(String filePath) throws FileSystemException { + MemoryFileSystemEntry entry = getEntry(filePath); + assertIsFile(filePath); + return (MemoryFile) entry; + } + + public void createFolder(String folderPath) throws FileSystemException { + if (exists(folderPath)) { + throw new FileSystemException("Folder or file " + folderPath + + " already exists"); + } + if (!exists(FileSystem.SEPARATOR)) { + createFolderInternal("/"); + } + String relativePath = folderPath.substring(1); + String[] pathElements = relativePath.split(FileSystem.SEPARATOR); + String currentFolderPath = ""; + for (int i = 0; i < pathElements.length; i++) { + String pathElement = pathElements[i]; + currentFolderPath += "/" + pathElement; + createFolderInternal(currentFolderPath); + } + } + + private void createFolderInternal(String folderPath) { + MemoryFolder folder = new MemoryFolder(); + entries.put(folderPath, folder); + } + + public void deleteFile(String filePath) throws FileSystemException { + assertExistence(filePath); + entries.remove(filePath); + } + + public void deleteFolder(String folderPath) throws FileSystemException { + assertExistence(folderPath); + if (hasChildren(folderPath)) { + throw new FileSystemException(folderPath + " not empty"); + } + entries.remove(folderPath); + } + + public boolean exists(String path) throws FileSystemException { + return entries.containsKey(path); + } + + public InputStream getInputStream(String filePath) + throws FileSystemException { + assertExistence(filePath); + assertIsFile(filePath); + + MemoryFile file = getFile(filePath); + return new ByteArrayInputStream(file.getData()); + } + + private void assertIsFolder(String folderPath) throws FileSystemException { + assertExistence(folderPath); + if (!getEntry(folderPath).isFolder()) { + throw new FileSystemException("Folder " + folderPath + + " does not exist"); + } + } + + private void assertIsFile(String filePath) throws FileSystemException { + if (!isFile(filePath)) { + throw new FileSystemException(filePath + " is a folder"); + } + } + + public OutputStream getOutputStream(String filePath) + throws FileSystemException { + String folderPath = filePath; + if (filePath.lastIndexOf(FileSystem.SEPARATOR) > 0) { + folderPath = filePath.substring(0, filePath.lastIndexOf("/")); + } else { + folderPath = "/"; + } + assertIsFolder(folderPath); + + final MemoryFile file = new MemoryFile(); + entries.put(filePath, file); + return new FilterOutputStream(new ByteArrayOutputStream()) { + public void close() throws IOException { + out.close(); + file.setData(((ByteArrayOutputStream) out).toByteArray()); + } + }; + } + + public RandomAccessOutputStream getRandomAccessOutputStream(String filePath) + throws UnsupportedOperationException { + throw new UnsupportedOperationException( + "Random access is not implemented for " + + this.getClass().getSimpleName()); + } + + public boolean hasChildren(String path) throws FileSystemException { + assertIsFolder(path); + return list(path).length > 0; + } + + public void init() { + createFolderInternal("/"); + } + + public boolean isFile(String path) throws FileSystemException { + assertExistence(path); + return !getEntry(path).isFolder(); + } + + private MemoryFileSystemEntry getEntry(String path) { + return ((MemoryFileSystemEntry) entries.get(path)); + } + + private void assertExistence(String path) throws FileSystemException { + if (!exists(path)) + throw new FileSystemException("no such file " + path); + } + + public boolean isFolder(String path) throws FileSystemException { + if (path.equals("/")) { + return true; + } else { + assertExistence(path); + return getEntry(path).isFolder(); + } + } + + public long lastModified(String path) throws FileSystemException { + assertExistence(path); + return getEntry(path).getLastModified(); + } + + public long length(String filePath) throws FileSystemException { + assertIsFile(filePath); + return getFile(filePath).getData().length; + } + + public String[] list(String folderPath) { + if (folderPath.equals("/")) { + folderPath = ""; + } + Set allNames = entries.keySet(); + Set selectedNames = new HashSet(); + for (Iterator iter = allNames.iterator(); iter.hasNext();) { + String name = (String) iter.next(); + if (name.matches(folderPath + "/[^/]*") && !name.equals("/")) { + selectedNames.add(name); + } + } + return (String[]) selectedNames.toArray(new String[0]); + } + + public String[] listFiles(String folderPath) { + return listInternal(folderPath, false); + } + + public String[] listFolders(String folderPath) { + return listInternal(folderPath, true); + } + + private String[] listInternal(String folderPath, boolean isFolder) { + String[] entryPaths = list(folderPath); + Set resultEntryPaths = new HashSet(); + for (int i = 0; i < entryPaths.length; i++) { + String entryPath = entryPaths[i]; + MemoryFileSystemEntry entry = getEntry(entryPath); + if (entry.isFolder() == isFolder) { + resultEntryPaths.add(entryPath); + } + } + return (String[]) resultEntryPaths.toArray(new String[0]); + } + + public void move(String srcPath, String destPath) { + Object src = entries.remove(srcPath); + entries.put(destPath, src); + } + + public void touch(String filePath) throws FileSystemException { + assertIsFile(filePath); + getEntry(filePath).touch(); + } + +} Index: src/main/java/org/apache/jackrabbit/core/fs/mem/MemoryFileSystemEntry.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/fs/mem/MemoryFileSystemEntry.java +++ src/main/java/org/apache/jackrabbit/core/fs/mem/MemoryFileSystemEntry.java @@ -0,0 +1,21 @@ +package org.apache.jackrabbit.core.fs.mem; + +public abstract class MemoryFileSystemEntry { + + private long lastModified; + + public abstract boolean isFolder(); + + public MemoryFileSystemEntry() { + lastModified = System.currentTimeMillis(); + } + + public long getLastModified() { + return lastModified; + } + + public void touch() { + this.lastModified = System.currentTimeMillis(); + } + +} Index: src/main/java/org/apache/jackrabbit/core/fs/mem/MemoryFolder.java =================================================================== --- src/main/java/org/apache/jackrabbit/core/fs/mem/MemoryFolder.java +++ src/main/java/org/apache/jackrabbit/core/fs/mem/MemoryFolder.java @@ -0,0 +1,10 @@ +package org.apache.jackrabbit.core.fs.mem; + + +public class MemoryFolder extends MemoryFileSystemEntry { + + public boolean isFolder() { + return true; + } + +} Index: src/test/java/org/apache/jackrabbit/core/fs/mem/MemoryFileSystemTest.java =================================================================== --- src/test/java/org/apache/jackrabbit/core/fs/mem/MemoryFileSystemTest.java +++ src/test/java/org/apache/jackrabbit/core/fs/mem/MemoryFileSystemTest.java @@ -0,0 +1,160 @@ +package org.apache.jackrabbit.core.fs.mem; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Arrays; + +import junit.framework.TestCase; + +import org.apache.jackrabbit.core.fs.FileSystem; +import org.apache.jackrabbit.core.fs.FileSystemException; + +public class MemoryFileSystemTest extends TestCase { + + private FileSystem fs; + private byte[] sampleBytes; + + protected void setUp() throws Exception { + super.setUp(); + sampleBytes = new byte[]{(byte)0x12, (byte)0x0F, (byte)0xF0}; + fs = new MemoryFileSystem(); + fs.init(); + } + + public void testIsFolder() throws Exception { + assertTrue(fs.isFolder("/")); + } + + public void testCreateFile() throws Exception { + fs.createFolder("/folder"); + createFile("/folder/file", sampleBytes); + assertTrue(fs.isFile("/folder/file")); + } + + public void testCreateFileInNonExistentFolder() throws IOException { + try { + createFile("/folder/file", sampleBytes); + fail(FileSystemException.class.getSimpleName() + " expected"); + } catch (FileSystemException e) { + // ok + } + } + + public void testGetInputStream() throws Exception { + createFile("/test", sampleBytes); + InputStream inputStream = fs.getInputStream("/test"); + verifyStreamInput(inputStream, sampleBytes); + } + + private void verifyStreamInput(InputStream inputStream, byte[] expectedBytes) throws IOException { + byte[] resultBytes = new byte[3]; + inputStream.read(resultBytes); + inputStream.close(); + + assertEquals(expectedBytes[0], resultBytes[0]); + assertEquals(expectedBytes[1], resultBytes[1]); + assertEquals(expectedBytes[2], resultBytes[2]); + } + + public void testCopy() throws Exception { + createFile("/test", sampleBytes); + fs.copy("/test", "/test2"); + assertTrue(fs.exists("/test2")); + verifyStreamInput(fs.getInputStream("/test2"), sampleBytes); + } + + private void createFile(String fileName, byte[] bytes) throws IOException, FileSystemException { + OutputStream outputStream = fs.getOutputStream(fileName); + outputStream.write(bytes); + outputStream.close(); + } + + public void testDeleteFile() throws Exception { + createFile("/test", sampleBytes); + assertTrue(fs.exists("/test")); + fs.deleteFile("/test"); + assertFalse(fs.exists("/test")); + } + + public void testLength() throws Exception { + createFile("/test", sampleBytes); + assertEquals(3, fs.length("/test")); + } + + public void testMove() throws Exception { + createFile("/test", sampleBytes); + fs.move("/test", "/test2"); + assertFalse(fs.exists("/test")); + assertTrue(fs.exists("/test2")); + verifyStreamInput(fs.getInputStream("/test2"), sampleBytes); + } + + public void testLastModified() throws Exception { + createFile("/test", sampleBytes); + long millis1 = fs.lastModified("/test"); + // ensure time gap + Thread.sleep(100); + createFile("/test", sampleBytes); + long millis2 = fs.lastModified("/test"); + assertTrue(millis1 < millis2); + } + + public void testTouch() throws Exception { + createFile("/test", sampleBytes); + long millis1 = fs.lastModified("/test"); + // ensure time gap + Thread.sleep(100); + fs.touch("/test"); + long millis2 = fs.lastModified("/test"); + assertTrue(millis1 < millis2); + } + + public void testCreateAndDeleteFolder() throws Exception { + fs.createFolder("/folder"); + assertTrue(fs.isFolder("/folder")); + fs.deleteFolder("/folder"); + assertFalse(fs.exists("/folder")); + } + + public void testDeleteNonEmptyFolder() throws Exception { + fs.createFolder("/folder/subfolder"); + try { + fs.deleteFolder("/folder"); + fail(FileSystemException.class.getSimpleName() + " expected"); + } catch (FileSystemException e) { + // ok + } + } + + public void testCreateSubFolderWithInNonExistentFolder() throws Exception { + fs.createFolder("/folder/subfolder"); + assertTrue(fs.isFolder("/folder")); + assertTrue(fs.isFolder("/folder/subfolder")); + } + + public void testList() throws Exception { + fs.createFolder("/folder/subfolder"); + fs.getOutputStream("/folder/file").close(); + fs.getOutputStream("/file").close(); + + String[] entries = fs.list("/"); + assertEquals(2, entries.length); + Arrays.sort(entries); + assertEquals(entries[0], "/file"); + assertEquals(entries[1], "/folder"); + + entries = fs.list("/folder"); + assertEquals(2, entries.length); + Arrays.sort(entries); + assertEquals(entries[0], "/folder/file"); + assertEquals(entries[1], "/folder/subfolder"); + + entries = fs.listFiles("/folder"); + assertEquals(1, entries.length); + assertEquals(entries[0], "/folder/file"); + + + } + +}