diff --git a/common/source/java/ch/systemsx/cisd/common/io/DefaultFileBasedHierarchicalContent.java b/common/source/java/ch/systemsx/cisd/common/io/DefaultFileBasedHierarchicalContent.java index 3b397d60d7efc514135cf497439f7d0e8ab85eee..8132da599f80da71b4820eb1326f7c5c4ea162e1 100644 --- a/common/source/java/ch/systemsx/cisd/common/io/DefaultFileBasedHierarchicalContent.java +++ b/common/source/java/ch/systemsx/cisd/common/io/DefaultFileBasedHierarchicalContent.java @@ -95,8 +95,7 @@ class DefaultFileBasedHierarchicalContent implements IHierarchicalContent if (existingFile != null && FileUtilities.isHDF5ContainerFile(existingFile)) { HDF5ContainerBasedHierarchicalContentNode containerNode = - new HDF5ContainerBasedHierarchicalContentNode(hierarchicalContentFactory, this, - existingFile); + new HDF5ContainerBasedHierarchicalContentNode(this, existingFile); String relativePath = FileUtilities.getRelativeFile(existingFile, file); return containerNode.getChildNode(relativePath); } diff --git a/common/source/java/ch/systemsx/cisd/common/io/DefaultFileBasedHierarchicalContentFactory.java b/common/source/java/ch/systemsx/cisd/common/io/DefaultFileBasedHierarchicalContentFactory.java index f418400406e0aac76e3794d31b1a489538cb1337..79d1a54fe1d6f8e681874e0e461ddab03af3efa7 100644 --- a/common/source/java/ch/systemsx/cisd/common/io/DefaultFileBasedHierarchicalContentFactory.java +++ b/common/source/java/ch/systemsx/cisd/common/io/DefaultFileBasedHierarchicalContentFactory.java @@ -39,7 +39,7 @@ public class DefaultFileBasedHierarchicalContentFactory implements IHierarchical { if (FileUtilities.isHDF5ContainerFile(file)) { - return new HDF5ContainerBasedHierarchicalContentNode(this, rootContent, file); + return new HDF5ContainerBasedHierarchicalContentNode(rootContent, file); } return new DefaultFileBasedHierarchicalContentNode(this, rootContent, file); } diff --git a/common/source/java/ch/systemsx/cisd/common/io/DefaultFileBasedHierarchicalContentNode.java b/common/source/java/ch/systemsx/cisd/common/io/DefaultFileBasedHierarchicalContentNode.java index 4cf025088bf96de8893532dc794664c973d9de3d..9618ae7bde42614f6aa5a411e4abbec76a10b81b 100644 --- a/common/source/java/ch/systemsx/cisd/common/io/DefaultFileBasedHierarchicalContentNode.java +++ b/common/source/java/ch/systemsx/cisd/common/io/DefaultFileBasedHierarchicalContentNode.java @@ -39,16 +39,20 @@ class DefaultFileBasedHierarchicalContentNode extends AbstractHierarchicalConten protected final File file; - protected final IHierarchicalContentFactory hierarchicalContentFactory; + private final IHierarchicalContentFactory hierarchicalContentFactoryOrNull; + + protected DefaultFileBasedHierarchicalContentNode(IHierarchicalContent root, File file) + { + this(null, root, file); + } protected DefaultFileBasedHierarchicalContentNode( - IHierarchicalContentFactory hierarchicalContentFactory, IHierarchicalContent root, - File file) + IHierarchicalContentFactory hierarchicalContentFactoryOrNull, + IHierarchicalContent root, File file) { - assert hierarchicalContentFactory != null; assert root != null; assert file != null; - this.hierarchicalContentFactory = hierarchicalContentFactory; + this.hierarchicalContentFactoryOrNull = hierarchicalContentFactoryOrNull; this.root = root; this.file = file; } @@ -82,13 +86,16 @@ class DefaultFileBasedHierarchicalContentNode extends AbstractHierarchicalConten @Override public List<IHierarchicalContentNode> doGetChildNodes() { + // if factory is not defined the method should be overriden + assert hierarchicalContentFactoryOrNull != null; + File[] files = file.listFiles(); List<IHierarchicalContentNode> result = new ArrayList<IHierarchicalContentNode>(); if (files != null) { for (File aFile : files) { - result.add(hierarchicalContentFactory.asHierarchicalContentNode(root, aFile)); + result.add(hierarchicalContentFactoryOrNull.asHierarchicalContentNode(root, aFile)); } } return result; diff --git a/common/source/java/ch/systemsx/cisd/common/io/HDF5ContainerBasedHierarchicalContentNode.java b/common/source/java/ch/systemsx/cisd/common/io/HDF5ContainerBasedHierarchicalContentNode.java index 4cdc0ce53551c3e496199f975751a9767936eb01..e870f861fdf76615b0d2deace7730b2ac8fa85d8 100644 --- a/common/source/java/ch/systemsx/cisd/common/io/HDF5ContainerBasedHierarchicalContentNode.java +++ b/common/source/java/ch/systemsx/cisd/common/io/HDF5ContainerBasedHierarchicalContentNode.java @@ -31,15 +31,15 @@ import ch.systemsx.cisd.hdf5.IHDF5SimpleReader; * * @author Piotr Buczek */ -class HDF5ContainerBasedHierarchicalContentNode extends DefaultFileBasedHierarchicalContentNode +public class HDF5ContainerBasedHierarchicalContentNode extends + DefaultFileBasedHierarchicalContentNode { private final Hdf5Container hdf5Container; - HDF5ContainerBasedHierarchicalContentNode( - IHierarchicalContentFactory hierarchicalContentFactory, IHierarchicalContent root, + public HDF5ContainerBasedHierarchicalContentNode(IHierarchicalContent root, File hdf5ContainerFile) { - super(hierarchicalContentFactory, root, hdf5ContainerFile); + super(root, hdf5ContainerFile); this.hdf5Container = new Hdf5Container(hdf5ContainerFile); } @@ -59,7 +59,6 @@ class HDF5ContainerBasedHierarchicalContentNode extends DefaultFileBasedHierarch @Override public List<IHierarchicalContentNode> doGetChildNodes() { - // NOTE this is a slow implementation - improve it when information can be retrieved from DB IHDF5SimpleReader reader = createReader(); try { diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/ISingleDataSetPathInfoProvider.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/ISingleDataSetPathInfoProvider.java index 71041ff246832d776ced4bcb4f61db232e807c20..469633d56106dcf07330cbf6b16f87ae89e0fb88 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/ISingleDataSetPathInfoProvider.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/ISingleDataSetPathInfoProvider.java @@ -31,6 +31,8 @@ public interface ISingleDataSetPathInfoProvider DataSetPathInfo tryGetPathInfoByRelativePath(String relativePath); + // DataSetPathInfo getParentPathInfo(DataSetPathInfo child); + List<DataSetPathInfo> listChildrenPathInfos(DataSetPathInfo parent); List<DataSetPathInfo> listMatchingPathInfos(String relativePathPattern); diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/content/PathInfoProviderBasedHierarchicalContent.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/content/PathInfoProviderBasedHierarchicalContent.java index 802b95dce2f4f0ed0963aad9c7635515624efe0f..1e7c62e86cfed361b8de5a3a39829dbf77bcbe97 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/content/PathInfoProviderBasedHierarchicalContent.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/content/PathInfoProviderBasedHierarchicalContent.java @@ -26,7 +26,9 @@ import java.util.List; import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel; import ch.systemsx.cisd.base.io.IRandomAccessFile; import ch.systemsx.cisd.base.io.RandomAccessFileImpl; +import ch.systemsx.cisd.common.filesystem.FileUtilities; import ch.systemsx.cisd.common.io.AbstractHierarchicalContentNode; +import ch.systemsx.cisd.common.io.HDF5ContainerBasedHierarchicalContentNode; import ch.systemsx.cisd.common.io.IHierarchicalContent; import ch.systemsx.cisd.common.io.IHierarchicalContentNode; import ch.systemsx.cisd.common.shared.basic.utils.StringUtils; @@ -93,7 +95,7 @@ class PathInfoProviderBasedHierarchicalContent implements IHierarchicalContent private IHierarchicalContentNode asNode(DataSetPathInfo pathInfo) { - return new PathInfoNode(pathInfo, root, dataSetPathInfoProvider); + return new PathInfoNode(pathInfo); } private DataSetPathInfo findPathInfo(String relativePath) throws IllegalArgumentException @@ -187,21 +189,15 @@ class PathInfoProviderBasedHierarchicalContent implements IHierarchicalContent return true; } - static class PathInfoNode extends AbstractHierarchicalContentNode + class PathInfoNode extends AbstractHierarchicalContentNode { - private final DataSetPathInfo pathInfo; - private final File root; - - private final ISingleDataSetPathInfoProvider dataSetPathInfoProvider; + private IFileContentProvider fileContentProviderOrNull; - PathInfoNode(DataSetPathInfo pathInfo, File root, - ISingleDataSetPathInfoProvider dataSetPathInfoProvider) + PathInfoNode(DataSetPathInfo pathInfo) { this.pathInfo = pathInfo; - this.root = root; - this.dataSetPathInfoProvider = dataSetPathInfoProvider; } public String getName() @@ -233,7 +229,7 @@ class PathInfoProviderBasedHierarchicalContent implements IHierarchicalContent List<IHierarchicalContentNode> result = new ArrayList<IHierarchicalContentNode>(); for (DataSetPathInfo child : pathInfos) { - result.add(new PathInfoNode(child, root, dataSetPathInfoProvider)); + result.add(asNode(child)); } return result; } @@ -244,37 +240,130 @@ class PathInfoProviderBasedHierarchicalContent implements IHierarchicalContent return pathInfo.getSizeInBytes(); } - // TODO 2011-04-19, Piotr Buczek: use abstraction to get file content - public File getFile() throws UnsupportedOperationException { - if (StringUtils.isBlank(getRelativePath())) + File result = doGetFile(); + if (result.exists()) { - return root; + return result; } else { - return new File(root, getRelativePath()); + throw new UnsupportedOperationException("This is not a normal file/directory node."); } } @Override protected IRandomAccessFile doGetFileContent() { - return new RandomAccessFileImpl(getFile(), "r"); + return getFileContentProvider().getReadOnlyRandomAccessFile(); } @Override protected InputStream doGetInputStream() { - try + return getFileContentProvider().getInputStream(); + } + + private IFileContentProvider getFileContentProvider() + { + if (fileContentProviderOrNull == null) + { + File file = doGetFile(); + fileContentProviderOrNull = getContent(file); + } + return fileContentProviderOrNull; + } + + /** + * Returns a file object with given node's relative path. The file doesn't have to exist on + * the file system. + */ + private File doGetFile() + { + if (StringUtils.isBlank(getRelativePath())) { - return new FileInputStream(getFile()); - } catch (FileNotFoundException ex) + return root; + } else { - throw CheckedExceptionTunnel.wrapIfNecessary(ex); + return new File(root, getRelativePath()); } } + } + + private IFileContentProvider getContent(File file) + { + if (file.exists()) + { + return asFileContentProvider(file); + } + + // The file doesn't exist in file system but it could be inside a HDF5 container. + // Go up in file hierarchy until existing file is found. + File existingFile = file; + while (existingFile != null && existingFile.exists() == false) + { + existingFile = existingFile.getParentFile(); + } + if (existingFile != null && FileUtilities.isHDF5ContainerFile(existingFile)) + { + HDF5ContainerBasedHierarchicalContentNode containerNode = + new HDF5ContainerBasedHierarchicalContentNode(this, existingFile); + String relativePath = FileUtilities.getRelativeFile(existingFile, file); + IHierarchicalContentNode node = containerNode.getChildNode(relativePath); + return asFileContentProvider(node); + } + throw new IllegalArgumentException("Resource '" + FileUtilities.getRelativeFile(root, file) + + "' does not exist."); + } + + private interface IFileContentProvider + { + public IRandomAccessFile getReadOnlyRandomAccessFile(); + + public InputStream getInputStream(); + } + + private static IFileContentProvider asFileContentProvider(final File existingFile) + { + assert existingFile.exists(); + return new IFileContentProvider() + { + + public IRandomAccessFile getReadOnlyRandomAccessFile() + { + return new RandomAccessFileImpl(existingFile, "r"); + } + + public InputStream getInputStream() + { + try + { + return new FileInputStream(existingFile); + } catch (FileNotFoundException ex) + { + throw CheckedExceptionTunnel.wrapIfNecessary(ex); + } + } + + }; + } + + private static IFileContentProvider asFileContentProvider(final IHierarchicalContentNode node) + { + return new IFileContentProvider() + { + + public IRandomAccessFile getReadOnlyRandomAccessFile() + { + return node.getFileContent(); + } + + public InputStream getInputStream() + { + return node.getInputStream(); + } + }; } } diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/dto/DataSetPathInfo.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/dto/DataSetPathInfo.java index dd4045a5838dd84093507453a9a7d6f9036ae93b..3544dc7fea2793c0bf0e3df98d8236b0d37efe52 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/dto/DataSetPathInfo.java +++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/dto/DataSetPathInfo.java @@ -78,6 +78,7 @@ public class DataSetPathInfo this.sizeInBytes = sizeInBytes; } + @Deprecated public DataSetPathInfo getParent() { return parent; diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/DatabaseBasedDataSetPathInfoProviderTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/DatabaseBasedDataSetPathInfoProviderTest.java index 3d23d3e984f3c10853d0ca78348d22ebb2a63996..82492d9e123794a5d2ea5608907e2a242ee3e912 100644 --- a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/DatabaseBasedDataSetPathInfoProviderTest.java +++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/DatabaseBasedDataSetPathInfoProviderTest.java @@ -167,6 +167,7 @@ public class DatabaseBasedDataSetPathInfoProviderTest extends AssertJUnit assertEquals(2, list.size()); } + @SuppressWarnings("deprecation") private void check(String expectedRelativePath, String expectedFileName, boolean expectingDirectory, long expectedSize, DataSetPathInfo info) { @@ -174,7 +175,6 @@ public class DatabaseBasedDataSetPathInfoProviderTest extends AssertJUnit assertEquals(expectedFileName, info.getFileName()); assertEquals(expectingDirectory, info.isDirectory()); assertEquals(expectedSize, info.getSizeInBytes()); - @SuppressWarnings("deprecation") List<DataSetPathInfo> children = info.getChildren(); for (DataSetPathInfo child : children) {