From e3fa461159f0301a951955f5b70d343838285854 Mon Sep 17 00:00:00 2001
From: felmer <franz-josef.elmer@id.ethz.ch>
Date: Wed, 6 Feb 2019 12:03:13 +0100
Subject: [PATCH] SSDM-7857: bug in DataSetDeliverer fixed: didn't created
 x:contentCopy tags. Provide about.xml, capabilitylist.xml

---
 .../datasource/AbstractEntityDeliverer.java   |   5 +-
 .../sync/datasource/DataSetDeliverer.java     |   2 +
 .../datasource/DataSourceRequestHandler.java  | 202 +++++++++++-------
 .../sync/datasource/DataSourceUtils.java      |  60 +++++-
 .../plugins/sync/datasource/Deliverers.java   |  48 +++++
 .../plugins/sync/datasource/IDeliverer.java   |  35 +++
 .../sync/datasource/MasterDataDeliverer.java  |   2 +-
 7 files changed, 267 insertions(+), 87 deletions(-)
 create mode 100644 datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/datasource/Deliverers.java
 create mode 100644 datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/datasource/IDeliverer.java

diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/datasource/AbstractEntityDeliverer.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/datasource/AbstractEntityDeliverer.java
index 75e9c14e8c1..29c1ae70193 100644
--- a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/datasource/AbstractEntityDeliverer.java
+++ b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/datasource/AbstractEntityDeliverer.java
@@ -48,7 +48,7 @@ import ch.systemsx.cisd.openbis.generic.server.batch.IBatchOperation;
 /**
  * @author Franz-Josef Elmer
  */
-abstract class AbstractEntityDeliverer<T>
+abstract class AbstractEntityDeliverer<T> implements IDeliverer
 {
     private static final int CHUNK_SIZE = 1000;
 
@@ -70,7 +70,8 @@ abstract class AbstractEntityDeliverer<T>
         operationLog = LogFactory.getLogger(LogCategory.OPERATION, getClass());
     }
 
-    void deliverEntities(XMLStreamWriter writer, String sessionToken, Set<String> spaces, Date requestTimestamp) throws XMLStreamException
+    @Override
+    public void deliverEntities(XMLStreamWriter writer, String sessionToken, Set<String> spaces, Date requestTimestamp) throws XMLStreamException
     {
         List<T> allEntities = getAllEntities(sessionToken);
         executeInBatches(allEntities, entities -> deliverEntities(writer, sessionToken, spaces, entities));
diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/datasource/DataSetDeliverer.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/datasource/DataSetDeliverer.java
index 53892dee278..4b93d9118f6 100644
--- a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/datasource/DataSetDeliverer.java
+++ b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/datasource/DataSetDeliverer.java
@@ -113,12 +113,14 @@ public class DataSetDeliverer extends AbstractEntityDeliverer<DataSet>
             List<ContentCopy> contentCopies = linkedData.getContentCopies();
             for (ContentCopy contentCopy : contentCopies)
             {
+                writer.writeStartElement("x:contentCopy");
                 addAttribute(writer, "externalCode", contentCopy.getExternalCode());
                 addAttribute(writer, "externalDMS", contentCopy.getExternalDms(), edms -> edms.getCode());
                 addAttribute(writer, "gitCommitHash", contentCopy.getGitCommitHash());
                 addAttribute(writer, "gitRepositoryId", contentCopy.getGitRepositoryId());
                 addAttribute(writer, "id", contentCopy.getId(), id -> id.getPermId());
                 addAttribute(writer, "path", contentCopy.getPath());
+                writer.writeEndElement();
             }
             addFileNodes(writer, code, context.getContentProvider().asContent(code).getRootNode());
             writer.writeEndElement();
diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/datasource/DataSourceRequestHandler.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/datasource/DataSourceRequestHandler.java
index 03ee078bdc9..c16e21089d3 100644
--- a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/datasource/DataSourceRequestHandler.java
+++ b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/datasource/DataSourceRequestHandler.java
@@ -18,7 +18,6 @@ package ch.ethz.sis.openbis.generic.server.dss.plugins.sync.datasource;
 
 import java.io.File;
 import java.util.Arrays;
-import java.util.Collections;
 import java.util.Date;
 import java.util.Enumeration;
 import java.util.HashMap;
@@ -27,7 +26,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
-import java.util.TreeSet;
+import java.util.stream.Collectors;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -35,25 +34,14 @@ import javax.xml.stream.XMLOutputFactory;
 import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.XMLStreamWriter;
 
-import org.apache.log4j.Logger;
-
-import ch.ethz.sis.openbis.generic.asapi.v3.IApplicationServerApi;
-import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.DataSet;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.space.Space;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.space.fetchoptions.SpaceFetchOptions;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.space.search.SpaceSearchCriteria;
-import ch.ethz.sis.openbis.generic.server.dss.plugins.sync.common.ServiceFinderUtils;
 import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel;
-import ch.systemsx.cisd.common.logging.LogCategory;
-import ch.systemsx.cisd.common.logging.LogFactory;
 import ch.systemsx.cisd.common.properties.PropertyUtils;
 import ch.systemsx.cisd.openbis.dss.generic.server.oaipmh.IRequestHandler;
 import ch.systemsx.cisd.openbis.dss.generic.shared.DataSourceQueryService;
-import ch.systemsx.cisd.openbis.dss.generic.shared.IHierarchicalContentProvider;
 import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProvider;
-import ch.systemsx.cisd.openbis.generic.server.jython.api.v1.IMasterDataRegistrationTransaction;
-import ch.systemsx.cisd.openbis.generic.server.jython.api.v1.impl.EncapsulatedCommonServer;
-import ch.systemsx.cisd.openbis.generic.server.jython.api.v1.impl.MasterDataRegistrationService;
 import ch.systemsx.cisd.openbis.generic.shared.dto.SessionContextDTO;
 
 /**
@@ -61,57 +49,125 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.SessionContextDTO;
  */
 public class DataSourceRequestHandler implements IRequestHandler
 {
-    private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION, DataSourceRequestHandler.class);
+    private enum Capability
+    {
+        ABOUT("about", "description", null, false),
+        CAPABILITY_LIST("capabilitylist", ABOUT, false),
+        RESOURCE_LIST("resourcelist", CAPABILITY_LIST, true)
+        {
+            @Override
+            void writeUrls(XMLStreamWriter writer, DeliveryContext context, IDeliverer deliverer,
+                    Map<String, List<String>> parameterMap, String sessionToken, Date requestTimestamp) throws XMLStreamException
+            {
+                SpaceSearchCriteria searchCriteria = new SpaceSearchCriteria();
+                SpaceFetchOptions fetchOptions = new SpaceFetchOptions();
+                List<Space> spaces = context.getV3api().searchSpaces(sessionToken, searchCriteria, fetchOptions).getObjects();
+                List<String> spaceCodes = spaces.stream().map(Space::getCode).collect(Collectors.toList());
+                Set<String> requestedSpaces = DataSourceUtils.getRequestedAndAllowedSubSet(spaceCodes,
+                        parameterMap.get("white_list"), parameterMap.get("black_list"));
+                deliverer.deliverEntities(writer, sessionToken, requestedSpaces, requestTimestamp);
+            }
+        };
 
-    private File tempDir;
+        private String name;
 
-    private String serverUrl;
+        private Capability up;
 
-    private String downloadUrl;
+        private Capability down;
 
-    private String servletPath;
+        private String capabilityAttribute;
 
-    private DataSourceQueryService queryService;
+        private boolean withAt;
 
-    private IApplicationServerApi v3api;
+        static
+        {
+            ABOUT.down = CAPABILITY_LIST;
+            CAPABILITY_LIST.down = RESOURCE_LIST;
+        }
 
-    private IHierarchicalContentProvider contentProvider;
+        private Capability(String name, Capability up, boolean withAt)
+        {
+            this(name, name, up, withAt);
+        }
 
-    private AbstractEntityDeliverer<DataSet> dataSetDeliverer;
+        private Capability(String name, String capabilityAttribute, Capability up, boolean withAt)
+        {
+            this.name = name;
+            this.capabilityAttribute = capabilityAttribute;
+            this.up = up;
+            this.withAt = withAt;
+        }
 
-    private ExperimentDeliverer experimentDeliverer;
+        boolean matchVerb(Set<String> verbs)
+        {
+            return verbs.contains(asVerb());
+        }
 
-    private MaterialDeliverer materialDeliverer;
+        String asVerb()
+        {
+            return name + ".xml";
+        }
 
-    private SampleDeliverer sampleDeliverer;
+        void write(XMLStreamWriter writer, DeliveryContext context, IDeliverer deliverer,
+                Map<String, List<String>> parameterMap, String sessionToken, Date requestTimestamp) throws XMLStreamException
+        {
+            writer.writeStartElement("rs:ln");
+            String verb = up == null ? asVerb() : up.asVerb();
+            writer.writeAttribute("href", createDownloadUrl(context, verb));
+            writer.writeAttribute("rel", up == null ? "describedby" : "up");
+            writer.writeEndElement();
+            writer.writeStartElement("rs:md");
+            if (withAt)
+            {
+                writer.writeAttribute("at", DataSourceUtils.convertToW3CDate(requestTimestamp));
+            }
+            writer.writeAttribute("capability", capabilityAttribute);
+            writer.writeEndElement();
+            writeUrls(writer, context, deliverer, parameterMap, sessionToken, requestTimestamp);
+        }
+
+        void writeUrls(XMLStreamWriter writer, DeliveryContext context, IDeliverer deliverer,
+                Map<String, List<String>> parameterMap, String sessionToken, Date requestTimestamp) throws XMLStreamException
+        {
+            writer.writeStartElement("url");
+            writer.writeStartElement("loc");
+            writer.writeCharacters(createDownloadUrl(context, down.asVerb()));
+            writer.writeEndElement();
+            writer.writeStartElement("rs:md");
+            writer.writeAttribute("capability", down.name);
+            writer.writeEndElement();
+        }
 
-    private ProjectDeliverer projectDeliverer;
+        private String createDownloadUrl(DeliveryContext context, String verb)
+        {
+            return context.getDownloadUrl() + context.getServletPath() + "/?verb=" + verb;
+        }
 
-    private MasterDataDeliverer masterDataDeliverer;
+    }
+
+    private DataSourceQueryService queryService;
+
+    private IDeliverer deliverer;
+
+    private DeliveryContext deliveryContext;
 
     @Override
     public void init(Properties properties)
     {
-        DeliveryContext deliveryContext = new DeliveryContext();
-        servletPath = new File(PropertyUtils.getMandatoryProperty(properties, "path")).getParent();
-        deliveryContext.setServletPath(servletPath);
-        tempDir = new File(PropertyUtils.getMandatoryProperty(properties, "temp-dir"));
-        serverUrl = PropertyUtils.getMandatoryProperty(properties, "server-url");
-        deliveryContext.setServerUrl(serverUrl);
-        downloadUrl = PropertyUtils.getMandatoryProperty(properties, "download-url");
-        deliveryContext.setDownloadUrl(downloadUrl);
         queryService = new DataSourceQueryService();
-        v3api = ServiceProvider.getV3ApplicationService();
-        deliveryContext.setV3api(v3api);
-        contentProvider = ServiceProvider.getHierarchicalContentProvider();
-        deliveryContext.setContentProvider(contentProvider);
-        dataSetDeliverer = new DataSetDeliverer(deliveryContext);
-        experimentDeliverer = new ExperimentDeliverer(deliveryContext);
-        materialDeliverer = new MaterialDeliverer(deliveryContext);
-        sampleDeliverer = new SampleDeliverer(deliveryContext);
-        projectDeliverer = new ProjectDeliverer(deliveryContext);
-        String openBisServerUrl = ServiceProvider.getConfigProvider().getOpenBisServerUrl();
-        masterDataDeliverer = new MasterDataDeliverer(deliveryContext);
+        deliveryContext = new DeliveryContext();
+        deliveryContext.setServletPath(new File(PropertyUtils.getMandatoryProperty(properties, "path")).getParent());
+        deliveryContext.setServerUrl(PropertyUtils.getMandatoryProperty(properties, "server-url"));
+        deliveryContext.setDownloadUrl(PropertyUtils.getMandatoryProperty(properties, "download-url"));
+        deliveryContext.setV3api(ServiceProvider.getV3ApplicationService());
+        deliveryContext.setContentProvider(ServiceProvider.getHierarchicalContentProvider());
+        Deliverers deliverers = new Deliverers();
+        deliverers.addDeliverer(new DataSetDeliverer(deliveryContext));
+        deliverers.addDeliverer(new MaterialDeliverer(deliveryContext));
+        deliverers.addDeliverer(new SampleDeliverer(deliveryContext));
+        deliverers.addDeliverer(new ProjectDeliverer(deliveryContext));
+        deliverers.addDeliverer(new MasterDataDeliverer(deliveryContext));
+        deliverer = deliverers;
     }
 
     @Override
@@ -119,7 +175,7 @@ public class DataSourceRequestHandler implements IRequestHandler
     {
         try
         {
-            Map<String, Set<String>> parameterMap = getParameterMap(request);
+            Map<String, List<String>> parameterMap = getParameterMap(request);
             XMLOutputFactory xmlOutputFactory = XMLOutputFactory.newInstance();
             XMLStreamWriter writer = xmlOutputFactory.createXMLStreamWriter(response.getWriter());
             writer.writeStartDocument();
@@ -132,11 +188,10 @@ public class DataSourceRequestHandler implements IRequestHandler
             writer.writeAttribute("xsi:schemaLocation",
                     "https://sis.id.ethz.ch/software/#openbis/xdterms/ ./xml/xdterms.xsd https://sis.id.ethz.ch/software/#openbis/xmdterms/");
             String sessionToken = session.getSessionToken();
-            Set<String> verbs = parameterMap.get("verb");
-            if (verbs.contains("resourcelist.xml"))
-            {
-                deliverResourceList(parameterMap, sessionToken, writer);
-            }
+            Date requestTimestamp = getRequestTimestamp();
+            Set<String> verbs = new HashSet<>(parameterMap.get("verb"));
+            Capability capability = findMatchingCapability(verbs);
+            capability.write(writer, deliveryContext, deliverer, parameterMap, sessionToken, requestTimestamp);
             writer.writeEndElement();
             writer.writeEndDocument();
         } catch (Exception e)
@@ -145,41 +200,22 @@ public class DataSourceRequestHandler implements IRequestHandler
         }
     }
 
-    private void deliverResourceList(Map<String, Set<String>> parameterMap, String sessionToken, XMLStreamWriter writer) throws XMLStreamException
+    private Capability findMatchingCapability(Set<String> verbs)
     {
-
-        writer.writeStartElement("rs:ln");
-        writer.writeAttribute("href", downloadUrl + servletPath + "/?verb=capabilitylist.xml");
-        writer.writeAttribute("rel", "up");
-        writer.writeEndElement();
-        writer.writeStartElement("rs:md");
-        Date requestTimestamp = getRequestTimestamp();
-        writer.writeAttribute("at", DataSourceUtils.convertToW3CDate(requestTimestamp));
-        writer.writeAttribute("capability", "resourceList");
-        writer.writeEndElement();
-        Set<String> ignoredSpaces = parameterMap.get("black_list");
-        if (ignoredSpaces == null)
-        {
-            ignoredSpaces = Collections.emptySet();
-        }
-        Set<String> requestedSpaces = new TreeSet<>();
-        List<Space> spaces = v3api.searchSpaces(sessionToken, new SpaceSearchCriteria(), new SpaceFetchOptions()).getObjects();
-        for (Space space : spaces)
+        if (verbs != null)
         {
-            if (ignoredSpaces.contains(space.getCode()) == false)
+            for (Capability capability : Capability.values())
             {
-                requestedSpaces.add(space.getCode());
+                if (capability.matchVerb(verbs))
+                {
+                    return capability;
+                }
             }
         }
-        dataSetDeliverer.deliverEntities(writer, sessionToken, requestedSpaces, requestTimestamp);
-        experimentDeliverer.deliverEntities(writer, sessionToken, requestedSpaces, requestTimestamp);
-        masterDataDeliverer.deliverEntities(writer, sessionToken, requestedSpaces, requestTimestamp);;
-        materialDeliverer.deliverEntities(writer, sessionToken, requestedSpaces, requestTimestamp);
-        projectDeliverer.deliverEntities(writer, sessionToken, requestedSpaces, requestTimestamp);
-        sampleDeliverer.deliverEntities(writer, sessionToken, requestedSpaces, requestTimestamp);
+        return Capability.ABOUT;
     }
 
-    protected Date getRequestTimestamp()
+    private Date getRequestTimestamp()
     {
         Date requestTimestamp = new Date();
         String query = "select xact_start FROM pg_stat_activity WHERE xact_start IS NOT NULL ORDER BY xact_start ASC LIMIT 1";
@@ -190,14 +226,14 @@ public class DataSourceRequestHandler implements IRequestHandler
         return requestTimestamp;
     }
 
-    private Map<String, Set<String>> getParameterMap(HttpServletRequest request)
+    private Map<String, List<String>> getParameterMap(HttpServletRequest request)
     {
         Enumeration<String> enumeration = request.getParameterNames();
-        Map<String, Set<String>> parameterMap = new HashMap<>();
+        Map<String, List<String>> parameterMap = new HashMap<>();
         while (enumeration.hasMoreElements())
         {
             String parameter = enumeration.nextElement();
-            parameterMap.put(parameter, new HashSet<>(Arrays.asList(request.getParameterValues(parameter))));
+            parameterMap.put(parameter, Arrays.asList(request.getParameterValues(parameter)));
         }
         return parameterMap;
     }
diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/datasource/DataSourceUtils.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/datasource/DataSourceUtils.java
index 6390ce5dbbb..e41a5891930 100644
--- a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/datasource/DataSourceUtils.java
+++ b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/datasource/DataSourceUtils.java
@@ -17,13 +17,18 @@
 package ch.ethz.sis.openbis.generic.server.dss.plugins.sync.datasource;
 
 import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Date;
+import java.util.LinkedHashSet;
+import java.util.List;
 import java.util.Locale;
+import java.util.Set;
 import java.util.TimeZone;
+import java.util.regex.Pattern;
 
 /**
  * @author Franz-Josef Elmer
- *
  */
 class DataSourceUtils
 {
@@ -35,4 +40,57 @@ class DataSourceUtils
         return format.format(date) + "Z";
     }
 
+    /**
+     * Return the sub set from the full where non of the regexs from the specified black lists matches and at least
+     * one regex of the white lists matches. An empty or null whiteLists means that only the check against black lists
+     * are done.
+     */
+    static Set<String> getRequestedAndAllowedSubSet(Collection<String> fullSet, List<String> whiteLists, List<String> blackLists)
+    {
+        List<Pattern> allowedPatterns = getRegexs(whiteLists);
+        List<Pattern> disallowedPatterns = getRegexs(blackLists);
+        Set<String> subSet = new LinkedHashSet<>();
+        for (String item : fullSet)
+        {
+            if (matchesARegex(disallowedPatterns, item))
+            {
+                continue;
+            }
+            if (allowedPatterns.isEmpty() || matchesARegex(allowedPatterns, item))
+            {
+                subSet.add(item);
+            }
+        }
+        return subSet;
+
+    }
+
+    private static boolean matchesARegex(List<Pattern> patterns, String item)
+    {
+        for (Pattern pattern : patterns)
+        {
+            if (pattern.matcher(item).matches())
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static List<Pattern> getRegexs(List<String> lists)
+    {
+        List<Pattern> regexs = new ArrayList<>();
+        if (lists != null)
+        {
+            for (String commaSeparatedList : lists)
+            {
+                String[] splitted = commaSeparatedList.split(",");
+                for (String string : splitted)
+                {
+                    regexs.add(Pattern.compile(string.trim().toUpperCase()));
+                }
+            }
+        }
+        return regexs;
+    }
 }
diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/datasource/Deliverers.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/datasource/Deliverers.java
new file mode 100644
index 00000000000..e521af442f4
--- /dev/null
+++ b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/datasource/Deliverers.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2019 ETH Zuerich, SIS
+ *
+ * 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.ethz.sis.openbis.generic.server.dss.plugins.sync.datasource;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+
+/**
+ * @author Franz-Josef Elmer
+ */
+public class Deliverers implements IDeliverer
+{
+    private List<IDeliverer> deliverers = new ArrayList<>();
+
+    public void addDeliverer(IDeliverer deliverer)
+    {
+        deliverers.add(deliverer);
+    }
+
+    @Override
+    public void deliverEntities(XMLStreamWriter writer, String sessionToken, Set<String> spaces, Date requestTimestamp) throws XMLStreamException
+    {
+        for (IDeliverer deliverer : deliverers)
+        {
+            deliverer.deliverEntities(writer, sessionToken, spaces, requestTimestamp);
+        }
+    }
+
+}
diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/datasource/IDeliverer.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/datasource/IDeliverer.java
new file mode 100644
index 00000000000..0939862791a
--- /dev/null
+++ b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/datasource/IDeliverer.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2019 ETH Zuerich, SIS
+ *
+ * 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.ethz.sis.openbis.generic.server.dss.plugins.sync.datasource;
+
+import java.util.Date;
+import java.util.Set;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+
+/**
+ * @author Franz-Josef Elmer
+ *
+ * @param <T>
+ */
+interface IDeliverer
+{
+
+    void deliverEntities(XMLStreamWriter writer, String sessionToken, Set<String> spaces, Date requestTimestamp) throws XMLStreamException;
+
+}
\ No newline at end of file
diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/datasource/MasterDataDeliverer.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/datasource/MasterDataDeliverer.java
index c3ffae1048f..69a2be5513b 100644
--- a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/datasource/MasterDataDeliverer.java
+++ b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/datasource/MasterDataDeliverer.java
@@ -89,7 +89,7 @@ public class MasterDataDeliverer extends AbstractEntityDeliverer<Object>
     }
 
     @Override
-    void deliverEntities(XMLStreamWriter writer, String sessionToken, Set<String> spaces, Date requestTimestamp) throws XMLStreamException
+    public void deliverEntities(XMLStreamWriter writer, String sessionToken, Set<String> spaces, Date requestTimestamp) throws XMLStreamException
     {
         startUrlElement(writer);
         addLocation(writer, "MASTER_DATA", "MASTER_DATA");
-- 
GitLab