From b35ca1318ed56a1ac75dcb2ea2bb10f23df62f38 Mon Sep 17 00:00:00 2001
From: kaloyane <kaloyane>
Date: Tue, 17 May 2011 09:11:03 +0000
Subject: [PATCH] [LMS-2104]: change the DemoProcessing + DemoReporting plugins
 to use hierarchical content abstraction. This can be used to prove virtual
 data sets are working in processing/reporting.

SVN: 21334
---
 .../dataset-1/sample-image.png                | Bin 0 -> 400 bytes
 .../dataset-1/sample-text-file.txt            |   2 +
 .../plugins/demo/DemoProcessingPlugin.java    |  48 +++++++--
 .../plugins/demo/DemoReportingPlugin.java     | 102 +++++++++---------
 .../HierarchicalContentTraverseUtil.java      |  69 ++++++++++++
 .../IHierarchicalContentNodeVisitor.java      |  33 ++++++
 .../tasks/PluginTaskParametersTest.java       |  70 ++++++++++--
 .../shared/basic/dto/ImageTableCell.java      |  11 ++
 8 files changed, 268 insertions(+), 67 deletions(-)
 create mode 100644 datastore_server/resource/test-data/PluginTaskParametersTest/dataset-1/sample-image.png
 create mode 100644 datastore_server/resource/test-data/PluginTaskParametersTest/dataset-1/sample-text-file.txt
 create mode 100644 datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/HierarchicalContentTraverseUtil.java
 create mode 100644 datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/IHierarchicalContentNodeVisitor.java

diff --git a/datastore_server/resource/test-data/PluginTaskParametersTest/dataset-1/sample-image.png b/datastore_server/resource/test-data/PluginTaskParametersTest/dataset-1/sample-image.png
new file mode 100644
index 0000000000000000000000000000000000000000..37f668e270eb93778f13a53f52eff954c1938382
GIT binary patch
literal 400
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmSN`?>!lvI6;x#X;^)
z4C~IxyaaL-l0AZa85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YPV
z+ueoXKL{?^yL>WGgtNdSvY3H^TNs2H8D`Cq017_$ba4!^I6e1*p}upX#L<uOOT(4a
zv{%n<S;@V*KS^<4n}5LOgDFCb&nHaTkl~fTwKq)pmWg@)(j`}p?oF@yyzhDayw7%`
zsaKE9zFqX;#IAWCa&}wDWU(DO;V4-V?k-`a&6mDyiIaQyW{W*4qCtu(uGy1M*>DM0
ze{SoPT^rBz>y^}@?$7gi*Xw<4U6^cWzW0@5M(57$`MO#2mK|%{l~Z-U_)*-8+vlCN
zjTN`VO5YAJ6%?DfE+;hg*iTpP`O8_d%~bt*RgO8erMg!Z{JSQtcZc)r{(tk9YnN=@
myF;_N-Xv0x?=<_L;P+N4(Jy9w4Lk|-GJ~h9pUXO@geCz0!<Wwh

literal 0
HcmV?d00001

diff --git a/datastore_server/resource/test-data/PluginTaskParametersTest/dataset-1/sample-text-file.txt b/datastore_server/resource/test-data/PluginTaskParametersTest/dataset-1/sample-text-file.txt
new file mode 100644
index 00000000000..822498f04cc
--- /dev/null
+++ b/datastore_server/resource/test-data/PluginTaskParametersTest/dataset-1/sample-text-file.txt
@@ -0,0 +1,2 @@
+Sample test file
+used for test purposeses.
\ No newline at end of file
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/demo/DemoProcessingPlugin.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/demo/DemoProcessingPlugin.java
index ef4b7d5a4c6..ddc3f42bf9b 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/demo/DemoProcessingPlugin.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/demo/DemoProcessingPlugin.java
@@ -20,9 +20,19 @@ import java.io.File;
 import java.util.List;
 import java.util.Properties;
 
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
+
+import ch.systemsx.cisd.common.io.IHierarchicalContentNode;
+import ch.systemsx.cisd.common.logging.LogCategory;
+import ch.systemsx.cisd.common.logging.LogFactory;
 import ch.systemsx.cisd.openbis.dss.generic.server.plugins.tasks.IProcessingPluginTask;
 import ch.systemsx.cisd.openbis.dss.generic.shared.DataSetProcessingContext;
+import ch.systemsx.cisd.openbis.dss.generic.shared.HierarchicalContentTraverseUtil;
+import ch.systemsx.cisd.openbis.dss.generic.shared.IHierarchicalContentNodeVisitor;
+import ch.systemsx.cisd.openbis.dss.generic.shared.IHierarchicalContentProvider;
 import ch.systemsx.cisd.openbis.dss.generic.shared.ProcessingStatus;
+import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProvider;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DatasetDescription;
 
 /**
@@ -34,6 +44,9 @@ public class DemoProcessingPlugin implements IProcessingPluginTask
 {
     private static final long serialVersionUID = 1L;
 
+    private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION,
+            DemoProcessingPlugin.class);
+
     public DemoProcessingPlugin(Properties properties, File storeRoot)
     {
     }
@@ -41,16 +54,33 @@ public class DemoProcessingPlugin implements IProcessingPluginTask
     public ProcessingStatus process(List<DatasetDescription> datasets,
             DataSetProcessingContext context)
     {
-        System.out.println("Processing of the following datasets has been requested: " + datasets);
-        System.out.println("sleeping for 2 sec");
-        try
-        {
-            Thread.sleep(2000);
-        } catch (InterruptedException ex)
-        {
-            ex.printStackTrace();
+        operationLog.info("Processing of the following datasets has been requested: " + datasets);
+        IHierarchicalContentProvider contentProvider =
+                ServiceProvider.getHierarchicalContentProvider();
+
+        for (DatasetDescription dataset : datasets) {
+            String dataSetCode = dataset.getDataSetCode();
+            IHierarchicalContentNodeVisitor printingVisitor = createPrintingVisitor(dataSetCode);
+            HierarchicalContentTraverseUtil.traverse(contentProvider, dataSetCode, printingVisitor);
         }
-        System.out.println("Processing done.");
+        operationLog.info("Processing done.");
         return null;
     }
+
+    private IHierarchicalContentNodeVisitor createPrintingVisitor(final String datasetCode)
+    {
+        return new IHierarchicalContentNodeVisitor()
+            {
+                public void visit(IHierarchicalContentNode node)
+                {
+                    String relativePath = node.getRelativePath();
+                    String fullPath = datasetCode + "/";
+                    if (false == StringUtils.isBlank(relativePath))
+                    {
+                        fullPath += relativePath;
+                    }
+                    operationLog.info("Processing " + node.getRelativePath());
+                }
+            };
+    }
 }
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/demo/DemoReportingPlugin.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/demo/DemoReportingPlugin.java
index 8484019c0d0..490069f8d5d 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/demo/DemoReportingPlugin.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/demo/DemoReportingPlugin.java
@@ -22,11 +22,13 @@ import java.util.Date;
 import java.util.List;
 import java.util.Properties;
 
-import org.apache.commons.io.FileUtils;
-
-import ch.systemsx.cisd.common.filesystem.FileUtilities;
+import ch.systemsx.cisd.common.io.IHierarchicalContentNode;
 import ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.AbstractTableModelReportingPlugin;
 import ch.systemsx.cisd.openbis.dss.generic.shared.DataSetProcessingContext;
+import ch.systemsx.cisd.openbis.dss.generic.shared.HierarchicalContentTraverseUtil;
+import ch.systemsx.cisd.openbis.dss.generic.shared.IHierarchicalContentNodeVisitor;
+import ch.systemsx.cisd.openbis.dss.generic.shared.IHierarchicalContentProvider;
+import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProvider;
 import ch.systemsx.cisd.openbis.dss.generic.shared.utils.ImageUtil;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DateTableCell;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DoubleTableCell;
@@ -61,77 +63,73 @@ public class DemoReportingPlugin extends AbstractTableModelReportingPlugin
         builder.addHeader("Size");
         for (DatasetDescription dataset : datasets)
         {
-            File file = getDataSubDir(context.getDirectoryProvider(), dataset);
-            if (file.isDirectory())
-            {
-                describe(builder, dataset, file);
-            } else
-            {
-                describeUnknown(builder, dataset, file);
-            }
+            describe(builder, dataset);
         }
         return builder.getTableModel();
     }
 
-    private static void describe(SimpleTableModelBuilder builder, DatasetDescription dataset,
-            File file)
+    private void describe(SimpleTableModelBuilder builder, DatasetDescription dataset)
     {
-        if (file.isFile())
-        {
-            describeFile(builder, dataset, file);
-        } else
-        {
-            File[] datasetFiles = FileUtilities.listFiles(file);
-            for (File datasetFile : datasetFiles)
-            {
-                describe(builder, dataset, datasetFile);
-            }
-        }
+        IHierarchicalContentNodeVisitor visitor =
+                createFileDescribingVisitor(builder, dataset);
+        IHierarchicalContentProvider provider = ServiceProvider.getHierarchicalContentProvider();
+        HierarchicalContentTraverseUtil.traverse(provider, dataset.getDataSetCode(), visitor);
     }
 
-    private void describeUnknown(SimpleTableModelBuilder builder, DatasetDescription dataset,
-            File file)
+    private IHierarchicalContentNodeVisitor createFileDescribingVisitor(
+            final SimpleTableModelBuilder builder, final DatasetDescription dataset)
     {
-        String datasetCode = dataset.getDataSetCode();
-        ISerializableComparable image = createImageCell(dataset, file);
-        List<ISerializableComparable> row =
-                Arrays.<ISerializableComparable> asList(new StringTableCell(datasetCode), image,
-                        new StringTableCell(file.getName()),
-                        new DateTableCell(new Date(file.lastModified())), new DoubleTableCell(0));
-        builder.addRow(row);
+        return new IHierarchicalContentNodeVisitor()
+            {
+
+                public void visit(IHierarchicalContentNode node)
+                {
+                    if (false == node.isDirectory())
+                    {
+                        describeFileNode(builder, dataset, node);
+                    }
+                }
+            };
     }
 
-    private static ISerializableComparable createImageCell(DatasetDescription dataset, File file)
+    private void describeFileNode(SimpleTableModelBuilder builder, DatasetDescription dataset,
+            IHierarchicalContentNode fileNode)
     {
-        if (ImageUtil.isImageFile(file))
+        ISerializableComparable image = createPathOrImageCell(dataset, fileNode);
+        long lastModified = 0;
+        try
+        {
+            lastModified = fileNode.getFile().lastModified();
+        } catch (UnsupportedOperationException uoe)
         {
-            String code = dataset.getDataSetCode();
-            String location = dataset.getDataSetLocation();
-            return new ImageTableCell(code, location, file.getPath(), 100, 60);
+            // ignore exceptions
         }
-        return new StringTableCell(file.getName());
-    }
-
-    private static void describeFile(SimpleTableModelBuilder builder, DatasetDescription dataset,
-            File file)
-    {
-        ISerializableComparable image = createImageCell(dataset, file);
         List<ISerializableComparable> row =
                 Arrays.<ISerializableComparable> asList(
                         new StringTableCell(dataset.getDataSetCode()), image, new StringTableCell(
-                                file.getName()), new DateTableCell(new Date(file.lastModified())),
-                        new DoubleTableCell(getSize(file)));
+                                fileNode.getName()), new DateTableCell(new Date(lastModified)),
+                        new DoubleTableCell(fileNode.getFileLength()));
         builder.addRow(row);
     }
 
-    private static long getSize(File file)
+    private ISerializableComparable createPathOrImageCell(DatasetDescription dataset,
+            IHierarchicalContentNode fileNode)
     {
-        if (file.isFile())
+        File fileOnDisk = null;
+        try
         {
-            return file.length();
-        } else
+            fileOnDisk = fileNode.getFile();
+        } catch (UnsupportedOperationException uoe)
         {
-            return FileUtils.sizeOfDirectory(file);
+            // do not break
         }
+
+        if (fileOnDisk != null && ImageUtil.isImageFile(fileOnDisk))
+        {
+            return new ImageTableCell(dataset.getDataSetCode(), fileNode.getRelativePath(), 100,
+                    60);
+        }
+        return new StringTableCell(fileNode.getName());
     }
+
 }
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/HierarchicalContentTraverseUtil.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/HierarchicalContentTraverseUtil.java
new file mode 100644
index 00000000000..c50a3bfc6e6
--- /dev/null
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/HierarchicalContentTraverseUtil.java
@@ -0,0 +1,69 @@
+/*
+ * 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 ch.systemsx.cisd.common.io.IHierarchicalContent;
+import ch.systemsx.cisd.common.io.IHierarchicalContentNode;
+
+/**
+ * A utility class to abstract traversing of {@link IHierarchicalContentNode}-s.
+ * 
+ * @author Kaloyan Enimanev
+ */
+public class HierarchicalContentTraverseUtil
+{
+
+    /**
+     * Traverses all {@link IHierarchicalContentNode}-s within a data set specified by a data set
+     * code.
+     * 
+     * @param provider a provider class used to construct {@link IHierarchicalContent}.
+     * @param dataSetCode the code of the data set to be traversed
+     * @param visitor a visitor that will be invoked for every traversed
+     *            {@link IHierarchicalContentNode}.
+     */
+    public static void traverse(IHierarchicalContentProvider provider, String dataSetCode,
+            IHierarchicalContentNodeVisitor visitor)
+    {
+        IHierarchicalContent content = null;
+        try
+        {
+            content = provider.asContent(dataSetCode);
+            visit(content.getRootNode(), visitor);
+        } finally
+        {
+            if (content != null)
+            {
+                content.close();
+            }
+        }
+
+    }
+
+    private static void visit(IHierarchicalContentNode node, IHierarchicalContentNodeVisitor visitor)
+    {
+        visitor.visit(node);
+        if (node.isDirectory())
+        {
+            for (IHierarchicalContentNode child : node.getChildNodes())
+            {
+                visit(child, visitor);
+            }
+        }
+    }
+
+}
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/IHierarchicalContentNodeVisitor.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/IHierarchicalContentNodeVisitor.java
new file mode 100644
index 00000000000..5f030954f08
--- /dev/null
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/IHierarchicalContentNodeVisitor.java
@@ -0,0 +1,33 @@
+/*
+ * 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 ch.systemsx.cisd.common.io.IHierarchicalContentNode;
+
+/**
+ * A visitor for {@link IHierarchicalContentNode}-s.
+ * 
+ * @author Kaloyan Enimanev
+ */
+public interface IHierarchicalContentNodeVisitor
+{
+    /**
+     * Visits a node.
+     */
+    void visit(IHierarchicalContentNode node);
+
+}
diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/tasks/PluginTaskParametersTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/tasks/PluginTaskParametersTest.java
index 9a79b0aa939..cedbef02952 100644
--- a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/tasks/PluginTaskParametersTest.java
+++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/tasks/PluginTaskParametersTest.java
@@ -26,16 +26,26 @@ import java.util.List;
 import java.util.Properties;
 
 import org.apache.commons.io.IOUtils;
+import org.jmock.Expectations;
+import org.jmock.Mockery;
+import org.springframework.beans.factory.BeanFactory;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 import ch.rinn.restrictions.Friend;
 import ch.systemsx.cisd.base.tests.AbstractFileSystemTestCase;
 import ch.systemsx.cisd.common.exceptions.ConfigurationFailureException;
+import ch.systemsx.cisd.common.io.DefaultFileBasedHierarchicalContentFactory;
+import ch.systemsx.cisd.common.io.IHierarchicalContent;
+import ch.systemsx.cisd.common.utilities.IDelegatedAction;
 import ch.systemsx.cisd.openbis.dss.generic.server.plugins.demo.DemoProcessingPlugin;
 import ch.systemsx.cisd.openbis.dss.generic.server.plugins.demo.DemoReportingPlugin;
-import ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.MockDataSetDirectoryProvider;
 import ch.systemsx.cisd.openbis.dss.generic.shared.DataSetProcessingContext;
+import ch.systemsx.cisd.openbis.dss.generic.shared.IHierarchicalContentProvider;
+import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProviderTestWrapper;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DatastoreServiceDescription;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IDatasetLocation;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DatasetDescription;
 
 /**
@@ -47,8 +57,55 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.DatasetDescription;
     { PluginTaskProviders.class, AbstractPluginTaskFactory.class })
 public class PluginTaskParametersTest extends AbstractFileSystemTestCase
 {
-    private static final String SHARE_ID = "42";
-    private static final File STORE_ROOT = new File(".");
+    private static final File STORE_ROOT = new File("./resource/test-data/"
+            + PluginTaskParametersTest.class.getSimpleName());
+
+    private Mockery context;
+
+    private IHierarchicalContentProvider contentProvider;
+
+    @BeforeMethod
+    public void beforeMethod()
+    {
+        context = new Mockery();
+        contentProvider = new IHierarchicalContentProvider()
+            {
+
+                public IHierarchicalContent asContent(String dataSetCode)
+                {
+                    File dataSetFolder = new File(STORE_ROOT, dataSetCode);
+                    return new DefaultFileBasedHierarchicalContentFactory().asHierarchicalContent(
+                            dataSetFolder, IDelegatedAction.DO_NOTHING);
+                }
+
+                public IHierarchicalContent asContent(File datasetDirectory)
+                {
+                    return null;
+                }
+
+                public IHierarchicalContent asContent(IDatasetLocation datasetLocation)
+                {
+                    return null;
+                }
+            };
+        final BeanFactory beanFactory = context.mock(BeanFactory.class);
+        ServiceProviderTestWrapper.setApplicationContext(beanFactory);
+
+        context.checking(new Expectations()
+            {
+                {
+                    allowing(beanFactory).getBean("hierarchical-content-provider");
+                    will(returnValue(contentProvider));
+                }
+            });
+
+    }
+
+    @AfterMethod
+    public void afterTest()
+    {
+        ServiceProviderTestWrapper.restoreApplicationContext();
+    }
 
     @Test
     public void testCreateReportingPluginsFactories() throws Exception
@@ -71,7 +128,7 @@ public class PluginTaskParametersTest extends AbstractFileSystemTestCase
         factories.logConfigurations();
         IReportingPluginTask pluginInstance1 = factories.getPluginInstance(plugin1);
         pluginInstance1.createReport(createDatasetDescriptions(), new DataSetProcessingContext(
-                new MockDataSetDirectoryProvider(STORE_ROOT, SHARE_ID), null, null, null));
+                null, null, null, null));
 
         List<DatastoreServiceDescription> descriptions = factories.getPluginDescriptions();
         assertEquals(2, descriptions.size());
@@ -145,8 +202,9 @@ public class PluginTaskParametersTest extends AbstractFileSystemTestCase
     private static List<DatasetDescription> createDatasetDescriptions()
     {
         DatasetDescription description = new DatasetDescription();
-        description.setDatasetCode(".");
-        description.setDataSetLocation("3123123123-123");
+        final String dataSetCode = "dataset-1";
+        description.setDatasetCode(dataSetCode);
+        description.setDataSetLocation(dataSetCode);
         description.setSampleCode("sampleCode");
         description.setSpaceCode("groupCode");
         description.setProjectCode("projCode");
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/ImageTableCell.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/ImageTableCell.java
index 1c8bc5ea0e7..187fa068246 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/ImageTableCell.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/ImageTableCell.java
@@ -49,6 +49,17 @@ public class ImageTableCell implements ISerializableComparable
         this(getPath(dataSetCode, dataSetLocation, originalPath), maxThumbnailWidth, maxThumbnailHeight);
     }
     
+    /**
+     * @param relativePathFromDataSetRoot the relative path to this image file starting from the
+     *            data set root.
+     */
+    public ImageTableCell(String dataSetCode, String relativePathFromDataSetRoot,
+            int maxThumbnailWidth,
+            int maxThumbnailHeight)
+    {
+        this(dataSetCode + relativePathFromDataSetRoot, maxThumbnailWidth, maxThumbnailHeight);
+    }
+
     public ImageTableCell(String path, int maxThumbnailWidth, int maxThumbnailHeight)
     {
         this.path = path;
-- 
GitLab