diff --git a/bds/source/java/ch/systemsx/cisd/bds/Utilities.java b/bds/source/java/ch/systemsx/cisd/bds/Utilities.java index c519323e154a2af456d1bfd0d821ea8c35a31abf..948a0623a3929ddbdc73a4f9f354b0c470e6007b 100644 --- a/bds/source/java/ch/systemsx/cisd/bds/Utilities.java +++ b/bds/source/java/ch/systemsx/cisd/bds/Utilities.java @@ -16,14 +16,17 @@ package ch.systemsx.cisd.bds; +import java.io.File; + import ch.systemsx.cisd.bds.storage.IDirectory; import ch.systemsx.cisd.bds.storage.IFile; import ch.systemsx.cisd.bds.storage.INode; +import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException; import ch.systemsx.cisd.common.exceptions.UserFailureException; /** * Storage utility methods. - * + * * @author Franz-Josef Elmer */ public class Utilities @@ -31,7 +34,7 @@ public class Utilities /** * Returns a subdirectory from the specified directory. If it does not exist it will be created. * - * @throws UserFailureException if there is already a node named <code>name</code> but which isn't a directory. + * @throws UserFailureException if there is already a node named <code>name</code> but which isn't a directory. */ public static IDirectory getOrCreateSubDirectory(IDirectory directory, String name) { @@ -46,7 +49,7 @@ public class Utilities } throw new UserFailureException("There is already a node named '" + name + "' but which isn't a directory."); } - + /** * Returns a subdirectory from the specified directory. * @@ -67,7 +70,7 @@ public class Utilities } return (IDirectory) node; } - + /** * Convenient short cut for <code>{@link #getString(IDirectory, String)}.trim()</code>. */ @@ -81,7 +84,7 @@ public class Utilities * * @param directory Directory of the requested file. * @param name Name of the file. - * @throws UserFailureException if the requested file does not exist. + * @throws UserFailureException if the requested file does not exist. */ public static String getString(IDirectory directory, String name) { @@ -97,9 +100,29 @@ public class Utilities IFile file = (IFile) node; return file.getStringContent(); } - + + /** + * Lists files of given <var>directory</var>. + * <p> + * Throws an <code>EnvironmentFailureException</code> if {@link File#listFiles()} returns <code>null</code>. + * </p> + * + * @param directory must be a directory. + */ + public final static File[] listFiles(final File directory) throws EnvironmentFailureException + { + assert directory.isDirectory(); + final File[] fileList = directory.listFiles(); + if (fileList == null) + { + throw EnvironmentFailureException.fromTemplate("Was not able to list files of directory '%s'", directory + .getAbsolutePath()); + } + return fileList; + } + private Utilities() { } - + } diff --git a/bds/source/java/ch/systemsx/cisd/bds/storage/INode.java b/bds/source/java/ch/systemsx/cisd/bds/storage/INode.java index c87af614b2079bd3a8ab6e6539dc352dc25be261..191eece28b395640097459fb7a0306f63df8890a 100644 --- a/bds/source/java/ch/systemsx/cisd/bds/storage/INode.java +++ b/bds/source/java/ch/systemsx/cisd/bds/storage/INode.java @@ -23,7 +23,7 @@ import ch.systemsx.cisd.common.exceptions.UserFailureException; /** * Abstraction of a node in a hierarchical data structure. - * + * * @author Franz-Josef Elmer */ public interface INode @@ -32,18 +32,27 @@ public interface INode * Returns the name of this node. */ public String getName(); - + /** * Returns the parent directory of this node or <code>null</code> if it is the root node. */ public IDirectory tryToGetParent(); - + + /** + * Copies this node to the specified directory of the file system. All descendants are also copied. + * + * @throws UserFailureException if this or a descended node is a link referring to a node which is not this node or + * a descended node. + * @throws EnvironmentFailureException if extraction causes an IOException. + */ + public void copyTo(File directory) throws UserFailureException, EnvironmentFailureException; + /** - * Extracts this node to the specified directory of the file system. All descendants are also extracted. + * Moves this node to the specified directory of the file system. All descendants are also moved. * - * @throws UserFailureException if this or a descended node is a link referring to a node which is not this - * node or a descended node. + * @throws UserFailureException if this or a descended node is a link referring to a node which is not this node or + * a descended node. * @throws EnvironmentFailureException if extraction causes an IOException. */ - public void extractTo(File directory) throws UserFailureException, EnvironmentFailureException; + public void moveTo(File directory) throws UserFailureException, EnvironmentFailureException; } diff --git a/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/AbstractNode.java b/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/AbstractNode.java index 7da7143c2e58728d539a7e50476b76fe830f45ce..29076c20f2875ff06192ed87d5624029db11a1a6 100644 --- a/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/AbstractNode.java +++ b/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/AbstractNode.java @@ -23,13 +23,11 @@ import ch.systemsx.cisd.bds.storage.INode; import ch.systemsx.cisd.common.exceptions.UserFailureException; /** - * - * * @author Franz-Josef Elmer */ abstract class AbstractNode implements INode { - protected final File nodeFile; + protected File nodeFile; AbstractNode(File file) { @@ -43,7 +41,7 @@ abstract class AbstractNode implements INode } this.nodeFile = file; } - + public String getName() { return nodeFile.getName(); @@ -60,7 +58,4 @@ abstract class AbstractNode implements INode { return nodeFile.getAbsolutePath(); } - - - } diff --git a/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/Directory.java b/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/Directory.java index 5580cd1e78cb1085f9f35b4b5e885452cc51f86e..2614c054ffa491520e1b39a987d88416d003034b 100644 --- a/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/Directory.java +++ b/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/Directory.java @@ -16,8 +16,12 @@ package ch.systemsx.cisd.bds.storage.filesystem; +import java.io.IOException; import java.util.Iterator; +import org.apache.commons.io.FileUtils; + +import ch.systemsx.cisd.bds.Utilities; import ch.systemsx.cisd.bds.storage.IDirectory; import ch.systemsx.cisd.bds.storage.IFile; import ch.systemsx.cisd.bds.storage.ILink; @@ -42,7 +46,7 @@ class Directory extends AbstractNode implements IDirectory public INode tryToGetNode(String name) { - java.io.File[] files = nodeFile.listFiles(); + final java.io.File[] files = Utilities.listFiles(nodeFile); for (java.io.File file : files) { if (file.getName().equals(name)) @@ -83,7 +87,7 @@ class Directory extends AbstractNode implements IDirectory public INode addFile(java.io.File file) throws UserFailureException, EnvironmentFailureException { INode node = NodeFactory.createNode(file); - node.extractTo(nodeFile); + node.moveTo(nodeFile); return node; } @@ -97,10 +101,14 @@ class Directory extends AbstractNode implements IDirectory { return new Iterator<INode>() { - private java.io.File[] files = nodeFile.listFiles(); + private java.io.File[] files = Utilities.listFiles(nodeFile); private int index; + // + // Iterator + // + public void remove() { throw new UnsupportedOperationException(); @@ -118,18 +126,43 @@ class Directory extends AbstractNode implements IDirectory }; } - public void extractTo(java.io.File directory) throws UserFailureException, EnvironmentFailureException + public final void copyTo(final java.io.File directory) throws EnvironmentFailureException { - java.io.File destination = new java.io.File(directory, getName()); - if (destination.mkdirs() == false) + assert directory != null; + try { - throw new EnvironmentFailureException("Couldn't create directory for some unknown reason: " - + destination.getAbsolutePath()); + FileUtils.copyDirectoryToDirectory(nodeFile, directory); + } catch (IOException ex) + { + throw EnvironmentFailureException.fromTemplate(ex, "Couldn't copy directory '%s' to directory '%s'.", + nodeFile.getAbsolutePath(), directory.getAbsolutePath()); } + } + + public final void moveTo(java.io.File directory) throws EnvironmentFailureException + { + assert directory != null; + directory.mkdirs(); + final java.io.File destination = new java.io.File(directory, getName()); + if (destination.exists() == false) + { + // Note that 'renameTo' does not change 'nodeFile' path + final boolean successful = nodeFile.renameTo(destination); + if (successful == false) + { + throw EnvironmentFailureException.fromTemplate("Couldn't not move directory '%s' to directory '%s'.", + nodeFile.getAbsolutePath(), directory.getAbsolutePath()); + } + assert nodeFile.exists() == false; + } + if (nodeFile.equals(destination) == false) + { + nodeFile = destination; + } + // Update children for (INode node : this) { - node.extractTo(destination); + node.moveTo(destination); } } - } diff --git a/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/File.java b/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/File.java index 1b3487f3003c745bb88fc3fce39470c31e289c6c..df72cfd9a3adacfd7b13e8f50965cc6119b9d694 100644 --- a/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/File.java +++ b/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/File.java @@ -17,19 +17,16 @@ package ch.systemsx.cisd.bds.storage.filesystem; import java.io.FileInputStream; -import java.io.FileOutputStream; import java.io.IOException; +import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import ch.systemsx.cisd.bds.storage.IFile; import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException; -import ch.systemsx.cisd.common.exceptions.UserFailureException; import ch.systemsx.cisd.common.utilities.FileUtilities; /** - * - * * @author Franz-Josef Elmer */ class File extends AbstractNode implements IFile @@ -39,7 +36,7 @@ class File extends AbstractNode implements IFile super(file); assert file.isFile() : "Not a file " + file.getAbsolutePath(); } - + public byte[] getBinaryContent() { FileInputStream inputStream = null; @@ -61,26 +58,35 @@ class File extends AbstractNode implements IFile return FileUtilities.loadToString(nodeFile); } - public void extractTo(java.io.File directory) throws UserFailureException, EnvironmentFailureException + public final void copyTo(final java.io.File directory) throws EnvironmentFailureException { - FileInputStream inputStream = null; - FileOutputStream outputStream = null; try { - inputStream = new FileInputStream(nodeFile); - directory.mkdirs(); - outputStream = new FileOutputStream(new java.io.File(directory, getName())); - IOUtils.copy(inputStream, outputStream); + FileUtils.copyFileToDirectory(nodeFile, directory); } catch (IOException ex) { - throw new EnvironmentFailureException("Couldn't extract file '" + this + "' to directory " - + directory.getAbsolutePath(), ex); - } finally - { - IOUtils.closeQuietly(inputStream); - IOUtils.closeQuietly(outputStream); + throw EnvironmentFailureException.fromTemplate(ex, "Couldn't not copy file '%s' to directory '%s'.", + nodeFile.getAbsolutePath(), directory.getAbsolutePath()); } - } + public final void moveTo(java.io.File directory) throws EnvironmentFailureException + { + assert directory != null; + final java.io.File destination = new java.io.File(directory, getName()); + if (destination.exists() == false) + { + // Note that 'renameTo' does not change 'nodeFile' path + final boolean successful = nodeFile.renameTo(destination); + if (successful == false) + { + throw EnvironmentFailureException.fromTemplate("Couldn't not move file '%s' to directory '%s'.", + nodeFile.getAbsolutePath(), directory.getAbsolutePath()); + } + } + if (nodeFile.equals(destination) == false) + { + nodeFile = destination; + } + } } diff --git a/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/Link.java b/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/Link.java index 87deccea4553589f18214cb01c1d7be46ad92ff1..142224cef7d453efb2a17aa2294ce1bae33ec8db 100644 --- a/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/Link.java +++ b/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/Link.java @@ -25,15 +25,15 @@ import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException; import ch.systemsx.cisd.common.exceptions.UserFailureException; /** - * - * * @author Franz-Josef Elmer */ class Link implements ILink { private final String name; + private IDirectory parent; + private final INode reference; Link(String name, INode reference) @@ -51,7 +51,7 @@ class Link implements ILink { parent = parentOrNull; } - + public IDirectory tryToGetParent() { return parent; @@ -62,9 +62,15 @@ class Link implements ILink return reference; } - public void extractTo(File directory) throws UserFailureException, EnvironmentFailureException + public void copyTo(File directory) throws UserFailureException, EnvironmentFailureException { // TODO Auto-generated method stub } + public void moveTo(File directory) throws UserFailureException, EnvironmentFailureException + { + // TODO Auto-generated method stub + + } + } diff --git a/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/NodeFactory.java b/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/NodeFactory.java index 82169ce3f18ee21545778ba8e7eb004f0d4ed65c..9359038b506db64759bd0b0fa0cedc8721f9c2f2 100644 --- a/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/NodeFactory.java +++ b/bds/source/java/ch/systemsx/cisd/bds/storage/filesystem/NodeFactory.java @@ -22,13 +22,11 @@ import ch.systemsx.cisd.bds.storage.INode; import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException; /** - * - * * @author Franz-Josef Elmer */ class NodeFactory { - static INode createNode(java.io.File file) + static INode createNode(java.io.File file) throws EnvironmentFailureException { assert file != null : "Unspecified node"; String absolutePath = file.getAbsolutePath(); @@ -49,7 +47,7 @@ class NodeFactory throw new EnvironmentFailureException("Couldn't get canonical path of file " + absolutePath); } } - + private NodeFactory() { } diff --git a/bds/sourceTest/java/ch/systemsx/cisd/bds/storage/filesystem/DirectoryTest.java b/bds/sourceTest/java/ch/systemsx/cisd/bds/storage/filesystem/DirectoryTest.java index 2d87700aa09052b386510d79b705d20a4846c7a2..3391d1b9e06bb2116ee6e0f1ff75dabf634ace77 100644 --- a/bds/sourceTest/java/ch/systemsx/cisd/bds/storage/filesystem/DirectoryTest.java +++ b/bds/sourceTest/java/ch/systemsx/cisd/bds/storage/filesystem/DirectoryTest.java @@ -33,8 +33,6 @@ import ch.systemsx.cisd.common.exceptions.UserFailureException; import ch.systemsx.cisd.common.utilities.FileUtilities; /** - * - * * @author Franz-Josef Elmer */ public class DirectoryTest extends StorageTestCase @@ -45,32 +43,32 @@ public class DirectoryTest extends StorageTestCase Directory directory = new Directory(TEST_DIR); assertEquals(TEST_DIR.getName(), directory.getName()); } - + @Test public void testMakeDirectory() { Directory directory = new Directory(TEST_DIR); IDirectory subdirectory = directory.makeDirectory("sub-directory"); - + assertEquals("sub-directory", subdirectory.getName()); File subdir = new File(TEST_DIR, "sub-directory"); assertEquals(true, subdir.exists()); assertEquals(true, subdir.isDirectory()); } - + @Test public void testMakeDirectoryTwice() { Directory directory = new Directory(TEST_DIR); directory.makeDirectory("sub-directory"); IDirectory subdirectory = directory.makeDirectory("sub-directory"); - + assertEquals("sub-directory", subdirectory.getName()); File subdir = new File(TEST_DIR, "sub-directory"); assertEquals(true, subdir.exists()); assertEquals(true, subdir.isDirectory()); } - + @Test public void testMakeDirectoryButThereIsAlreadyAFileWithSameName() { @@ -85,7 +83,7 @@ public class DirectoryTest extends StorageTestCase assertTrue(e.getMessage().indexOf("sub-directory") >= 0); } } - + @Test public void testAddKeyValuePair() { @@ -93,9 +91,32 @@ public class DirectoryTest extends StorageTestCase assertEquals("42\n", FileUtilities.loadToString(new File(TEST_DIR, "answer"))); assertEquals("42\n", stringFile.getStringContent()); } - + + @Test + public void testCopyTo() + { + File dir = new File(TEST_DIR, "dir"); + dir.mkdirs(); + Directory directory = new Directory(dir); + directory.addKeyValuePair("p1", "property 1"); + IDirectory subdir = directory.makeDirectory("subdir"); + subdir.addKeyValuePair("p2", "property 2"); + File destination = new File(TEST_DIR, "destination"); + assertFalse(destination.exists()); + directory.copyTo(destination); + assertTrue(destination.exists()); + File copiedDir = new File(destination, "dir"); + assertTrue(copiedDir.exists()); + assertEquals("property 1\n", FileUtilities.loadToString(new File(copiedDir, "p1"))); + File copiedSubDir = new File(copiedDir, "subdir"); + assertTrue(copiedSubDir.isDirectory()); + assertEquals("property 2\n", FileUtilities.loadToString(new File(copiedSubDir, "p2"))); + // Source directory still exists + assertEquals(true, new File(TEST_DIR, "dir").exists()); + } + @Test - public void testExtractTo() + public void testMoveTo() { File dir = new File(TEST_DIR, "dir"); dir.mkdirs(); @@ -105,9 +126,7 @@ public class DirectoryTest extends StorageTestCase subdir.addKeyValuePair("p2", "property 2"); File destination = new File(TEST_DIR, "destination"); assertFalse(destination.exists()); - - directory.extractTo(destination); - + directory.moveTo(destination); assertTrue(destination.exists()); File copiedDir = new File(destination, "dir"); assertTrue(copiedDir.exists()); @@ -115,8 +134,10 @@ public class DirectoryTest extends StorageTestCase File copiedSubDir = new File(copiedDir, "subdir"); assertTrue(copiedSubDir.isDirectory()); assertEquals("property 2\n", FileUtilities.loadToString(new File(copiedSubDir, "p2"))); + // Source directory does no longer exist + assertEquals(false, new File(TEST_DIR, "dir").exists()); } - + @Test public void testAddFile() { @@ -129,9 +150,9 @@ public class DirectoryTest extends StorageTestCase File dest = new File(TEST_DIR, "destination"); dest.mkdir(); Directory directory = new Directory(dest); - + INode copiedDir = directory.addFile(dir); - + assertEquals("dir", copiedDir.getName()); assertTrue(copiedDir instanceof IDirectory); File copiedRealDir = new File(dest, "dir"); diff --git a/bds/sourceTest/java/ch/systemsx/cisd/bds/storage/filesystem/FileTest.java b/bds/sourceTest/java/ch/systemsx/cisd/bds/storage/filesystem/FileTest.java index 29346c1a6180a935c02cb1bc497d70505f795096..43773505c9f59e1630a8b790b836a371b9b55023 100644 --- a/bds/sourceTest/java/ch/systemsx/cisd/bds/storage/filesystem/FileTest.java +++ b/bds/sourceTest/java/ch/systemsx/cisd/bds/storage/filesystem/FileTest.java @@ -23,8 +23,6 @@ import org.testng.annotations.Test; import ch.systemsx.cisd.common.utilities.FileUtilities; /** - * - * * @author Franz-Josef Elmer */ public class FileTest extends StorageTestCase @@ -40,7 +38,7 @@ public class FileTest extends StorageTestCase assertEquals("Hello\nworld!\n", stringFile.getStringContent()); assertEquals("Hello\nworld!\n", new String(stringFile.getBinaryContent())); } - + @Test public void testExtractTo() { @@ -49,7 +47,8 @@ public class FileTest extends StorageTestCase File stringFile = new File(file); java.io.File subdir = new java.io.File(TEST_DIR, "subdir"); - stringFile.extractTo(subdir); + stringFile.copyTo(subdir); assertEquals("Hello\nworld!\n", FileUtilities.loadToString(new java.io.File(subdir, stringFile.getName()))); } + } diff --git a/bds/sourceTest/java/ch/systemsx/cisd/bds/storage/filesystem/StorageTestCase.java b/bds/sourceTest/java/ch/systemsx/cisd/bds/storage/filesystem/StorageTestCase.java index 0e2b052ebd1fefbef18bd3433632df288facb2cb..647b3c55b9fb01b72c62a4b099330b09a23d8f9e 100644 --- a/bds/sourceTest/java/ch/systemsx/cisd/bds/storage/filesystem/StorageTestCase.java +++ b/bds/sourceTest/java/ch/systemsx/cisd/bds/storage/filesystem/StorageTestCase.java @@ -23,19 +23,17 @@ import org.apache.commons.io.FileUtils; import org.testng.annotations.BeforeMethod; /** - * - * * @author Franz-Josef Elmer */ public class StorageTestCase { static final File TEST_DIR = new File("targets" + File.separator + "unit-test-wd"); - + @BeforeMethod public void setup() throws IOException { TEST_DIR.mkdirs(); FileUtils.cleanDirectory(TEST_DIR); } - + }