From 2ab143960ac6796f7feca68cd4626f4bcc4e289b Mon Sep 17 00:00:00 2001
From: brinn <brinn>
Date: Fri, 4 Sep 2009 18:29:17 +0000
Subject: [PATCH] change: give ExternalData access to all parents of a data set
 change: replace ExternalDataPE by ExternalData in IDataStoreService

SVN: 12481
---
 .../server/DataSetCommandExecutor.java        |  4 +-
 .../dss/generic/server/DataStoreService.java  |  4 +-
 .../server/DataStoreServiceLogger.java        |  6 +--
 .../server/IDataSetCommandExecutor.java       |  4 +-
 .../dss/generic/server/UploadingCommand.java  | 53 +++++++++----------
 .../generic/server/DataStoreServiceTest.java  |  6 +--
 .../generic/server/UploadingCommandTest.java  | 17 ++++--
 .../server/business/bo/ExternalDataTable.java |  7 ++-
 .../bo/datasetlister/DatasetLister.java       | 25 ++++++---
 .../generic/shared/IDataStoreService.java     |  6 +--
 .../shared/basic/dto/ExternalData.java        | 36 ++++++++-----
 .../translator/ExternalDataTranslator.java    | 11 ++--
 .../business/bo/ExternalDataTableTest.java    | 45 ++++++++++++----
 13 files changed, 143 insertions(+), 81 deletions(-)

diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataSetCommandExecutor.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataSetCommandExecutor.java
index 4a90ae1cc1e..20484481b65 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataSetCommandExecutor.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataSetCommandExecutor.java
@@ -28,9 +28,9 @@ import ch.systemsx.cisd.common.collections.IExtendedBlockingQueue;
 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.generic.shared.basic.dto.ExternalData;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DataSetUploadContext;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DatasetDescription;
-import ch.systemsx.cisd.openbis.generic.shared.dto.ExternalDataPE;
 
 /**
  * @author Franz-Josef Elmer
@@ -108,7 +108,7 @@ class DataSetCommandExecutor implements IDataSetCommandExecutor
     }
 
     public void scheduleUploadingDataSetsToCIFEX(ICIFEXRPCServiceFactory cifexServiceFactory,
-            MailClientParameters mailClientParameters, List<ExternalDataPE> dataSets,
+            MailClientParameters mailClientParameters, List<ExternalData> dataSets,
             DataSetUploadContext uploadContext)
     {
         scheduleCommand(new UploadingCommand(cifexServiceFactory, mailClientParameters, dataSets,
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreService.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreService.java
index b85b732d1ed..69c27cde5aa 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreService.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreService.java
@@ -33,10 +33,10 @@ import ch.systemsx.cisd.openbis.dss.generic.server.plugins.tasks.IReportingPlugi
 import ch.systemsx.cisd.openbis.dss.generic.server.plugins.tasks.PluginTaskProvider;
 import ch.systemsx.cisd.openbis.dss.generic.server.plugins.tasks.PluginTaskProviders;
 import ch.systemsx.cisd.openbis.generic.shared.IDataStoreService;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TableModel;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DataSetUploadContext;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DatasetDescription;
-import ch.systemsx.cisd.openbis.generic.shared.dto.ExternalDataPE;
 
 /**
  * Implementation of {@link IDataStoreService} which will be accessed remotely by the opneBIS
@@ -151,7 +151,7 @@ public class DataStoreService extends AbstractServiceWithLogger<IDataStoreServic
         commandExecuter.scheduleDeletionOfDataSets(dataSetLocations);
     }
 
-    public void uploadDataSetsToCIFEX(String sessionToken, List<ExternalDataPE> dataSets,
+    public void uploadDataSetsToCIFEX(String sessionToken, List<ExternalData> dataSets,
             DataSetUploadContext context) throws InvalidAuthenticationException
     {
         sessionTokenManager.assertValidSessionToken(sessionToken);
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreServiceLogger.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreServiceLogger.java
index 6d296f946de..75ad05a1d93 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreServiceLogger.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreServiceLogger.java
@@ -22,10 +22,10 @@ import org.apache.log4j.Logger;
 
 import ch.systemsx.cisd.common.exceptions.InvalidAuthenticationException;
 import ch.systemsx.cisd.openbis.generic.shared.IDataStoreService;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TableModel;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DataSetUploadContext;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DatasetDescription;
-import ch.systemsx.cisd.openbis.generic.shared.dto.ExternalDataPE;
 
 /**
  * @author Franz-Josef Elmer
@@ -91,11 +91,11 @@ class DataStoreServiceLogger implements IDataStoreService
         log("deleteDataSets", "LOCATIONS(%s)", dataSetLocations);
     }
 
-    public void uploadDataSetsToCIFEX(String sessionToken, List<ExternalDataPE> dataSets,
+    public void uploadDataSetsToCIFEX(String sessionToken, List<ExternalData> dataSets,
             DataSetUploadContext context) throws InvalidAuthenticationException
     {
         StringBuilder builder = new StringBuilder();
-        for (ExternalDataPE externalDataPE : dataSets)
+        for (ExternalData externalDataPE : dataSets)
         {
             builder.append(' ').append(externalDataPE.getCode());
         }
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/IDataSetCommandExecutor.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/IDataSetCommandExecutor.java
index 6973fd21a7f..d1df9bf0f14 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/IDataSetCommandExecutor.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/IDataSetCommandExecutor.java
@@ -19,9 +19,9 @@ package ch.systemsx.cisd.openbis.dss.generic.server;
 import java.util.List;
 
 import ch.systemsx.cisd.openbis.dss.generic.server.plugins.tasks.IProcessingPluginTask;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DataSetUploadContext;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DatasetDescription;
-import ch.systemsx.cisd.openbis.generic.shared.dto.ExternalDataPE;
 
 /**
  * Executor of commands operating on data sets in a data store. Commands are expected to be executed
@@ -49,7 +49,7 @@ interface IDataSetCommandExecutor
      *            failed.
      */
     void scheduleUploadingDataSetsToCIFEX(ICIFEXRPCServiceFactory cifexServiceFactory,
-            MailClientParameters mailClientParameters, List<ExternalDataPE> dataSets,
+            MailClientParameters mailClientParameters, List<ExternalData> dataSets,
             DataSetUploadContext uploadContext);
 
     /** Schedules the specified processing task for provided datasets */
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/UploadingCommand.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/UploadingCommand.java
index ac808681abf..6b4132e21c4 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/UploadingCommand.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/UploadingCommand.java
@@ -26,9 +26,9 @@ import java.io.OutputStream;
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Date;
 import java.util.List;
-import java.util.Set;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipOutputStream;
 
@@ -47,14 +47,13 @@ import ch.systemsx.cisd.common.mail.IMailClient;
 import ch.systemsx.cisd.common.mail.MailClient;
 import ch.systemsx.cisd.common.types.BooleanOrUnknown;
 import ch.systemsx.cisd.common.utilities.TokenGenerator;
-import ch.systemsx.cisd.openbis.generic.shared.dto.DataPE;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Group;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Person;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Project;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DataSetUploadContext;
-import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentPE;
-import ch.systemsx.cisd.openbis.generic.shared.dto.ExternalDataPE;
-import ch.systemsx.cisd.openbis.generic.shared.dto.GroupPE;
-import ch.systemsx.cisd.openbis.generic.shared.dto.PersonPE;
-import ch.systemsx.cisd.openbis.generic.shared.dto.ProjectPE;
-import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE;
 
 /**
  * A command which zips the given data sets and uploads the ZIP file to CIFEX.
@@ -150,7 +149,7 @@ class UploadingCommand implements IDataSetCommand
             addRow("sample", key, value);
         }
 
-        void sample(String key, PersonPE person)
+        void sample(String key, Person person)
         {
             addRow("sample", key, person);
         }
@@ -165,7 +164,7 @@ class UploadingCommand implements IDataSetCommand
             addRow("experiment", key, value);
         }
 
-        void experiment(String key, PersonPE person)
+        void experiment(String key, Person person)
         {
             addRow("experiment", key, person);
         }
@@ -175,7 +174,7 @@ class UploadingCommand implements IDataSetCommand
             addRow("experiment", key, date);
         }
 
-        private void addRow(String category, String key, PersonPE person)
+        private void addRow(String category, String key, Person person)
         {
             StringBuilder stringBuilder = new StringBuilder();
             if (person != null)
@@ -223,7 +222,7 @@ class UploadingCommand implements IDataSetCommand
 
     private final ICIFEXRPCServiceFactory cifexServiceFactory;
 
-    private final List<ExternalDataPE> dataSets;
+    private final List<ExternalData> dataSets;
 
     private final String fileName;
 
@@ -243,7 +242,7 @@ class UploadingCommand implements IDataSetCommand
     boolean deleteAfterUploading = true;
 
     UploadingCommand(ICIFEXRPCServiceFactory cifexServiceFactory,
-            MailClientParameters mailClientParameters, List<ExternalDataPE> dataSets,
+            MailClientParameters mailClientParameters, List<ExternalData> dataSets,
             DataSetUploadContext context)
     {
         this.cifexServiceFactory = cifexServiceFactory;
@@ -302,7 +301,7 @@ class UploadingCommand implements IDataSetCommand
         {
             outputStream = new FileOutputStream(zipFile);
             zipOutputStream = new ZipOutputStream(outputStream);
-            for (ExternalDataPE dataSet : dataSets)
+            for (ExternalData dataSet : dataSets)
             {
                 String location = dataSet.getLocation();
                 File dataSetFile = new File(store, location);
@@ -354,21 +353,21 @@ class UploadingCommand implements IDataSetCommand
         }
     }
 
-    private String createMetaData(ExternalDataPE dataSet)
+    private String createMetaData(ExternalData dataSet)
     {
         MetaDataBuilder builder = new MetaDataBuilder();
         builder.dataSet("code", dataSet.getCode());
         builder.dataSet("production_timestamp", dataSet.getProductionDate());
         builder.dataSet("producer_code", dataSet.getDataProducerCode());
         builder.dataSet("data_set_type", dataSet.getDataSetType().getCode());
-        builder.dataSet("is_measured", dataSet.isMeasured());
+        builder.dataSet("is_measured", dataSet.isDerived() == false);
         builder.dataSet("is_complete", BooleanOrUnknown.T.equals(dataSet.getComplete()));
 
         StringBuilder stringBuilder = new StringBuilder();
-        Set<DataPE> parents = dataSet.getParents();
+        Collection<ExternalData> parents = dataSet.getParents();
         if (parents.isEmpty() == false)
         {
-            for (DataPE parent : parents)
+            for (ExternalData parent : parents)
             {
                 if (stringBuilder.length() > 0)
                 {
@@ -378,18 +377,18 @@ class UploadingCommand implements IDataSetCommand
             }
         }
         builder.dataSet("parent_codes", stringBuilder.toString());
-        SamplePE sample = dataSet.getSample();
+        Sample sample = dataSet.getSample();
         if (sample != null)
         {
             builder.sample("type_code", sample.getSampleType().getCode());
             builder.sample("code", sample.getCode());
-            GroupPE group = sample.getGroup();
+            Group group = sample.getGroup();
             builder.sample("group_code", group == null ? "(shared)" : group.getCode());
             builder.sample("registration_timestamp", sample.getRegistrationDate());
             builder.sample("registrator", sample.getRegistrator());
         }
-        ExperimentPE experiment = dataSet.getExperiment();
-        ProjectPE project = experiment.getProject();
+        Experiment experiment = dataSet.getExperiment();
+        Project project = experiment.getProject();
         builder.experiment("group_code", project.getGroup().getCode());
         builder.experiment("project_code", project.getCode());
         builder.experiment("experiment_code", experiment.getCode());
@@ -399,11 +398,11 @@ class UploadingCommand implements IDataSetCommand
         return builder.toString();
     }
 
-    private String createRootPath(ExternalDataPE dataSet)
+    private String createRootPath(ExternalData dataSet)
     {
-        SamplePE sample = dataSet.getSample();
-        ExperimentPE experiment = sample == null ? dataSet.getExperiment() : sample.getExperiment();
-        ProjectPE project = experiment.getProject();
+        Sample sample = dataSet.getSample();
+        Experiment experiment = sample == null ? dataSet.getExperiment() : sample.getExperiment();
+        Project project = experiment.getProject();
         project.getGroup().getCode();
         return project.getGroup().getCode() + "/" + project.getCode() + "/" + experiment.getCode()
                 + "/" + (sample == null ? "" : sample.getCode() + "/") + dataSet.getCode();
@@ -463,7 +462,7 @@ class UploadingCommand implements IDataSetCommand
     {
         final StringBuilder b = new StringBuilder();
         b.append("Upload data sets to CIFEX: ");
-        for (ExternalDataPE dataset : dataSets)
+        for (ExternalData dataset : dataSets)
         {
             b.append(dataset.getCode());
             b.append(',');
diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreServiceTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreServiceTest.java
index 1d6fe1bb8c9..877426063f7 100644
--- a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreServiceTest.java
+++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreServiceTest.java
@@ -36,8 +36,8 @@ import ch.systemsx.cisd.common.filesystem.FileUtilities;
 import ch.systemsx.cisd.openbis.dss.generic.server.plugins.tasks.PluginTaskProviders;
 import ch.systemsx.cisd.openbis.dss.generic.shared.utils.PluginUtilTest;
 import ch.systemsx.cisd.openbis.generic.shared.IDataStoreService;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DataSetUploadContext;
-import ch.systemsx.cisd.openbis.generic.shared.dto.ExternalDataPE;
 
 /**
  * @author Franz-Josef Elmer
@@ -223,7 +223,7 @@ public class DataStoreServiceTest extends AssertJUnit
     @Test
     public void testUploadDataSetsForInvalidPassword()
     {
-        final List<ExternalDataPE> dataSets = new ArrayList<ExternalDataPE>();
+        final List<ExternalData> dataSets = new ArrayList<ExternalData>();
         final DataSetUploadContext uploadContext = new DataSetUploadContext();
         uploadContext.setCifexURL(CIFEX_URL);
         uploadContext.setUserID("user");
@@ -254,7 +254,7 @@ public class DataStoreServiceTest extends AssertJUnit
     @Test
     public void testUploadDataSets()
     {
-        final List<ExternalDataPE> dataSets = new ArrayList<ExternalDataPE>();
+        final List<ExternalData> dataSets = new ArrayList<ExternalData>();
         final DataSetUploadContext uploadContext = new DataSetUploadContext();
         uploadContext.setCifexURL(CIFEX_URL);
         uploadContext.setUserID("user");
diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/UploadingCommandTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/UploadingCommandTest.java
index ca2a223cd32..aa6fa517293 100644
--- a/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/UploadingCommandTest.java
+++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/UploadingCommandTest.java
@@ -46,15 +46,19 @@ import ch.systemsx.cisd.cifex.rpc.UploadState;
 import ch.systemsx.cisd.cifex.rpc.UploadStatus;
 import ch.systemsx.cisd.common.filesystem.FileUtilities;
 import ch.systemsx.cisd.common.logging.BufferedAppender;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DataPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DataSetTypePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DataSetUploadContext;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DataStorePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DatabaseInstancePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentTypePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ExternalDataPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.GroupPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.PersonPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ProjectPE;
+import ch.systemsx.cisd.openbis.generic.shared.translator.ExternalDataTranslator;
 
 /**
  * @author Franz-Josef Elmer
@@ -147,9 +151,11 @@ public class UploadingCommandTest extends AssertJUnit
         uploadContext.setFileName(ZIP_FILENAME);
         createTestData(LOCATION1);
         ds2 = createTestData(LOCATION2);
-        ExternalDataPE dataSet1 = createDataSet("1", LOCATION1);
-        ExternalDataPE dataSet2 = createDataSet("2", LOCATION2);
-        List<ExternalDataPE> dataSets = Arrays.<ExternalDataPE> asList(dataSet1, dataSet2);
+        ExternalData dataSet1 =
+                ExternalDataTranslator.translate(createDataSet("1", LOCATION1), "?", "?");
+        ExternalData dataSet2 =
+                ExternalDataTranslator.translate(createDataSet("2", LOCATION2), "?", "?");
+        List<ExternalData> dataSets = Arrays.<ExternalData> asList(dataSet1, dataSet2);
         command = new UploadingCommand(factory, mailClientParameters, dataSets, uploadContext);
         command.deleteAfterUploading = false;
     }
@@ -165,6 +171,7 @@ public class UploadingCommandTest extends AssertJUnit
         externalData.setDataSetType(dataSetTypePE);
         externalData.setExperiment(createExperiment());
         externalData.setParent(createParent("parent"));
+        externalData.setDataStore(new DataStorePE());
         return externalData;
     }
 
@@ -192,6 +199,10 @@ public class UploadingCommandTest extends AssertJUnit
         project.setCode("p1");
         GroupPE group = new GroupPE();
         group.setCode("g1");
+        DatabaseInstancePE instance = new DatabaseInstancePE();
+        instance.setCode("instance");
+        instance.setOriginalSource(true);
+        group.setDatabaseInstance(instance);
         project.setGroup(group);
         experiment.setProject(project);
         return experiment;
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ExternalDataTable.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ExternalDataTable.java
index 816aba87e6d..98d5ee95b23 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ExternalDataTable.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ExternalDataTable.java
@@ -38,6 +38,7 @@ import ch.systemsx.cisd.openbis.generic.shared.IDataStoreService;
 import ch.systemsx.cisd.openbis.generic.shared.basic.BasicConstant;
 import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DatastoreServiceDescription;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TableModel;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DataSetUploadContext;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DataStorePE;
@@ -51,6 +52,7 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.Session;
 import ch.systemsx.cisd.openbis.generic.shared.dto.EventPE.EntityType;
 import ch.systemsx.cisd.openbis.generic.shared.dto.properties.EntityKind;
+import ch.systemsx.cisd.openbis.generic.shared.translator.ExternalDataTranslator;
 import ch.systemsx.cisd.openbis.generic.shared.util.HibernateUtils;
 
 /**
@@ -320,8 +322,9 @@ public final class ExternalDataTable extends AbstractExternalDataBusinessObject
     {
         IDataStoreService service = dssFactory.create(dataStore.getRemoteUrl());
         String sessionToken = dataStore.getSessionToken();
-        List<ExternalDataPE> cleanDataSets =
-                HibernateTransformer.HIBERNATE_BEAN_REPLICATOR.get().copy(dataSets);
+        List<ExternalData> cleanDataSets =
+                ExternalDataTranslator.translate(HibernateTransformer.HIBERNATE_BEAN_REPLICATOR
+                        .get().copy(dataSets), "?", "?");
         service.uploadDataSetsToCIFEX(sessionToken, cleanDataSets, context);
     }
 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/DatasetLister.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/DatasetLister.java
index 99e6ae42ec2..e0320633ecf 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/DatasetLister.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/DatasetLister.java
@@ -24,7 +24,9 @@ import it.unimi.dsi.fastutil.longs.LongSet;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 import ch.rinn.restrictions.Friend;
 import ch.systemsx.cisd.common.types.BooleanOrUnknown;
@@ -222,11 +224,11 @@ public class DatasetLister implements IDatasetLister
     private void enrichWithParents(final Long2ObjectMap<ExternalData> datasetMap)
     {
         LongSet datasetIds = extractIds(datasetMap);
-        Long2ObjectMap<ExternalData> parentsMap = resolveParents(datasetIds, datasetMap);
+        Long2ObjectMap<Set<ExternalData>> parentsMap = resolveParents(datasetIds, datasetMap);
         for (ExternalData dataset : datasetMap.values())
         {
-            ExternalData parent = parentsMap.get(dataset.getId());
-            dataset.setParent(parent);
+            final Set<ExternalData> parent = parentsMap.get(dataset.getId());
+            dataset.setParents(parent);
         }
     }
 
@@ -244,20 +246,27 @@ public class DatasetLister implements IDatasetLister
      * Returns a map from a child id to its parent dataset for the specified dataset ids.<br>
      * Uses datasetCache not to resolve datasets which have already been resolved.
      */
-    private Long2ObjectMap<ExternalData> resolveParents(LongSet datasetIds,
+    private Long2ObjectMap<Set<ExternalData>> resolveParents(LongSet datasetIds,
             Long2ObjectMap<ExternalData> datasetCache)
     {
-        List<DatasetRelationRecord> datasetParents = asList(setQuery.getDatasetParents(datasetIds));
-        Long2ObjectMap<ExternalData> parentsMap =
+        final List<DatasetRelationRecord> datasetParents = asList(setQuery.getDatasetParents(datasetIds));
+        final Long2ObjectMap<ExternalData> parentsMap =
                 fetchUnknownDatasetParents(datasetParents, datasetCache);
 
-        Long2ObjectMap<ExternalData> childToParentMap = new Long2ObjectOpenHashMap<ExternalData>();
+        final Long2ObjectMap<Set<ExternalData>> childToParentMap =
+                new Long2ObjectOpenHashMap<Set<ExternalData>>();
         for (DatasetRelationRecord relation : datasetParents)
         {
             long parentId = relation.data_id_parent;
             ExternalData parentDataset = getCachedItem(parentId, parentsMap, datasetCache);
             assert parentDataset != null : "inconsistent parent dataset " + parentId;
-            childToParentMap.put(relation.data_id_child, parentDataset);
+            Set<ExternalData> parents = childToParentMap.get(relation.data_id_child);
+            if (parents == null)
+            {
+                parents = new HashSet<ExternalData>();
+                childToParentMap.put(relation.data_id_child, parents);
+            }
+            parents.add(parentDataset);
         }
         return childToParentMap;
     }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/IDataStoreService.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/IDataStoreService.java
index 9d1d090ba91..bb84d03d79e 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/IDataStoreService.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/IDataStoreService.java
@@ -19,10 +19,10 @@ package ch.systemsx.cisd.openbis.generic.shared;
 import java.util.List;
 
 import ch.systemsx.cisd.common.exceptions.InvalidAuthenticationException;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TableModel;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DataSetUploadContext;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DatasetDescription;
-import ch.systemsx.cisd.openbis.generic.shared.dto.ExternalDataPE;
 
 /**
  * Service interface of Data Store Server.
@@ -35,7 +35,7 @@ public interface IDataStoreService
     /**
      * Every time this interface and related DTO's are changed, we should increment this number.
      */
-    public static final int VERSION = 3; // for release S61
+    public static final int VERSION = 4; // for release S64
 
     /**
      * Returns the version of this service.
@@ -71,7 +71,7 @@ public interface IDataStoreService
      * @param context Context data needed for uploading.
      * @throws InvalidAuthenticationException if <code>sessionToken</code> is invalid.
      */
-    public void uploadDataSetsToCIFEX(String sessionToken, List<ExternalDataPE> dataSets,
+    public void uploadDataSetsToCIFEX(String sessionToken, List<ExternalData> dataSets,
             DataSetUploadContext context) throws InvalidAuthenticationException;
 
     /** Runs the reporting task with the specified id for provided datasets */
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/ExternalData.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/ExternalData.java
index 2acdf91c015..7b7cf0816f4 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/ExternalData.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/ExternalData.java
@@ -17,7 +17,9 @@
 package ch.systemsx.cisd.openbis.generic.shared.basic.dto;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Date;
+import java.util.Iterator;
 import java.util.List;
 
 import ch.systemsx.cisd.openbis.generic.shared.basic.IEntityInformationHolder;
@@ -54,9 +56,7 @@ public class ExternalData extends CodeWithRegistration<ExternalData> implements
 
     private String producerCode;
 
-    private ExternalData parent;
-
-    private String parentCode;
+    private Collection<ExternalData> parents;
 
     private String location;
 
@@ -208,26 +208,34 @@ public class ExternalData extends CodeWithRegistration<ExternalData> implements
 
     public ExternalData getParent()
     {
-        return parent;
+        if (parents == null)
+        {
+            return null;
+        }
+        final Iterator<ExternalData> it = parents.iterator();
+        if (it.hasNext())
+        {
+            return parents.iterator().next();
+        } else
+        {
+            return null;
+        }
     }
 
-    public void setParent(ExternalData parent)
+    public Collection<ExternalData> getParents()
     {
-        this.parent = parent;
-        if (parent != null)
-        {
-            setParentCode(parent.getCode());
-        }
+        return parents;
     }
 
-    public final String getParentCode()
+    public void setParents(Collection<ExternalData> parents)
     {
-        return parentCode;
+        this.parents = parents;
     }
 
-    public final void setParentCode(final String parentCode)
+    public final String getParentCode()
     {
-        this.parentCode = parentCode;
+        final ExternalData parent = getParent();
+        return (parent == null) ? null : parent.getCode();
     }
 
     public final String getLocation()
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/translator/ExternalDataTranslator.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/translator/ExternalDataTranslator.java
index 0bf9e18a2a4..5471f8f9490 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/translator/ExternalDataTranslator.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/translator/ExternalDataTranslator.java
@@ -17,7 +17,9 @@
 package ch.systemsx.cisd.openbis.generic.shared.translator;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 
 import org.apache.commons.lang.StringEscapeUtils;
@@ -74,7 +76,6 @@ public class ExternalDataTranslator
             final LoadableFields... withExperimentFields)
     {
         SamplePE sample = externalDataPE.getSample();
-        DataPE parent = externalDataPE.tryGetParent();
         ExternalData externalData = new ExternalData();
         externalData.setId(HibernateUtils.getId(externalDataPE));
         externalData.setCode(StringEscapeUtils.escapeHtml(externalDataPE.getCode()));
@@ -89,8 +90,12 @@ public class ExternalDataTranslator
         externalData.setInvalidation(tryToGetInvalidation(sample));
         externalData.setLocation(StringEscapeUtils.escapeHtml(externalDataPE.getLocation()));
         externalData.setLocatorType(TypeTranslator.translate(externalDataPE.getLocatorType()));
-        externalData
-                .setParent(parent == null ? null : fillExternalData(new ExternalData(), parent));
+        final Collection<ExternalData> parents = new HashSet<ExternalData>();
+        externalData.setParents(parents);
+        for (DataPE parentPE : externalDataPE.getParents())
+        {
+            parents.add(fillExternalData(new ExternalData(), parentPE));
+        }
         setChildren(externalDataPE, externalData);
         externalData.setProductionDate(externalDataPE.getProductionDate());
         externalData.setModificationDate(externalDataPE.getModificationDate());
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ExternalDataTableTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ExternalDataTableTest.java
index fc80bf487b9..b14970ad9be 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ExternalDataTableTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ExternalDataTableTest.java
@@ -23,6 +23,8 @@ import java.util.Arrays;
 import java.util.List;
 
 import org.apache.commons.lang.StringUtils;
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
 import org.jmock.Expectations;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
@@ -35,11 +37,14 @@ import ch.systemsx.cisd.openbis.generic.shared.CommonTestUtils;
 import ch.systemsx.cisd.openbis.generic.shared.IDataStoreService;
 import ch.systemsx.cisd.openbis.generic.shared.basic.BasicConstant;
 import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DataSetTypePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DataSetUploadContext;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DataStorePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DatabaseInstancePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.EventPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentTypePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ExternalDataPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.GroupPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.PersonPE;
@@ -279,34 +284,51 @@ public final class ExternalDataTableTest extends AbstractBOTest
         return ExternalDataTable.createDeletionEvent(dataset, person, reason);
     }
 
+    @SuppressWarnings("unchecked")
     @Test
     public void testUploadDataSets()
     {
-        final ExternalDataPE d1 = createDataSet("d1", dss1);
-        final ExternalDataPE d2 = createDataSet("d2", dss2);
+        final ExternalDataPE d1PE = createDataSet("d1", dss1);
+        final ExternalDataPE d2PE = createDataSet("d2", dss2);
         final DataSetUploadContext uploadContext = new DataSetUploadContext();
         uploadContext.setCifexURL("cifexURL");
         uploadContext.setUserID(EXAMPLE_SESSION.getUserName());
         uploadContext.setPassword("pwd");
         uploadContext.setUserEMail(EXAMPLE_SESSION.getPrincipal().getEmail());
-        uploadContext.setComment(ExternalDataTable.createUploadComment(Arrays.asList(d1, d2)));
+        uploadContext.setComment(ExternalDataTable.createUploadComment(Arrays.asList(d1PE, d2PE)));
         context.checking(new Expectations()
             {
                 {
-                    prepareFindFullDatasets(d1, true);
-                    prepareFindFullDatasets(d2, true);
+                    prepareFindFullDatasets(d1PE, true);
+                    prepareFindFullDatasets(d2PE, true);
 
-                    List<String> d2Locations = Arrays.asList(d2.getLocation());
+                    List<String> d2Locations = Arrays.asList(d2PE.getLocation());
                     one(dataStoreService2).getKnownDataSets(dss2.getSessionToken(), d2Locations);
                     will(returnValue(d2Locations));
 
-                    one(dataStoreService2).uploadDataSetsToCIFEX(dss2.getSessionToken(),
-                            Arrays.asList(d2), uploadContext);
+                    one(dataStoreService2).uploadDataSetsToCIFEX(with(equal(dss2.getSessionToken())),
+                            with(new BaseMatcher<List>() {
+
+                                public boolean matches(Object item)
+                                {
+                                    List<ExternalData> list = (List<ExternalData>) item;
+                                    if (list.size() != 1)
+                                    {
+                                        return false;
+                                    }
+                                    ExternalData data = list.get(0);
+                                    return d2PE.getCode().equals(data.getCode());
+                                }
+
+                                public void describeTo(Description description)
+                                {
+                                    description.appendText("Data set d2");
+                                }}), with(same(uploadContext)));
                 }
             });
 
         ExternalDataTable externalDataTable = createExternalDataTable();
-        externalDataTable.loadByDataSetCodes(Arrays.asList(d1.getCode(), d2.getCode()));
+        externalDataTable.loadByDataSetCodes(Arrays.asList(d1PE.getCode(), d2PE.getCode()));
         String message = externalDataTable.uploadLoadedDataSetsToCIFEX(uploadContext);
 
         assertEquals(
@@ -373,10 +395,15 @@ public final class ExternalDataTableTest extends AbstractBOTest
         data.setLocation("here/" + code);
         ExperimentPE experiment = new ExperimentPE();
         experiment.setCode("exp1");
+        experiment.setExperimentType(new ExperimentTypePE());
         ProjectPE project = new ProjectPE();
         project.setCode("p1");
         GroupPE group = new GroupPE();
         group.setCode("g1");
+        DatabaseInstancePE instance = new DatabaseInstancePE();
+        instance.setCode("instance");
+        instance.setOriginalSource(true);
+        group.setDatabaseInstance(instance);
         project.setGroup(group);
         experiment.setProject(project);
         data.setExperiment(experiment);
-- 
GitLab