From 5ef19ef6b3fe9d22bcacb55a8c135393eecff4ab Mon Sep 17 00:00:00 2001
From: juanf <juanf>
Date: Mon, 27 Nov 2017 13:36:43 +0000
Subject: [PATCH] SSDM-3467 : Making imports context sensitive - server changes

SVN: 38956
---
 .../v1/GeneralInformationChangingService.java | 42 +++++++++--
 ...neralInformationChangingServiceLogger.java | 32 +++++++++
 .../parser/SampleUploadSectionsParser.java    | 48 ++++++++++++-
 .../web/client/IGenericClientService.java     | 27 +++++++
 .../web/server/GenericClientService.java      | 72 +++++++++++++++----
 .../openbis/public/resources/js/openbis.js    | 36 ++++++++++
 .../IGeneralInformationChangingService.java   | 38 +++++++++-
 7 files changed, 271 insertions(+), 24 deletions(-)

diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationChangingService.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationChangingService.java
index 644a4fb2990..7b9f62a92f5 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationChangingService.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationChangingService.java
@@ -240,14 +240,18 @@ public class GeneralInformationChangingService extends
 
     @Override
     @RolesAllowed(RoleWithHierarchy.PROJECT_USER)
-    public final String registerSamples(
+    public final String registerSamplesWithSilentOverrides(
             final String sessionToken,
             final String sampleTypeCode,
+            final String spaceIdentifierSilentOverrideOrNull,
+            final String experimentIdentifierSilentOverrideOrNull,
             final String sessionKey,
             final String defaultGroupIdentifier)
     {
-        List<BatchRegistrationResult> results = genericClientService.registerSamples(
+        List<BatchRegistrationResult> results = genericClientService.registerSamplesWithSilentOverrides(
                 getSampleType(sampleTypeCode, sessionToken),
+                spaceIdentifierSilentOverrideOrNull,
+                experimentIdentifierSilentOverrideOrNull,
                 sessionKey, false, null,
                 defaultGroupIdentifier,
                 false);
@@ -257,20 +261,46 @@ public class GeneralInformationChangingService extends
 
     @Override
     @RolesAllowed(RoleWithHierarchy.PROJECT_USER)
-    public final String updateSamples(
+    public final String registerSamples(
+            final String sessionToken,
+            final String sampleTypeCode,
+            final String sessionKey,
+            final String defaultGroupIdentifier)
+    {
+        return registerSamplesWithSilentOverrides(sessionToken, sampleTypeCode, null, null, sessionKey, defaultGroupIdentifier);
+    }
+
+    @Override
+    @RolesAllowed(RoleWithHierarchy.PROJECT_USER)
+    public final String updateSamplesWithSilentOverrides(
             final String sessionToken,
             final String sampleTypeCode,
+            final String spaceIdentifierSilentOverrideOrNull,
+            final String experimentIdentifierSilentOverrideOrNull,
             final String sessionKey,
             final String defaultGroupIdentifier)
     {
-        List<BatchRegistrationResult> results = genericClientService.updateSamples(
+        List<BatchRegistrationResult> results = genericClientService.updateSamplesWithSilentOverrides(
                 getSampleType(sampleTypeCode, sessionToken),
+                spaceIdentifierSilentOverrideOrNull,
+                experimentIdentifierSilentOverrideOrNull,
                 sessionKey, false, null,
                 defaultGroupIdentifier);
 
         return results.get(0).getMessage();
     }
 
+    @Override
+    @RolesAllowed(RoleWithHierarchy.PROJECT_USER)
+    public final String updateSamples(
+            final String sessionToken,
+            final String sampleTypeCode,
+            final String sessionKey,
+            final String defaultGroupIdentifier)
+    {
+        return updateSamplesWithSilentOverrides(sessionToken, sampleTypeCode, null, null, sessionKey, defaultGroupIdentifier);
+    }
+
     @Override
     @RolesAllowed(RoleWithHierarchy.PROJECT_USER)
     public final Map<String, Object> uploadedSamplesInfo(
@@ -278,11 +308,9 @@ public class GeneralInformationChangingService extends
             final String sampleTypeCode,
             final String sessionKey)
     {
-        Map<String, Object> info = genericClientService.uploadedSamplesInfo(
+        return genericClientService.uploadedSamplesInfo(
                 getSampleType(sampleTypeCode, sessionToken),
                 sessionKey);
-
-        return info;
     }
 
     @Override
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationChangingServiceLogger.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationChangingServiceLogger.java
index 7ab105f0323..3f09313432b 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationChangingServiceLogger.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationChangingServiceLogger.java
@@ -134,6 +134,22 @@ class GeneralInformationChangingServiceLogger extends AbstractServerLogger imple
                 abbreviate(assignments.getMaterials()));
     }
 
+    @Override
+    public String registerSamplesWithSilentOverrides(String sessionToken, String sampleTypeCode, String spaceIdentifierSilentOverrideOrNull,
+            String experimentIdentifierSilentOverrideOrNull, String sessionKey,
+            String defaultGroupIdentifier)
+    {
+        logAccess(sessionToken, "registerSamplesWithSilentOverrides",
+                "sampleTypeCode(%s), sessionKey(%s), spaceIdentifierSilentOverrideOrNull(%s), experimentIdentifierSilentOverrideOrNull(%s), defaultGroupIdentifier(%s)",
+                sampleTypeCode,
+                spaceIdentifierSilentOverrideOrNull,
+                experimentIdentifierSilentOverrideOrNull,
+                sessionKey,
+                defaultGroupIdentifier);
+
+        return null;
+    }
+
     @Override
     public String registerSamples(String sessionToken, String sampleTypeCode, String sessionKey, String defaultGroupIdentifier)
     {
@@ -146,6 +162,22 @@ class GeneralInformationChangingServiceLogger extends AbstractServerLogger imple
         return null;
     }
 
+    @Override
+    public String updateSamplesWithSilentOverrides(String sessionToken, String sampleTypeCode, String spaceIdentifierSilentOverrideOrNull,
+            String experimentIdentifierSilentOverrideOrNull, String sessionKey,
+            String defaultGroupIdentifier)
+    {
+        logAccess(sessionToken, "updateSamplesWithSilentOverrides",
+                "sampleTypeCode(%s), sessionKey(%s), spaceIdentifierSilentOverrideOrNull(%s), experimentIdentifierSilentOverrideOrNull(%s), defaultGroupIdentifier(%s)",
+                sampleTypeCode,
+                spaceIdentifierSilentOverrideOrNull,
+                experimentIdentifierSilentOverrideOrNull,
+                sessionKey,
+                defaultGroupIdentifier);
+
+        return null;
+    }
+
     @Override
     public String updateSamples(String sessionToken, String sampleTypeCode, String sessionKey, String defaultGroupIdentifier)
     {
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/parser/SampleUploadSectionsParser.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/parser/SampleUploadSectionsParser.java
index 06dc2fcd9e2..ba0386f3962 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/parser/SampleUploadSectionsParser.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/parser/SampleUploadSectionsParser.java
@@ -23,6 +23,8 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.commons.lang.StringUtils;
+
 import ch.systemsx.cisd.common.io.DelegatedReader;
 import ch.systemsx.cisd.common.parser.ExcelFileLoader;
 import ch.systemsx.cisd.common.parser.IParserObjectFactory;
@@ -84,6 +86,8 @@ public class SampleUploadSectionsParser
     }
 
     public static BatchSamplesOperation prepareSamples(final SampleType sampleType,
+            final String spaceIdentifierSilentOverrideOrNull,
+            final String experimentIdentifierSilentOverrideOrNull,
             final Collection<NamedInputStream> files, String defaultGroupIdentifier,
             final SampleCodeGenerator sampleCodeGeneratorOrNull, final boolean allowExperiments,
             String excelSheetName, BatchOperationKind operationKind)
@@ -91,7 +95,9 @@ public class SampleUploadSectionsParser
         final List<NewSamplesWithTypes> newSamples = new ArrayList<NewSamplesWithTypes>();
         boolean isAutoGenerateCodes = (sampleCodeGeneratorOrNull != null);
         final List<BatchRegistrationResult> results =
-                loadSamplesFromFiles(files, sampleType, isAutoGenerateCodes, newSamples,
+                loadSamplesFromFiles(files, sampleType, spaceIdentifierSilentOverrideOrNull, experimentIdentifierSilentOverrideOrNull,
+                        isAutoGenerateCodes,
+                        newSamples,
                         allowExperiments, excelSheetName, operationKind);
 
         if (defaultGroupIdentifier != null)
@@ -184,8 +190,46 @@ public class SampleUploadSectionsParser
         return tabFileLoader;
     }
 
+    public static String getIdentifierOrNull(String identifierOrNullOrDelete)
+    {
+        switch (identifierOrNullOrDelete)
+        {
+            case "--DELETE--":
+                return null;
+            case "__DELETE__":
+                return null;
+            default:
+                return identifierOrNullOrDelete;
+        }
+    }
+
+    private static void setSilentOverrides(String spaceIdentifierSilentOverrideOrNull,
+            String experimentIdentifierSilentOverrideOrNull, List<NewSample> newSamples)
+    {
+        for (NewSample newSample : newSamples)
+        {
+            if (spaceIdentifierSilentOverrideOrNull != null)
+            {
+                if (newSample.getIdentifier() != null)
+                {
+                    int endOfSpaceIdentfier = StringUtils.ordinalIndexOf(newSample.getIdentifier(), "/", 2);
+                    String sampleIdentifierSilentOverrideOrNull =
+                            spaceIdentifierSilentOverrideOrNull + newSample.getIdentifier().substring(endOfSpaceIdentfier);
+                    newSample.setIdentifier(sampleIdentifierSilentOverrideOrNull);
+                }
+                newSample.setDefaultSpaceIdentifier(getIdentifierOrNull(spaceIdentifierSilentOverrideOrNull));
+            }
+            if (experimentIdentifierSilentOverrideOrNull != null)
+            {
+                newSample.setExperimentIdentifier(getIdentifierOrNull(experimentIdentifierSilentOverrideOrNull));
+            }
+        }
+    }
+
     private static List<BatchRegistrationResult> loadSamplesFromFiles(
             Collection<NamedInputStream> uploadedFiles, SampleType sampleType,
+            String spaceIdentifierSilentOverrideOrNull,
+            String experimentIdentifierSilentOverrideOrNull,
             boolean isAutoGenerateCodes, final List<NewSamplesWithTypes> newSamples,
             boolean allowExperiments, String excelSheetName, BatchOperationKind operationKind)
     {
@@ -228,6 +272,7 @@ public class SampleUploadSectionsParser
                         final List<NewSample> loadedSamples =
                                 excelFileLoader.load(fs.getSheet(), fs.getBegin(), fs.getEnd(),
                                         fileName + sectionInFile, defaults);
+                        setSilentOverrides(spaceIdentifierSilentOverrideOrNull, experimentIdentifierSilentOverrideOrNull, loadedSamples);
                         if (loadedSamples.size() > 0)
                         {
                             newSamples.add(new NewSamplesWithTypes(typeFromSection, loadedSamples));
@@ -271,6 +316,7 @@ public class SampleUploadSectionsParser
                         final List<NewSample> loadedSamples =
                                 tabFileLoader.load(new DelegatedReader(reader, fileName
                                         + sectionInFile), defaults);
+                        setSilentOverrides(spaceIdentifierSilentOverrideOrNull, experimentIdentifierSilentOverrideOrNull, loadedSamples);
                         if (loadedSamples.size() > 0)
                         {
                             newSamples.add(new NewSamplesWithTypes(typeFromSection, loadedSamples));
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/IGenericClientService.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/IGenericClientService.java
index 1b85c0d9c76..a5d485ae2e9 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/IGenericClientService.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/IGenericClientService.java
@@ -71,6 +71,21 @@ public interface IGenericClientService extends IClientService
     public Sample registerSample(final String sessionKey, final NewSample sample)
             throws UserFailureException;
 
+    /**
+     * Registers new samples from files which have been previously uploaded forcing the experimentIdentifier
+     * <p>
+     * Uploaded files can be found as session attribute under given <var>sessionKey</var>.
+     * </p>
+     * 
+     * @param updateExisting if true and some entities already exist, they will be updated (instead of throwing the exception and breaking the whole
+     *            operation).
+     */
+    public List<BatchRegistrationResult> registerSamplesWithSilentOverrides(final SampleType sampleType,
+            final String spaceIdentifierSilentOverrideOrNull,
+            final String experimentIdentifierSilentOverrideOrNull,
+            String sessionKey, boolean async, String userEmail, String defaultGroupIdentifier, boolean updateExisting)
+            throws UserFailureException;
+
     /**
      * Registers new samples from files which have been previously uploaded.
      * <p>
@@ -93,6 +108,17 @@ public interface IGenericClientService extends IClientService
     public List<BatchRegistrationResult> registerExperiments(final ExperimentType experimentType,
             String sessionKey, boolean async, String userEmail) throws UserFailureException;
 
+    /**
+     * Updates samples from files which have been previously uploaded.
+     * <p>
+     * Uploaded files can be found as session attribute under given <var>sessionKey</var>.
+     * </p>
+     */
+    public List<BatchRegistrationResult> updateSamplesWithSilentOverrides(final SampleType sampleType,
+            final String spaceIdentifierSilentOverrideOrNull,
+            final String experimentIdentifierSilentOverrideOrNull,
+            String sessionKey, boolean async, String userEmail, String defaultGroupIdentifier) throws UserFailureException;
+
     /**
      * Updates samples from files which have been previously uploaded.
      * <p>
@@ -192,4 +218,5 @@ public interface IGenericClientService extends IClientService
     public Map<String, Object> uploadedSamplesInfo(
             final SampleType sampleType,
             final String sessionKey);
+
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/server/GenericClientService.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/server/GenericClientService.java
index a84fdb999bd..d04c1aa2a9a 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/server/GenericClientService.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/server/GenericClientService.java
@@ -187,8 +187,10 @@ public class GenericClientService extends AbstractClientService implements IGene
     }
 
     @Override
-    public final List<BatchRegistrationResult> registerSamples(
+    public final List<BatchRegistrationResult> registerSamplesWithSilentOverrides(
             final SampleType sampleType,
+            final String spaceIdentifierSilentOverrideOrNull,
+            final String experimentIdentifierSilentOverrideOrNull,
             final String sessionKey,
             final boolean async,
             final String userEmail,
@@ -207,7 +209,10 @@ public class GenericClientService extends AbstractClientService implements IGene
             final BatchOperationKind operationKind = updateExisting ? BatchOperationKind.UPDATE : BatchOperationKind.REGISTRATION;
             uploadedFiles = getUploadedFiles(sessionKey, httpSession);
             BatchSamplesOperation info =
-                    parseSamples(sampleType, uploadedFiles, defaultGroupIdentifier, isAutoGenerateCodes, true, null, operationKind, sessionToken);
+                    parseSamples(sampleType, spaceIdentifierSilentOverrideOrNull, experimentIdentifierSilentOverrideOrNull, uploadedFiles,
+                            defaultGroupIdentifier, isAutoGenerateCodes,
+                            true, null,
+                            operationKind, sessionToken);
 
             if (async)
             {
@@ -230,7 +235,9 @@ public class GenericClientService extends AbstractClientService implements IGene
                         {
                             // Some stuff is repeated on the async executor, this is expected
                             BatchSamplesOperation asyncInfo =
-                                    parseSamples(sampleType, this.getFilesForTask(), defaultGroupIdentifier, isAutoGenerateCodes, true, null,
+                                    parseSamples(sampleType, spaceIdentifierSilentOverrideOrNull, experimentIdentifierSilentOverrideOrNull,
+                                            this.getFilesForTask(), defaultGroupIdentifier,
+                                            isAutoGenerateCodes, true, null,
                                             operationKind, sessionToken);
                             // Execute task
                             genericServer.registerOrUpdateSamples(sessionToken, asyncInfo.getSamples());
@@ -287,6 +294,18 @@ public class GenericClientService extends AbstractClientService implements IGene
         }
     }
 
+    @Override
+    public final List<BatchRegistrationResult> registerSamples(
+            final SampleType sampleType,
+            final String sessionKey,
+            final boolean async,
+            final String userEmail,
+            final String defaultGroupIdentifier,
+            final boolean updateExisting)
+    {
+        return registerSamplesWithSilentOverrides(sampleType, null, null, sessionKey, async, userEmail, defaultGroupIdentifier, updateExisting);
+    }
+
     private boolean shouldContinuousSampleCodesCreated()
     {
         return PropertyUtils.getBoolean(this.getServiceProperties(), Constants.CREATE_CONTINUOUS_SAMPLES_CODES_KEY, false);
@@ -334,8 +353,10 @@ public class GenericClientService extends AbstractClientService implements IGene
     }
 
     @Override
-    public final List<BatchRegistrationResult> updateSamples(
+    public final List<BatchRegistrationResult> updateSamplesWithSilentOverrides(
             final SampleType sampleType,
+            final String spaceIdentifierSilentOverrideOrNull,
+            final String experimentIdentifierSilentOverrideOrNull,
             final String sessionKey,
             boolean async,
             final String userEmail,
@@ -349,7 +370,9 @@ public class GenericClientService extends AbstractClientService implements IGene
         {
             uploadedFiles = getUploadedFiles(sessionKey, httpSession);
             BatchSamplesOperation info =
-                    parseSamples(sampleType, uploadedFiles, defaultGroupIdentifier, false, true, null, BatchOperationKind.UPDATE, sessionToken);
+                    parseSamples(sampleType, spaceIdentifierSilentOverrideOrNull, experimentIdentifierSilentOverrideOrNull, uploadedFiles,
+                            defaultGroupIdentifier, false, true, null, BatchOperationKind.UPDATE,
+                            sessionToken);
 
             if (async)
             {
@@ -372,7 +395,8 @@ public class GenericClientService extends AbstractClientService implements IGene
                         {
                             // Some stuff is repeated on the async executor, this is expected
                             BatchSamplesOperation asyncInfo =
-                                    parseSamples(sampleType, this.getFilesForTask(), defaultGroupIdentifier, false, true, null,
+                                    parseSamples(sampleType, spaceIdentifierSilentOverrideOrNull, experimentIdentifierSilentOverrideOrNull,
+                                            this.getFilesForTask(), defaultGroupIdentifier, false, true, null,
                                             BatchOperationKind.UPDATE, sessionToken);
                             // Execute task
                             genericServer.updateSamples(sessionToken, asyncInfo.getSamples());
@@ -401,6 +425,17 @@ public class GenericClientService extends AbstractClientService implements IGene
         }
     }
 
+    @Override
+    public final List<BatchRegistrationResult> updateSamples(
+            final SampleType sampleType,
+            final String sessionKey,
+            boolean async,
+            final String userEmail,
+            final String defaultGroupIdentifier)
+    {
+        return updateSamplesWithSilentOverrides(sampleType, null, null, sessionKey, async, userEmail, defaultGroupIdentifier);
+    }
+
     @Override
     public final List<BatchRegistrationResult> registerOrUpdateSamplesAndMaterials(
             final String sessionKey,
@@ -422,7 +457,8 @@ public class GenericClientService extends AbstractClientService implements IGene
             uploadedFiles = getUploadedFiles(sessionKey, session);
 
             BatchSamplesOperation samplesInfo =
-                    parseSamples(sampleType, uploadedFiles, defaultGroupIdentifier, defaultGroupIdentifier != null, true, "SAMPLES", operationKind,
+                    parseSamples(sampleType, null, null, uploadedFiles, defaultGroupIdentifier, defaultGroupIdentifier != null, true, "SAMPLES",
+                            operationKind,
                             sessionToken);
 
             final MaterialType materialType = new MaterialType();
@@ -450,7 +486,9 @@ public class GenericClientService extends AbstractClientService implements IGene
                         {
                             // Some stuff is repeated on the async executor, this is expected
                             BatchSamplesOperation asyncSamplesInfo =
-                                    parseSamples(sampleType, this.getFilesForTask(), defaultGroupIdentifier, defaultGroupIdentifier != null, true,
+                                    parseSamples(sampleType, null, null, this.getFilesForTask(), defaultGroupIdentifier,
+                                            defaultGroupIdentifier != null,
+                                            true,
                                             "SAMPLES", operationKind, sessionToken);
                             BatchMaterialsOperation asyncMaterialsInfo =
                                     parseMaterials(session, this.getFilesForTask(), materialType, "MATERIALS", updateExisting);
@@ -538,7 +576,9 @@ public class GenericClientService extends AbstractClientService implements IGene
         return helper.exp;
     }
 
-    private BatchSamplesOperation parseSamples(final SampleType sampleType, UploadedFilesBean uploadedFiles,
+    private BatchSamplesOperation parseSamples(final SampleType sampleType, String spaceIdentifierSilentOverrideOrNull,
+            String experimentIdentifierSilentOverrideOrNull,
+            UploadedFilesBean uploadedFiles,
             String defaultGroupIdentifier, final boolean isAutoGenerateCodes,
             final boolean allowExperiments, String excelSheetName, BatchOperationKind operationKind, String sessionToken)
     {
@@ -553,7 +593,8 @@ public class GenericClientService extends AbstractClientService implements IGene
         }
 
         BatchSamplesOperation batchSamplesOperation =
-                SampleUploadSectionsParser.prepareSamples(sampleType, files,
+                SampleUploadSectionsParser.prepareSamples(sampleType, spaceIdentifierSilentOverrideOrNull, experimentIdentifierSilentOverrideOrNull,
+                        files,
                         defaultGroupIdentifier, sampleCodeGeneratorOrNull, allowExperiments,
                         excelSheetName, operationKind);
 
@@ -619,7 +660,7 @@ public class GenericClientService extends AbstractClientService implements IGene
         try
         {
             uploadedFiles = getUploadedFiles(sessionKey, httpSession);
-            return parseSamples(sampleType, uploadedFiles, defaultGroupIdentifier, isAutoGenerateCodes, allowExperiments, excelSheetName,
+            return parseSamples(sampleType, null, null, uploadedFiles, defaultGroupIdentifier, isAutoGenerateCodes, allowExperiments, excelSheetName,
                     operationKind, sessionToken);
         } finally
         {
@@ -1117,11 +1158,11 @@ public class GenericClientService extends AbstractClientService implements IGene
             convExperimentIdentifierOrNull =
                     new ExperimentIdentifierFactory(updates
                             .getExperimentIdentifierOrNull().getIdentifier())
-                    .createIdentifier();
+                                    .createIdentifier();
         }
         return convExperimentIdentifierOrNull;
     }
-    
+
     private ProjectIdentifier getProjectIdentifier(SampleUpdates updates)
     {
         String identifier = updates.getProjectIdentifierOrNull();
@@ -1131,6 +1172,7 @@ public class GenericClientService extends AbstractClientService implements IGene
         }
         return new ProjectIdentifierFactory(identifier).createIdentifier();
     }
+
     @Override
     public Date updateMaterial(TechId materialId, List<IEntityProperty> properties,
             String[] metaprojects, Date version)
@@ -1331,6 +1373,8 @@ public class GenericClientService extends AbstractClientService implements IGene
         {
             BatchSamplesOperation batchSamplesOperation = SampleUploadSectionsParser.prepareSamples(
                     sampleType,
+                    null,
+                    null,
                     files,
                     null,
                     null,
@@ -1340,7 +1384,7 @@ public class GenericClientService extends AbstractClientService implements IGene
             info.put("identifiersPressent", Boolean.TRUE);
         } catch (Exception ex)
         {
-            if (ex.getMessage().contains("Mandatory column 'identifier' is missing."))
+            if (ex.getMessage() != null && ex.getMessage().contains("Mandatory column 'identifier' is missing."))
             {
                 info.put("identifiersPressent", Boolean.FALSE);
             }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/js/openbis.js b/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/js/openbis.js
index 252b98febdf..07704d7a495 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/js/openbis.js
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/js/openbis.js
@@ -1285,6 +1285,24 @@ openbis.prototype.removeFromMetaproject = function(metaprojectId, assignmentsToR
 	});
 }
 
+/**
+ * @see IGeneralInformationChangingService.registerSamplesWithSilentOverrides(String, String, String, String, String, String)
+ * @method
+ */
+openbis.prototype.registerSamplesWithSilentOverrides = function(sampleTypeCode, spaceIdentifierSilentOverrideOrNull, experimentIdentifierSilentOverrideOrNull, sessionKey, defaultGroupIdentifier, action) {
+	this._internal.ajaxRequest({
+		url: this._internal.generalInfoChangingServiceUrl,
+		data: { "method" : "registerSamplesWithSilentOverrides",
+				"params" : [ this.getSession(),
+							 sampleTypeCode,
+							 spaceIdentifierSilentOverrideOrNull,
+							 experimentIdentifierSilentOverrideOrNull,
+							 sessionKey,
+							 defaultGroupIdentifier] },
+		success: action
+	});
+}
+
 /**
  * @see IGeneralInformationChangingService.registerSamples(String, String, String, String)
  * @method
@@ -1301,6 +1319,24 @@ openbis.prototype.registerSamples = function(sampleTypeCode, sessionKey, default
 	});
 }
 
+/**
+ * @see IGeneralInformationChangingService.updateSamplesWithSilentOverrides(String, String, String, String, String, String)
+ * @method
+ */
+openbis.prototype.updateSamplesWithSilentOverrides = function(sampleTypeCode, spaceIdentifierSilentOverrideOrNull, experimentIdentifierSilentOverrideOrNull, sessionKey, defaultGroupIdentifier, action) {
+	this._internal.ajaxRequest({
+		url: this._internal.generalInfoChangingServiceUrl,
+		data: { "method" : "updateSamplesWithSilentOverrides",
+				"params" : [ this.getSession(),
+							 sampleTypeCode,
+							 spaceIdentifierSilentOverrideOrNull,
+							 experimentIdentifierSilentOverrideOrNull,
+							 sessionKey,
+							 defaultGroupIdentifier] },
+		success: action
+	});
+}
+
 /**
  * @see IGeneralInformationChangingService.updateSamples(String, String, String, String)
  * @method
diff --git a/openbis_api/source/java/ch/systemsx/cisd/openbis/generic/shared/api/v1/IGeneralInformationChangingService.java b/openbis_api/source/java/ch/systemsx/cisd/openbis/generic/shared/api/v1/IGeneralInformationChangingService.java
index 948ad6e855d..516b2f620e5 100644
--- a/openbis_api/source/java/ch/systemsx/cisd/openbis/generic/shared/api/v1/IGeneralInformationChangingService.java
+++ b/openbis_api/source/java/ch/systemsx/cisd/openbis/generic/shared/api/v1/IGeneralInformationChangingService.java
@@ -144,8 +144,26 @@ public interface IGeneralInformationChangingService extends IRpcService
      * Registers samples parsing a file stored on the HTTP Session.
      * 
      * @param sampleTypeCode Sample type to parse
+     * @param spaceIdentifierSilentOverrideOrNull Silently overrides Space identifier if given
+     * @param experimentIdentifierSilentOverrideOrNull Silently overrides Experiment identifier if given
      * @param sessionKey key of the file stored on the HTTP Session
-     * @param defaultGroupIdentifier key of the file stored on the HTTP Session
+     * @param defaultGroupIdentifier
+     * @since 1.5
+     */
+    public String registerSamplesWithSilentOverrides(
+            final String sessionToken,
+            final String sampleTypeCode,
+            final String spaceIdentifierSilentOverrideOrNull,
+            final String experimentIdentifierSilentOverrideOrNull,
+            final String sessionKey,
+            final String defaultGroupIdentifier);
+
+    /**
+     * Registers samples parsing a file stored on the HTTP Session.
+     * 
+     * @param sampleTypeCode Sample type to parse
+     * @param sessionKey key of the file stored on the HTTP Session
+     * @param defaultGroupIdentifier
      * @since 1.5
      */
     public String registerSamples(
@@ -159,7 +177,23 @@ public interface IGeneralInformationChangingService extends IRpcService
      * 
      * @param sampleTypeCode Sample type to parse
      * @param sessionKey key of the file stored on the HTTP Session
-     * @param defaultGroupIdentifier key of the file stored on the HTTP Session
+     * @param defaultGroupIdentifier
+     * @since 1.5
+     */
+    public String updateSamplesWithSilentOverrides(
+            final String sessionToken,
+            final String sampleTypeCode,
+            final String spaceIdentifierSilentOverrideOrNull,
+            final String experimentIdentifierSilentOverrideOrNull,
+            final String sessionKey,
+            final String defaultGroupIdentifier);
+
+    /**
+     * Updates samples parsing a file stored on the HTTP Session.
+     * 
+     * @param sampleTypeCode Sample type to parse
+     * @param sessionKey key of the file stored on the HTTP Session
+     * @param defaultGroupIdentifier
      * @since 1.5
      */
     public String updateSamples(
-- 
GitLab