From 7c62f42574a39e99cff056e78f3949481db73ef2 Mon Sep 17 00:00:00 2001
From: buczekp <buczekp>
Date: Tue, 19 Apr 2011 18:08:08 +0000
Subject: [PATCH] [LMS-2172] fixed dependencies and implemented
 IHierarchicalContent with fine grained DB operations

SVN: 20990
---
 .../DatabaseBasedDataSetPathInfoProvider.java | 118 ++++++--
 .../shared/IDataSetPathInfoProvider.java      |  14 +-
 .../ISingleDataSetPathInfoProvider.java       |  37 +++
 ...InfoDBAwareHierarchicalContentFactory.java |  22 +-
 ...hInfoProviderBasedHierarchicalContent.java | 274 ++++++++++++++++++
 .../utils/PathInfoDataSourceProvider.java     |  15 +-
 .../systemtests/PathInfoDatabaseTest.java     |   2 +-
 ...abaseBasedDataSetPathInfoProviderTest.java |  35 +--
 8 files changed, 466 insertions(+), 51 deletions(-)
 create mode 100644 datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/ISingleDataSetPathInfoProvider.java
 create mode 100644 datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/content/PathInfoProviderBasedHierarchicalContent.java

diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DatabaseBasedDataSetPathInfoProvider.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DatabaseBasedDataSetPathInfoProvider.java
index 83566c7b7a8..fbca74650c3 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DatabaseBasedDataSetPathInfoProvider.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DatabaseBasedDataSetPathInfoProvider.java
@@ -28,6 +28,7 @@ import net.lemnik.eodsql.Select;
 
 import ch.rinn.restrictions.Private;
 import ch.systemsx.cisd.openbis.dss.generic.shared.IDataSetPathInfoProvider;
+import ch.systemsx.cisd.openbis.dss.generic.shared.ISingleDataSetPathInfoProvider;
 import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetPathInfo;
 import ch.systemsx.cisd.openbis.dss.generic.shared.utils.PathInfoDataSourceProvider;
 
@@ -56,21 +57,36 @@ public class DatabaseBasedDataSetPathInfoProvider implements IDataSetPathInfoPro
     @Private
     static interface IPathInfoDAO extends BaseQuery
     {
-        @Select("select id from data_sets where code = ?{1}")
+        static String SELECT_DATA_SET_FILES =
+                "SELECT id, parent_id, relative_path, file_name, size_in_bytes, is_directory FROM data_set_files ";
+
+        @Select("SELECT id FROM data_sets WHERE code = ?{1}")
         public Long tryToGetDataSetId(String dataSetCode);
 
-        @Select("select id, parent_id, relative_path, file_name, size_in_bytes, is_directory from data_set_files where dase_id = ?{1}")
+        @Select(SELECT_DATA_SET_FILES + "WHERE dase_id = ?{1}")
         public List<DataSetFileRecord> listDataSetFiles(long dataSetId);
-        
-        @Select("select id, parent_id, relative_path, file_name, size_in_bytes, is_directory from data_set_files where dase_id = ?{1} and relative_path ~ ?{2}")
-        public List<DataSetFileRecord> listDataSetFilesByRegularExpression(long dataSetId, String regex);
+
+        @Select(SELECT_DATA_SET_FILES + "WHERE dase_id = ?{1} AND parent_id is null")
+        public DataSetFileRecord getDataSetRootFile(long dataSetId);
+
+        @Select(SELECT_DATA_SET_FILES + "WHERE dase_id = ?{1} AND relative_path = ?{2}")
+        public DataSetFileRecord tryToGetRelativeDataSetFile(long dataSetId, String relativePath);
+
+        @Select(SELECT_DATA_SET_FILES + "WHERE dase_id = ?{1} AND relative_path ~ ?{2}")
+        public List<DataSetFileRecord> listDataSetFilesByRelativePathRegex(long dataSetId,
+                String relativePathRegex);
+
+        @Select(SELECT_DATA_SET_FILES
+                + "WHERE dase_id = ?{1} AND relative_path like '?{2}' AND file_name ~ ?{3}")
+        public List<DataSetFileRecord> listDataSetFilesByFilenameRegex(long dataSetId,
+                String startingPath, String filenameRegex);
     }
 
     private static interface ILoader
     {
         List<DataSetFileRecord> listDataSetFiles(long dataSetId);
     }
-    
+
     private IPathInfoDAO dao;
 
     public DatabaseBasedDataSetPathInfoProvider()
@@ -90,13 +106,13 @@ public class DatabaseBasedDataSetPathInfoProvider implements IDataSetPathInfoPro
             {
                 public List<DataSetFileRecord> listDataSetFiles(long dataSetId)
                 {
-                    return getDao().listDataSetFilesByRegularExpression(dataSetId,
+                    return getDao().listDataSetFilesByRelativePathRegex(dataSetId,
                             "^" + regularExpression + "$");
                 }
             }).getInfos();
     }
 
-    public DataSetPathInfo tryGetDataSetRootPathInfo(String dataSetCode)
+    public DataSetPathInfo tryGetFullDataSetRootPathInfo(String dataSetCode)
     {
         return new Loader(dataSetCode, new ILoader()
             {
@@ -106,10 +122,79 @@ public class DatabaseBasedDataSetPathInfoProvider implements IDataSetPathInfoPro
                 }
             }).getRoot();
     }
-    
+
+    public ISingleDataSetPathInfoProvider tryGetSingleDataSetPathInfoProvider(String dataSetCode)
+    {
+        final Long dataSetId = getDao().tryToGetDataSetId(dataSetCode);
+        if (dataSetId != null)
+        {
+            return new ISingleDataSetPathInfoProvider()
+                {
+                    public DataSetPathInfo getRootPathInfo()
+                    {
+                        DataSetFileRecord record = getDao().getDataSetRootFile(dataSetId);
+                        return asPathInfo(record);
+                    }
+
+                    public DataSetPathInfo tryGetPathInfoByRelativePath(String relativePath)
+                    {
+                        DataSetFileRecord record =
+                                getDao().tryToGetRelativeDataSetFile(dataSetId, relativePath);
+                        if (record != null)
+                        {
+                            return asPathInfo(record);
+                        } else
+                        {
+                            return null;
+                        }
+                    }
+
+                    public List<DataSetPathInfo> listMatchingPathInfos(String relativePathPattern)
+                    {
+                        List<DataSetFileRecord> records =
+                                getDao().listDataSetFilesByRelativePathRegex(dataSetId,
+                                        prepareDBStyleRegex(relativePathPattern));
+                        return asPathInfos(records);
+                    }
+
+                    public List<DataSetPathInfo> listMatchingPathInfos(String startingPath,
+                            String fileNamePattern)
+                    {
+                        List<DataSetFileRecord> records =
+                                getDao().listDataSetFilesByFilenameRegex(dataSetId, startingPath,
+                                        prepareDBStyleRegex(fileNamePattern));
+                        return asPathInfos(records);
+                    }
+
+                    private DataSetPathInfo asPathInfo(DataSetFileRecord record)
+                    {
+                        DataSetPathInfo result = new DataSetPathInfo();
+                        result.setFileName(record.file_name);
+                        result.setRelativePath(record.relative_path);
+                        result.setDirectory(record.is_directory);
+                        result.setSizeInBytes(record.size_in_bytes);
+                        return result;
+                    }
+
+                    private List<DataSetPathInfo> asPathInfos(List<DataSetFileRecord> records)
+                    {
+                        List<DataSetPathInfo> results = new ArrayList<DataSetPathInfo>();
+                        for (DataSetFileRecord record : records)
+                        {
+                            results.add(asPathInfo(record));
+                        }
+                        return results;
+                    }
+
+                };
+        }
+        return null;
+    }
+
     private final class Loader
     {
         private Map<Long, DataSetPathInfo> idToInfoMap = new HashMap<Long, DataSetPathInfo>();
+
         private DataSetPathInfo root;
 
         Loader(String dataSetCode, ILoader loader)
@@ -169,7 +254,7 @@ public class DatabaseBasedDataSetPathInfoProvider implements IDataSetPathInfoPro
         {
             return root;
         }
-        
+
         List<DataSetPathInfo> getInfos()
         {
             return new ArrayList<DataSetPathInfo>(idToInfoMap.values());
@@ -187,15 +272,10 @@ public class DatabaseBasedDataSetPathInfoProvider implements IDataSetPathInfoPro
         return dao;
     }
 
-    public static boolean isDataSourceDefined()
+    // java style patterns match the whole text, db style patterns match any fragment
+    private static String prepareDBStyleRegex(String pattern)
     {
-        try
-        {
-            PathInfoDataSourceProvider.getDataSource();
-            return true;
-        } catch (IllegalArgumentException ex)
-        {
-            return false;
-        }
+        return "^" + pattern + "$";
     }
+
 }
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/IDataSetPathInfoProvider.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/IDataSetPathInfoProvider.java
index 4f5e1024992..b132a332f9f 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/IDataSetPathInfoProvider.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/IDataSetPathInfoProvider.java
@@ -16,20 +16,22 @@
 
 package ch.systemsx.cisd.openbis.dss.generic.shared;
 
-
 import java.util.List;
 
 import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetPathInfo;
 
-
 /**
  * Provides informations about paths in data sets.
- *
+ * 
  * @author Franz-Josef Elmer
  */
 public interface IDataSetPathInfoProvider
 {
-    public List<DataSetPathInfo> listPathInfosByRegularExpression(String dataSetCode, String regularExpression);
-    
-    public DataSetPathInfo tryGetDataSetRootPathInfo(String dataSetCode);
+    public List<DataSetPathInfo> listPathInfosByRegularExpression(String dataSetCode,
+            String regularExpression);
+
+    public DataSetPathInfo tryGetFullDataSetRootPathInfo(String dataSetCode);
+
+    public ISingleDataSetPathInfoProvider tryGetSingleDataSetPathInfoProvider(String dataSetCode);
+
 }
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
new file mode 100644
index 00000000000..6053b9ba3f5
--- /dev/null
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/ISingleDataSetPathInfoProvider.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2011 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.dss.generic.shared;
+
+import java.util.List;
+
+import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetPathInfo;
+
+/**
+ * Provides information about paths of single data set.
+ * 
+ * @author Piotr Buczek
+ */
+public interface ISingleDataSetPathInfoProvider
+{
+    DataSetPathInfo getRootPathInfo();
+
+    DataSetPathInfo tryGetPathInfoByRelativePath(String relativePath);
+
+    List<DataSetPathInfo> listMatchingPathInfos(String relativePathPattern);
+
+    List<DataSetPathInfo> listMatchingPathInfos(String startingPath, String fileNamePattern);
+}
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/content/PathInfoDBAwareHierarchicalContentFactory.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/content/PathInfoDBAwareHierarchicalContentFactory.java
index 9cc0d78b7fc..bcafe1f0aa9 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/content/PathInfoDBAwareHierarchicalContentFactory.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/content/PathInfoDBAwareHierarchicalContentFactory.java
@@ -11,9 +11,10 @@ import ch.systemsx.cisd.common.io.IHierarchicalContentFactory;
 import ch.systemsx.cisd.common.logging.LogCategory;
 import ch.systemsx.cisd.common.logging.LogFactory;
 import ch.systemsx.cisd.common.utilities.IDelegatedAction;
-import ch.systemsx.cisd.openbis.dss.generic.server.DatabaseBasedDataSetPathInfoProvider;
 import ch.systemsx.cisd.openbis.dss.generic.shared.IDataSetPathInfoProvider;
-import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetPathInfo;
+import ch.systemsx.cisd.openbis.dss.generic.shared.ISingleDataSetPathInfoProvider;
+import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProvider;
+import ch.systemsx.cisd.openbis.dss.generic.shared.utils.PathInfoDataSourceProvider;
 
 /**
  * The implementation of {@link IHierarchicalContentFactory} that aware of Path Info DB.
@@ -27,13 +28,18 @@ public class PathInfoDBAwareHierarchicalContentFactory extends
     private final static Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION,
             PathInfoDBAwareHierarchicalContentFactory.class);
 
+    /**
+     * Returns implementation of {@link IHierarchicalContentFactory} based on configuration of Path
+     * Info DB. If the DB is not configured than file system based implementation will be used.
+     * Otherwise the implementation will use the DB to retrieve file metadata.
+     */
     public static IHierarchicalContentFactory create()
     {
-        if (DatabaseBasedDataSetPathInfoProvider.isDataSourceDefined())
+        if (PathInfoDataSourceProvider.isDataSourceDefined())
         {
             operationLog.info("Path Info DB is properly configured");
             return new PathInfoDBAwareHierarchicalContentFactory(
-                    new DatabaseBasedDataSetPathInfoProvider());
+                    ServiceProvider.getDataSetPathInfoProvider());
         } else
         {
             operationLog.info("Path Info DB was NOT configured. "
@@ -54,11 +60,13 @@ public class PathInfoDBAwareHierarchicalContentFactory extends
     public IHierarchicalContent asHierarchicalContent(File file, IDelegatedAction onCloseAction)
     {
         final String dataSetCode = file.getName();
-        DataSetPathInfo rootPathInfo = pathInfoProvider.tryGetDataSetRootPathInfo(dataSetCode);
-        if (rootPathInfo != null) // exists in DB
+        ISingleDataSetPathInfoProvider dataSetPathInfoProvider =
+                pathInfoProvider.tryGetSingleDataSetPathInfoProvider(dataSetCode);
+        if (dataSetPathInfoProvider != null) // data set exists in DB
         {
             operationLog.debug("Data set " + dataSetCode + " was found in Path Info DB.");
-            return new SimplePathInfoBasedHierarchicalContent(rootPathInfo, file, onCloseAction);
+            return new PathInfoProviderBasedHierarchicalContent(dataSetPathInfoProvider, file,
+                    onCloseAction);
         } else
         {
             operationLog.info("Data set " + dataSetCode + " was NOT found in Path Info DB. "
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
new file mode 100644
index 00000000000..84dd4912da0
--- /dev/null
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/content/PathInfoProviderBasedHierarchicalContent.java
@@ -0,0 +1,274 @@
+/*
+ * Copyright 2011 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.dss.generic.shared.content;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.util.ArrayList;
+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.io.AbstractHierarchicalContentNode;
+import ch.systemsx.cisd.common.io.IHierarchicalContent;
+import ch.systemsx.cisd.common.io.IHierarchicalContentNode;
+import ch.systemsx.cisd.common.shared.basic.utils.StringUtils;
+import ch.systemsx.cisd.common.utilities.IDelegatedAction;
+import ch.systemsx.cisd.openbis.dss.generic.shared.ISingleDataSetPathInfoProvider;
+import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetPathInfo;
+
+/**
+ * {@link IHierarchicalContent} implementation using {@link ISingleDataSetPathInfoProvider} to
+ * retrieve file metadata.
+ * 
+ * @author Piotr Buczek
+ */
+class PathInfoProviderBasedHierarchicalContent implements IHierarchicalContent
+{
+
+    private final File root;
+
+    private final IDelegatedAction onCloseAction;
+
+    private IHierarchicalContentNode rootNode;
+
+    private final ISingleDataSetPathInfoProvider dataSetPathInfoProvider;
+
+    PathInfoProviderBasedHierarchicalContent(
+            ISingleDataSetPathInfoProvider dataSetPathInfoProvider, File dataSetDir,
+            IDelegatedAction onCloseAction)
+    {
+        assert dataSetPathInfoProvider != null;
+        this.dataSetPathInfoProvider = dataSetPathInfoProvider;
+        if (dataSetDir.exists() == false)
+        {
+            throw new IllegalArgumentException(dataSetDir.getAbsolutePath() + " doesn't exist");
+        }
+        if (dataSetDir.isDirectory() == false)
+        {
+            throw new IllegalArgumentException(dataSetDir.getAbsolutePath() + " is not a directory");
+        }
+        this.onCloseAction = onCloseAction;
+        this.root = dataSetDir;
+    }
+
+    public IHierarchicalContentNode getRootNode()
+    {
+        if (rootNode == null)
+        {
+            DataSetPathInfo pathInfo = dataSetPathInfoProvider.getRootPathInfo();
+            rootNode = asNode(pathInfo);
+        }
+        return rootNode;
+    }
+
+    public IHierarchicalContentNode getNode(String relativePath)
+    {
+        if (StringUtils.isBlank(relativePath))
+        {
+            return getRootNode();
+        } else
+        {
+            DataSetPathInfo pathInfo = findPathInfo(relativePath);
+            return asNode(pathInfo);
+        }
+    }
+
+    private IHierarchicalContentNode asNode(DataSetPathInfo pathInfo)
+    {
+        return new PathInfoNode(root, pathInfo);
+    }
+
+    private DataSetPathInfo findPathInfo(String relativePath) throws IllegalArgumentException
+    {
+        DataSetPathInfo result = dataSetPathInfoProvider.tryGetPathInfoByRelativePath(relativePath);
+        if (result != null)
+        {
+            return result;
+        } else
+        {
+            throw new IllegalArgumentException("Resource '" + relativePath + "' does not exist.");
+        }
+    }
+
+    public List<IHierarchicalContentNode> listMatchingNodes(final String relativePathPattern)
+    {
+        List<IHierarchicalContentNode> result = new ArrayList<IHierarchicalContentNode>();
+        List<DataSetPathInfo> matchingPathInfos =
+                dataSetPathInfoProvider.listMatchingPathInfos(relativePathPattern);
+        for (DataSetPathInfo pathInfo : matchingPathInfos)
+        {
+            result.add(asNode(pathInfo));
+        }
+        return result;
+    }
+
+    public List<IHierarchicalContentNode> listMatchingNodes(final String startingPath,
+            final String fileNamePattern)
+    {
+        List<IHierarchicalContentNode> result = new ArrayList<IHierarchicalContentNode>();
+        List<DataSetPathInfo> matchingPathInfos =
+                dataSetPathInfoProvider.listMatchingPathInfos(startingPath, fileNamePattern);
+        for (DataSetPathInfo pathInfo : matchingPathInfos)
+        {
+            result.add(asNode(pathInfo));
+        }
+        return result;
+    }
+
+    public void close()
+    {
+        onCloseAction.execute();
+    }
+
+    //
+    // Object
+    //
+
+    @Override
+    public String toString()
+    {
+        return "PathInfoProviderBasedHierarchicalContent [root=" + root + "]";
+    }
+
+    @Override
+    public int hashCode()
+    {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((root == null) ? 0 : root.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (this == obj)
+        {
+            return true;
+        }
+        if (obj == null)
+        {
+            return false;
+        }
+        if (!(obj instanceof PathInfoProviderBasedHierarchicalContent))
+        {
+            return false;
+        }
+        PathInfoProviderBasedHierarchicalContent other =
+                (PathInfoProviderBasedHierarchicalContent) obj;
+        if (root == null)
+        {
+            if (other.root != null)
+            {
+                return false;
+            }
+        } else if (!root.equals(other.root))
+        {
+            return false;
+        }
+        return true;
+    }
+
+    static class PathInfoNode extends AbstractHierarchicalContentNode
+    {
+
+        private final DataSetPathInfo pathInfo;
+
+        private final File root;
+
+        PathInfoNode(File root, DataSetPathInfo pathInfo)
+        {
+            this.root = root;
+            this.pathInfo = pathInfo;
+        }
+
+        public String getName()
+        {
+            return pathInfo.getFileName();
+        }
+
+        public boolean exists()
+        {
+            return true;
+        }
+
+        public boolean isDirectory()
+        {
+            return pathInfo.isDirectory();
+        }
+
+        @Override
+        protected String doGetRelativePath()
+        {
+            return pathInfo.getRelativePath();
+        }
+
+        @Override
+        protected List<IHierarchicalContentNode> doGetChildNodes()
+        {
+            List<IHierarchicalContentNode> result = new ArrayList<IHierarchicalContentNode>();
+            for (DataSetPathInfo child : pathInfo.getChildren())
+            {
+                result.add(new PathInfoNode(root, child));
+            }
+            return result;
+        }
+
+        @Override
+        protected long doGetFileLength()
+        {
+            return pathInfo.getSizeInBytes();
+        }
+
+        // TODO 2011-04-19, Piotr Buczek: use abstraction to get file content
+
+        public File getFile() throws UnsupportedOperationException
+        {
+            if (StringUtils.isBlank(getRelativePath()))
+            {
+                return root;
+            } else
+            {
+                return new File(root, getRelativePath());
+            }
+        }
+
+        @Override
+        protected IRandomAccessFile doGetFileContent()
+        {
+            return new RandomAccessFileImpl(getFile(), "r");
+        }
+
+        @Override
+        protected InputStream doGetInputStream()
+        {
+            try
+            {
+                return new FileInputStream(getFile());
+            } catch (FileNotFoundException ex)
+            {
+                throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+            }
+        }
+
+    }
+
+}
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/PathInfoDataSourceProvider.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/PathInfoDataSourceProvider.java
index 5ba1b1efecb..8cf7327a085 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/PathInfoDataSourceProvider.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/utils/PathInfoDataSourceProvider.java
@@ -22,7 +22,7 @@ import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProvider;
 
 /**
  * Helper method for providing data source to pathinfo database.
- *
+ * 
  * @author Franz-Josef Elmer
  */
 public class PathInfoDataSourceProvider
@@ -33,4 +33,17 @@ public class PathInfoDataSourceProvider
     {
         return ServiceProvider.getDataSourceProvider().getDataSource(DATA_SOURCE_NAME);
     }
+
+    public static boolean isDataSourceDefined()
+    {
+        try
+        {
+            PathInfoDataSourceProvider.getDataSource();
+            return true;
+        } catch (IllegalArgumentException ex)
+        {
+            return false;
+        }
+    }
+
 }
diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/PathInfoDatabaseTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/PathInfoDatabaseTest.java
index ad7cf801f42..a6c3baf009e 100644
--- a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/PathInfoDatabaseTest.java
+++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/datastoreserver/systemtests/PathInfoDatabaseTest.java
@@ -101,7 +101,7 @@ public class PathInfoDatabaseTest extends SystemTestCase
         stopWatch.reset();
         stopWatch.start();
         final Pattern pattern = Pattern.compile(regex);
-        DataSetPathInfo root = ServiceProvider.getDataSetPathInfoProvider().tryGetDataSetRootPathInfo("ds-1");
+        DataSetPathInfo root = ServiceProvider.getDataSetPathInfoProvider().tryGetFullDataSetRootPathInfo("ds-1");
         System.out.println(stopWatch.getTime() + " msec for reading db");
         results.clear();
         search(results, root, pattern);
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 48135455d67..6702c7829bc 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
@@ -36,17 +36,17 @@ import ch.systemsx.cisd.openbis.dss.generic.shared.IDataSetPathInfoProvider;
 import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetPathInfo;
 
 /**
- * 
- *
  * @author Franz-Josef Elmer
  */
-@Friend(toClasses=DatabaseBasedDataSetPathInfoProvider.class)
+@Friend(toClasses = DatabaseBasedDataSetPathInfoProvider.class)
 public class DatabaseBasedDataSetPathInfoProviderTest extends AssertJUnit
 {
     private static final Long DATA_SET_ID = 41L;
-    
+
     private Mockery context;
+
     private IPathInfoDAO dao;
+
     private IDataSetPathInfoProvider pathInfoProvider;
 
     @BeforeMethod
@@ -56,7 +56,7 @@ public class DatabaseBasedDataSetPathInfoProviderTest extends AssertJUnit
         dao = context.mock(IPathInfoDAO.class);
         pathInfoProvider = new DatabaseBasedDataSetPathInfoProvider(dao);
     }
-    
+
     @AfterMethod
     public void tearDown(Method method)
     {
@@ -69,7 +69,7 @@ public class DatabaseBasedDataSetPathInfoProviderTest extends AssertJUnit
             throw new Error(method.getName() + "() : ", t);
         }
     }
-    
+
     @Test
     public void testListDataSetRootPathInfoForUnknownDataSet()
     {
@@ -81,7 +81,7 @@ public class DatabaseBasedDataSetPathInfoProviderTest extends AssertJUnit
                 }
             });
 
-        DataSetPathInfo info = pathInfoProvider.tryGetDataSetRootPathInfo("ds-1");
+        DataSetPathInfo info = pathInfoProvider.tryGetFullDataSetRootPathInfo("ds-1");
 
         assertEquals(null, info);
     }
@@ -100,11 +100,11 @@ public class DatabaseBasedDataSetPathInfoProviderTest extends AssertJUnit
                 }
             });
 
-        DataSetPathInfo info = pathInfoProvider.tryGetDataSetRootPathInfo("ds-1");
+        DataSetPathInfo info = pathInfoProvider.tryGetFullDataSetRootPathInfo("ds-1");
 
         assertEquals(null, info);
     }
-    
+
     @Test
     public void testListDataSetRootPathInfoWithTwoResults()
     {
@@ -124,9 +124,9 @@ public class DatabaseBasedDataSetPathInfoProviderTest extends AssertJUnit
                     will(returnValue(Arrays.asList(r1, r2, r3, r4, r5, r6)));
                 }
             });
-        
-        DataSetPathInfo info = pathInfoProvider.tryGetDataSetRootPathInfo("ds-1");
-        
+
+        DataSetPathInfo info = pathInfoProvider.tryGetFullDataSetRootPathInfo("ds-1");
+
         check("dir", "dir", true, 53, info);
         check("dir/text.txt", "text.txt", false, 23, info.getChildren().get(0));
         check("dir/dir", "dir", true, 30, info.getChildren().get(1));
@@ -134,9 +134,9 @@ public class DatabaseBasedDataSetPathInfoProviderTest extends AssertJUnit
         check("dir/dir/hi", "hi", false, 27, info.getChildren().get(1).getChildren().get(1));
         check("dir/dir2", "dir2", true, 0, info.getChildren().get(2));
     }
-    
+
     @Test
-    public void testListPathInfosByRegularExpression()
+    public void testPathInfosByRelativePathRegex()
     {
         final String regex = "blabla";
         final DataSetFileRecord r1 = record(1, 2L, "dir/text.txt", "text.txt", 23, false);
@@ -147,12 +147,13 @@ public class DatabaseBasedDataSetPathInfoProviderTest extends AssertJUnit
                     one(dao).tryToGetDataSetId("ds-1");
                     will(returnValue(DATA_SET_ID));
 
-                    one(dao).listDataSetFilesByRegularExpression(DATA_SET_ID, "^" + regex + "$");
+                    one(dao).listDataSetFilesByRelativePathRegex(DATA_SET_ID, "^" + regex + "$");
                     will(returnValue(Arrays.asList(r1, r2)));
                 }
             });
-        
-        List<DataSetPathInfo> list = pathInfoProvider.listPathInfosByRegularExpression("ds-1", regex);
+
+        List<DataSetPathInfo> list =
+                pathInfoProvider.listPathInfosByRegularExpression("ds-1", regex);
         Collections.sort(list, new Comparator<DataSetPathInfo>()
             {
                 public int compare(DataSetPathInfo i1, DataSetPathInfo i2)
-- 
GitLab