diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/AbstractImportTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/AbstractImportTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..67d7a0dc388cb81b1d4b5e155003db95af81da7a
--- /dev/null
+++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/AbstractImportTest.java
@@ -0,0 +1,23 @@
+package ch.ethz.sis.openbis.systemtest.plugin.excelimport;
+
+import org.springframework.test.context.testng.AbstractTransactionalTestNGSpringContextTests;
+import org.testng.annotations.BeforeSuite;
+
+import ch.systemsx.cisd.openbis.generic.server.util.TestInitializer;
+import ch.systemsx.cisd.openbis.generic.shared.Constants;
+import ch.systemsx.cisd.openbis.generic.shared.coreplugin.CorePluginsUtils;
+
+public class AbstractImportTest extends AbstractTransactionalTestNGSpringContextTests
+{
+
+    private static final String CORE_PLUGINS_FOLDER = "source/core-plugins";
+
+    @BeforeSuite
+    public void setupSuite()
+    {
+        System.setProperty(CorePluginsUtils.CORE_PLUGINS_FOLDER_KEY, CORE_PLUGINS_FOLDER);
+        System.setProperty(Constants.ENABLED_MODULES_KEY, "xls-import");
+        TestInitializer.initEmptyDbNoIndex();
+    }
+
+}
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/ImportDatasetTypesTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/ImportDatasetTypesTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..61604e5b91b31d14394ec40180c18f17033bdc9e
--- /dev/null
+++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/ImportDatasetTypesTest.java
@@ -0,0 +1,104 @@
+package ch.ethz.sis.openbis.systemtest.plugin.excelimport;
+
+import static org.testng.Assert.assertEquals;
+
+import java.io.IOException;
+import java.nio.file.Paths;
+
+import org.apache.commons.io.FilenameUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.transaction.TransactionConfiguration;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.DataSetType;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.IApplicationServerInternalApi;
+import ch.systemsx.cisd.common.exceptions.UserFailureException;
+
+@ContextConfiguration(locations = "classpath:applicationContext.xml")
+@TransactionConfiguration(transactionManager = "transaction-manager")
+public class ImportDatasetTypesTest extends AbstractImportTest
+{
+
+    @Autowired
+    private IApplicationServerInternalApi v3api;
+
+    private static final String TEST_USER = "test";
+
+    private static final String PASSWORD = "password";
+
+    private static final String DATASET_TYPES_XLS = "dataset_types/normal_dataset.xls";
+
+    private static final String DATASET_NO_CODE = "dataset_types/no_code.xls";
+
+    private static final String DATASET_WITH_VALIDATION_SCRIPT = "dataset_types/with_validation.xls";
+
+    private static final String DATASET_WITHOUT_PROPERTIES = "dataset_types/no_properties.xls";
+
+    private static String FILES_DIR;
+
+    private String sessionToken;
+
+    @BeforeClass
+    public void setupClass() throws IOException
+    {
+        String testDir = Paths.get(ImportVocabularyTypesTest.class.getResource(ImportVocabularyTypesTest.class.getSimpleName() + ".class").getPath())
+                .getParent().toString();
+        FILES_DIR = FilenameUtils.concat(testDir, "test_files");
+    }
+
+    @BeforeMethod
+    public void beforeTest()
+    {
+        sessionToken = v3api.login(TEST_USER, PASSWORD);
+    }
+
+    @Test
+    @DirtiesContext
+    public void testNormalDatasetsTypesAreCreated() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, DATASET_TYPES_XLS)));
+        // WHEN
+        DataSetType rawData = TestUtils.getDatasetType(v3api, sessionToken, "RAW_DATA");
+        // THEN
+        assertEquals(rawData.getCode(), "RAW_DATA");
+        assertEquals(rawData.getPropertyAssignments().size(), 2);
+    }
+
+    @Test
+    @DirtiesContext
+    public void testDatasetsWithoutPropertiesTypesAreCreated() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, DATASET_WITHOUT_PROPERTIES)));
+        // WHEN
+        DataSetType rawData = TestUtils.getDatasetType(v3api, sessionToken, "RAW_DATA");
+        // THEN
+        assertEquals(rawData.getCode(), "RAW_DATA");
+        assertEquals(rawData.getPropertyAssignments().size(), 0);
+    }
+
+    @Test
+    @DirtiesContext
+    public void testSampleTypesWithValidationScript() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, TestUtils.getValidationPluginMap(),
+                Paths.get(FilenameUtils.concat(FILES_DIR, DATASET_WITH_VALIDATION_SCRIPT)));
+        // WHEN
+        DataSetType collection = TestUtils.getDatasetType(v3api, sessionToken, "RAW_DATA");
+        // THEN
+        assertEquals(collection.getValidationPlugin().getName().toUpperCase(), "RAW_DATA.VALID");
+    }
+
+    @Test(expectedExceptions = UserFailureException.class)
+    public void shouldThrowExceptionIfNoSampleCode() throws IOException
+    {
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, DATASET_NO_CODE)));
+    }
+
+}
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/ImportExperimentTypesTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/ImportExperimentTypesTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..405b24fd03da4851e713760045c33d0dde3be86a
--- /dev/null
+++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/ImportExperimentTypesTest.java
@@ -0,0 +1,87 @@
+package ch.ethz.sis.openbis.systemtest.plugin.excelimport;
+
+import static org.testng.Assert.assertEquals;
+
+import java.io.IOException;
+import java.nio.file.Paths;
+
+import org.apache.commons.io.FilenameUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.transaction.TransactionConfiguration;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.ExperimentType;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.IApplicationServerInternalApi;
+import ch.systemsx.cisd.common.exceptions.UserFailureException;
+
+@ContextConfiguration(locations = "classpath:applicationContext.xml")
+@TransactionConfiguration(transactionManager = "transaction-manager")
+public class ImportExperimentTypesTest extends AbstractImportTest
+{
+    @Autowired
+    private IApplicationServerInternalApi v3api;
+
+    private static final String TEST_USER = "test";
+
+    private static final String PASSWORD = "password";
+
+    private static final String EXPERIMENT_TYPES_XLS = "experiment_types/normal_experiment.xls";
+
+    private static final String EXPERIMENT_NO_CODE = "experiment_types/no_code.xls";
+
+    private static final String EXPERIMENT_WITH_VALIDATION_SCRIPT = "experiment_types/with_validation_script.xls";
+
+    private static String FILES_DIR;
+
+    private String sessionToken;
+
+    @BeforeClass
+    public void setupClass() throws IOException
+    {
+        String testDir = Paths.get(ImportVocabularyTypesTest.class.getResource(ImportVocabularyTypesTest.class.getSimpleName() + ".class").getPath())
+                .getParent().toString();
+        FILES_DIR = FilenameUtils.concat(testDir, "test_files");
+    }
+
+    @BeforeMethod
+    public void beforeTest()
+    {
+        sessionToken = v3api.login(TEST_USER, PASSWORD);
+    }
+
+    @Test
+    @DirtiesContext
+    public void testNormalExperimentTypesAreCreated() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, EXPERIMENT_TYPES_XLS)));
+        // WHEN
+        ExperimentType collection = TestUtils.getExperimentType(v3api, sessionToken, "COLLECTION");
+        // THEN
+        assertEquals(collection.getCode(), "COLLECTION");
+    }
+
+    @Test
+    @DirtiesContext
+    public void testExperimentTypesWithValidationScript() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, TestUtils.getValidationPluginMap(),
+                Paths.get(FilenameUtils.concat(FILES_DIR, EXPERIMENT_WITH_VALIDATION_SCRIPT)));
+        // WHEN
+        ExperimentType collection = TestUtils.getExperimentType(v3api, sessionToken, "COLLECTION");
+        // THEN
+        assertEquals(collection.getValidationPlugin().getName().toUpperCase(), "COLLECTION.VALID");
+    }
+
+    @Test(expectedExceptions = UserFailureException.class)
+    public void shouldThrowExceptionIfNoSampleCode() throws IOException
+    {
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, EXPERIMENT_NO_CODE)));
+    }
+
+}
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/ImportExperimentsTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/ImportExperimentsTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..e7f968f048c1ddaf58578c5c7971e9382f23f3a4
--- /dev/null
+++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/ImportExperimentsTest.java
@@ -0,0 +1,328 @@
+package ch.ethz.sis.openbis.systemtest.plugin.excelimport;
+
+import static org.testng.Assert.assertEquals;
+
+import java.io.IOException;
+import java.nio.file.Paths;
+
+import org.apache.commons.io.FilenameUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.transaction.TransactionConfiguration;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.Experiment;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.IApplicationServerInternalApi;
+import ch.systemsx.cisd.common.exceptions.UserFailureException;
+
+@ContextConfiguration(locations = "classpath:applicationContext.xml")
+@TransactionConfiguration(transactionManager = "transaction-manager")
+public class ImportExperimentsTest extends AbstractImportTest
+{
+    @Autowired
+    private IApplicationServerInternalApi v3api;
+
+    private static final String TEST_USER = "test";
+
+    private static final String PASSWORD = "password";
+
+    private static final String EXPERIMENT_XLS = "experiments/all_inside.xls";
+
+    private static final String EXPERIMENTS_ALL_ELSEWHERE = "experiments/all_elsewhere.xls";
+
+    private static final String EXPERIMENTS_WITH_TYPE_ELSEWHERE = "experiments/experiment_type_elsewhere.xls";
+
+    private static final String EXPERIMENTS_NO_CODE = "experiments/no_code.xls";
+
+    private static final String EXPERIMENTS_WITH_NON_MANDATORY_PROPERTY_MISSING = "experiments/no_non_mandatory_property.xls";
+
+    private static final String EXPERIMENTS_NO_PROJECT_ATTRIBUTE = "experiments/no_project.xls";
+
+    private static final String EXPERIMENTS_WITH_SPACE_AND_PROJECT_ELSEWHERE = "experiments/space_and_project_elsewhere.xls";
+
+    private static final String EXPERIMENTS_SPACE_ELSEWHERE = "experiments/space_elsewhere.xls";
+
+    private static final String EXPERIMENTS_WITH_TYPE_AND_SPACE_ELSEWHERE = "experiments/type_and_space_elsewhere.xls";
+
+    private static final String EXPERIMENTS_WITH_MANDATORY_PROPERTY_MISSING = "experiments/with_mandatory_property_missing.xls";
+
+    private static final String EXPERIMENTS_WITH_MANDATORY_PROPERTY_PRESENT = "experiments/with_mandatory_property.xls";
+
+    private static final String EXPERIMENTS_PROPERTIES_COLUMNS_AS_LABELS = "experiments/with_properties_as_labels.xls";
+
+    private static final String EXPERIMENTS_PROPERTIES_COLUMNS_AS_LABELS_TYPE_ON_SERVER = "experiments/with_properties_as_labels_type_elsewhere.xls";
+
+    private static final String SPACE = "experiments/space.xls";
+
+    private static final String PROJECT = "experiments/project.xls";
+
+    private static final String EXPERIMENT_TYPE = "experiments/experiment_type.xls";
+
+    private static String FILES_DIR;
+
+    private String sessionToken;
+
+    @BeforeClass
+    public void setupClass() throws IOException
+    {
+        String testDir = Paths.get(this.getClass().getResource(this.getClass().getSimpleName() + ".class").getPath())
+                .getParent().toString();
+        FILES_DIR = FilenameUtils.concat(testDir, "test_files");
+    }
+
+    @BeforeMethod
+    public void beforeTest()
+    {
+        sessionToken = v3api.login(TEST_USER, PASSWORD);
+    }
+
+    @Test
+    @DirtiesContext
+    public void testProjectsAreCreated() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, EXPERIMENT_XLS)));
+        // WHEN
+        Experiment experiment = TestUtils.getExperiment(v3api, sessionToken, "TEST_EXPERIMENT", "TEST_PROJECT", "TEST_SPACE");
+        // THEN
+        assertEquals(experiment.getCode(), "TEST_EXPERIMENT");
+        assertEquals(experiment.getProject().getCode(), "TEST_PROJECT");
+        assertEquals(experiment.getProperties().get("$NAME"), "Value");
+        assertEquals(experiment.getProperties().get("DEFAULT_OBJECT_TYPE"), "OBJECT_TYPE");
+    }
+
+    @Test
+    @DirtiesContext
+    public void testProjectsAreCreatedSecondExperiment() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, EXPERIMENT_XLS)));
+        // WHEN
+        Experiment experiment = TestUtils.getExperiment(v3api, sessionToken, "TEST_EXPERIMENT2", "TEST_PROJECT", "TEST_SPACE");
+        // THEN
+        assertEquals(experiment.getCode(), "TEST_EXPERIMENT2");
+        assertEquals(experiment.getProject().getCode(), "TEST_PROJECT");
+        assertEquals(experiment.getProperties().get("$NAME"), "Other Value");
+        assertEquals(experiment.getProperties().get("DEFAULT_OBJECT_TYPE"), "Random string");
+    }
+
+    @Test
+    @DirtiesContext
+    public void testProjectsAreCreatedWithEverythingOnServer() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, EXPERIMENT_TYPE)));
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, SPACE)));
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, PROJECT)));
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, EXPERIMENTS_ALL_ELSEWHERE)));
+        // WHEN
+        Experiment experiment = TestUtils.getExperiment(v3api, sessionToken, "TEST_EXPERIMENT", "TEST_PROJECT", "TEST_SPACE");
+        // THEN
+        assertEquals(experiment.getCode(), "TEST_EXPERIMENT");
+        assertEquals(experiment.getProject().getCode(), "TEST_PROJECT");
+        assertEquals(experiment.getProperties().get("$NAME"), "Value");
+        assertEquals(experiment.getProperties().get("DEFAULT_OBJECT_TYPE"), "OBJECT_TYPE");
+    }
+
+    @Test
+    @DirtiesContext
+    public void testProjectsAreCreatedWithEverythingOnServerAndInXls() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, EXPERIMENT_TYPE)));
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, SPACE)));
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, PROJECT)));
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, EXPERIMENT_XLS)));
+        // WHEN
+        Experiment experiment = TestUtils.getExperiment(v3api, sessionToken, "TEST_EXPERIMENT", "TEST_PROJECT", "TEST_SPACE");
+        // THEN
+        assertEquals(experiment.getCode(), "TEST_EXPERIMENT");
+        assertEquals(experiment.getProject().getCode(), "TEST_PROJECT");
+        assertEquals(experiment.getProperties().get("$NAME"), "Value");
+        assertEquals(experiment.getProperties().get("DEFAULT_OBJECT_TYPE"), "OBJECT_TYPE");
+    }
+
+    @Test(expectedExceptions = UserFailureException.class)
+    public void shouldThrowExceptionIfExperimentTypeDoesntExist() throws IOException
+    {
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, SPACE)));
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, PROJECT)));
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, EXPERIMENTS_ALL_ELSEWHERE)));
+    }
+
+    @Test(expectedExceptions = UserFailureException.class)
+    public void shouldThrowExceptionIfProjectDoesntExist() throws IOException
+    {
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, EXPERIMENT_TYPE)));
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, SPACE)));
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, EXPERIMENTS_ALL_ELSEWHERE)));
+    }
+
+    @Test
+    @DirtiesContext
+    public void testProjectsAreCreatedWithTypeOnServer() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, EXPERIMENT_TYPE)));
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, EXPERIMENTS_WITH_TYPE_ELSEWHERE)));
+        // WHEN
+        Experiment experiment = TestUtils.getExperiment(v3api, sessionToken, "TEST_EXPERIMENT", "TEST_PROJECT", "TEST_SPACE");
+        // THEN
+        assertEquals(experiment.getCode(), "TEST_EXPERIMENT");
+        assertEquals(experiment.getProject().getCode(), "TEST_PROJECT");
+        assertEquals(experiment.getProperties().get("$NAME"), "Value");
+        assertEquals(experiment.getProperties().get("DEFAULT_OBJECT_TYPE"), "OBJECT_TYPE");
+    }
+
+    @Test
+    @DirtiesContext
+    public void testProjectsAreCreatedWithTypeOnServerAndInXls() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, EXPERIMENT_TYPE)));
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, SPACE)));
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, PROJECT)));
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, EXPERIMENTS_WITH_TYPE_ELSEWHERE)));
+        // WHEN
+        Experiment experiment = TestUtils.getExperiment(v3api, sessionToken, "TEST_EXPERIMENT", "TEST_PROJECT", "TEST_SPACE");
+        // THEN
+        assertEquals(experiment.getCode(), "TEST_EXPERIMENT");
+        assertEquals(experiment.getProject().getCode(), "TEST_PROJECT");
+        assertEquals(experiment.getProperties().get("$NAME"), "Value");
+        assertEquals(experiment.getProperties().get("DEFAULT_OBJECT_TYPE"), "OBJECT_TYPE");
+    }
+
+    @Test(expectedExceptions = UserFailureException.class)
+    public void shouldThrowExceptionIfExperimentNoCode() throws IOException
+    {
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, EXPERIMENTS_NO_CODE)));
+    }
+
+    @Test
+    @DirtiesContext
+    public void testProjectsAreCreatedWhenNonMandatoryPropertiesAreNotProvided() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, EXPERIMENTS_WITH_NON_MANDATORY_PROPERTY_MISSING)));
+        // WHEN
+        Experiment experiment = TestUtils.getExperiment(v3api, sessionToken, "TEST_EXPERIMENT", "TEST_PROJECT", "TEST_SPACE");
+        // THEN
+        assertEquals(experiment.getCode(), "TEST_EXPERIMENT");
+        assertEquals(experiment.getProject().getCode(), "TEST_PROJECT");
+        assertEquals(experiment.getProperties().get("$NAME"), null);
+        assertEquals(experiment.getProperties().get("DEFAULT_OBJECT_TYPE"), "OBJECT_TYPE");
+    }
+
+    @Test(expectedExceptions = UserFailureException.class)
+    public void shouldThrowExceptionIfExperimentNoProject() throws IOException
+    {
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, EXPERIMENTS_NO_PROJECT_ATTRIBUTE)));
+    }
+
+    @Test
+    @DirtiesContext
+    public void testProjectsAreCreatedWithSpaceAndProjectOnServer() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, SPACE)));
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, PROJECT)));
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, EXPERIMENTS_WITH_SPACE_AND_PROJECT_ELSEWHERE)));
+        // WHEN
+        Experiment experiment = TestUtils.getExperiment(v3api, sessionToken, "TEST_EXPERIMENT", "TEST_PROJECT", "TEST_SPACE");
+        // THEN
+        assertEquals(experiment.getCode(), "TEST_EXPERIMENT");
+        assertEquals(experiment.getProject().getCode(), "TEST_PROJECT");
+        assertEquals(experiment.getProperties().get("$NAME"), "Value");
+        assertEquals(experiment.getProperties().get("DEFAULT_OBJECT_TYPE"), "OBJECT_TYPE");
+    }
+
+    @Test
+    @DirtiesContext
+    public void testProjectsAreCreatedWithSpaceOnServer() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, SPACE)));
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, EXPERIMENTS_SPACE_ELSEWHERE)));
+        // WHEN
+        Experiment experiment = TestUtils.getExperiment(v3api, sessionToken, "TEST_EXPERIMENT", "TEST_PROJECT", "TEST_SPACE");
+        // THEN
+        assertEquals(experiment.getCode(), "TEST_EXPERIMENT");
+        assertEquals(experiment.getProject().getCode(), "TEST_PROJECT");
+        assertEquals(experiment.getProperties().get("$NAME"), "Value");
+        assertEquals(experiment.getProperties().get("DEFAULT_OBJECT_TYPE"), "OBJECT_TYPE");
+    }
+
+    @Test
+    @DirtiesContext
+    public void testProjectsAreCreatedWithTypeAndSpaceOnServer() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, EXPERIMENT_TYPE)));
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, SPACE)));
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, EXPERIMENTS_WITH_TYPE_AND_SPACE_ELSEWHERE)));
+        // WHEN
+        Experiment experiment = TestUtils.getExperiment(v3api, sessionToken, "TEST_EXPERIMENT", "TEST_PROJECT", "TEST_SPACE");
+        // THEN
+        assertEquals(experiment.getCode(), "TEST_EXPERIMENT");
+        assertEquals(experiment.getProject().getCode(), "TEST_PROJECT");
+        assertEquals(experiment.getProperties().get("$NAME"), "Value");
+        assertEquals(experiment.getProperties().get("DEFAULT_OBJECT_TYPE"), "OBJECT_TYPE");
+    }
+
+    @Test(expectedExceptions = UserFailureException.class)
+    public void shouldThrowExceptionIfMandatoryPropertyMissing() throws IOException
+    {
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, EXPERIMENTS_WITH_MANDATORY_PROPERTY_MISSING)));
+    }
+
+    @Test
+    @DirtiesContext
+    public void testProjectsAreCreatedIfMandatoryPropertyArePresent() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, EXPERIMENTS_WITH_MANDATORY_PROPERTY_PRESENT)));
+        // WHEN
+        Experiment experiment = TestUtils.getExperiment(v3api, sessionToken, "TEST_EXPERIMENT", "TEST_PROJECT", "TEST_SPACE");
+        // THEN
+        assertEquals(experiment.getCode(), "TEST_EXPERIMENT");
+        assertEquals(experiment.getProject().getCode(), "TEST_PROJECT");
+        assertEquals(experiment.getProperties().get("$NAME"), "Value");
+        assertEquals(experiment.getProperties().get("DEFAULT_OBJECT_TYPE"), "OBJECT_TYPE");
+    }
+
+    @Test
+    @DirtiesContext
+    public void testProjectsAreCreatedWhenPropertiesAreAddressedByLabelsWithTypeInXls() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, EXPERIMENTS_PROPERTIES_COLUMNS_AS_LABELS)));
+        // WHEN
+        Experiment experiment = TestUtils.getExperiment(v3api, sessionToken, "TEST_EXPERIMENT", "TEST_PROJECT", "TEST_SPACE");
+        // THEN
+        assertEquals(experiment.getCode(), "TEST_EXPERIMENT");
+        assertEquals(experiment.getProject().getCode(), "TEST_PROJECT");
+        assertEquals(experiment.getProperties().get("$NAME"), "Value");
+        assertEquals(experiment.getProperties().get("DEFAULT_OBJECT_TYPE"), "OBJECT_TYPE");
+    }
+
+    @Test
+    @DirtiesContext
+    public void testProjectsAreCreatedWhenPropertiesAreAddressedByLabelsWithTypeOnServer() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, EXPERIMENT_TYPE)));
+        TestUtils.createFrom(v3api, sessionToken,
+                Paths.get(FilenameUtils.concat(FILES_DIR, EXPERIMENTS_PROPERTIES_COLUMNS_AS_LABELS_TYPE_ON_SERVER)));
+        // WHEN
+        Experiment experiment = TestUtils.getExperiment(v3api, sessionToken, "TEST_EXPERIMENT", "TEST_PROJECT", "TEST_SPACE");
+        // THEN
+        assertEquals(experiment.getCode(), "TEST_EXPERIMENT");
+        assertEquals(experiment.getProject().getCode(), "TEST_PROJECT");
+        assertEquals(experiment.getProperties().get("$NAME"), "Value");
+        assertEquals(experiment.getProperties().get("DEFAULT_OBJECT_TYPE"), "OBJECT_TYPE");
+    }
+
+}
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/ImportProjectsTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/ImportProjectsTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..7685f9b3e40bf74460fe7eae26db8bbabe5ec6fb
--- /dev/null
+++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/ImportProjectsTest.java
@@ -0,0 +1,131 @@
+package ch.ethz.sis.openbis.systemtest.plugin.excelimport;
+
+import static org.testng.Assert.assertEquals;
+
+import java.io.IOException;
+import java.nio.file.Paths;
+
+import org.apache.commons.io.FilenameUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.transaction.TransactionConfiguration;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.project.Project;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.IApplicationServerInternalApi;
+import ch.systemsx.cisd.common.exceptions.UserFailureException;
+
+@ContextConfiguration(locations = "classpath:applicationContext.xml")
+@TransactionConfiguration(transactionManager = "transaction-manager")
+public class ImportProjectsTest extends AbstractImportTest
+{
+    @Autowired
+    private IApplicationServerInternalApi v3api;
+
+    private static final String TEST_USER = "test";
+
+    private static final String PASSWORD = "password";
+
+    private static final String PROJECTS_XLS = "projects/with_spaces.xls";
+
+    private static final String PROJECTS_NO_CODE = "projects/no_code.xls";
+
+    private static final String PROJECTS_NO_DESCRIPTION = "projects/no_desc.xls";
+
+    private static final String PROJECTS_NO_SPACE = "projects/no_space.xls";
+
+    private static final String PROJECTS_WITH_SPACES_ON_SERVER = "projects/with_spaces_on_server.xls";
+
+    private static final String SPACES = "projects/spaces.xls";
+
+    private static String FILES_DIR;
+
+    private String sessionToken;
+
+    @BeforeClass
+    public void setupClass() throws IOException
+    {
+        String testDir = Paths.get(ImportVocabularyTypesTest.class.getResource(this.getClass().getSimpleName() + ".class").getPath())
+                .getParent().toString();
+        FILES_DIR = FilenameUtils.concat(testDir, "test_files");
+    }
+
+    @BeforeMethod
+    public void beforeTest()
+    {
+        sessionToken = v3api.login(TEST_USER, PASSWORD);
+    }
+
+    @Test
+    @DirtiesContext
+    public void testProjectsAreCreated() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, PROJECTS_XLS)));
+        // WHEN
+        Project project = TestUtils.getProject(v3api, sessionToken, "TEST_PROJECT");
+        // THEN
+        assertEquals(project.getCode(), "TEST_PROJECT");
+        assertEquals(project.getDescription(), "TEST");
+        assertEquals(project.getSpace().getCode(), "TEST_SPACE");
+    }
+
+    @Test
+    @DirtiesContext
+    public void testProjectsAreCreatedSecondProject() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, PROJECTS_XLS)));
+        // WHEN
+        Project project = TestUtils.getProject(v3api, sessionToken, "TEST_PROJECT2");
+        // THEN
+        assertEquals(project.getCode(), "TEST_PROJECT2");
+        assertEquals(project.getDescription(), "description of another project");
+        assertEquals(project.getSpace().getCode(), "TEST_SPACE2");
+    }
+
+    @Test(expectedExceptions = UserFailureException.class)
+    public void shouldThrowExceptionIfNoProjectCode() throws IOException
+    {
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, PROJECTS_NO_CODE)));
+    }
+
+    @Test
+    @DirtiesContext
+    public void testProjectsAreCreatedNoDescription() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, PROJECTS_NO_DESCRIPTION)));
+        // WHEN
+        Project project = TestUtils.getProject(v3api, sessionToken, "TEST_PROJECT");
+        // THEN
+        assertEquals(project.getCode(), "TEST_PROJECT");
+        assertEquals(project.getDescription(), null);
+        assertEquals(project.getSpace().getCode(), "TEST_SPACE");
+    }
+
+    @Test(expectedExceptions = UserFailureException.class)
+    public void shouldThrowExceptionIfNoProjectSpace() throws IOException
+    {
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, PROJECTS_NO_SPACE)));
+    }
+
+    @Test
+    @DirtiesContext
+    public void testProjectsAreCreatedSpaceOnServer() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, SPACES)));
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, PROJECTS_WITH_SPACES_ON_SERVER)));
+        // WHEN
+        Project project = TestUtils.getProject(v3api, sessionToken, "TEST_PROJECT");
+        // THEN
+        assertEquals(project.getCode(), "TEST_PROJECT");
+        assertEquals(project.getDescription(), "TEST");
+        assertEquals(project.getSpace().getCode(), "TEST_SPACE");
+    }
+
+}
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/ImportPropertyTypesTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/ImportPropertyTypesTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..4c8a1b333dd61832cd134599694fd97407a18df4
--- /dev/null
+++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/ImportPropertyTypesTest.java
@@ -0,0 +1,148 @@
+package ch.ethz.sis.openbis.systemtest.plugin.excelimport;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import java.io.IOException;
+import java.nio.file.Paths;
+
+import org.apache.commons.io.FilenameUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.transaction.TransactionConfiguration;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.property.DataType;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.property.PropertyType;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.IApplicationServerInternalApi;
+import ch.systemsx.cisd.common.exceptions.UserFailureException;
+
+@ContextConfiguration(locations = "classpath:applicationContext.xml")
+@TransactionConfiguration(transactionManager = "transaction-manager")
+public class ImportPropertyTypesTest extends AbstractImportTest
+{
+
+    @Autowired
+    private IApplicationServerInternalApi v3api;
+
+    private static final String TEST_USER = "test";
+
+    private static final String PASSWORD = "password";
+
+    private static final String PROPERTY_TYPES_XLS = "property_types/normal_property_type.xls";
+
+    private static final String PROPERTY_NO_CODE = "property_types/no_code.xls";
+
+    private static final String PROPERTY_NO_DATA_TYPE = "property_types/no_data_type.xls";
+
+    private static final String PROPERTY_NO_DESCRIPTION = "property_types/no_desc.xls";
+
+    private static final String PROPERTY_NO_LABEL = "property_types/no_label.xls";
+
+    private static final String PROPERTY_VOCAB_TYPE_NO_VOCABULARY_CODE = "property_types/no_vocab_code.xls";
+
+    private static final String PROPERTY_NON_VOCAB_TYPE_VOCABULARY_CODE = "property_types/vocabcode_when_not_vocabtype.xls";
+
+    private static final String PROPERTY_VOCABULARY_ON_SERVER = "property_types/with_vocab_on_server.xls";
+
+    private static final String PROPERTY_VOCAB_TYPE = "property_types/with_vocab.xls";
+
+    private static final String VOCABULARY_DETECTION = "property_types/vocabulary_detection.xls";
+
+    private static String FILES_DIR;
+
+    private String sessionToken;
+
+    @BeforeClass
+    public void setupClass() throws IOException
+    {
+        String testDir = Paths.get(ImportVocabularyTypesTest.class.getResource(this.getClass().getSimpleName() + ".class").getPath())
+                .getParent().toString();
+        FILES_DIR = FilenameUtils.concat(testDir, "test_files");
+    }
+
+    @BeforeMethod
+    public void beforeTest()
+    {
+        sessionToken = v3api.login(TEST_USER, PASSWORD);
+    }
+
+    @Test
+    @DirtiesContext
+    public void testNormalPropertyTypesAreCreated() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, PROPERTY_TYPES_XLS)));
+        // WHEN
+        PropertyType notes = TestUtils.getPropertyType(v3api, sessionToken, "NOTES");
+        // THEN
+        assertEquals(notes.getCode(), "NOTES");
+        assertEquals(notes.getLabel(), "Notes");
+        assertEquals(notes.getDataType(), DataType.MULTILINE_VARCHAR);
+        assertEquals(notes.getDescription(), "Notes Descripton");
+        assertFalse(notes.isInternalNameSpace());
+        assertFalse(notes.isManagedInternally());
+        assertNull(notes.getVocabulary());
+    }
+
+    @Test
+    @DirtiesContext
+    public void testInternalPropertyTypesAreCreated() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, PROPERTY_TYPES_XLS)));
+        // WHEN
+        PropertyType notes = TestUtils.getPropertyType(v3api, sessionToken, "$INTERNAL_PROP");
+        // THEN
+        assertEquals(notes.getCode(), "$INTERNAL_PROP");
+        assertEquals(notes.getLabel(), "Name");
+        assertEquals(notes.getDataType(), DataType.VARCHAR);
+        assertEquals(notes.getDescription(), "Name");
+        assertTrue(notes.isInternalNameSpace());
+        assertFalse(notes.isManagedInternally());
+        assertNull(notes.getVocabulary());
+    }
+
+    @Test(expectedExceptions = UserFailureException.class)
+    public void testPropertyTypeNoCode() throws IOException
+    {
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, PROPERTY_NO_CODE)));
+    }
+
+    @Test(expectedExceptions = UserFailureException.class)
+    public void testPropertyTypeNoLabel() throws IOException
+    {
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, PROPERTY_NO_LABEL)));
+    }
+
+    @Test(expectedExceptions = UserFailureException.class)
+    public void testPropertyTypeNoVocabularyCodeWhenVocabularyType() throws IOException
+    {
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, PROPERTY_VOCAB_TYPE_NO_VOCABULARY_CODE)));
+    }
+
+    @Test(expectedExceptions = UserFailureException.class)
+    public void testPropertyTypeNoDataType() throws IOException
+    {
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, PROPERTY_NO_DATA_TYPE)));
+    }
+
+    @Test(expectedExceptions = UserFailureException.class)
+    public void testPropertyTypeNoDescription() throws IOException
+    {
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, PROPERTY_NO_DESCRIPTION)));
+    }
+
+    @Test(expectedExceptions = UserFailureException.class)
+    public void testPropertyTypeVocabularyCodeToNonVocabularyType() throws IOException
+    {
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, PROPERTY_NON_VOCAB_TYPE_VOCABULARY_CODE)));
+    }
+
+}
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/ImportSampleTypesTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/ImportSampleTypesTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..5e4a97922e6f9ac077f6e3913ec2eabd6f482d27
--- /dev/null
+++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/ImportSampleTypesTest.java
@@ -0,0 +1,233 @@
+package ch.ethz.sis.openbis.systemtest.plugin.excelimport;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import java.io.IOException;
+import java.nio.file.Paths;
+
+import org.apache.commons.io.FilenameUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.transaction.TransactionConfiguration;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.plugin.Plugin;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.plugin.PluginType;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.property.PropertyAssignment;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.SampleType;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.IApplicationServerInternalApi;
+import ch.systemsx.cisd.common.exceptions.UserFailureException;
+
+@ContextConfiguration(locations = "classpath:applicationContext.xml")
+@TransactionConfiguration(transactionManager = "transaction-manager")
+public class ImportSampleTypesTest extends AbstractImportTest
+{
+
+    private static final String SAMPLE_TYPES_XLS = "sample_types/normal_samples.xls";
+
+    private static final String SAMPLE_TYPES_XLS_DIFFERENT_PROPERTY_ASSIGN = "sample_types/normal_samples_v2.xls";
+
+    private static final String SAMPLE_TYPES_WITH_DYNAMIC_SCRIPT = "sample_types/with_dynamic_script.xls";
+
+    private static final String SAMPLE_TYPES_WITH_VALIDATION_SCRIPT = "sample_types/with_validation_script.xls";
+
+    private static final String SAMPLE_TYPES_WITH_VOCABULARY = "sample_types/with_vocabulary_in_xls.xls";
+
+    private static final String SAMPLE_TYPES_WITH_VOCABULARY_ON_SERVER = "sample_types/with_vocabulary_on_server.xls";
+
+    private static final String VOCABULARY_DETECTION = "sample_types/vocabulary_detection.xls";
+
+    private static final String SAMPLE_TYPES_WITH_AUTO_GENERATED_CODES = "sample_types/with_auto_generated_codes.xls";
+
+    private static final String SAMPLE_TYPE_NO_CODE = "sample_types/no_code.xls";
+
+    @Autowired
+    private IApplicationServerInternalApi v3api;
+
+    private static final String TEST_USER = "test";
+
+    private static final String PASSWORD = "password";
+
+    private static String FILES_DIR;
+
+    private String sessionToken;
+
+    @BeforeClass
+    public void setupClass() throws IOException
+    {
+        String testDir =
+                Paths.get(ImportVocabularyTypesTest.class.getResource(ImportVocabularyTypesTest.class.getSimpleName() + ".class").getPath())
+                        .getParent().toString();
+        FILES_DIR = FilenameUtils.concat(testDir, "test_files");
+    }
+
+    @BeforeMethod
+    public void beforeTest()
+    {
+        sessionToken = v3api.login(TEST_USER, PASSWORD);
+    }
+
+    @Test
+    @DirtiesContext
+    public void testNormalSampleTypesAreCreated() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, SAMPLE_TYPES_XLS)));
+        // WHEN
+        SampleType antibody = TestUtils.getSampleType(v3api, sessionToken, "ANTIBODY");
+        // THEN
+        assertFalse(antibody.isAutoGeneratedCode());
+    }
+
+    @Test
+    @DirtiesContext
+    public void testPropertyTypeAssignmentsFromNormalSampleTypesAreCreated() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, SAMPLE_TYPES_XLS)));
+        // WHEN
+        SampleType antibody = TestUtils.getSampleType(v3api, sessionToken, "ANTIBODY");
+        // THEN
+        boolean allMandatory = antibody.getPropertyAssignments().stream().allMatch(propAssignment -> propAssignment.isMandatory() == true);
+        boolean allShownInEditView =
+                antibody.getPropertyAssignments().stream().allMatch(propAssignment -> propAssignment.isShowInEditView() == true);
+        boolean generalInformationExists =
+                antibody.getPropertyAssignments().stream().anyMatch(propAssignment -> propAssignment.getSection().equals("General information"));
+        boolean someOtherSectionExists =
+                antibody.getPropertyAssignments().stream().anyMatch(propAssignment -> propAssignment.getSection().equals("Some other section"));
+        boolean threePropertyAssignments = antibody.getPropertyAssignments().size() == 3;
+        assertTrue(threePropertyAssignments);
+        assertTrue(generalInformationExists);
+        assertTrue(someOtherSectionExists);
+        assertTrue(allShownInEditView);
+        assertTrue(allMandatory);
+    }
+
+    @Test
+    @DirtiesContext
+    public void testPropertyTypeAssignmentsFromNormalv2SampleTypesAreCreated() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, SAMPLE_TYPES_XLS_DIFFERENT_PROPERTY_ASSIGN)));
+        // WHEN
+        SampleType antibody = TestUtils.getSampleType(v3api, sessionToken, "ANTIBODY");
+        // THEN
+        boolean allNotMandatory = antibody.getPropertyAssignments().stream().allMatch(propAssignment -> propAssignment.isMandatory() == false);
+        boolean allNotShownInEditView =
+                antibody.getPropertyAssignments().stream().allMatch(propAssignment -> propAssignment.isShowInEditView() == false);
+        boolean threePropertyAssignments = antibody.getPropertyAssignments().size() == 3;
+        assertTrue(threePropertyAssignments);
+        assertTrue(allNotShownInEditView);
+        assertTrue(allNotMandatory);
+    }
+
+    @Test
+    @DirtiesContext
+    public void testPropertyTypesFromNormalSampleTypesAreCreated() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, SAMPLE_TYPES_XLS)));
+        // WHEN
+        SampleType antibody = TestUtils.getSampleType(v3api, sessionToken, "ANTIBODY");
+        // THEN
+        boolean namePropertyExists =
+                antibody.getPropertyAssignments().stream().anyMatch(propAssignment -> propAssignment.getPropertyType().getCode().equals("$NAME"));
+        boolean forWhatPropertyExists =
+                antibody.getPropertyAssignments().stream().anyMatch(propAssignment -> propAssignment.getPropertyType().getCode().equals("FOR_WHAT"));
+        boolean epitopePropertyExists =
+                antibody.getPropertyAssignments().stream().anyMatch(propAssignment -> propAssignment.getPropertyType().getCode().equals("EPITOPE"));
+
+        assertNotNull(antibody);
+        assertTrue(namePropertyExists);
+        assertTrue(forWhatPropertyExists);
+        assertTrue(epitopePropertyExists);
+    }
+
+    @Test
+    @DirtiesContext
+    public void testSampleTypesWithPropertyHavingDynamicScript() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, TestUtils.getDynamicPluginMap(),
+                Paths.get(FilenameUtils.concat(FILES_DIR, SAMPLE_TYPES_WITH_DYNAMIC_SCRIPT)));
+        // WHEN
+        SampleType antibody = TestUtils.getSampleType(v3api, sessionToken, "ANTIBODY");
+        // THEN
+        Plugin dynamicScript = antibody.getPropertyAssignments().get(0).getPlugin();
+        assertNotNull(dynamicScript);
+        assertEquals(dynamicScript.getName().toUpperCase(), "$NAME.DYNAMIC");
+        assertEquals(dynamicScript.getScript(), TestUtils.getDynamicScript());
+        assertEquals(dynamicScript.getPluginType(), PluginType.DYNAMIC_PROPERTY);
+    }
+
+    @Test
+    @DirtiesContext
+    public void testSampleTypesWithPropertyHavingValidationScript() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, TestUtils.getValidationPluginMap(),
+                Paths.get(FilenameUtils.concat(FILES_DIR, SAMPLE_TYPES_WITH_VALIDATION_SCRIPT)));
+        // WHEN
+        SampleType antibody = TestUtils.getSampleType(v3api, sessionToken, "ANTIBODY");
+        // THEN
+        Plugin validationScript = antibody.getValidationPlugin();
+        assertNotNull(validationScript);
+        assertEquals(validationScript.getName().toUpperCase(), "ANTIBODY.VALID");
+        assertEquals(validationScript.getScript(), TestUtils.getValidationScript());
+        assertEquals(validationScript.getPluginType(), PluginType.ENTITY_VALIDATION);
+    }
+
+    @Test
+    @DirtiesContext
+    public void testSampleTypesWithVocabularyInXls() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, SAMPLE_TYPES_WITH_VOCABULARY)));
+        // WHEN
+        SampleType antibody = TestUtils.getSampleType(v3api, sessionToken, "ANTIBODY");
+        // THEN
+        PropertyAssignment propertyAssignment = antibody.getPropertyAssignments().get(0);
+        assertNotNull(propertyAssignment);
+        assertEquals(propertyAssignment.getPropertyType().getVocabulary().getCode(), "DETECTION");
+    }
+
+    @Test
+    @DirtiesContext
+    public void testSampleTypesWithVocabularyOnServer() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, VOCABULARY_DETECTION)));
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, SAMPLE_TYPES_WITH_VOCABULARY_ON_SERVER)));
+        // WHEN
+        SampleType antibody = TestUtils.getSampleType(v3api, sessionToken, "ANTIBODY");
+        // THEN
+        PropertyAssignment propertyAssignment = antibody.getPropertyAssignments().get(0);
+        assertNotNull(propertyAssignment);
+        assertEquals(propertyAssignment.getPropertyType().getVocabulary().getCode(), "DETECTION");
+    }
+
+    @Test
+    @DirtiesContext
+    public void testSampleTypesWithAutoGeneratedCodeAttribute() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, SAMPLE_TYPES_WITH_AUTO_GENERATED_CODES)));
+        // WHEN
+        SampleType antibody = TestUtils.getSampleType(v3api, sessionToken, "SECONDBODY");
+        // THEN
+        assertTrue(antibody.isAutoGeneratedCode());
+    }
+
+    @Test(expectedExceptions = UserFailureException.class)
+    public void shouldThrowExceptionIfNoSampleCode() throws IOException
+    {
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, SAMPLE_TYPE_NO_CODE)));
+    }
+
+}
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/ImportSamplesTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/ImportSamplesTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..3eb5d61c9395f92cc22e81caec1235c5b2c8daa5
--- /dev/null
+++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/ImportSamplesTest.java
@@ -0,0 +1,225 @@
+package ch.ethz.sis.openbis.systemtest.plugin.excelimport;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import org.apache.commons.io.FilenameUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.transaction.TransactionConfiguration;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.Sample;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.IApplicationServerInternalApi;
+import ch.systemsx.cisd.common.exceptions.UserFailureException;
+
+@ContextConfiguration(locations = "classpath:applicationContext.xml")
+@TransactionConfiguration(transactionManager = "transaction-manager")
+public class ImportSamplesTest extends AbstractImportTest
+{
+    @Autowired
+    private IApplicationServerInternalApi v3api;
+
+    private static final String TEST_USER = "test";
+
+    private static final String PASSWORD = "password";
+
+    private static final String SAMPLES_XLS = "samples/all_in.xls";
+
+    private static final String SAMPLES_SPACE_ELSEWHERE = "samples/space_elsewhere.xls";
+
+    private static final String SAMPLES_SAMPLE_TYPE_ELSWHERE = "samples/sample_type_elsewhere.xls";
+
+    private static final String SAMPLES_SPACE_PROJECT_EXPERIMENT_ELSEWHERE = "samples/space_project_experiment_elsewhere.xls";
+
+    private static final String SPACE = "samples/space.xls";
+
+    private static final String SAMPLE_TYPE = "samples/sample_type.xls";
+
+    private static final String VOCABULARY_TYPE = "samples/vocab_type.xls";
+
+    private static final String EXPERIMENT = "samples/experiment.xls";
+
+    private static final String EXPERIMENT_TYPE = "samples/experiment_type.xls";
+
+    private static final String PROJECT = "samples/project.xls";
+
+    private static String FILES_DIR;
+
+    private String sessionToken;
+
+    @BeforeClass
+    public void setupClass() throws IOException
+    {
+        String testDir = Paths.get(this.getClass().getResource(this.getClass().getSimpleName() + ".class").getPath())
+                .getParent().toString();
+        FILES_DIR = FilenameUtils.concat(testDir, "test_files");
+    }
+
+    @BeforeMethod
+    public void beforeTest()
+    {
+        sessionToken = v3api.login(TEST_USER, PASSWORD);
+    }
+
+    @Test
+    @DirtiesContext
+    public void testSamplesAreCreated() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, SAMPLES_XLS)));
+        // WHEN
+        Sample sample = TestUtils.getSample(v3api, sessionToken, "AAA", "TEST_SPACE");
+        // THEN
+        assertEquals(sample.getCode(), "AAA");
+        assertEquals(sample.getProject(), null);
+        assertEquals(sample.getExperiment().getCode(), "TEST_EXPERIMENT2");
+        assertEquals(sample.getSpace().getCode(), "TEST_SPACE");
+    }
+
+    @Test
+    @DirtiesContext
+    public void testSamplesAreCreatedSecondSample() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, SAMPLES_XLS)));
+        // WHEN
+        Sample sample = TestUtils.getSample(v3api, sessionToken, "VVV", "TEST_SPACE");
+        // THEN
+        assertEquals(sample.getCode(), "VVV");
+        assertEquals(sample.getProject(), null);
+        assertEquals(sample.getExperiment().getCode(), "TEST_EXPERIMENT");
+        assertEquals(sample.getSpace().getCode(), "TEST_SPACE");
+    }
+
+    @Test
+    @DirtiesContext
+    public void testSamplesAreCreatedThirdSample() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, SAMPLES_XLS)));
+        // WHEN
+        Sample sample = TestUtils.getSample(v3api, sessionToken, "S1", "TEST_SPACE");
+        // THEN
+        assertEquals(sample.getCode(), "S1");
+        assertEquals(sample.getProject(), null);
+        assertEquals(sample.getExperiment().getCode(), "TEST_EXPERIMENT");
+        assertEquals(sample.getSpace().getCode(), "TEST_SPACE");
+    }
+
+    @Test
+    @DirtiesContext
+    public void testSamplesAreCreatedWhenSpaceOnServer() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, SPACE)));
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, SAMPLES_SPACE_ELSEWHERE)));
+        // WHEN
+        Sample sample = TestUtils.getSample(v3api, sessionToken, "VVV", "TEST_SPACE");
+        // THEN
+        assertNotNull(sample);
+    }
+
+    @Test
+    @DirtiesContext
+    public void testSamplesAreCreatedWhenSpaceInSeparateXls() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken,
+                Paths.get(FilenameUtils.concat(FILES_DIR, SAMPLES_SPACE_ELSEWHERE)),
+                Paths.get(FilenameUtils.concat(FILES_DIR, SPACE)));
+        // WHEN
+        Sample sample = TestUtils.getSample(v3api, sessionToken, "VVV", "TEST_SPACE");
+        // THEN
+        assertNotNull(sample);
+    }
+
+    @Test(expectedExceptions = UserFailureException.class)
+    public void shouldThrowExceptionIfSpaceDoesntExist() throws IOException
+    {
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, SAMPLES_SPACE_ELSEWHERE)));
+    }
+
+    @Test
+    @DirtiesContext
+    public void testSamplesAreCreatedWhenSampleTypeOnServer() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken,
+                Paths.get(FilenameUtils.concat(FILES_DIR, VOCABULARY_TYPE)),
+                Paths.get(FilenameUtils.concat(FILES_DIR, SAMPLE_TYPE)));
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, SAMPLES_SAMPLE_TYPE_ELSWHERE)));
+        // WHEN
+        Sample sample = TestUtils.getSample(v3api, sessionToken, "VVV", "TEST_SPACE");
+        // THEN
+        assertNotNull(sample);
+    }
+
+    @Test
+    @DirtiesContext
+    public void testSamplesAreCreatedWhenSampleTypeInSeparateXls() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken,
+                Paths.get(FilenameUtils.concat(FILES_DIR, SAMPLES_SAMPLE_TYPE_ELSWHERE)),
+                Paths.get(FilenameUtils.concat(FILES_DIR, SAMPLE_TYPE)));
+        // WHEN
+        Sample sample = TestUtils.getSample(v3api, sessionToken, "VVV", "TEST_SPACE");
+        // THEN
+        assertNotNull(sample);
+    }
+
+    @Test(expectedExceptions = UserFailureException.class)
+    public void shouldThrowExceptionIfSamplesSpaceProjectDoesntExist() throws IOException
+    {
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, SAMPLES_SPACE_PROJECT_EXPERIMENT_ELSEWHERE)));
+    }
+
+    @Test
+    @DirtiesContext
+    public void testSamplesAreCreatedWhenSamplesSpaceProjectTypeOnServer() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, SPACE)));
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, PROJECT)));
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, EXPERIMENT_TYPE)));
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, EXPERIMENT)));
+        try
+        {
+            Thread.sleep(2000);
+        } catch (InterruptedException e)
+        {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, SAMPLES_SPACE_PROJECT_EXPERIMENT_ELSEWHERE)));
+        // WHEN
+        Sample sample = TestUtils.getSample(v3api, sessionToken, "VVV", "TEST_SPACE");
+        // THEN
+        assertNotNull(sample);
+    }
+
+    @Test
+    @DirtiesContext
+    public void testSamplesAreCreatedWhenSamplesSpaceProjectInSeparateXls() throws IOException
+    {
+        // GIVEN
+        Path space = Paths.get(FilenameUtils.concat(FILES_DIR, SPACE));
+        Path project = Paths.get(FilenameUtils.concat(FILES_DIR, PROJECT));
+        Path experiment = Paths.get(FilenameUtils.concat(FILES_DIR, EXPERIMENT));
+        Path samples = Paths.get(FilenameUtils.concat(FILES_DIR, SAMPLES_SPACE_PROJECT_EXPERIMENT_ELSEWHERE));
+        TestUtils.createFrom(v3api, sessionToken, space, experiment, samples, project);
+        // WHEN
+        Sample sample = TestUtils.getSample(v3api, sessionToken, "VVV", "TEST_SPACE");
+        // THEN
+        assertNotNull(sample);
+    }
+
+}
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/ImportSpacesTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/ImportSpacesTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..657e4b86a9605c7e6b277860b5ff3a9ea8a8e951
--- /dev/null
+++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/ImportSpacesTest.java
@@ -0,0 +1,103 @@
+package ch.ethz.sis.openbis.systemtest.plugin.excelimport;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
+import java.io.IOException;
+import java.nio.file.Paths;
+
+import org.apache.commons.io.FilenameUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.transaction.TransactionConfiguration;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.DataSetType;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.space.Space;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.IApplicationServerInternalApi;
+import ch.systemsx.cisd.common.exceptions.UserFailureException;
+
+@ContextConfiguration(locations = "classpath:applicationContext.xml")
+@TransactionConfiguration(transactionManager = "transaction-manager")
+public class ImportSpacesTest extends AbstractImportTest
+{
+    @Autowired
+    private IApplicationServerInternalApi v3api;
+
+    private static final String TEST_USER = "test";
+
+    private static final String PASSWORD = "password";
+
+    private static final String SPACES_XLS = "spaces/normal_spaces.xls";
+
+    private static final String SPACES_NO_CODE = "spaces/no_code.xls";
+
+    private static final String SPACES_NO_DESCRIPTION = "spaces/no_desc.xls";
+
+    private static String FILES_DIR;
+
+    private String sessionToken;
+
+    @BeforeClass
+    public void setupClass() throws IOException
+    {
+        String testDir = Paths.get(ImportVocabularyTypesTest.class.getResource(ImportVocabularyTypesTest.class.getSimpleName() + ".class").getPath())
+                .getParent().toString();
+        FILES_DIR = FilenameUtils.concat(testDir, "test_files");
+    }
+
+    @BeforeMethod
+    public void beforeTest()
+    {
+        sessionToken = v3api.login(TEST_USER, PASSWORD);
+    }
+
+    @Test
+    @DirtiesContext
+    public void testNormalSpacesAreCreated() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, SPACES_XLS)));
+        // WHEN
+        Space rawData = TestUtils.getSpace(v3api, sessionToken, "TEST_SPACE");
+        // THEN
+        assertEquals(rawData.getCode(), "TEST_SPACE");
+        assertEquals(rawData.getDescription(), "TEST");
+    }
+
+    @Test
+    @DirtiesContext
+    public void testNormalSpacesAreCreatedSecondSpace() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, SPACES_XLS)));
+        // WHEN
+        Space space = TestUtils.getSpace(v3api, sessionToken, "TEST_SPACE2");
+        // THEN
+        assertEquals(space.getCode(), "TEST_SPACE2");
+        assertEquals(space.getDescription(), "TEST desc");
+    }
+
+    @Test(expectedExceptions = UserFailureException.class)
+    public void shouldThrowExceptionIfNoSpaceCode() throws IOException
+    {
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, SPACES_NO_CODE)));
+    }
+
+    @Test
+    @DirtiesContext
+    public void shouldCreateSpaceWhenNoDescription() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, SPACES_NO_DESCRIPTION)));
+        // WHEN
+        Space space = TestUtils.getSpace(v3api, sessionToken, "TEST_SPACE");
+        // THEN
+        assertEquals(space.getCode(), "TEST_SPACE");
+        assertEquals(space.getDescription(), null);
+    }
+
+}
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/ImportVocabularyTypesTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/ImportVocabularyTypesTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..5c4f3ae5791cdea835715022bc704b64532f57dc
--- /dev/null
+++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/ImportVocabularyTypesTest.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright 2015 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.systemtest.plugin.excelimport;
+
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertEquals;
+
+import java.io.IOException;
+import java.nio.file.Paths;
+import java.util.List;
+
+import org.apache.commons.io.FilenameUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.testng.AbstractTransactionalTestNGSpringContextTests;
+import org.springframework.test.context.transaction.TransactionConfiguration;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.BeforeSuite;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.vocabulary.Vocabulary;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.vocabulary.VocabularyTerm;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.IApplicationServerInternalApi;
+import ch.systemsx.cisd.common.exceptions.UserFailureException;
+import ch.systemsx.cisd.openbis.generic.server.util.TestInitializer;
+import ch.systemsx.cisd.openbis.generic.shared.Constants;
+import ch.systemsx.cisd.openbis.generic.shared.coreplugin.CorePluginsUtils;
+
+@ContextConfiguration(locations = "classpath:applicationContext.xml")
+@TransactionConfiguration(transactionManager = "transaction-manager")
+public class ImportVocabularyTypesTest extends AbstractImportTest
+{
+
+    private static final String VOCABULARIES_TYPES_XLS = "vocabularies/normal_vocab.xls";
+
+    private static final String VOCABULARIES_NO_CODE = "vocabularies/vocab_no_code.xlsx";
+
+    private static final String VOCABULARIES_NO_DESCRIPTION = "vocabularies/vocab_no_desc.xlsx";
+
+    private static final String VOCABULARIES_NO_TERM_CODE = "vocabularies/vocab_no_term_code.xlsx";
+
+    private static final String VOCABULARIES_NO_TERM_DESCRIPTION = "vocabularies/vocab_no_term_desc.xlsx";
+
+    private static final String VOCABULARIES_NO_TERM_LABEL = "vocabularies/vocab_no_term_label.xlsx";
+
+    private static final String VOCABULARIES_NO_TERMS = "vocabularies/vocab_no_term_label.xlsx";
+
+    @Autowired
+    private IApplicationServerInternalApi v3api;
+
+    private static final String TEST_USER = "test";
+
+    private static final String PASSWORD = "password";
+
+    private static String FILES_DIR;
+
+    private String sessionToken;
+
+    @BeforeClass
+    public void setupClass() throws IOException
+    {
+        String testDir =
+                Paths.get(ImportVocabularyTypesTest.class.getResource(ImportVocabularyTypesTest.class.getSimpleName() + ".class").getPath())
+                        .getParent().toString();
+        FILES_DIR = FilenameUtils.concat(testDir, "test_files");
+
+    }
+
+    @BeforeMethod
+    public void beforeTest()
+    {
+        sessionToken = v3api.login(TEST_USER, PASSWORD);
+    }
+
+    @Test
+    @DirtiesContext
+    public void testNormalVocabularyCreationIsCreated() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, VOCABULARIES_TYPES_XLS)));
+        // WHEN
+        Vocabulary detection = TestUtils.getVocabulary(v3api, sessionToken, "DETECTION");
+        // THEN
+        assertNotNull(detection);
+        assertEquals(detection.getDescription(), "Protein detection system");
+    }
+
+    @Test
+    @DirtiesContext
+    public void testNormalVocabularyHasFirstTermCreated() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, VOCABULARIES_TYPES_XLS)));
+        // WHEN
+        Vocabulary detection = TestUtils.getVocabulary(v3api, sessionToken, "DETECTION");
+        // THEN
+        VocabularyTerm term = detection.getTerms().get(0);
+        assertEquals(term.getCode(), "HRP");
+        assertEquals(term.getDescription(), "The antibody is conjugated with the horseradish peroxydase");
+        assertEquals(term.getLabel(), "horseradish peroxydase");
+    }
+
+    @Test
+    @DirtiesContext
+    public void testNormalVocabularyCreatedNoExtraVocabulary() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, VOCABULARIES_TYPES_XLS)));
+        // WHEN
+        List<Vocabulary> vocabularies = TestUtils.getAllVocabularies(v3api, sessionToken);
+        // THEN
+        assertEquals(vocabularies.size(), 3); // 2 created + 1 default
+    }
+
+    @Test
+    @DirtiesContext
+    public void testNormalVocabularyHasSecondTermCreated() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, VOCABULARIES_TYPES_XLS)));
+        // WHEN
+        Vocabulary detection = TestUtils.getVocabulary(v3api, sessionToken, "DETECTION");
+        // THEN
+        VocabularyTerm term = detection.getTerms().get(1);
+        assertEquals(term.getCode(), "TEST_VOC");
+        assertEquals(term.getDescription(), "some focabulary that is used in tests and nothing else");
+        assertEquals(term.getLabel(), "vocabulary for tests");
+    }
+
+    @Test(expectedExceptions = UserFailureException.class)
+    public void shouldThrowExceptionIfNoVocabularyCode() throws IOException
+    {
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, VOCABULARIES_NO_CODE)));
+    }
+
+    @Test(expectedExceptions = UserFailureException.class)
+    public void shouldThrowExceptionIfNoTermCode() throws IOException
+    {
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, VOCABULARIES_NO_TERM_CODE)));
+    }
+
+    @Test
+    public void shouldNotThrowExceptionIfNoVocabularyDescription() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, VOCABULARIES_NO_DESCRIPTION)));
+        // WHEN
+        Vocabulary detection = TestUtils.getVocabulary(v3api, sessionToken, "DETECTION");
+        // THEN
+        assertNotNull(detection);
+        assertNull(detection.getDescription());
+    }
+
+    @Test
+    public void shouldNotThrowExceptionIfNoTermLabel() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, VOCABULARIES_NO_TERM_LABEL)));
+        // WHEN
+        Vocabulary detection = TestUtils.getVocabulary(v3api, sessionToken, "DETECTION");
+        // THEN
+        assertNotNull(detection);
+        assertNull(detection.getTerms().get(0).getLabel());
+    }
+
+    @Test
+    public void shouldNotThrowExceptionIfNoTerms() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, VOCABULARIES_NO_TERMS)));
+        // WHEN
+        Vocabulary detection = TestUtils.getVocabulary(v3api, sessionToken, "DETECTION");
+        // THEN
+        assertNotNull(detection);
+    }
+
+    @Test
+    public void w() throws IOException
+    {
+        // GIVEN
+        TestUtils.createFrom(v3api, sessionToken, Paths.get(FilenameUtils.concat(FILES_DIR, VOCABULARIES_NO_TERM_DESCRIPTION)));
+        // WHEN
+        Vocabulary detection = TestUtils.getVocabulary(v3api, sessionToken, "DETECTION");
+        // THEN
+        assertNotNull(detection);
+        assertNull(detection.getTerms().get(0).getDescription());
+    }
+
+}
\ No newline at end of file
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/TestUtils.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/TestUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..a64c2107175a56024ed4e7058145b3a7d7244172
--- /dev/null
+++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/TestUtils.java
@@ -0,0 +1,318 @@
+package ch.ethz.sis.openbis.systemtest.plugin.excelimport;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.search.SearchResult;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.DataSetType;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.fetchoptions.DataSetTypeFetchOptions;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.search.DataSetTypeSearchCriteria;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.Experiment;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.ExperimentType;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.fetchoptions.ExperimentFetchOptions;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.fetchoptions.ExperimentTypeFetchOptions;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.id.ExperimentIdentifier;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.id.IExperimentId;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.search.ExperimentTypeSearchCriteria;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.project.Project;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.project.fetchoptions.ProjectFetchOptions;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.project.search.ProjectSearchCriteria;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.property.PropertyType;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.property.fetchoptions.PropertyAssignmentFetchOptions;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.property.fetchoptions.PropertyTypeFetchOptions;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.property.search.PropertyTypeSearchCriteria;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.Sample;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.SampleType;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.fetchoptions.SampleFetchOptions;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.fetchoptions.SampleTypeFetchOptions;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.id.ISampleId;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.id.SampleIdentifier;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.search.SampleTypeSearchCriteria;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.service.CustomASServiceExecutionOptions;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.service.id.CustomASServiceCode;
+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.asapi.v3.dto.vocabulary.Vocabulary;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.vocabulary.fetchoptions.VocabularyFetchOptions;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.vocabulary.id.VocabularyPermId;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.vocabulary.search.VocabularySearchCriteria;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.IApplicationServerInternalApi;
+
+public class TestUtils
+{
+
+    public static final String XLS_PARAM = "xls";
+
+    public static final String SCRIPTS_PARAM = "scripts";
+
+    public static final String XLS_IMPORT_API = "xls-import-api";
+
+    static Vocabulary getVocabulary(IApplicationServerInternalApi v3api, String sessionToken, String code)
+    {
+        VocabularySearchCriteria criteria = new VocabularySearchCriteria();
+        criteria.withId().thatEquals(new VocabularyPermId(code));
+
+        VocabularyFetchOptions fo = new VocabularyFetchOptions();
+        fo.withTerms();
+
+        SearchResult<Vocabulary> result = v3api.searchVocabularies(sessionToken, criteria, fo);
+
+        if (result.getObjects().size() > 0)
+        {
+            return result.getObjects().get(0);
+        } else
+        {
+            return null;
+        }
+    }
+
+    static List<Vocabulary> getAllVocabularies(IApplicationServerInternalApi v3api, String sessionToken)
+    {
+        VocabularySearchCriteria criteria = new VocabularySearchCriteria();
+        VocabularyFetchOptions fo = new VocabularyFetchOptions();
+        fo.withTerms();
+
+        SearchResult<Vocabulary> result = v3api.searchVocabularies(sessionToken, criteria, fo);
+
+        if (result.getObjects().size() > 0)
+        {
+            return result.getObjects();
+        } else
+        {
+            return null;
+        }
+    }
+
+    static SampleType getSampleType(IApplicationServerInternalApi v3api, String sessionToken, String code)
+    {
+        SampleTypeSearchCriteria criteria = new SampleTypeSearchCriteria();
+        criteria.withCode().thatEquals(code);
+
+        SampleTypeFetchOptions fo = new SampleTypeFetchOptions();
+        fo.withValidationPlugin().withScript();
+        PropertyAssignmentFetchOptions propCriteria = fo.withPropertyAssignments();
+        propCriteria.withPlugin().withScript();
+        propCriteria.withPropertyType().withVocabulary();
+
+        SearchResult<SampleType> result = v3api.searchSampleTypes(sessionToken, criteria, fo);
+
+        if (result.getObjects().size() > 0)
+        {
+            return result.getObjects().get(0);
+        } else
+        {
+            return null;
+        }
+    }
+
+    static ExperimentType getExperimentType(IApplicationServerInternalApi v3api, String sessionToken, String code)
+    {
+        ExperimentTypeSearchCriteria criteria = new ExperimentTypeSearchCriteria();
+        criteria.withCode().thatEquals(code);
+
+        ExperimentTypeFetchOptions fo = new ExperimentTypeFetchOptions();
+        fo.withValidationPlugin().withScript();
+        PropertyAssignmentFetchOptions propCriteria = fo.withPropertyAssignments();
+        propCriteria.withPlugin().withScript();
+        propCriteria.withPropertyType().withVocabulary();
+
+        SearchResult<ExperimentType> result = v3api.searchExperimentTypes(sessionToken, criteria, fo);
+
+        if (result.getObjects().size() > 0)
+        {
+            return result.getObjects().get(0);
+        } else
+        {
+            return null;
+        }
+    }
+
+    static DataSetType getDatasetType(IApplicationServerInternalApi v3api, String sessionToken, String code)
+    {
+        DataSetTypeSearchCriteria criteria = new DataSetTypeSearchCriteria();
+        criteria.withCode().thatEquals(code);
+
+        DataSetTypeFetchOptions fo = new DataSetTypeFetchOptions();
+        fo.withValidationPlugin().withScript();
+        PropertyAssignmentFetchOptions propCriteria = fo.withPropertyAssignments();
+        propCriteria.withPlugin().withScript();
+        propCriteria.withPropertyType().withVocabulary();
+
+        SearchResult<DataSetType> result = v3api.searchDataSetTypes(sessionToken, criteria, fo);
+
+        if (result.getObjects().size() > 0)
+        {
+            return result.getObjects().get(0);
+        } else
+        {
+            return null;
+        }
+    }
+
+    static PropertyType getPropertyType(IApplicationServerInternalApi v3api, String sessionToken, String code)
+    {
+        PropertyTypeSearchCriteria criteria = new PropertyTypeSearchCriteria();
+        criteria.withCode().thatEquals(code);
+
+        PropertyTypeFetchOptions fo = new PropertyTypeFetchOptions();
+        fo.withVocabulary();
+
+        SearchResult<PropertyType> result = v3api.searchPropertyTypes(sessionToken, criteria, fo);
+
+        if (result.getObjects().size() > 0)
+        {
+            return result.getObjects().get(0);
+        } else
+        {
+            return null;
+        }
+    }
+
+    static Space getSpace(IApplicationServerInternalApi v3api, String sessionToken, String code)
+    {
+        SpaceSearchCriteria criteria = new SpaceSearchCriteria();
+        criteria.withCode().thatEquals(code);
+
+        SpaceFetchOptions fo = new SpaceFetchOptions();
+
+        SearchResult<Space> result = v3api.searchSpaces(sessionToken, criteria, fo);
+
+        if (result.getObjects().size() > 0)
+        {
+            return result.getObjects().get(0);
+        } else
+        {
+            return null;
+        }
+    }
+
+    static Project getProject(IApplicationServerInternalApi v3api, String sessionToken, String code)
+    {
+        ProjectSearchCriteria criteria = new ProjectSearchCriteria();
+        criteria.withCode().thatEquals(code);
+
+        ProjectFetchOptions fo = new ProjectFetchOptions();
+        fo.withSpace();
+
+        SearchResult<Project> result = v3api.searchProjects(sessionToken, criteria, fo);
+
+        if (result.getObjects().size() > 0)
+        {
+            return result.getObjects().get(0);
+        } else
+        {
+            return null;
+        }
+    }
+
+    static Experiment getExperiment(IApplicationServerInternalApi v3api, String sessionToken, String experimentCode, String projectCode,
+            String spaceCode)
+    {
+        List<IExperimentId> ids = new ArrayList<>();
+        ids.add(new ExperimentIdentifier(spaceCode, projectCode, experimentCode));
+
+        ExperimentFetchOptions fo = new ExperimentFetchOptions();
+        fo.withProject();
+        fo.withProperties();
+        fo.withType();
+
+        List<Experiment> result = v3api.getExperiments(sessionToken, ids, fo).values().stream().collect(Collectors.toList());
+
+        if (result.size() > 0)
+        {
+            return result.get(0);
+        } else
+        {
+            return null;
+        }
+    }
+
+    static Sample getSample(IApplicationServerInternalApi v3api, String sessionToken, String sampleCode, String spaceCode)
+    {
+        List<ISampleId> ids = new ArrayList<>();
+        ids.add(new SampleIdentifier(spaceCode, null, null, sampleCode));
+
+        SampleFetchOptions fo = new SampleFetchOptions();
+        fo.withChildren();
+        fo.withParents();
+        fo.withExperiment();
+        fo.withProject();
+        fo.withProperties();
+        fo.withSpace();
+        fo.withType();
+
+        List<Sample> result = v3api.getSamples(sessionToken, ids, fo).values().stream().collect(Collectors.toList());
+
+        if (result.size() > 0)
+        {
+            return result.get(0);
+        } else
+        {
+            return null;
+        }
+    }
+
+    static String createFrom(IApplicationServerInternalApi v3api, String sessionToken, Path... xls_paths) throws IOException
+    {
+        List<byte[]> excels = new ArrayList<>();
+        for (Path xls_path : xls_paths)
+        {
+            byte[] xls = Files.readAllBytes(xls_path);
+            excels.add(xls);
+        }
+        CustomASServiceExecutionOptions options = new CustomASServiceExecutionOptions();
+        options.withParameter(XLS_PARAM, excels);
+        return (String) v3api.executeCustomASService(sessionToken, new CustomASServiceCode(XLS_IMPORT_API), options);
+    }
+
+    static String createFrom(IApplicationServerInternalApi v3api, String sessionToken, Map<String, String> scripts, Path... xls_paths)
+            throws IOException
+    {
+        List<byte[]> excels = new ArrayList<>();
+        for (Path xls_path : xls_paths)
+        {
+            byte[] xls = Files.readAllBytes(xls_path);
+            excels.add(xls);
+        }
+        CustomASServiceExecutionOptions options = new CustomASServiceExecutionOptions();
+        options.withParameter(XLS_PARAM, excels);
+        options.withParameter(SCRIPTS_PARAM, scripts);
+        return (String) v3api.executeCustomASService(sessionToken, new CustomASServiceCode(XLS_IMPORT_API), options);
+    }
+
+    static String getValidationScript()
+    {
+        return "def validate(entity, isNew):\n  if isNew:\n    return";
+    }
+
+    static String getDynamicScript()
+    {
+        return "def calculate():\n    return 1";
+    }
+
+    static Map<String, String> getValidationPluginMap()
+    {
+        String dynamicScriptString = getValidationScript();
+        Map<String, String> scriptsMap = new HashMap<>();
+        scriptsMap.put("valid.py", dynamicScriptString);
+
+        return scriptsMap;
+    }
+
+    static Map<String, String> getDynamicPluginMap()
+    {
+        String dynamicScriptString = getDynamicScript();
+        Map<String, String> scriptsMap = new HashMap<>();
+        scriptsMap.put("dynamic/dynamic.py", dynamicScriptString);
+
+        return scriptsMap;
+    }
+
+}
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/dataset_types/no_code.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/dataset_types/no_code.xls
new file mode 100644
index 0000000000000000000000000000000000000000..d54b992af7d5ef3497b591b71b0a937aeecee4c6
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/dataset_types/no_code.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/dataset_types/no_properties.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/dataset_types/no_properties.xls
new file mode 100644
index 0000000000000000000000000000000000000000..5a4648215981dec891c3791194051c2e247ddbfd
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/dataset_types/no_properties.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/dataset_types/normal_dataset.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/dataset_types/normal_dataset.xls
new file mode 100644
index 0000000000000000000000000000000000000000..d72039c8ae394e9954c07af64559e7d34a812961
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/dataset_types/normal_dataset.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/dataset_types/with_validation.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/dataset_types/with_validation.xls
new file mode 100644
index 0000000000000000000000000000000000000000..cdee2cb18599a074ff8c34a4666c7a46027d080c
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/dataset_types/with_validation.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiment_types/no_code.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiment_types/no_code.xls
new file mode 100644
index 0000000000000000000000000000000000000000..bcae94a211270a70536fbeb0c0128e35813f4d76
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiment_types/no_code.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiment_types/normal_experiment.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiment_types/normal_experiment.xls
new file mode 100644
index 0000000000000000000000000000000000000000..d3c3dda61bd16fa12d7ab9bbaf65cba6ba70caa2
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiment_types/normal_experiment.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiment_types/with_validation_script.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiment_types/with_validation_script.xls
new file mode 100644
index 0000000000000000000000000000000000000000..20daeadf5af7c7a35d34185b165cb95a6decfc23
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiment_types/with_validation_script.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/all_elsewhere.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/all_elsewhere.xls
new file mode 100644
index 0000000000000000000000000000000000000000..fa502e8210ac48b660a275973dd373cabdbc351a
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/all_elsewhere.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/all_inside.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/all_inside.xls
new file mode 100644
index 0000000000000000000000000000000000000000..48fe7da35a0f258b912a5449d61a69dab46ebc64
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/all_inside.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/experiment_type.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/experiment_type.xls
new file mode 100644
index 0000000000000000000000000000000000000000..79d7b595f514ef121fb09f982c5e9ec1f50efe05
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/experiment_type.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/experiment_type_elsewhere.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/experiment_type_elsewhere.xls
new file mode 100644
index 0000000000000000000000000000000000000000..5b5939c6d0491056bdd0f551c2df7bbade805f1c
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/experiment_type_elsewhere.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/no_code.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/no_code.xls
new file mode 100644
index 0000000000000000000000000000000000000000..e768de099fb1028c3c631e60384f6a6037d2075d
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/no_code.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/no_non_mandatory_property.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/no_non_mandatory_property.xls
new file mode 100644
index 0000000000000000000000000000000000000000..f6f9c73a5872c901a041afe139ca6097153a81e8
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/no_non_mandatory_property.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/no_project.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/no_project.xls
new file mode 100644
index 0000000000000000000000000000000000000000..b10a360b48af59ead2b011f4697a55e325679f64
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/no_project.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/project.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/project.xls
new file mode 100644
index 0000000000000000000000000000000000000000..22fe9892d7d761ca40f1007c3ad4d257c1eedf6e
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/project.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/space.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/space.xls
new file mode 100644
index 0000000000000000000000000000000000000000..f38abaf801838e24b49534c7e95ec11d69a5733d
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/space.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/space_and_project_elsewhere.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/space_and_project_elsewhere.xls
new file mode 100644
index 0000000000000000000000000000000000000000..662154538b1d733036d6d7ae60cc5e6948175f7a
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/space_and_project_elsewhere.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/space_elsewhere.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/space_elsewhere.xls
new file mode 100644
index 0000000000000000000000000000000000000000..002041a89a52c99a4b3334778eca0e2e715a317d
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/space_elsewhere.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/type_and_space_elsewhere.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/type_and_space_elsewhere.xls
new file mode 100644
index 0000000000000000000000000000000000000000..ca53bd70919b60029dcf4876ff0a65571c3f9224
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/type_and_space_elsewhere.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/with_mandatory_property.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/with_mandatory_property.xls
new file mode 100644
index 0000000000000000000000000000000000000000..bb9a38e731caee28ea3164d7735da5a8c3aee1fc
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/with_mandatory_property.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/with_mandatory_property_missing.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/with_mandatory_property_missing.xls
new file mode 100644
index 0000000000000000000000000000000000000000..2232c73fd30a0d85ffb21a4146f818f333fa6989
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/with_mandatory_property_missing.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/with_properties_as_labels.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/with_properties_as_labels.xls
new file mode 100644
index 0000000000000000000000000000000000000000..2cd522d4a96d4eda75587ba4878e561e26fe5085
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/with_properties_as_labels.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/with_properties_as_labels_type_elsewhere.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/with_properties_as_labels_type_elsewhere.xls
new file mode 100644
index 0000000000000000000000000000000000000000..05a162bffb0ed5d4a768e0414d1b5c7c64a3c860
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/experiments/with_properties_as_labels_type_elsewhere.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/full/scripts/dynamic/dynamic.py b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/full/scripts/dynamic/dynamic.py
new file mode 100644
index 0000000000000000000000000000000000000000..187583711b0b2d81f1ad5525763cae8d23561239
--- /dev/null
+++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/full/scripts/dynamic/dynamic.py
@@ -0,0 +1,2 @@
+def calculate():
+    return 1
\ No newline at end of file
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/full/scripts/valid.py b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/full/scripts/valid.py
new file mode 100644
index 0000000000000000000000000000000000000000..d87950f600d11b50b96dcedef36fe8f36971140c
--- /dev/null
+++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/full/scripts/valid.py
@@ -0,0 +1,3 @@
+def validate(entity, isNew):
+  if isNew:
+    return
\ No newline at end of file
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/full/types.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/full/types.xls
new file mode 100644
index 0000000000000000000000000000000000000000..c859da3c3dcf761af1c72df29ba1ba1f8f583e59
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/full/types.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/projects/no_code.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/projects/no_code.xls
new file mode 100644
index 0000000000000000000000000000000000000000..40565df30dd0a1cbab6b9fd1bf8e98cc37d98713
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/projects/no_code.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/projects/no_desc.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/projects/no_desc.xls
new file mode 100644
index 0000000000000000000000000000000000000000..256aff470a2c0e67bf6e8ca7c0574b57bfd9384a
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/projects/no_desc.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/projects/no_space.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/projects/no_space.xls
new file mode 100644
index 0000000000000000000000000000000000000000..be1a6f5b673089c4d40f17c3f79ed055202e3736
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/projects/no_space.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/projects/spaces.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/projects/spaces.xls
new file mode 100644
index 0000000000000000000000000000000000000000..ee521c4efcf08b1f3263ffbf239d07a1f784ab2b
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/projects/spaces.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/projects/with_spaces.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/projects/with_spaces.xls
new file mode 100644
index 0000000000000000000000000000000000000000..124040d0a40c49d88cec4de77dab2616c88e355f
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/projects/with_spaces.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/projects/with_spaces_on_server.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/projects/with_spaces_on_server.xls
new file mode 100644
index 0000000000000000000000000000000000000000..c372754c23f24f7491ca9e20132dd151d05a881f
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/projects/with_spaces_on_server.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/property_types/no_code.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/property_types/no_code.xls
new file mode 100644
index 0000000000000000000000000000000000000000..0495c967c5583cdd003fa7db0d9e03bd3ac53660
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/property_types/no_code.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/property_types/no_data_type.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/property_types/no_data_type.xls
new file mode 100644
index 0000000000000000000000000000000000000000..ea8c86ae63ab1cd00c3925c7ad483bad33f98918
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/property_types/no_data_type.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/property_types/no_desc.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/property_types/no_desc.xls
new file mode 100644
index 0000000000000000000000000000000000000000..a93f2d1d00f5c469c84e476b82264e5f35b7df95
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/property_types/no_desc.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/property_types/no_label.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/property_types/no_label.xls
new file mode 100644
index 0000000000000000000000000000000000000000..2920993c13829a6ef699a562d4d1df250ae36226
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/property_types/no_label.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/property_types/no_vocab_code.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/property_types/no_vocab_code.xls
new file mode 100644
index 0000000000000000000000000000000000000000..30f6effc706cf7eaa62952b3477469eedfda1a36
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/property_types/no_vocab_code.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/property_types/normal_property_type.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/property_types/normal_property_type.xls
new file mode 100644
index 0000000000000000000000000000000000000000..b60b0d1af6c8bcc493e04f7ab025c2f30bcba1b4
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/property_types/normal_property_type.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/property_types/vocabcode_when_not_vocabtype.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/property_types/vocabcode_when_not_vocabtype.xls
new file mode 100644
index 0000000000000000000000000000000000000000..07b06775fb363a9c78ca6845927f0ce4d1baf16e
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/property_types/vocabcode_when_not_vocabtype.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/property_types/vocabulary_detection.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/property_types/vocabulary_detection.xls
new file mode 100644
index 0000000000000000000000000000000000000000..9dbed1010de4ae51769dcd5dc3f427bbcda4cc50
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/property_types/vocabulary_detection.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/property_types/with_vocab.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/property_types/with_vocab.xls
new file mode 100644
index 0000000000000000000000000000000000000000..c11888fc27960ed5f93d193e2d8e5c4e50e398e7
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/property_types/with_vocab.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/property_types/with_vocab_on_server.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/property_types/with_vocab_on_server.xls
new file mode 100644
index 0000000000000000000000000000000000000000..97378724a33e3c75a66a7e7b98343673fdd57991
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/property_types/with_vocab_on_server.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/sample_types/no_code.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/sample_types/no_code.xls
new file mode 100644
index 0000000000000000000000000000000000000000..a20c2669d8420cc4f14dd1e7f570d97344fd8a0c
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/sample_types/no_code.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/sample_types/normal_samples.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/sample_types/normal_samples.xls
new file mode 100644
index 0000000000000000000000000000000000000000..26f1ce1b3d41182ad5ee0b16def5a35afd8ced4a
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/sample_types/normal_samples.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/sample_types/normal_samples_v2.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/sample_types/normal_samples_v2.xls
new file mode 100644
index 0000000000000000000000000000000000000000..9ca2cccef1e90d0d169369dcb19e04e8a9584685
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/sample_types/normal_samples_v2.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/sample_types/vocabulary_detection.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/sample_types/vocabulary_detection.xls
new file mode 100644
index 0000000000000000000000000000000000000000..778cead50ffb0439af049dfeed92324f4c52acd0
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/sample_types/vocabulary_detection.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/sample_types/with_auto_generated_codes.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/sample_types/with_auto_generated_codes.xls
new file mode 100644
index 0000000000000000000000000000000000000000..53fa161043a304cc4b506dadc5cfdf6d61d88946
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/sample_types/with_auto_generated_codes.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/sample_types/with_dynamic_script.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/sample_types/with_dynamic_script.xls
new file mode 100644
index 0000000000000000000000000000000000000000..f6dbb88115880f4ff23e23dec6bb325db9b97573
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/sample_types/with_dynamic_script.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/sample_types/with_validation_script.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/sample_types/with_validation_script.xls
new file mode 100644
index 0000000000000000000000000000000000000000..745fab798e0d9a94093918215080479a6a05e4ac
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/sample_types/with_validation_script.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/sample_types/with_vocabulary_in_xls.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/sample_types/with_vocabulary_in_xls.xls
new file mode 100644
index 0000000000000000000000000000000000000000..513d56b4c83351e59f7a8de2a68cd54e80d1440e
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/sample_types/with_vocabulary_in_xls.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/sample_types/with_vocabulary_on_server.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/sample_types/with_vocabulary_on_server.xls
new file mode 100644
index 0000000000000000000000000000000000000000..e8c32928586b43ab4803e601408e4eb45812fb5e
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/sample_types/with_vocabulary_on_server.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/all_elsewhere.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/all_elsewhere.xls
new file mode 100644
index 0000000000000000000000000000000000000000..4749694789683c3bc418946c887fd6671f9aa1f1
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/all_elsewhere.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/all_in.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/all_in.xls
new file mode 100644
index 0000000000000000000000000000000000000000..148abc66a5cecb7ce20d395899f58cf68a64cc76
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/all_in.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/experiment.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/experiment.xls
new file mode 100644
index 0000000000000000000000000000000000000000..c9ab2810593b69711331702f3e2c081581b8db4e
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/experiment.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/experiment_type.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/experiment_type.xls
new file mode 100644
index 0000000000000000000000000000000000000000..90d5b40a5dc26d4c7861e4027493d63056f0d1c7
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/experiment_type.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/project.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/project.xls
new file mode 100644
index 0000000000000000000000000000000000000000..8a075fdf2f6f5907ebc85b2e42fadd5d2c89f402
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/project.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/sample_type.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/sample_type.xls
new file mode 100644
index 0000000000000000000000000000000000000000..191b054327cd829c1b497f5492c02fbcb6748811
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/sample_type.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/sample_type_elsewhere.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/sample_type_elsewhere.xls
new file mode 100644
index 0000000000000000000000000000000000000000..cae6691312385b98caa13d04e59a18f8ef0b5350
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/sample_type_elsewhere.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/space.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/space.xls
new file mode 100644
index 0000000000000000000000000000000000000000..7184089ea5a51ad491f02f3940e0bb33c3f2eceb
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/space.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/space_elsewhere.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/space_elsewhere.xls
new file mode 100644
index 0000000000000000000000000000000000000000..684cfcf3e39a832f8176340492c62e97ee867d78
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/space_elsewhere.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/space_project_experiment_elsewhere.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/space_project_experiment_elsewhere.xls
new file mode 100644
index 0000000000000000000000000000000000000000..174b541bb4a23cf4dac1dc2a987577974f2216e6
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/space_project_experiment_elsewhere.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/vocab_type.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/vocab_type.xls
new file mode 100644
index 0000000000000000000000000000000000000000..2798f91d6081a200fa1521726e8f466b37d23e26
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/vocab_type.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/vocab_type_elsewhere.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/vocab_type_elsewhere.xls
new file mode 100644
index 0000000000000000000000000000000000000000..4deec4455c64c7895f2864a6667ca3199b40a326
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/vocab_type_elsewhere.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/with_ambiguous_code.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/with_ambiguous_code.xls
new file mode 100644
index 0000000000000000000000000000000000000000..56c21ac4eb5641ff8eaad5dd6db6e88e0714c1bb
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/with_ambiguous_code.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/with_ambiguous_code_but_with$.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/with_ambiguous_code_but_with$.xls
new file mode 100644
index 0000000000000000000000000000000000000000..744ae3ea4b84432acbd15f1a7e5aadac5c906a11
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/with_ambiguous_code_but_with$.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/with_no_such_child.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/with_no_such_child.xls
new file mode 100644
index 0000000000000000000000000000000000000000..71c45c3e02b29a2cab48e9234eaad90ab5fe20b6
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/with_no_such_child.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/with_no_such_parent.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/with_no_such_parent.xls
new file mode 100644
index 0000000000000000000000000000000000000000..a63d1b6c4e297640462f3c241d2bd900843f84b2
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/samples/with_no_such_parent.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/spaces/no_code.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/spaces/no_code.xls
new file mode 100644
index 0000000000000000000000000000000000000000..66b359e91807e8236803f18014f10d6065b2a41f
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/spaces/no_code.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/spaces/no_desc.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/spaces/no_desc.xls
new file mode 100644
index 0000000000000000000000000000000000000000..bd91bf15e2faa913d5ba3585a2e2038795e577b9
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/spaces/no_desc.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/spaces/normal_spaces.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/spaces/normal_spaces.xls
new file mode 100644
index 0000000000000000000000000000000000000000..13967a518d6a7491eac13ef97c2e23f603e7a738
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/spaces/normal_spaces.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/vocabularies/normal_vocab.xls b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/vocabularies/normal_vocab.xls
new file mode 100644
index 0000000000000000000000000000000000000000..1012b0c10cbb0b0a2126c01bc9e51634840bb300
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/vocabularies/normal_vocab.xls differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/vocabularies/vocab_no_code.xlsx b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/vocabularies/vocab_no_code.xlsx
new file mode 100644
index 0000000000000000000000000000000000000000..327e9952a7cc9b025bb491abb3faf88c9b28fcc2
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/vocabularies/vocab_no_code.xlsx differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/vocabularies/vocab_no_desc.xlsx b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/vocabularies/vocab_no_desc.xlsx
new file mode 100644
index 0000000000000000000000000000000000000000..63cbf942b4efa579282c864e0ad1ae76b120c050
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/vocabularies/vocab_no_desc.xlsx differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/vocabularies/vocab_no_term_code.xlsx b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/vocabularies/vocab_no_term_code.xlsx
new file mode 100644
index 0000000000000000000000000000000000000000..78d4d0ce9a6fee95cc7686ef661d0627926ddd8b
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/vocabularies/vocab_no_term_code.xlsx differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/vocabularies/vocab_no_term_desc.xlsx b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/vocabularies/vocab_no_term_desc.xlsx
new file mode 100644
index 0000000000000000000000000000000000000000..dff69ee861ac7fce118e6b72243bcdd629aa709b
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/vocabularies/vocab_no_term_desc.xlsx differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/vocabularies/vocab_no_term_label.xlsx b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/vocabularies/vocab_no_term_label.xlsx
new file mode 100644
index 0000000000000000000000000000000000000000..db47fe26e67e19819b649ee6b27cdfc9b91c2e00
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/vocabularies/vocab_no_term_label.xlsx differ
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/vocabularies/vocab_no_terms.xlsx b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/vocabularies/vocab_no_terms.xlsx
new file mode 100644
index 0000000000000000000000000000000000000000..0fa1b978f1ca7eae53c5d2108de04333e6d3dc3e
Binary files /dev/null and b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/plugin/excelimport/test_files/vocabularies/vocab_no_terms.xlsx differ
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/initialize-master-data.py b/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/initialize-master-data.py
index 62361d509737c36a559990587d9a0656df1908ef..a341dfe1806c4017775f32cb3692f612e73e7e66 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/initialize-master-data.py
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/initialize-master-data.py
@@ -14,34 +14,16 @@
 # limitations under the License.
 #
 # MasterDataRegistrationTransaction Class
-import os
-import sys
-
-from ch.ethz.sis.openbis.generic.asapi.v3.dto.operation import SynchronousOperationExecutionOptions
 from ch.ethz.sis.openbis.generic.server.asapi.v3 import ApplicationServerApi
 from ch.systemsx.cisd.openbis.generic.server import CommonServiceProvider
-from parsers import get_creations_from, DuplicatesHandler, CreationToOperationParser
-from processors import OpenbisDuplicatesHandler, VocabularyLabelHandler, PropertiesLabelHandler, unify_properties_representation_of
-from search_engines import SearchEngine
-from utils.file_handling import list_xls_files
+from utils.file_handling import list_xls_byte_arrays, get_all_scripts
+from ch.ethz.sis.openbis.generic.asapi.v3.dto.service.id import CustomASServiceCode
+from ch.ethz.sis.openbis.generic.asapi.v3.dto.service import CustomASServiceExecutionOptions
 
 api = CommonServiceProvider.getApplicationContext().getBean(ApplicationServerApi.INTERNAL_SERVICE_NAME)
-
-creations = get_creations_from(list_xls_files())
-distinct_creations = DuplicatesHandler.get_distinct_creations(creations)
 sessionToken = api.loginAsSystem()
-search_engine = SearchEngine(api, sessionToken)
-existing_elements = search_engine.find_all_existing_elements(distinct_creations)
-server_duplicates_handler = OpenbisDuplicatesHandler(distinct_creations, existing_elements)
-creations = server_duplicates_handler.remove_existing_elements_from_creations()
-creations = server_duplicates_handler.rewrite_parentchild_creationid_to_permid()
-entity_kinds = search_engine.find_existing_entity_kind_definitions_for(creations)
-existing_vocabularies = search_engine.find_all_existing_vocabularies()
-existing_unified_kinds = unify_properties_representation_of(creations, entity_kinds, existing_vocabularies, existing_elements)
-creations = PropertiesLabelHandler.rewrite_property_labels_to_codes(creations, existing_unified_kinds)
-operations = CreationToOperationParser.parse(creations)
-result = api.executeOperations(sessionToken, operations, SynchronousOperationExecutionOptions())
+props = CustomASServiceExecutionOptions().withParameter('xls', list_xls_byte_arrays()).withParameter('scripts', get_all_scripts())
+result = api.executeCustomASService(sessionToken, CustomASServiceCode("xls-import-api"), props);
 print("========================eln-life-sciences-types xls ingestion result========================")
 print(result)
 print("========================eln-life-sciences-types xls ingestion result========================")
-
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/test_files/more-things-2.xls b/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/test_files/more-things-2.xls
new file mode 100644
index 0000000000000000000000000000000000000000..c750d1f5aa7c9b3b228be097fda16fffba5887da
Binary files /dev/null and b/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/test_files/more-things-2.xls differ
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/test_files/types.xls b/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/test_files/types.xls
index 0bd64dcb024d5526412bc01fb848a3c0be4c16f1..eb7e796f789815ac5c18713099ea02a9cf5c69d6 100644
Binary files a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/test_files/types.xls and b/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/test_files/types.xls differ
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/utils/__init__.py b/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/utils/__init__.py
index 89ef9593c0dea1c72987ccf048db117712cb6867..04636895a894b6fb23696ab379730bb7d7752a34 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/utils/__init__.py
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/utils/__init__.py
@@ -1,3 +1 @@
 import file_handling
-import openbis_utils
-import dotdict
\ No newline at end of file
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/utils/file_handling.py b/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/utils/file_handling.py
index d0ab3a35b32825bc5d99f24bda5ab32a14cb3078..0b2f68e480126a92d288026a78dcaea080d522de 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/utils/file_handling.py
+++ b/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/utils/file_handling.py
@@ -1,21 +1,49 @@
 import os
 import sys
+from collections import deque
+from java.nio.file import Files, Paths
+from java.io import File
+from java.util import HashMap
+from java.util import ArrayList
 
-TYPES_FOLDER = "%s/life-sciences-types/" % [p for p in sys.path if p.find('core-plugins') >= 0][0]
-SCRIPTS = os.path.join(TYPES_FOLDER + 'scripts')
+TYPES_FOLDER = "%s/test_files/" % [p for p in sys.path if p.find('core-plugins') >= 0][0]
+SCRIPTS = os.path.join(TYPES_FOLDER, 'scripts')
 
 
-def get_script(script_path):
-    assert './' not in script_path
-    script_path = os.path.join(SCRIPTS, script_path)
-    return script_path
+def get_all_scripts():
+    scripts = HashMap()
+    for rel_path, script in list_all_files(SCRIPTS):
+        scripts.put(rel_path, script)
 
+    return scripts
 
-def get_filename_from_path(path):
-    return os.path.splitext(os.path.basename(path))[0]
 
-
-def list_xls_files():
+def list_xls_byte_arrays():
+    xls = ArrayList()
     for f in os.listdir(TYPES_FOLDER):
         if f.endswith('.xls') or f.endswith('.xlsx'):
-            yield os.path.join(TYPES_FOLDER, f)
+            excel_file = open(os.path.join(TYPES_FOLDER, f))
+            xls.add(excel_file.read())
+            excel_file.close()
+    return xls
+
+
+def list_all_files(source_root_path):
+    todo = []
+    todo.append(File(source_root_path))
+    while todo:
+        f = todo.pop()
+        if f.isDirectory():
+            new_files = f.listFiles()
+            if new_files is not None:
+                todo.extend(f.listFiles())
+            continue
+        if f.isFile():
+            source_file = f.getAbsolutePath()
+            script_file = open(source_file)
+            script = script_file.read()
+            script_file.close()
+            file_path = source_file.replace(source_root_path, "")
+            if file_path.startswith("/"):
+                file_path = file_path[1:]
+            yield file_path, script
diff --git a/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/entrypoint.py b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/entrypoint.py
new file mode 100644
index 0000000000000000000000000000000000000000..12b5fa31ac52634d336d59ad14ef4843ccee051c
--- /dev/null
+++ b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/entrypoint.py
@@ -0,0 +1,26 @@
+from ch.ethz.sis.openbis.generic.asapi.v3.dto.operation import SynchronousOperationExecutionOptions
+from parsers import get_creations_from, CreationToOperationParser
+from processors import OpenbisDuplicatesHandler, PropertiesLabelHandler, DuplicatesHandler, unify_properties_representation_of
+from search_engines import SearchEngine
+from utils import FileHandler
+
+
+def process(context, parameters):
+    xls_byte_arrays = parameters.get('xls')
+    scripts = parameters.get('scripts')
+    creations = get_creations_from(xls_byte_arrays, FileHandler(scripts))
+    distinct_creations = DuplicatesHandler.get_distinct_creations(creations)
+    sessionToken = context.sessionToken
+    api = context.applicationService
+    search_engine = SearchEngine(api, sessionToken)
+    existing_elements = search_engine.find_all_existing_elements(distinct_creations)
+    server_duplicates_handler = OpenbisDuplicatesHandler(distinct_creations, existing_elements)
+    creations = server_duplicates_handler.remove_existing_elements_from_creations()
+    creations = server_duplicates_handler.rewrite_parentchild_creationid_to_permid()
+    entity_kinds = search_engine.find_existing_entity_kind_definitions_for(creations)
+    existing_vocabularies = search_engine.find_all_existing_vocabularies()
+    existing_unified_kinds = unify_properties_representation_of(creations, entity_kinds, existing_vocabularies, existing_elements)
+    creations = PropertiesLabelHandler.rewrite_property_labels_to_codes(creations, existing_unified_kinds)
+    operations = CreationToOperationParser.parse(creations)
+    res = str(api.executeOperations(sessionToken, operations, SynchronousOperationExecutionOptions()).getResults())
+    return res
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/parsers/__init__.py b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/__init__.py
similarity index 87%
rename from openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/parsers/__init__.py
rename to openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/__init__.py
index 5ef6cabca013fb843b68c59074ee5c67bfdf74b3..8bd51a73523de48430e7220196cd52e007bd61ae 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/parsers/__init__.py
+++ b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/__init__.py
@@ -1,6 +1,6 @@
 from .creation_to_operation import CreationToOperationParser
 from .definition_to_creation import DefinitionToCreationParser
-from .definition_to_creation import DuplicatesHandler, VocabularyDefinitionToCreationParser, \
+from .definition_to_creation import VocabularyDefinitionToCreationParser, \
                     PropertyTypeDefinitionToCreationParser, SampleTypeDefinitionToCreationParser, ExperimentTypeDefinitionToCreationParser, \
                     DatasetTypeDefinitionToCreationParser, SpaceDefinitionToCreationParser, ProjectDefinitionToCreationParser, \
                     ExperimentDefinitionToCreationParser, ScriptDefinitionToCreationParser, SampleDefinitionToCreationParser
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/parsers/creation_to_operation/__init__.py b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/creation_to_operation/__init__.py
similarity index 100%
rename from openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/parsers/creation_to_operation/__init__.py
rename to openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/creation_to_operation/__init__.py
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/parsers/creation_to_operation/creation_to_operation.py b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/creation_to_operation/creation_to_operation.py
similarity index 100%
rename from openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/parsers/creation_to_operation/creation_to_operation.py
rename to openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/creation_to_operation/creation_to_operation.py
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/parsers/definition_to_creation/__init__.py b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/definition_to_creation/__init__.py
similarity index 90%
rename from openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/parsers/definition_to_creation/__init__.py
rename to openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/definition_to_creation/__init__.py
index b57ceeb03d8999dc5b928dfa8a374095b465e963..d159ca9e2b5dcbbc8bb437eb7aa9bf621111acf1 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/parsers/definition_to_creation/__init__.py
+++ b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/definition_to_creation/__init__.py
@@ -2,5 +2,3 @@ from .creation_parsers import VocabularyDefinitionToCreationParser, PropertyType
                     ExperimentTypeDefinitionToCreationParser, DatasetTypeDefinitionToCreationParser, SpaceDefinitionToCreationParser, \
                     ProjectDefinitionToCreationParser, ExperimentDefinitionToCreationParser, ScriptDefinitionToCreationParser, SampleDefinitionToCreationParser
 from .definition_to_creation import DefinitionToCreationParser
-from .duplicates_handler import DuplicatesHandler
-
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/parsers/definition_to_creation/creation_parsers.py b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/definition_to_creation/creation_parsers.py
similarity index 70%
rename from openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/parsers/definition_to_creation/creation_parsers.py
rename to openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/definition_to_creation/creation_parsers.py
index 3ddf7109a930ac16739b594d96f4222b46f18e8e..7b894567cab17bc0d3b0451a41857229b72600f8 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/parsers/definition_to_creation/creation_parsers.py
+++ b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/definition_to_creation/creation_parsers.py
@@ -15,29 +15,28 @@ from ch.ethz.sis.openbis.generic.asapi.v3.dto.vocabulary.create import Vocabular
 from ch.ethz.sis.openbis.generic.asapi.v3.dto.vocabulary.create import VocabularyTermCreation
 from ch.ethz.sis.openbis.generic.asapi.v3.dto.vocabulary.id import VocabularyPermId
 from java.lang import UnsupportedOperationException
-from utils.file_handling import get_script
 from utils.openbis_utils import is_internal_namespace, get_script_name_for
 
 
 def get_boolean_from_string(text):
-    return True if text.lower() == u'true' else False
+    return True if text and text.lower() == u'true' else False
 
 
 class DefinitionToCreationParserFactory(object):
 
     @staticmethod
-    def get_parsers(definition):
+    def get_parsers(definition, context):
         if definition.type == u'VOCABULARY_TYPE':
             return [VocabularyDefinitionToCreationParser()]
         elif definition.type == u'SAMPLE_TYPE':
             return [SampleTypeDefinitionToCreationParser(), PropertyTypeDefinitionToCreationParser(),
-                    ScriptDefinitionToCreationParser()]
+                    ScriptDefinitionToCreationParser(context)]
         elif definition.type == u'EXPERIMENT_TYPE':
             return [ExperimentTypeDefinitionToCreationParser(), PropertyTypeDefinitionToCreationParser(),
-                    ScriptDefinitionToCreationParser()]
+                    ScriptDefinitionToCreationParser(context)]
         elif definition.type == u'DATASET_TYPE':
             return [DatasetTypeDefinitionToCreationParser(), PropertyTypeDefinitionToCreationParser(),
-                    ScriptDefinitionToCreationParser()]
+                    ScriptDefinitionToCreationParser(context)]
         elif definition.type == u'SPACE':
             return [SpaceDefinitionToCreationParser()]
         elif definition.type == u'PROJECT':
@@ -65,12 +64,12 @@ class PropertyTypeDefinitionToCreationParser(DefinitionToCreationParser):
 
         for prop in definition.properties:
             property_type_creation = PropertyTypeCreation()
-            property_type_creation.code = prop[u'code']
-            property_type_creation.label = prop[u'property label']
-            property_type_creation.description = prop[u'description']
-            property_type_creation.dataType = DataType.valueOf(prop[u'data type'])
-            property_type_creation.internalNameSpace = is_internal_namespace(prop[u'code'])
-            property_type_creation.vocabularyId = VocabularyPermId(prop[u'vocabulary code']) if prop[u'vocabulary code'] is not None else None
+            property_type_creation.code = prop.get(u'code')
+            property_type_creation.label = prop.get(u'property label')
+            property_type_creation.description = prop.get(u'description')
+            property_type_creation.dataType = DataType.valueOf(prop.get(u'data type'))
+            property_type_creation.internalNameSpace = is_internal_namespace(prop.get(u'code'))
+            property_type_creation.vocabularyId = VocabularyPermId(prop.get(u'vocabulary code')) if prop.get(u'vocabulary code') is not None else None
             property_creations.append(property_type_creation)
 
         return property_creations
@@ -83,18 +82,18 @@ class VocabularyDefinitionToCreationParser(DefinitionToCreationParser):
     type = "VocabularyCreation"
 
     def parse(self, definition):
-        code = definition.attributes[u'code']
+        code = definition.attributes.get(u'code')
         vocabulary_creation = VocabularyCreation()
         vocabulary_creation.code = code
         vocabulary_creation.internalNameSpace = is_internal_namespace(code)
-        vocabulary_creation.description = definition.attributes[u'description']
+        vocabulary_creation.description = definition.attributes.get(u'description')
 
         vocabulary_creations_terms = []
         for prop in definition.properties:
             vocabulary_creation_term = VocabularyTermCreation()
-            vocabulary_creation_term.code = prop[u'code']
-            vocabulary_creation_term.label = prop[u'label']
-            vocabulary_creation_term.description = prop[u'description']
+            vocabulary_creation_term.code = prop.get(u'code')
+            vocabulary_creation_term.label = prop.get(u'label')
+            vocabulary_creation_term.description = prop.get(u'description')
             vocabulary_creations_terms.append(vocabulary_creation_term)
 
         vocabulary_creation.terms = vocabulary_creations_terms
@@ -109,16 +108,16 @@ class PropertyAssignmentDefinitionToCreationParser(DefinitionToCreationParser):
     type = "PropertyAssignmentCreation"
 
     def parse(self, prop):
-        code = prop[u'code']
+        code = prop.get(u'code')
         property_assingment_creation = PropertyAssignmentCreation()
-        is_mandatory = get_boolean_from_string(prop[u'mandatory'])
+        is_mandatory = get_boolean_from_string(prop.get(u'mandatory'))
         property_assingment_creation.mandatory = is_mandatory
-        should_show_in_edit_view = get_boolean_from_string(prop[u'show in edit views'])
+        should_show_in_edit_view = get_boolean_from_string(prop.get(u'show in edit views'))
         property_assingment_creation.showInEditView = should_show_in_edit_view
-        property_assingment_creation.section = prop[u'section']
+        property_assingment_creation.section = prop.get(u'section')
         property_assingment_creation.propertyTypeId = PropertyTypePermId(code)
-        if u'dynamic script' in prop and prop[u'dynamic script'] is not None:
-            dynamic_script_path = prop[u'dynamic script']
+        if u'dynamic script' in prop and prop.get(u'dynamic script') is not None:
+            dynamic_script_path = prop.get(u'dynamic script')
             property_assingment_creation.pluginId = PluginPermId(get_script_name_for(code, dynamic_script_path))
 
         return property_assingment_creation
@@ -131,13 +130,13 @@ class SampleTypeDefinitionToCreationParser(DefinitionToCreationParser):
     type = "SampleTypeCreation"
 
     def parse(self, definition):
-        code = definition.attributes[u'code']
+        code = definition.attributes.get(u'code')
         sample_creation = SampleTypeCreation()
         sample_creation.code = code
-        should_auto_generate_codes = get_boolean_from_string(definition.attributes[u'auto generate codes'])
+        should_auto_generate_codes = get_boolean_from_string(definition.attributes.get(u'auto generate codes'))
         sample_creation.autoGeneratedCode = should_auto_generate_codes
-        if u'validation script' in definition.attributes and definition.attributes[u'validation script'] is not None:
-            validation_script_path = definition.attributes[u'validation script']
+        if u'validation script' in definition.attributes and definition.attributes.get(u'validation script') is not None:
+            validation_script_path = definition.attributes.get(u'validation script')
             sample_creation.validationPluginId = PluginPermId(get_script_name_for(code, validation_script_path))
 
         property_assingment_creations = []
@@ -157,8 +156,12 @@ class ExperimentTypeDefinitionToCreationParser(DefinitionToCreationParser):
     type = "ExperimentTypeCreation"
 
     def parse(self, definition):
+        code = definition.attributes.get(u'code')
         experiment_type_creation = ExperimentTypeCreation()
-        experiment_type_creation.code = definition.attributes[u'code']
+        experiment_type_creation.code = code
+        if u'validation script' in definition.attributes and definition.attributes.get(u'validation script') is not None:
+            validation_script_path = definition.attributes.get(u'validation script')
+            experiment_type_creation.validationPluginId = PluginPermId(get_script_name_for(code, validation_script_path))
 
         property_assingment_creations = []
         property_assignment_parser = PropertyAssignmentDefinitionToCreationParser()
@@ -178,7 +181,11 @@ class DatasetTypeDefinitionToCreationParser(DefinitionToCreationParser):
 
     def parse(self, definition):
         dataset_type_creation = DataSetTypeCreation()
-        dataset_type_creation.code = definition.attributes[u'code']
+        code = definition.attributes.get(u'code')
+        dataset_type_creation.code = code
+        if u'validation script' in definition.attributes and definition.attributes.get(u'validation script') is not None:
+            validation_script_path = definition.attributes.get(u'validation script')
+            dataset_type_creation.validationPluginId = PluginPermId(get_script_name_for(code, validation_script_path))
 
         property_assingment_creations = []
         property_assignment_parser = PropertyAssignmentDefinitionToCreationParser()
@@ -197,12 +204,15 @@ class SpaceDefinitionToCreationParser(DefinitionToCreationParser):
     type = "SpaceCreation"
 
     def parse(self, definition):
-        space_creation = SpaceCreation()
-        space_creation.code = definition.attributes[u'code']
-        space_creation.description = definition.attributes[u'description']
-        creation_id = definition.attributes[u'code']
-        space_creation.creationId = CreationId(creation_id)
-        return space_creation
+        space_creations = []
+        for prop in definition.properties:
+            space_creation = SpaceCreation()
+            space_creation.code = prop.get(u'code')
+            space_creation.description = prop.get(u'description')
+            creation_id = prop.get(u'code')
+            space_creation.creationId = CreationId(creation_id)
+            space_creations.append(space_creation)
+        return space_creations
 
     def get_type(self):
         return SpaceDefinitionToCreationParser.type
@@ -212,13 +222,19 @@ class ProjectDefinitionToCreationParser(DefinitionToCreationParser):
     type = "ProjectCreation"
 
     def parse(self, definition):
-        project_creation = ProjectCreation()
-        project_creation.code = definition.attributes[u'code']
-        project_creation.description = definition.attributes[u'description']
-        project_creation.spaceId = CreationId(definition.attributes[u'space'])
-        creation_id = definition.attributes[u'code']
-        project_creation.creationId = CreationId(creation_id)
-        return project_creation
+        project_creations = []
+        print(definition.properties)
+        print("MAKRKRKRKRK")
+        for prop in definition.properties:
+            project_creation = ProjectCreation()
+            project_creation.code = prop.get(u'code')
+            project_creation.description = prop.get(u'description')
+            project_creation.spaceId = CreationId(prop.get(u'space'))
+            creation_id = prop.get(u'code')
+            project_creation.creationId = CreationId(creation_id)
+            project_creations.append(project_creation)
+        print(project_creations)
+        return project_creations
 
     def get_type(self):
         return ProjectDefinitionToCreationParser.type
@@ -232,10 +248,10 @@ class ExperimentDefinitionToCreationParser(DefinitionToCreationParser):
         mandatory_attributes = [u'code', u'project']
         for experiment_properties in definition.properties:
             experiment_creation = ExperimentCreation()
-            experiment_creation.typeId = EntityTypePermId(definition.attributes[u'experiment type'])
-            experiment_creation.code = experiment_properties[u'code']
-            experiment_creation.projectId = CreationId(experiment_properties[u'project'])
-            creation_id = experiment_properties[u'code']
+            experiment_creation.typeId = EntityTypePermId(definition.attributes.get(u'experiment type'))
+            experiment_creation.code = experiment_properties.get(u'code')
+            experiment_creation.projectId = CreationId(experiment_properties.get(u'project'))
+            creation_id = experiment_properties.get(u'code')
             experiment_creation.creationId = CreationId(creation_id)
             for prop, value in experiment_properties.items():
                 if prop not in mandatory_attributes:
@@ -256,32 +272,32 @@ class SampleDefinitionToCreationParser(DefinitionToCreationParser):
                                 u'children']
         for sample_properties in definition.properties:
             sample_creation = SampleCreation()
-            sample_creation.typeId = EntityTypePermId(definition.attributes[u'sample type'])
-            if u'code' in sample_properties and sample_properties[u'code'] is not None:
-                sample_creation.code = sample_properties[u'code']
-                creation_id = sample_properties[u'code']
+            sample_creation.typeId = EntityTypePermId(definition.attributes.get(u'sample type'))
+            if u'code' in sample_properties and sample_properties.get(u'code') is not None:
+                sample_creation.code = sample_properties.get(u'code')
+                creation_id = sample_properties.get(u'code')
                 sample_creation.creationId = CreationId(creation_id)
-            if u'$' in sample_properties and sample_properties[u'$'] is not None:
+            if u'$' in sample_properties and sample_properties.get(u'$') is not None:
                 # may overwrite creationId from code, which is intended
-                sample_creation.creationId = CreationId(sample_properties[u'$'])
-            if u'auto generate code' in sample_properties and sample_properties[u'auto generate code'] is not None and \
-                    sample_properties[u'auto generate code'] != '':
-                sample_creation.autoGeneratedCode = get_boolean_from_string(sample_properties[u'auto generate code'])
-            if u'space' in sample_properties and sample_properties[u'space'] is not None:
-                sample_creation.spaceId = CreationId(sample_properties[u'space'])
-            if u'project' in sample_properties and sample_properties[u'project'] is not None:
-                sample_creation.projectId = CreationId(sample_properties[u'project'])
-            if u'experiment' in sample_properties and sample_properties[u'experiment'] is not None:
-                sample_creation.experimentId = CreationId(sample_properties[u'experiment'])
-            if u'parents' in sample_properties and sample_properties[u'parents'] is not None:
+                sample_creation.creationId = CreationId(sample_properties.get(u'$'))
+            if u'auto generate code' in sample_properties and sample_properties.get(u'auto generate code') is not None and \
+                    sample_properties.get(u'auto generate code') != '':
+                sample_creation.autoGeneratedCode = get_boolean_from_string(sample_properties.get(u'auto generate code'))
+            if u'space' in sample_properties and sample_properties.get(u'space') is not None:
+                sample_creation.spaceId = CreationId(sample_properties.get(u'space'))
+            if u'project' in sample_properties and sample_properties.get(u'project') is not None:
+                sample_creation.projectId = CreationId(sample_properties.get(u'project'))
+            if u'experiment' in sample_properties and sample_properties.get(u'experiment') is not None:
+                sample_creation.experimentId = CreationId(sample_properties.get(u'experiment'))
+            if u'parents' in sample_properties and sample_properties.get(u'parents') is not None:
                 parent_creationids = []
-                parents = sample_properties[u'parents'].split('\n')
+                parents = sample_properties.get(u'parents').split('\n')
                 for parent in parents:
                     parent_creationids.append(CreationId(parent))
                 sample_creation.parentIds = parent_creationids
-            if u'children' in sample_properties and sample_properties[u'children'] is not None:
+            if u'children' in sample_properties and sample_properties.get(u'children') is not None:
                 child_creationids = []
-                children = sample_properties[u'children'].split('\n')
+                children = sample_properties.get(u'children').split('\n')
                 for child in children:
                     child_creationids.append(CreationId(child))
                 sample_creation.childIds = child_creationids
@@ -299,16 +315,17 @@ class SampleDefinitionToCreationParser(DefinitionToCreationParser):
 class ScriptDefinitionToCreationParser(DefinitionToCreationParser):
     type = "ScriptCreation"
 
+    def __init__(self, context=None):
+        self.context = context
+
     def parse(self, definition):
         scripts = []
         if u'validation script' in definition.attributes:
-            validation_script_path = definition.attributes[u'validation script']
+            validation_script_path = definition.attributes.get(u'validation script')
             if validation_script_path is not None:
-                code = definition.attributes[u'code']
+                code = definition.attributes.get(u'code')
                 validation_script_creation = PluginCreation()
-                script_file = open(get_script(validation_script_path))
-                script = script_file.read()
-                script_file.close()
+                script = self.context.get_script(validation_script_path)
                 validation_script_creation.name = get_script_name_for(code, validation_script_path)
                 validation_script_creation.script = script
                 validation_script_creation.pluginType = PluginType.ENTITY_VALIDATION
@@ -316,13 +333,11 @@ class ScriptDefinitionToCreationParser(DefinitionToCreationParser):
 
         for prop in definition.properties:
             if u'dynamic script' in prop:
-                dynamic_prop_script_path = prop[u'dynamic script']
-                code = prop[u'code']
+                dynamic_prop_script_path = prop.get(u'dynamic script')
+                code = prop.get(u'code')
                 if dynamic_prop_script_path is not None:
                     validation_script_creation = PluginCreation()
-                    script_file = open(get_script(dynamic_prop_script_path))
-                    script = script_file.read()
-                    script_file.close()
+                    script = self.context.get_script(dynamic_prop_script_path)
                     validation_script_creation.name = get_script_name_for(code, dynamic_prop_script_path)
                     validation_script_creation.script = script
                     validation_script_creation.pluginType = PluginType.DYNAMIC_PROPERTY
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/parsers/definition_to_creation/definition_to_creation.py b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/definition_to_creation/definition_to_creation.py
similarity index 92%
rename from openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/parsers/definition_to_creation/definition_to_creation.py
rename to openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/definition_to_creation/definition_to_creation.py
index fdfcf6b402a9b25850626dd0275fd4e61a2b58c7..a9673c6443806a745078a8036d991b00bc6f521c 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/parsers/definition_to_creation/definition_to_creation.py
+++ b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/definition_to_creation/definition_to_creation.py
@@ -4,12 +4,12 @@ from .creation_parsers import DefinitionToCreationParserFactory
 class DefinitionToCreationParser(object):
 
     @staticmethod
-    def parse(definitions):
+    def parse(definitions, context):
         creations = {}
 
         for definition in definitions:
             # One definition may contain more than one creation
-            parsers = DefinitionToCreationParserFactory.get_parsers(definition)
+            parsers = DefinitionToCreationParserFactory.get_parsers(definition, context)
             for parser in parsers:
                 creation = parser.parse(definition)
                 if creation is None or creation == []:
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/parsers/excel_to_poi/__init__.py b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/excel_to_poi/__init__.py
similarity index 100%
rename from openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/parsers/excel_to_poi/__init__.py
rename to openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/excel_to_poi/__init__.py
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/parsers/excel_to_poi/excel_to_poi.py b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/excel_to_poi/excel_to_poi.py
similarity index 94%
rename from openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/parsers/excel_to_poi/excel_to_poi.py
rename to openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/excel_to_poi/excel_to_poi.py
index ca1d8032bc8d07d366d2cd0492a4d512cd43c1cc..3c3fb54b6b470f07bcdef9995c771cd545d2f721 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/parsers/excel_to_poi/excel_to_poi.py
+++ b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/excel_to_poi/excel_to_poi.py
@@ -2,14 +2,14 @@ from org.apache.commons.lang import StringUtils
 from org.apache.poi.ss.usermodel import CellType
 from org.apache.poi.ss.usermodel import WorkbookFactory
 from org.apache.poi.ss.util import NumberToTextConverter
-from org.python.core.io import FileIO
+from java.io import ByteArrayInputStream
 
 
 class ExcelToPoiParser(object):
 
     @staticmethod
-    def parse(excel_file_path):
-        workbook = WorkbookFactory.create(FileIO(excel_file_path, 'r').asInputStream())
+    def parse(excel_byte_array):
+        workbook = WorkbookFactory.create(ByteArrayInputStream(excel_byte_array))
 
         data_colection = []
         definitions = []
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/parsers/excels_to_creations_parser.py b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/excels_to_creations_parser.py
similarity index 78%
rename from openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/parsers/excels_to_creations_parser.py
rename to openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/excels_to_creations_parser.py
index 2e843a7b16a559265709ce1cf7d2aaad47e8e8a4..46fd5e579ee5af636ee31cd2f14f19dc12c067b5 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/parsers/excels_to_creations_parser.py
+++ b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/excels_to_creations_parser.py
@@ -12,11 +12,11 @@ def merge_dicts(product, dict_to_merge):
     return product
 
 
-def get_creations_from(xls_files):
+def get_creations_from(xls_byte_arrays, context):
     creations = {}
-    for excel_file_path in xls_files:
-        poi_definitions = ExcelToPoiParser.parse(excel_file_path)
+    for excel_byte_array in xls_byte_arrays:
+        poi_definitions = ExcelToPoiParser.parse(excel_byte_array)
         definitions = PoiToDefinitionParser.parse(poi_definitions)
-        partial_creations = DefinitionToCreationParser.parse(definitions)
+        partial_creations = DefinitionToCreationParser.parse(definitions, context)
         creations = merge_dicts(creations, partial_creations)
     return creations
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/parsers/poi_to_definition/__init__.py b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/poi_to_definition/__init__.py
similarity index 100%
rename from openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/parsers/poi_to_definition/__init__.py
rename to openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/poi_to_definition/__init__.py
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/parsers/poi_to_definition/definition.py b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/poi_to_definition/definition.py
similarity index 100%
rename from openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/parsers/poi_to_definition/definition.py
rename to openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/poi_to_definition/definition.py
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/parsers/poi_to_definition/definition_parsers.py b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/poi_to_definition/definition_parsers.py
similarity index 91%
rename from openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/parsers/poi_to_definition/definition_parsers.py
rename to openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/poi_to_definition/definition_parsers.py
index 42865c4eb33cf950d323e8afb1d366ce333a5bbe..d17255c0f85deeb23f734f17ccd72eaf8ef9e499 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/parsers/poi_to_definition/definition_parsers.py
+++ b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/poi_to_definition/definition_parsers.py
@@ -7,15 +7,15 @@ class DefinitionParserFactory(object):
 
         @staticmethod
         def get_parser(definition_type):
-            if definition_type in ['VOCABULARY_TYPE', 'SAMPLE_TYPE', 'EXPERIMENT_TYPE', 'DATASET_TYPE', 'SPACE', 'PROJECT', 'EXPERIMENT', 'SAMPLE']:
+            if definition_type in ['VOCABULARY_TYPE', 'SAMPLE_TYPE', 'EXPERIMENT_TYPE', 'DATASET_TYPE', 'EXPERIMENT', 'SAMPLE']:
                 return GeneralDefinitionParser
-            elif definition_type == 'PROPERTY_TYPE':
-                return PropertyTypeDefinitionParser
+            elif definition_type in ['PROPERTY_TYPE', 'SPACE', 'PROJECT']:
+                return PropertiesOnlyDefinitionParser
             else:
                 raise UnsupportedOperationException("Definition of " + str(definition_type) + " is not supported (probably yet).")
 
 
-class PropertyTypeDefinitionParser(object):
+class PropertiesOnlyDefinitionParser(object):
 
     @staticmethod
     def parse(poi_definition):
@@ -36,7 +36,7 @@ class PropertyTypeDefinitionParser(object):
         poi_definition = PoiCleaner.clean_data(poi_definition, row_numbers)
         definition = Definition()
         definition.type = poi_definition[DEFINITION_TYPE_ROW][DEFINITION_TYPE_CELL]
-        if PropertyTypeDefinitionParser.hasProperties(poi_definition):
+        if PropertiesOnlyDefinitionParser.hasProperties(poi_definition):
             properties_headers = poi_definition[PROPERTIES_HEADER_ROW]
 
             for property_definitions in poi_definition[PROPERTIES_VALUES_ROW_START:]:
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/parsers/poi_to_definition/poi_cleaner.py b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/poi_to_definition/poi_cleaner.py
similarity index 100%
rename from openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/parsers/poi_to_definition/poi_cleaner.py
rename to openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/poi_to_definition/poi_cleaner.py
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/parsers/poi_to_definition/poi_to_definition.py b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/poi_to_definition/poi_to_definition.py
similarity index 100%
rename from openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/parsers/poi_to_definition/poi_to_definition.py
rename to openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/parsers/poi_to_definition/poi_to_definition.py
diff --git a/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/plugin.properties b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/plugin.properties
new file mode 100644
index 0000000000000000000000000000000000000000..bc08ec93452ac9d021602b4b91c1e017da7d6ca0
--- /dev/null
+++ b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/plugin.properties
@@ -0,0 +1,2 @@
+class = ch.ethz.sis.openbis.generic.server.asapi.v3.helper.service.JythonBasedCustomASServiceExecutor
+script-path = entrypoint.py
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/processors/__init__.py b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/processors/__init__.py
similarity index 76%
rename from openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/processors/__init__.py
rename to openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/processors/__init__.py
index 555be1ea3567ff06ef70060a6d06e1cfe4e03ba2..ba0cc9fc6fc6932ef10c5457b96ed6cade8e6a30 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/processors/__init__.py
+++ b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/processors/__init__.py
@@ -1,4 +1,4 @@
 from .openbis_duplicates_handler import OpenbisDuplicatesHandler
+from .duplicates_handler import DuplicatesHandler
 from .properties_label_handler import PropertiesLabelHandler
-from .vocabulary_label_handler import VocabularyLabelHandler
 from .representation_unifier import unify_properties_representation_of
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/processors/duplicates_handler.py b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/processors/duplicates_handler.py
similarity index 100%
rename from openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/processors/duplicates_handler.py
rename to openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/processors/duplicates_handler.py
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/processors/openbis_duplicates_handler.py b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/processors/openbis_duplicates_handler.py
similarity index 98%
rename from openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/processors/openbis_duplicates_handler.py
rename to openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/processors/openbis_duplicates_handler.py
index c324f438822ebed8a05ce8e8d2f0ca57c2e19c3c..4b04c23a42cb1b6c49edfbd53cc682b3c7c44ebd 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/processors/openbis_duplicates_handler.py
+++ b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/processors/openbis_duplicates_handler.py
@@ -46,10 +46,10 @@ class OpenbisDuplicatesHandler(object):
                     for child in creation.childIds:
                         new_id = None
                         for existing_element in self.existing_elements[SampleDefinitionToCreationParser.type]:
-                            if existing_element.permId.permId == child.creationId:
+                            if existing_element.permId.permId == str(child):
                                 new_id = existing_element.permId
                                 break
-                            elif existing_element.identifier.identifier == child.creationId:
+                            elif existing_element.identifier.identifier == str(child):
                                 new_id = existing_element.identifier
                                 break
 
@@ -63,10 +63,10 @@ class OpenbisDuplicatesHandler(object):
                     for parent in creation.parentIds:
                         new_id = None
                         for existing_element in self.existing_elements[SampleDefinitionToCreationParser.type]:
-                            if existing_element.permId.permId == parent.creationId:
+                            if existing_element.permId.permId == str(parent):
                                 new_id = existing_element.permId
                                 break
-                            elif existing_element.identifier.identifier == parent.creationId:
+                            elif existing_element.identifier.identifier == str(parent):
                                 new_id = existing_element.identifier
                                 break
 
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/processors/properties_label_handler.py b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/processors/properties_label_handler.py
similarity index 100%
rename from openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/processors/properties_label_handler.py
rename to openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/processors/properties_label_handler.py
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/processors/representation_unifier.py b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/processors/representation_unifier.py
similarity index 95%
rename from openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/processors/representation_unifier.py
rename to openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/processors/representation_unifier.py
index f4d12239aec1023861402145d4aa69420dccb567..c11a1fa124bdad229d14261a41c4e38d04f972d5 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/processors/representation_unifier.py
+++ b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/processors/representation_unifier.py
@@ -73,10 +73,11 @@ def property_type_representation_from(property_type, creations, existing_vocabul
     prop_type_representation['dataType'] = property_type.dataType
     vocabulary = None
     if hasattr(property_type, 'vocabularyId'):
-        vocabulary = _find_vocabulary(creations[VocabularyDefinitionToCreationParser.type], property_type.vocabularyId)
+        if VocabularyDefinitionToCreationParser.type in creations:
+            vocabulary = _find_vocabulary(creations[VocabularyDefinitionToCreationParser.type], property_type.vocabularyId)
         if vocabulary is None:
             vocabulary = _find_vocabulary(existing_vocabularies, property_type.vocabularyId)
-    else:
+    if vocabulary is None and hasattr(property_type, 'vocabulary'):
         vocabulary = property_type.vocabulary
     prop_type_representation['vocabulary'] = vocabulary
 
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/search_engines/__init__.py b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/search_engines/__init__.py
similarity index 100%
rename from openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/search_engines/__init__.py
rename to openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/search_engines/__init__.py
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/search_engines/search_criteria_factory.py b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/search_engines/search_criteria_factory.py
similarity index 65%
rename from openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/search_engines/search_criteria_factory.py
rename to openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/search_engines/search_criteria_factory.py
index 977204b9c70166aa59ab2a0277a9c87b3526ef87..5a9a76933767bfe6cd6f47d60db328948dd70401 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/search_engines/search_criteria_factory.py
+++ b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/search_engines/search_criteria_factory.py
@@ -1,4 +1,56 @@
 from utils.dotdict import dotdict
+from ch.ethz.sis.openbis.generic.server.asapi.v3.helper.sample import FullSampleIdentifier
+
+
+class SampleCreationSampleChildrenParentSearchCriteria(object):
+
+    def __init__(self, search_criteria_class):
+        self.search_criteria_class = search_criteria_class
+
+    def get_search_criteria(self, specific_creations):
+        search_criterias = []
+        for creation in specific_creations:
+            if creation.parentIds is not None:
+                for parent in creation.parentIds:
+                    self._get_criteria_from_string(str(parent), search_criterias)
+            if creation.childIds is not None:
+                for child in creation.childIds:
+                    self._get_criteria_from_string(str(child), search_criterias)
+        return search_criterias
+
+    def _get_criteria_from_string(self, sample_identifier_or_permid, search_criterias):
+        identifier = None
+        try:
+            identifier = FullSampleIdentifier(sample_identifier_or_permid, None)
+        except:
+            # No other way to see if this is a SampleIdentifier or not
+            # Adapted easier do and ask for forgiveness strategy
+            # Exception is passed with assumption parent string was not
+            # intended to be SampleIdentifier
+            pass
+
+        if identifier is not None:
+            search_criteria = self.search_criteria_class()
+            search_criteria.withAndOperator()
+            identier_parts = identifier.getParts()
+            space_code = identier_parts.spaceCodeOrNull
+            project_code = identier_parts.projectCodeOrNull
+            sample_code = identifier.sampleCode
+            search_criteria.withCode().thatEquals(sample_code)
+            if project_code is not None:
+                search_criteria.withProject().withCode().thatEquals(project_code)
+            else:
+                search_criteria.withoutProject()
+
+            if space_code is not None:
+                search_criteria.withSpace().withCode().thatEquals(space_code)
+            else:
+                search_criteria.withoutSpace()
+            search_criterias.append(search_criteria)
+        else:
+            search_criteria = self.search_criteria_class()
+            search_criteria.withPermId().thatEquals(sample_identifier_or_permid)
+            search_criterias.append(search_criteria)
 
 
 class SampleCreationSampleSearchCriteria(object):
@@ -27,7 +79,6 @@ class SampleCreationSampleSearchCriteria(object):
                     search_criteria.withSpace().withCode().thatEquals(creation.spaceId.creationId)
                 else:
                     search_criteria.withoutSpace()
-
                 search_criterias.append(search_criteria)
 
         return search_criterias
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/search_engines/search_engine.py b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/search_engines/search_engine.py
similarity index 96%
rename from openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/search_engines/search_engine.py
rename to openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/search_engines/search_engine.py
index 6a59a76df23be60169444f715f7a56d14fa9893b..89c180acf4ed7003939cc49e30fbaae3630ae7a4 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/search_engines/search_engine.py
+++ b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/search_engines/search_engine.py
@@ -25,7 +25,7 @@ from parsers import VocabularyDefinitionToCreationParser, PropertyTypeDefinition
 from search_criteria_factory import DefaultCreationElementSearchCriteria, SampleCreationSampleSearchCriteria, \
                                     ScriptCreationScriptSearchCriteria, EntityCreationEntityTypeSearchCriteria, \
                                     FindAllSearchCriteria, SpaceFromPropertiesSearchCriteria, ProjectFromPropertiesSearchCriteria, \
-                                    ExperimentFromPropertiesSearchCriteria
+                                    ExperimentFromPropertiesSearchCriteria, SampleCreationSampleChildrenParentSearchCriteria
 
 
 class SearchEngine():
@@ -57,6 +57,10 @@ class SearchEngine():
 
         return existing_elements
 
+    def find_all_existing_children_parent_candidates(self):
+
+        return existing_elements
+
     def find_existing_entity_kind_definitions_for(self, creations):
         experiment_fetch_options = ExperimentTypeFetchOptions()
         experiment_fetch_options.withPropertyAssignments().withPropertyType().withVocabulary().withTerms()
@@ -105,6 +109,13 @@ class SearchEngine():
             'fetch_options':VocabularyFetchOptions()
             },
             {
+            'creations_type': SampleDefinitionToCreationParser.type,
+            'search_criteria_build_strategy' : SampleCreationSampleChildrenParentSearchCriteria,
+            'search_criteria_class' : SampleSearchCriteria,
+            'search_operation': SearchSamplesOperation,
+            'fetch_options': SampleFetchOptions()
+            },
+            {
             'creations_type': PropertyTypeDefinitionToCreationParser.type,
             'search_criteria_build_strategy' : DefaultCreationElementSearchCriteria,
             'search_criteria_class' : PropertyTypeSearchCriteria,
diff --git a/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/utils/__init__.py b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/utils/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..153b00a1d2ff75adbd7fc9ae2062e159cd3afddb
--- /dev/null
+++ b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/utils/__init__.py
@@ -0,0 +1,3 @@
+from .file_handling import FileHandler
+import openbis_utils
+import dotdict
\ No newline at end of file
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/utils/dotdict.py b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/utils/dotdict.py
similarity index 100%
rename from openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/utils/dotdict.py
rename to openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/utils/dotdict.py
diff --git a/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/utils/file_handling.py b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/utils/file_handling.py
new file mode 100644
index 0000000000000000000000000000000000000000..e63ce020c04177ab6880e4809b89b8a3172f1efb
--- /dev/null
+++ b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/utils/file_handling.py
@@ -0,0 +1,11 @@
+import os
+
+
+class FileHandler(object):
+
+    def __init__(self, scripts):
+        self.scripts = scripts
+
+    def get_script(self, script_path):
+        return self.scripts[script_path]
+
diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/utils/openbis_utils.py b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/utils/openbis_utils.py
similarity index 79%
rename from openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/utils/openbis_utils.py
rename to openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/utils/openbis_utils.py
index d1bf332f7764ad4c331cbb3c0f1c9e3013261b1c..32a0b334c8f8595d1b3e0acce7866f93163658cf 100644
--- a/openbis_standard_technologies/dist/core-plugins/eln-lims-life-sciences/1/as/utils/openbis_utils.py
+++ b/openbis_standard_technologies/dist/core-plugins/xls-import/1/as/services/xls-import-api/utils/openbis_utils.py
@@ -1,9 +1,9 @@
 from ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.id import SampleIdentifier
-from utils.file_handling import get_filename_from_path
+import os
 
 
 def is_internal_namespace(property_value):
-    return property_value.startswith(u'$')
+    return property_value and property_value.startswith(u'$')
 
 
 def get_script_name_for(owner_code, script_path):
@@ -16,3 +16,7 @@ def create_sample_identifier_string(sample_creation):
     code = sample_creation.code
     sample_identifier = SampleIdentifier(spaceId, projectId, None, code)
     return sample_identifier.identifier
+
+
+def get_filename_from_path(path):
+        return os.path.splitext(os.path.basename(path))[0]