diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/RelationshipService.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/RelationshipService.java
index 4641cba9989c202fb1fc2d4a986b3d6fc254f8d7..4ce46b299834cbe05e8f86a03b4f456612ce4844 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/RelationshipService.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/RelationshipService.java
@@ -89,6 +89,7 @@ public class RelationshipService implements IRelationshipService
         }
 
         sample.setExperiment(experiment);
+        RelationshipUtils.updateModificationDateAndModifier(experiment, session);
 
         for (DataPE dataset : sample.getDatasets())
         {
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/util/RelationshipUtils.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/util/RelationshipUtils.java
index 361832750e0a2577234ea39d044516c9888d4a9e..65481fe00916c5e530aecc2d0e7d413fc5bdea53 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/util/RelationshipUtils.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/util/RelationshipUtils.java
@@ -67,15 +67,15 @@ public class RelationshipUtils
         {
             if (stackTraceElement.getClassName().contains("OptimisticLockingTest"))
             {
-                System.err.println("===== UPDATE modification date and modifier ===== "
+                System.out.println("===== UPDATE modification date and modifier ===== "
                         + stackTraceElement.getMethodName());
-                System.err.println("bean: " + beanOrNull);
-                System.err.println("user: " + session.tryGetPerson());
-                System.err.println("\t" + stackTrace[3]);
-                System.err.println("\t" + stackTrace[4]);
-                System.err.println("\t" + stackTrace[5]);
-                System.err.println("\t...");
-                System.err.println("\t" + stackTraceElement);
+                System.out.println("bean: " + beanOrNull);
+                System.out.println("user: " + session.tryGetPerson());
+                System.out.println("\t" + stackTrace[3]);
+                System.out.println("\t" + stackTrace[4]);
+                System.out.println("\t" + stackTrace[5]);
+                System.out.println("\t...");
+                System.out.println("\t" + stackTraceElement);
                 break;
             }
         }
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/util/TimeIntervalChecker.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/util/TimeIntervalChecker.java
index 8c26dfcb61f26101720fff65624853de0062f948..be77acedf6e7ac0dfcbfbc1c3d4e99500de0ba92 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/util/TimeIntervalChecker.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/util/TimeIntervalChecker.java
@@ -42,11 +42,11 @@ public class TimeIntervalChecker extends AssertJUnit
     }
 
     /**
-     * Creates an instance for now minus specified shift in seconds.
+     * Creates an instance for now minus specified shift in milliseconds.
      */
-    public TimeIntervalChecker(long shiftInSeconds)
+    public TimeIntervalChecker(long shiftInMillisecond)
     {
-        notBeforeDate = new Date(System.currentTimeMillis() - shiftInSeconds * 1000);
+        notBeforeDate = new Date(System.currentTimeMillis() - shiftInMillisecond);
     }
 
     /**
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/optimistic_locking/ExperimentOptimisticLockingTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/optimistic_locking/ExperimentOptimisticLockingTest.java
index 1f796860efb87e8c08de66f86f13e5ce3b142443..0cb3e1bca2436ea6adb122a40b8fce4436b38dac 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/optimistic_locking/ExperimentOptimisticLockingTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/optimistic_locking/ExperimentOptimisticLockingTest.java
@@ -20,41 +20,25 @@ import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.fail;
 
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
 
-import org.apache.log4j.Logger;
 import org.testng.annotations.Test;
 
-import ch.systemsx.cisd.common.concurrent.MessageChannel;
-import ch.systemsx.cisd.common.concurrent.MessageChannelBuilder;
 import ch.systemsx.cisd.common.exception.UserFailureException;
-import ch.systemsx.cisd.common.logging.LogCategory;
-import ch.systemsx.cisd.common.logging.LogFactory;
-import ch.systemsx.cisd.openbis.common.conversation.context.ServiceConversationsThreadContext;
-import ch.systemsx.cisd.openbis.common.conversation.progress.IServiceConversationProgressListener;
 import ch.systemsx.cisd.openbis.generic.server.util.TimeIntervalChecker;
-import ch.systemsx.cisd.openbis.generic.shared.basic.IIdentifierHolder;
 import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.FileFormatType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityProperty;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ListSampleCriteria;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.LocatorType;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewAttachment;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewExperiment;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewSample;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.builders.SampleTypeBuilder;
 import ch.systemsx.cisd.openbis.generic.shared.dto.AtomicEntityOperationDetails;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DataSetUpdatesDTO;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentUpdatesDTO;
 import ch.systemsx.cisd.openbis.generic.shared.dto.NewDataSet;
-import ch.systemsx.cisd.openbis.generic.shared.dto.NewProperty;
 import ch.systemsx.cisd.openbis.generic.shared.dto.SampleUpdatesDTO;
-import ch.systemsx.cisd.openbis.generic.shared.dto.StorageFormat;
 import ch.systemsx.cisd.openbis.generic.shared.dto.builders.AtomicEntityOperationDetailsBuilder;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifierFactory;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifierFactory;
@@ -64,36 +48,13 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifierFa
  */
 public class ExperimentOptimisticLockingTest extends OptimisticLockingTestCase
 {
-    private static final String DATA_STORE_CODE = "STANDARD";
-
-    private static final LocatorType LOCATOR_TYPE = new LocatorType(
-            LocatorType.DEFAULT_LOCATOR_TYPE_CODE);
-
-    private static final FileFormatType FILE_FORMAT_TYPE = new FileFormatType("XML");
-
-    private static final DataSetType DATA_SET_TYPE = new DataSetType("UNKNOWN");
-
-    private static final List<IEntityProperty> NO_PROPERTIES = Collections
-            .<IEntityProperty> emptyList();
-
-    private static final List<NewAttachment> NO_ATTACHMENTS = Collections
-            .<NewAttachment> emptyList();
-
-    private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION,
-            ExperimentOptimisticLockingTest.class);
-
-    private static final String REGISTERED = "registered";
-
-    private static final String FIRST_REGISTERED = "First registered";
-
-    protected static final String SAMPLE_TYPE_CODE = "NORMAL";
 
     @Test
     public void testRegisterExperiment()
     {
-        NewExperiment experiment = experiment(1);
+        NewExperiment experiment = toolBox.experiment(1);
         logIntoCommonClientService();
-        TimeIntervalChecker timeIntervalChecker = new TimeIntervalChecker();
+        TimeIntervalChecker timeIntervalChecker = new TimeIntervalChecker(1000);
 
         genericClientService.registerExperiment(SESSION_KEY, SESSION_KEY, experiment);
 
@@ -110,14 +71,14 @@ public class ExperimentOptimisticLockingTest extends OptimisticLockingTestCase
     @Test
     public void testChangePropertyOfAnExistingExperiment()
     {
-        Experiment experiment = createAndLoadExperiment(1);
+        Experiment experiment = toolBox.createAndLoadExperiment(1);
         String sessionToken = logIntoCommonClientService().getSessionID();
         ExperimentUpdatesDTO updates = new ExperimentUpdatesDTO();
         updates.setVersion(experiment.getVersion());
         updates.setExperimentId(new TechId(experiment));
-        updates.setProjectIdentifier(createProjectIdentifier(experiment.getProject()
+        updates.setProjectIdentifier(toolBox.createProjectIdentifier(experiment.getProject()
                 .getIdentifier()));
-        updates.setAttachments(NO_ATTACHMENTS);
+        updates.setAttachments(ToolBox.NO_ATTACHMENTS);
         List<IEntityProperty> properties = new ArrayList<IEntityProperty>();
         properties.addAll(experiment.getProperties());
         properties.get(0).setValue("testChangePropertyOfAnExistingExperiment");
@@ -126,7 +87,7 @@ public class ExperimentOptimisticLockingTest extends OptimisticLockingTestCase
 
         genericServer.updateExperiment(sessionToken, updates);
 
-        Experiment retrievedExperiment = loadExperiment(experiment);
+        Experiment retrievedExperiment = toolBox.loadExperiment(experiment);
         checkModifierAndModificationDateOfExperiment(timeIntervalChecker, retrievedExperiment,
                 "test");
         assertEquals("DESCRIPTION: testChangePropertyOfAnExistingExperiment", retrievedExperiment
@@ -136,14 +97,15 @@ public class ExperimentOptimisticLockingTest extends OptimisticLockingTestCase
     @Test
     public void testChangeProjectOfAnExistingExperiment()
     {
-        Experiment experiment = createAndLoadExperiment(1);
-        assertEquals(project1.getIdentifier(), experiment.getProject().getIdentifier());
+        Experiment experiment = toolBox.createAndLoadExperiment(1);
+        assertEquals(toolBox.project1.getIdentifier(), experiment.getProject().getIdentifier());
         String sessionToken = logIntoCommonClientService().getSessionID();
         ExperimentUpdatesDTO updates = new ExperimentUpdatesDTO();
         updates.setVersion(experiment.getVersion());
         updates.setExperimentId(new TechId(experiment));
-        updates.setProjectIdentifier(createProjectIdentifier(project2.getIdentifier()));
-        updates.setAttachments(NO_ATTACHMENTS);
+        updates.setProjectIdentifier(toolBox.createProjectIdentifier(toolBox.project2
+                .getIdentifier()));
+        updates.setAttachments(ToolBox.NO_ATTACHMENTS);
         updates.setProperties(experiment.getProperties());
         TimeIntervalChecker timeIntervalChecker = new TimeIntervalChecker();
 
@@ -153,19 +115,21 @@ public class ExperimentOptimisticLockingTest extends OptimisticLockingTestCase
                 commonServer.getExperimentInfo(systemSessionToken, new TechId(experiment));
         checkModifierAndModificationDateOfExperiment(timeIntervalChecker, retrievedExperiment,
                 "test");
-        assertEquals(project2.getIdentifier(), retrievedExperiment.getProject().getIdentifier());
+        assertEquals(toolBox.project2.getIdentifier(), retrievedExperiment.getProject()
+                .getIdentifier());
     }
 
     @Test
     public void testUpdateExperimentWithOldVersion()
     {
-        Experiment experiment = createAndLoadExperiment(1);
+        Experiment experiment = toolBox.createAndLoadExperiment(1);
         String sessionToken = logIntoCommonClientService().getSessionID();
         ExperimentUpdatesDTO updates = new ExperimentUpdatesDTO();
         updates.setVersion(experiment.getVersion());
         updates.setExperimentId(new TechId(experiment));
-        updates.setProjectIdentifier(createProjectIdentifier(project2.getIdentifier()));
-        updates.setAttachments(NO_ATTACHMENTS);
+        updates.setProjectIdentifier(toolBox.createProjectIdentifier(toolBox.project2
+                .getIdentifier()));
+        updates.setAttachments(ToolBox.NO_ATTACHMENTS);
         updates.setProperties(experiment.getProperties());
         genericServer.updateExperiment(sessionToken, updates);
 
@@ -180,98 +144,38 @@ public class ExperimentOptimisticLockingTest extends OptimisticLockingTestCase
         }
     }
 
-    @Test
-    public void testRegisterSamplesForSameExperimentInTwoThreads()
-    {
-        final NewExperiment experiment = experiment(1);
-        genericServer.registerExperiment(systemSessionToken, experiment, NO_ATTACHMENTS);
-        final MessageChannel messageChannelMain =
-                new MessageChannelBuilder(10000).name("samples main").logger(operationLog)
-                        .getChannel();
-        final MessageChannel messageChannelSecond =
-                new MessageChannelBuilder(10000).name("samples second").logger(operationLog)
-                        .getChannel();
-        final IServiceConversationProgressListener listener =
-                new AbstractServiceConversationProgressListener(operationLog)
-                    {
-                        @Override
-                        public void handleProgress(String phaseName, int totalItemsToProcess,
-                                int numItemsProcessed)
-                        {
-                            logger.info(phaseName + " " + numItemsProcessed + "/"
-                                    + totalItemsToProcess);
-                            if (phaseName.equals("createContainerSamples")
-                                    && numItemsProcessed == 1 && totalItemsToProcess == 2)
-                            {
-                                messageChannelMain.send(FIRST_REGISTERED);
-                            }
-                        }
-                    };
-        TimeIntervalChecker timeIntervalChecker = new TimeIntervalChecker();
-        new Thread(new Runnable()
-            {
-                @Override
-                public void run()
-                {
-                    NewSample sample3 = sample(3, experiment);
-
-                    String sessionToken =
-                            genericServer.tryToAuthenticate("test", "a").getSessionToken();
-                    messageChannelMain.assertNextMessage(FIRST_REGISTERED);
-                    genericServer.registerSample(sessionToken, sample3, NO_ATTACHMENTS);
-                    messageChannelSecond.send(REGISTERED);
-                }
-            }).start();
-        ServiceConversationsThreadContext.setProgressListener(listener);
-        AtomicEntityOperationDetailsBuilder builder = new AtomicEntityOperationDetailsBuilder();
-        builder.user(USER_ID).batchSize(1);
-        NewSample sample1 = sample(1, experiment);
-        NewSample sample2 = sample(2, experiment);
-        builder.sample(sample1).sample(sample2);
-
-        etlService.performEntityOperations(systemSessionToken, builder.getDetails());
-        messageChannelSecond.assertNextMessage(REGISTERED);
-
-        Experiment experimentInfo = loadExperiment(experiment);
-        List<Sample> samples =
-                commonServer.listSamples(systemSessionToken,
-                        ListSampleCriteria.createForExperiment(new TechId(experimentInfo)));
-        assertEquals("[OLT-S1, OLT-S2, OLT-S3]", extractCodes(samples).toString());
-        checkModifierAndModificationDateOfExperiment(timeIntervalChecker, experimentInfo, "test");
-    }
-
     @Test
     public void testMoveSampleBetweenExperiments()
     {
-        Experiment experiment1 = createAndLoadExperiment(1);
-        Experiment experiment2 = createAndLoadExperiment(2);
-        NewSample sample = sample(1, experiment1);
-        genericServer.registerSample(systemSessionToken, sample, NO_ATTACHMENTS);
-        Sample loadedSample = loadSample(sample);
+        Experiment experiment1 = toolBox.createAndLoadExperiment(1);
+        Experiment experiment2 = toolBox.createAndLoadExperiment(2);
+        NewSample sample = toolBox.sample(1, experiment1);
+        genericServer.registerSample(systemSessionToken, sample, ToolBox.NO_ATTACHMENTS);
+        Sample loadedSample = toolBox.loadSample(sample);
         SampleUpdatesDTO sampleUpdate =
-                new SampleUpdatesDTO(new TechId(loadedSample), NO_PROPERTIES,
+                new SampleUpdatesDTO(new TechId(loadedSample), ToolBox.NO_PROPERTIES,
                         ExperimentIdentifierFactory.parse(experiment2.getIdentifier()),
-                        NO_ATTACHMENTS, loadedSample.getModificationDate(),
+                        ToolBox.NO_ATTACHMENTS, loadedSample.getModificationDate(),
                         SampleIdentifierFactory.parse(sample), null, null);
         sampleUpdate.setUpdateExperimentLink(true);
         AtomicEntityOperationDetails details =
-                new AtomicEntityOperationDetailsBuilder().user(USER_ID).sampleUpdate(sampleUpdate)
-                        .getDetails();
+                new AtomicEntityOperationDetailsBuilder().user(ToolBox.USER_ID)
+                        .sampleUpdate(sampleUpdate).getDetails();
         String sessionToken = logIntoCommonClientService().getSessionID();
         TimeIntervalChecker timeIntervalChecker = new TimeIntervalChecker();
 
         etlService.performEntityOperations(sessionToken, details);
 
-        Experiment loadedExperiment1 = loadExperiment(experiment1);
+        Experiment loadedExperiment1 = toolBox.loadExperiment(experiment1);
         checkModifierAndModificationDateOfExperiment(timeIntervalChecker, loadedExperiment1,
-                USER_ID);
+                ToolBox.USER_ID);
         List<Sample> samples1 =
                 commonServer.listSamples(systemSessionToken,
                         ListSampleCriteria.createForExperiment(new TechId(loadedExperiment1)));
         assertEquals("[]", samples1.toString());
-        Experiment loadedExperiment2 = loadExperiment(experiment2);
+        Experiment loadedExperiment2 = toolBox.loadExperiment(experiment2);
         checkModifierAndModificationDateOfExperiment(timeIntervalChecker, loadedExperiment2,
-                USER_ID);
+                ToolBox.USER_ID);
         List<Sample> samples2 =
                 commonServer.listSamples(systemSessionToken,
                         ListSampleCriteria.createForExperiment(new TechId(loadedExperiment2)));
@@ -281,21 +185,22 @@ public class ExperimentOptimisticLockingTest extends OptimisticLockingTestCase
     @Test
     public void testRemoveSampleFromExperiment()
     {
-        Experiment experiment = createAndLoadExperiment(1);
-        NewSample sample = sample(1, experiment);
-        genericServer.registerSample(systemSessionToken, sample, NO_ATTACHMENTS);
+        Experiment experiment = toolBox.createAndLoadExperiment(1);
+        NewSample sample = toolBox.sample(1, experiment);
+        genericServer.registerSample(systemSessionToken, sample, ToolBox.NO_ATTACHMENTS);
         ExperimentUpdatesDTO update = new ExperimentUpdatesDTO();
         update.setExperimentId(new TechId(experiment));
         update.setSampleCodes(new String[0]);
-        update.setProperties(NO_PROPERTIES);
-        update.setAttachments(NO_ATTACHMENTS);
-        update.setProjectIdentifier(createProjectIdentifier(experiment.getProject().getIdentifier()));
+        update.setProperties(ToolBox.NO_PROPERTIES);
+        update.setAttachments(ToolBox.NO_ATTACHMENTS);
+        update.setProjectIdentifier(toolBox.createProjectIdentifier(experiment.getProject()
+                .getIdentifier()));
         String sessionToken = logIntoCommonClientService().getSessionID();
         TimeIntervalChecker timeIntervalChecker = new TimeIntervalChecker();
 
         genericServer.updateExperiment(sessionToken, update);
 
-        Experiment loadedExperiment = loadExperiment(experiment);
+        Experiment loadedExperiment = toolBox.loadExperiment(experiment);
         checkModifierAndModificationDateOfExperiment(timeIntervalChecker, loadedExperiment, "test");
         List<Sample> samples =
                 commonServer.listSamples(systemSessionToken,
@@ -306,10 +211,10 @@ public class ExperimentOptimisticLockingTest extends OptimisticLockingTestCase
     @Test
     public void testMoveDataSetBetweenExperiments()
     {
-        Experiment exp1 = createAndLoadExperiment(1);
-        Experiment exp2 = createAndLoadExperiment(2);
+        Experiment exp1 = toolBox.createAndLoadExperiment(1);
+        Experiment exp2 = toolBox.createAndLoadExperiment(2);
         AtomicEntityOperationDetailsBuilder builder = new AtomicEntityOperationDetailsBuilder();
-        NewDataSet dataSet = dataSet("DS-1", exp1);
+        NewDataSet dataSet = toolBox.dataSet("DS-1", exp1);
         builder.dataSet(dataSet);
         etlService.performEntityOperations(systemSessionToken, builder.getDetails());
         List<ExternalData> dataSets =
@@ -320,80 +225,25 @@ public class ExperimentOptimisticLockingTest extends OptimisticLockingTestCase
         update.setDatasetId(new TechId(loadedDataSet));
         update.setVersion(loadedDataSet.getModificationDate());
         update.setExperimentIdentifierOrNull(ExperimentIdentifierFactory.parse(exp2.getIdentifier()));
-        update.setProperties(NO_PROPERTIES);
+        update.setProperties(ToolBox.NO_PROPERTIES);
         update.setFileFormatTypeCode(dataSet.getFileFormatType().getCode());
         String sessionToken = logIntoCommonClientService().getSessionID();
         TimeIntervalChecker timeIntervalChecker = new TimeIntervalChecker();
 
         genericServer.updateDataSet(sessionToken, update);
 
-        Experiment loadedExperiment1 = loadExperiment(exp1);
+        Experiment loadedExperiment1 = toolBox.loadExperiment(exp1);
         checkModifierAndModificationDateOfExperiment(timeIntervalChecker, loadedExperiment1, "test");
         List<ExternalData> dataSets1 =
                 etlService.listDataSetsByExperimentID(systemSessionToken, new TechId(exp1));
         assertEquals("[]", dataSets1.toString());
-        Experiment loadedExperiment2 = loadExperiment(exp2);
+        Experiment loadedExperiment2 = toolBox.loadExperiment(exp2);
         checkModifierAndModificationDateOfExperiment(timeIntervalChecker, loadedExperiment2, "test");
         List<ExternalData> dataSets2 =
                 etlService.listDataSetsByExperimentID(systemSessionToken, new TechId(exp2));
         assertEquals(dataSet.getCode(), dataSets2.get(0).getCode());
     }
 
-    @Test
-    public void testRegisterDataSetsForSameExperimentInTwoThreads()
-    {
-        final Experiment experiment = createAndLoadExperiment(1);
-        final MessageChannel messageChannelMain =
-                new MessageChannelBuilder(10000).name("data sets main").logger(operationLog)
-                        .getChannel();
-        final MessageChannel messageChannelSecond =
-                new MessageChannelBuilder(10000).name("data sets second").logger(operationLog)
-                        .getChannel();
-        final IServiceConversationProgressListener listener =
-                new AbstractServiceConversationProgressListener(operationLog)
-                    {
-                        @Override
-                        public void handleProgress(String phaseName, int totalItemsToProcess,
-                                int numItemsProcessed)
-                        {
-                            if (phaseName.equals("createDataSets") && numItemsProcessed == 1
-                                    && totalItemsToProcess == 2)
-                            {
-                                messageChannelMain.send(FIRST_REGISTERED);
-                                System.out.println(loadExperiment(experiment).getModifier()
-                                        .getUserId());
-                            }
-                        }
-                    };
-        TimeIntervalChecker timeIntervalChecker = new TimeIntervalChecker();
-        new Thread(new Runnable()
-            {
-                @Override
-                public void run()
-                {
-                    messageChannelMain.assertNextMessage(FIRST_REGISTERED);
-                    AtomicEntityOperationDetails details =
-                            new AtomicEntityOperationDetailsBuilder().user("test")
-                                    .dataSet(dataSet("DS3", experiment)).getDetails();
-                    etlService.performEntityOperations(systemSessionToken, details);
-                    messageChannelSecond.send(REGISTERED);
-                }
-            }).start();
-        ServiceConversationsThreadContext.setProgressListener(listener);
-        AtomicEntityOperationDetailsBuilder builder = new AtomicEntityOperationDetailsBuilder();
-        builder.user(USER_ID).batchSize(1);
-        builder.dataSet(dataSet("DS1", experiment)).dataSet(dataSet("DS2", experiment));
-
-        etlService.performEntityOperations(systemSessionToken, builder.getDetails());
-        messageChannelSecond.assertNextMessage(REGISTERED);
-
-        Experiment loadedExperiment = loadExperiment(experiment);
-        List<ExternalData> dataSets =
-                etlService.listDataSetsByExperimentID(systemSessionToken, new TechId(experiment));
-        assertEquals("[DS1, DS2, DS3]", extractCodes(dataSets).toString());
-        checkModifierAndModificationDateOfExperiment(timeIntervalChecker, loadedExperiment, "test");
-    }
-
     private void checkModifierAndModificationDateOfExperiment(
             TimeIntervalChecker timeIntervalChecker, Experiment experiment, String userId)
     {
@@ -401,60 +251,4 @@ public class ExperimentOptimisticLockingTest extends OptimisticLockingTestCase
         timeIntervalChecker.assertDateInInterval(experiment.getModificationDate());
     }
 
-    private Experiment createAndLoadExperiment(int number)
-    {
-        NewExperiment experiment = experiment(number);
-        genericServer.registerExperiment(systemSessionToken, experiment, NO_ATTACHMENTS);
-        return loadExperiment(experiment);
-    }
-
-    private Experiment loadExperiment(final IIdentifierHolder experiment)
-    {
-        return commonServer.getExperimentInfo(systemSessionToken,
-                ExperimentIdentifierFactory.parse(experiment.getIdentifier()));
-    }
-
-    private NewSample sample(int number, IIdentifierHolder experiment)
-    {
-        NewSample sample = sample(number);
-        sample.setExperimentIdentifier(experiment.getIdentifier());
-        return sample;
-    }
-
-    private NewSample sample(int number)
-    {
-        NewSample sample = new NewSample();
-        sample.setIdentifier("/" + SPACE_1 + "/OLT-S" + number);
-        sample.setSampleType(new SampleTypeBuilder().code(SAMPLE_TYPE_CODE).getSampleType());
-        return sample;
-    }
-
-    private Sample loadSample(IIdentifierHolder sample)
-    {
-        return etlService.tryGetSampleWithExperiment(systemSessionToken,
-                SampleIdentifierFactory.parse(sample.getIdentifier()));
-    }
-
-    private NewDataSet dataSet(String code, Experiment experiment)
-    {
-        NewDataSet dataSet = dataSet(code);
-        dataSet.setExperimentIdentifierOrNull(ExperimentIdentifierFactory.parse(experiment
-                .getIdentifier()));
-        return dataSet;
-    }
-
-    private NewDataSet dataSet(String code)
-    {
-        NewDataSet dataSet = new NewDataSet();
-        dataSet.setCode(code);
-        dataSet.setDataSetType(DATA_SET_TYPE);
-        dataSet.setFileFormatType(FILE_FORMAT_TYPE);
-        dataSet.setDataSetProperties(Collections.<NewProperty> emptyList());
-        dataSet.setLocation("a/b/c/" + code);
-        dataSet.setLocatorType(LOCATOR_TYPE);
-        dataSet.setStorageFormat(StorageFormat.PROPRIETARY);
-        dataSet.setDataStoreCode(DATA_STORE_CODE);
-        return dataSet;
-    }
-
 }
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/optimistic_locking/MultiThreadExperimentOptimisticLockingTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/optimistic_locking/MultiThreadExperimentOptimisticLockingTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..3ff192795ad96d0537f51a903bba826e1160addb
--- /dev/null
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/optimistic_locking/MultiThreadExperimentOptimisticLockingTest.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2012 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.systemtest.optimistic_locking;
+
+import static org.testng.AssertJUnit.assertEquals;
+
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.testng.annotations.Test;
+
+import ch.systemsx.cisd.common.concurrent.MessageChannel;
+import ch.systemsx.cisd.common.concurrent.MessageChannelBuilder;
+import ch.systemsx.cisd.common.logging.LogCategory;
+import ch.systemsx.cisd.common.logging.LogFactory;
+import ch.systemsx.cisd.openbis.common.conversation.context.ServiceConversationsThreadContext;
+import ch.systemsx.cisd.openbis.common.conversation.progress.IServiceConversationProgressListener;
+import ch.systemsx.cisd.openbis.generic.server.util.TimeIntervalChecker;
+import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ListSampleCriteria;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewExperiment;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewSample;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
+import ch.systemsx.cisd.openbis.generic.shared.dto.AtomicEntityOperationDetails;
+import ch.systemsx.cisd.openbis.generic.shared.dto.builders.AtomicEntityOperationDetailsBuilder;
+
+/**
+ * @author Franz-Josef Elmer
+ */
+public class MultiThreadExperimentOptimisticLockingTest extends
+        MultiThreadOptimisticLockingTestCase
+{
+    private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION,
+            MultiThreadExperimentOptimisticLockingTest.class);
+
+    @Test
+    public void testRegisterSamplesForSameExperimentInTwoThreads()
+    {
+        final NewExperiment experiment = toolBox.experiment(1);
+        genericServer.registerExperiment(systemSessionToken, experiment, ToolBox.NO_ATTACHMENTS);
+        final MessageChannel messageChannelMain =
+                new MessageChannelBuilder(10000).name("samples main").logger(operationLog)
+                        .getChannel();
+        final MessageChannel messageChannelSecond =
+                new MessageChannelBuilder(10000).name("samples second").logger(operationLog)
+                        .getChannel();
+        final IServiceConversationProgressListener listener =
+                new AbstractServiceConversationProgressListener(operationLog)
+                    {
+                        @Override
+                        public void handleProgress(String phaseName, int totalItemsToProcess,
+                                int numItemsProcessed)
+                        {
+                            logger.info(phaseName + " " + numItemsProcessed + "/"
+                                    + totalItemsToProcess);
+                            if (phaseName.equals("createContainerSamples")
+                                    && numItemsProcessed == 1 && totalItemsToProcess == 2)
+                            {
+                                messageChannelMain.send(ToolBox.FIRST_REGISTERED);
+                            }
+                        }
+                    };
+        TimeIntervalChecker timeIntervalChecker = new TimeIntervalChecker();
+        new Thread(new Runnable()
+            {
+                @Override
+                public void run()
+                {
+                    NewSample sample3 = toolBox.sample(3, experiment);
+
+                    String sessionToken =
+                            genericServer.tryToAuthenticate("test", "a").getSessionToken();
+                    messageChannelMain.assertNextMessage(ToolBox.FIRST_REGISTERED);
+                    genericServer.registerSample(sessionToken, sample3, ToolBox.NO_ATTACHMENTS);
+                    messageChannelSecond.send(ToolBox.REGISTERED);
+                }
+            }).start();
+        ServiceConversationsThreadContext.setProgressListener(listener);
+        AtomicEntityOperationDetailsBuilder builder = new AtomicEntityOperationDetailsBuilder();
+        builder.user(ToolBox.USER_ID).batchSize(1);
+        NewSample sample1 = toolBox.sample(1, experiment);
+        NewSample sample2 = toolBox.sample(2, experiment);
+        builder.sample(sample1).sample(sample2);
+
+        etlService.performEntityOperations(systemSessionToken, builder.getDetails());
+        messageChannelSecond.assertNextMessage(ToolBox.REGISTERED);
+
+        Experiment experimentInfo = toolBox.loadExperiment(experiment);
+        List<Sample> samples =
+                commonServer.listSamples(systemSessionToken,
+                        ListSampleCriteria.createForExperiment(new TechId(experimentInfo)));
+        assertEquals("[OLT-S1, OLT-S2, OLT-S3]", toolBox.extractCodes(samples).toString());
+        checkModifierAndModificationDateOfExperiment(timeIntervalChecker, experimentInfo, "test");
+    }
+
+    @Test
+    public void testRegisterDataSetsForSameExperimentInTwoThreads()
+    {
+        final Experiment experiment = toolBox.createAndLoadExperiment(1);
+        final MessageChannel messageChannelMain =
+                new MessageChannelBuilder(10000).name("data sets main").logger(operationLog)
+                        .getChannel();
+        final MessageChannel messageChannelSecond =
+                new MessageChannelBuilder(10000).name("data sets second").logger(operationLog)
+                        .getChannel();
+        final IServiceConversationProgressListener listener =
+                new AbstractServiceConversationProgressListener(operationLog)
+                    {
+                        @Override
+                        public void handleProgress(String phaseName, int totalItemsToProcess,
+                                int numItemsProcessed)
+                        {
+                            if (phaseName.equals("createDataSets") && numItemsProcessed == 1
+                                    && totalItemsToProcess == 2)
+                            {
+                                messageChannelMain.send(ToolBox.FIRST_REGISTERED);
+                            }
+                        }
+                    };
+        TimeIntervalChecker timeIntervalChecker = new TimeIntervalChecker();
+        new Thread(new Runnable()
+            {
+                @Override
+                public void run()
+                {
+                    messageChannelMain.assertNextMessage(ToolBox.FIRST_REGISTERED);
+                    AtomicEntityOperationDetails details =
+                            new AtomicEntityOperationDetailsBuilder().user("test")
+                                    .dataSet(toolBox.dataSet("DS3", experiment)).getDetails();
+                    etlService.performEntityOperations(systemSessionToken, details);
+                    messageChannelSecond.send(ToolBox.REGISTERED);
+                }
+            }).start();
+        ServiceConversationsThreadContext.setProgressListener(listener);
+        AtomicEntityOperationDetailsBuilder builder = new AtomicEntityOperationDetailsBuilder();
+        builder.user(ToolBox.USER_ID).batchSize(1);
+        builder.dataSet(toolBox.dataSet("DS1", experiment)).dataSet(
+                toolBox.dataSet("DS2", experiment));
+
+        etlService.performEntityOperations(systemSessionToken, builder.getDetails());
+        messageChannelSecond.assertNextMessage(ToolBox.REGISTERED);
+
+        Experiment loadedExperiment = toolBox.loadExperiment(experiment);
+        List<ExternalData> dataSets =
+                etlService.listDataSetsByExperimentID(systemSessionToken, new TechId(experiment));
+        assertEquals("[DS1, DS2, DS3]", toolBox.extractCodes(dataSets).toString());
+        checkModifierAndModificationDateOfExperiment(timeIntervalChecker, loadedExperiment, "test");
+    }
+
+    private void checkModifierAndModificationDateOfExperiment(
+            TimeIntervalChecker timeIntervalChecker, Experiment experiment, String userId)
+    {
+        assertEquals(userId, experiment.getModifier().getUserId());
+        timeIntervalChecker.assertDateInInterval(experiment.getModificationDate());
+    }
+
+}
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/optimistic_locking/MultiThreadOptimisticLockingTestCase.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/optimistic_locking/MultiThreadOptimisticLockingTestCase.java
new file mode 100644
index 0000000000000000000000000000000000000000..727ffdce1defdd5cfbf83c51ebcb51882730e54f
--- /dev/null
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/optimistic_locking/MultiThreadOptimisticLockingTestCase.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2012 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.systemtest.optimistic_locking;
+
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+
+import ch.systemsx.cisd.openbis.systemtest.PersistentSystemTestCase;
+
+/**
+ * Super class of system test doing commit after each service operation. Can be used to write tests
+ * with more than one Thread.
+ * 
+ * @author Franz-Josef Elmer
+ */
+public class MultiThreadOptimisticLockingTestCase extends PersistentSystemTestCase
+{
+    protected ToolBox toolBox;
+
+    @BeforeMethod
+    public void createSpacesAndProjects()
+    {
+        toolBox = new ToolBox(commonServer, genericServer, etlService, systemSessionToken);
+        toolBox.createSpacesAndProjects();
+    }
+
+    @AfterMethod
+    public void deleteSpaces()
+    {
+        toolBox.deleteSpaces();
+    }
+}
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/optimistic_locking/MultiThreadProjectOptimisticLockingTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/optimistic_locking/MultiThreadProjectOptimisticLockingTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..169bec53c75c4bb697b4671ce5010af4af800a26
--- /dev/null
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/optimistic_locking/MultiThreadProjectOptimisticLockingTest.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2012 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.systemtest.optimistic_locking;
+
+import static org.testng.AssertJUnit.assertEquals;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.testng.annotations.Test;
+
+import ch.systemsx.cisd.common.concurrent.MessageChannel;
+import ch.systemsx.cisd.common.concurrent.MessageChannelBuilder;
+import ch.systemsx.cisd.common.logging.LogCategory;
+import ch.systemsx.cisd.common.logging.LogFactory;
+import ch.systemsx.cisd.openbis.common.conversation.context.ServiceConversationsThreadContext;
+import ch.systemsx.cisd.openbis.common.conversation.progress.IServiceConversationProgressListener;
+import ch.systemsx.cisd.openbis.generic.server.util.TimeIntervalChecker;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewAttachment;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewExperiment;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.builders.ExperimentTypeBuilder;
+import ch.systemsx.cisd.openbis.generic.shared.dto.AtomicEntityOperationDetails;
+import ch.systemsx.cisd.openbis.generic.shared.dto.builders.AtomicEntityOperationDetailsBuilder;
+
+/**
+ * @author Franz-Josef Elmer
+ */
+public class MultiThreadProjectOptimisticLockingTest extends MultiThreadOptimisticLockingTestCase
+{
+    private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION,
+            MultiThreadProjectOptimisticLockingTest.class);
+
+    private static final String CREATE_EXPERIMENTS_PHASE = "createExperiments";
+
+    /*
+     * This test registers three experiments for the same project. Two of them are registered by the
+     * main thread using performEntityOperations(). A second thread registers an experiment between
+     * the registration of the two other experiments. This is done by using a
+     * IServiceConversationProgressListener together with two message channels to coordinate the
+     * order of actions in both threads.
+     */
+    @Test
+    public void testRegisterExperimentsInTwoThreads()
+    {
+        assertEquals("system", toolBox.project1.getModifier().getUserId());
+        final StringBuilder stringBuilder = new StringBuilder();
+        final MessageChannel messageChannelMain =
+                new MessageChannelBuilder(10000).name("main").logger(operationLog).getChannel();
+        final MessageChannel messageChannelSecond =
+                new MessageChannelBuilder(10000).name("second").logger(operationLog).getChannel();
+        final IServiceConversationProgressListener listener =
+                new AbstractServiceConversationProgressListener(operationLog)
+                    {
+                        @Override
+                        public void handleProgress(String phaseName, int totalItemsToProcess,
+                                int numItemsProcessed)
+                        {
+                            stringBuilder.append(phaseName).append(" ").append(numItemsProcessed)
+                                    .append("/").append(totalItemsToProcess).append("\n");
+                            if (phaseName.equals(CREATE_EXPERIMENTS_PHASE)
+                                    && numItemsProcessed == 1 && totalItemsToProcess == 2)
+                            {
+                                messageChannelMain.send(ToolBox.FIRST_REGISTERED);
+                            }
+                        }
+                    };
+        TimeIntervalChecker timeIntervalChecker = new TimeIntervalChecker();
+
+        new Thread(new Runnable()
+            {
+                @Override
+                public void run()
+                {
+                    NewExperiment experiment3 = toolBox.experiment(3);
+                    String sessionToken =
+                            genericServer.tryToAuthenticate("test", "a").getSessionToken();
+                    messageChannelMain.assertNextMessage(ToolBox.FIRST_REGISTERED);
+                    genericServer.registerExperiment(sessionToken, experiment3,
+                            Collections.<NewAttachment> emptyList());
+                    messageChannelSecond.send(ToolBox.REGISTERED);
+                }
+            }).start();
+
+        ServiceConversationsThreadContext.setProgressListener(listener);
+        AtomicEntityOperationDetailsBuilder builder = new AtomicEntityOperationDetailsBuilder();
+        builder.user(ToolBox.USER_ID);
+        builder.experiment(toolBox.experiment(1)).experiment(toolBox.experiment(2));
+        AtomicEntityOperationDetails details = builder.getDetails();
+
+        etlService.performEntityOperations(systemSessionToken, details);
+
+        messageChannelSecond.assertNextMessage(ToolBox.REGISTERED);
+
+        List<Experiment> experiments =
+                commonServer.listExperiments(systemSessionToken,
+                        new ExperimentTypeBuilder().code(ToolBox.EXPERIMENT_TYPE_CODE)
+                                .getExperimentType(), toolBox
+                                .createProjectIdentifier(toolBox.project1.getIdentifier()));
+        assertEquals("[OLT-E1, OLT-E2, OLT-E3]", toolBox.extractCodes(experiments).toString());
+        toolBox.checkModifierAndModificationDateOfProject1(timeIntervalChecker);
+        assertEquals("authorize 1/2\n" + "authorize 2/2\n" + "createExperiments 1/2\n"
+                + "createExperiments 2/2\n", stringBuilder.toString());
+    }
+}
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/optimistic_locking/OptimisticLockingTestCase.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/optimistic_locking/OptimisticLockingTestCase.java
index afbfc621ea92e987a238a3397139c58ce9ea6474..f9efe8cbe0c693bbff3187fe582fee3c4aeb553e 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/optimistic_locking/OptimisticLockingTestCase.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/optimistic_locking/OptimisticLockingTestCase.java
@@ -16,221 +16,23 @@
 
 package ch.systemsx.cisd.openbis.systemtest.optimistic_locking;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
 
-import ch.systemsx.cisd.openbis.generic.shared.basic.ICodeHolder;
-import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Deletion;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DeletionType;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Grantee;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityProperty;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ListSampleCriteria;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewAttachment;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewExperiment;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Person;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Project;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.RoleWithHierarchy.RoleCode;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleType;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Space;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.builders.ExperimentTypeBuilder;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.builders.PropertyBuilder;
-import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.DatabaseInstanceIdentifier;
-import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ProjectIdentifier;
-import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ProjectIdentifierFactory;
-import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SpaceIdentifierFactory;
-import ch.systemsx.cisd.openbis.systemtest.PersistentSystemTestCase;
+import ch.systemsx.cisd.openbis.systemtest.SystemTestCase;
 
 /**
+ * Super class of system tests with rollback after each test.
+ * 
  * @author Franz-Josef Elmer
  */
-public class OptimisticLockingTestCase extends PersistentSystemTestCase
+public class OptimisticLockingTestCase extends SystemTestCase
 {
-    protected static final String USER_ID = "optimist";
-
-    protected static final String SPACE_1 = "OPTIMISTIC_LOCKING_1";
-
-    protected static final String SPACE_2 = "OPTIMISTIC_LOCKING_2";
-
-    protected static final String EXPERIMENT_TYPE_CODE = "SIRNA_HCS";
-
-    protected Space space1;
-
-    protected Space space2;
-
-    protected Project project1;
-
-    protected Project project2;
+    protected ToolBox toolBox;
 
     @BeforeMethod
     public void createSpacesAndProjects()
     {
-        space1 = findOrCreateSpace(SPACE_1);
-        space2 = findOrCreateSpace(SPACE_2);
-        project1 = findOrCreateProject("/" + SPACE_1 + "/P1");
-        project2 = findOrCreateProject("/" + SPACE_2 + "/P2");
-        createInstanceAdmin(USER_ID);
-    }
-
-    @AfterMethod
-    public void deleteSpaces()
-    {
-        deleteSpace(space1);
-        deleteSpace(space2);
-    }
-
-    private void deleteSpace(Space space)
-    {
-        trashExperiments(space);
-        trashSamples(space);
-        emptyTrashCan();
-        deleteProjects(space);
-        commonServer.deleteSpaces(systemSessionToken, Arrays.asList(new TechId(space.getId())),
-                "cleanup");
-    }
-
-    private void deleteProjects(Space space)
-    {
-        List<Project> projects = commonServer.listProjects(systemSessionToken);
-        List<TechId> projectIds = new ArrayList<TechId>();
-        for (Project project : projects)
-        {
-            if (project.getSpace().getCode().equals(space.getCode()))
-            {
-                projectIds.add(new TechId(project));
-            }
-        }
-        commonServer.deleteProjects(systemSessionToken, projectIds, "cleanup");
-    }
-
-    private void emptyTrashCan()
-    {
-        List<Deletion> deletions = commonServer.listDeletions(systemSessionToken, false);
-        commonServer.deletePermanently(systemSessionToken, TechId.createList(deletions));
-    }
-
-    private void trashSamples(Space space)
-    {
-        ListSampleCriteria criteria = new ListSampleCriteria();
-        criteria.setSampleType(SampleType.createAllSampleType(Collections.<SampleType> emptyList(),
-                false));
-        criteria.setSpaceCode(space.getCode());
-        criteria.setIncludeSpace(true);
-        criteria.setIncludeInstance(false);
-        criteria.setExcludeWithoutExperiment(false);
-        List<Sample> samples = commonServer.listSamples(systemSessionToken, criteria);
-        commonServer.deleteSamples(systemSessionToken, TechId.createList(samples), "cleanup",
-                DeletionType.TRASH);
-    }
-
-    private void trashExperiments(Space space)
-    {
-        List<Experiment> experiments =
-                commonServer.listExperiments(systemSessionToken,
-                        new ExperimentTypeBuilder().code(EXPERIMENT_TYPE_CODE).getExperimentType(),
-                        new SpaceIdentifierFactory(space.getIdentifier()).createIdentifier());
-        commonServer.deleteExperiments(systemSessionToken, TechId.createList(experiments),
-                "cleanup", DeletionType.TRASH);
+        toolBox = new ToolBox(commonServer, genericServer, etlService, systemSessionToken);
+        toolBox.createSpacesAndProjects();
     }
-
-    private void createInstanceAdmin(String userId)
-    {
-        List<Person> persons = commonServer.listPersons(systemSessionToken);
-        for (Person person : persons)
-        {
-            if (person.getUserId().equals(userId))
-            {
-                return;
-            }
-        }
-        commonServer.registerPerson(systemSessionToken, userId);
-        commonServer.registerInstanceRole(systemSessionToken, RoleCode.ADMIN,
-                Grantee.createPerson(userId));
-    }
-
-    protected Project findOrCreateProject(String projectIdentifier)
-    {
-        Project project = tryToFindProject(projectIdentifier);
-        if (project != null)
-        {
-            return project;
-        }
-        commonServer.registerProject(systemSessionToken, new ProjectIdentifierFactory(
-                projectIdentifier).createIdentifier(), "A test project", null, Collections
-                .<NewAttachment> emptyList());
-        return tryToFindProject(projectIdentifier);
-    }
-
-    protected Project tryToFindProject(String projectIdentifier)
-    {
-        List<Project> projects = commonServer.listProjects(systemSessionToken);
-        for (Project project : projects)
-        {
-            if (project.getIdentifier().equals(projectIdentifier))
-            {
-                return project;
-            }
-        }
-        return null;
-    }
-
-    protected Space findOrCreateSpace(String spaceCode)
-    {
-        Space space = tryToFindSpace(spaceCode);
-        if (space != null)
-        {
-            return space;
-        }
-        commonServer.registerSpace(systemSessionToken, spaceCode, "A test space");
-        return tryToFindSpace(spaceCode);
-    }
-
-    protected Space tryToFindSpace(String spaceCode)
-    {
-        DatabaseInstanceIdentifier identifier = new DatabaseInstanceIdentifier(null);
-        List<Space> spaces = commonServer.listSpaces(systemSessionToken, identifier);
-        for (Space space : spaces)
-        {
-            if (space.getCode().equals(spaceCode))
-            {
-                return space;
-            }
-        }
-        return null;
-    }
-
-    protected NewExperiment experiment(int number)
-    {
-        NewExperiment experiment =
-                new NewExperiment(project1.getIdentifier() + "/OLT-E" + number,
-                        EXPERIMENT_TYPE_CODE);
-        experiment.setAttachments(Collections.<NewAttachment> emptyList());
-        experiment.setProperties(new IEntityProperty[]
-            { new PropertyBuilder("DESCRIPTION").value("hello " + number).getProperty() });
-        return experiment;
-    }
-
-    protected List<String> extractCodes(List<? extends ICodeHolder> codeHolders)
-    {
-        List<String> result = new ArrayList<String>();
-        for (ICodeHolder codeHolder : codeHolders)
-        {
-            result.add(codeHolder.getCode());
-        }
-        Collections.sort(result);
-        return result;
-    }
-
-    protected ProjectIdentifier createProjectIdentifier(String identifier)
-    {
-        return new ProjectIdentifierFactory(identifier).createIdentifier();
-    }
-
 }
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/optimistic_locking/ProjectOptimisticLockingTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/optimistic_locking/ProjectOptimisticLockingTest.java
index f1fb28eb17867a09473609f929f6d8a1cc10b785..d1d75fc9f9d5c3ada1db20b0b06902e4ff5009ed 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/optimistic_locking/ProjectOptimisticLockingTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/optimistic_locking/ProjectOptimisticLockingTest.java
@@ -22,15 +22,8 @@ import static org.testng.AssertJUnit.fail;
 import java.util.Collections;
 import java.util.List;
 
-import org.apache.log4j.Logger;
 import org.testng.annotations.Test;
 
-import ch.systemsx.cisd.common.concurrent.MessageChannel;
-import ch.systemsx.cisd.common.concurrent.MessageChannelBuilder;
-import ch.systemsx.cisd.common.logging.LogCategory;
-import ch.systemsx.cisd.common.logging.LogFactory;
-import ch.systemsx.cisd.openbis.common.conversation.context.ServiceConversationsThreadContext;
-import ch.systemsx.cisd.openbis.common.conversation.progress.IServiceConversationProgressListener;
 import ch.systemsx.cisd.openbis.generic.client.web.client.exception.UserFailureException;
 import ch.systemsx.cisd.openbis.generic.server.util.TimeIntervalChecker;
 import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
@@ -42,7 +35,6 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Project;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ProjectUpdates;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.builders.ExperimentTypeBuilder;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.builders.PropertyBuilder;
-import ch.systemsx.cisd.openbis.generic.shared.dto.AtomicEntityOperationDetails;
 import ch.systemsx.cisd.openbis.generic.shared.dto.builders.AtomicEntityOperationDetailsBuilder;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ProjectIdentifier;
 
@@ -51,32 +43,23 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ProjectIdentifier;
  */
 public class ProjectOptimisticLockingTest extends OptimisticLockingTestCase
 {
-    private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION,
-            ProjectOptimisticLockingTest.class);
-
-    private static final String REGISTERED = "registered";
-
-    private static final String FIRST_REGISTERED = "First registered";
-
-    private static final String CREATE_EXPERIMENTS_PHASE = "createExperiments";
-
     @Test
     public void testCreateProject()
     {
         Project project = new Project();
         project.setCode("POLT-1");
-        String identifier = "/" + space1.getCode() + "/POLT-1";
+        String identifier = "/" + toolBox.space1.getCode() + "/POLT-1";
         project.setIdentifier(identifier);
         project.setDescription("ProjectOptimisticLockingTest test");
-        project.setSpace(space1);
+        project.setSpace(toolBox.space1);
         logIntoCommonClientService();
-        TimeIntervalChecker timeIntervalChecker = new TimeIntervalChecker(1);
+        TimeIntervalChecker timeIntervalChecker = new TimeIntervalChecker(1000);
 
         commonClientService.registerProject(SESSION_KEY, project);
 
         Project p =
-                commonServer
-                        .getProjectInfo(systemSessionToken, createProjectIdentifier(identifier));
+                commonServer.getProjectInfo(systemSessionToken,
+                        toolBox.createProjectIdentifier(identifier));
         assertEquals(project.getDescription(), p.getDescription());
         assertEquals("test", p.getRegistrator().getUserId());
         assertEquals("test", p.getModifier().getUserId());
@@ -87,7 +70,8 @@ public class ProjectOptimisticLockingTest extends OptimisticLockingTestCase
     @Test
     public void testUpdateProjectAndCheckModificationDateAndModifier()
     {
-        ProjectIdentifier projectIdentifier = createProjectIdentifier(project1.getIdentifier());
+        ProjectIdentifier projectIdentifier =
+                toolBox.createProjectIdentifier(toolBox.project1.getIdentifier());
         Project p = commonServer.getProjectInfo(systemSessionToken, projectIdentifier);
         ProjectUpdates updates = new ProjectUpdates();
         updates.setVersion(p.getVersion());
@@ -96,12 +80,12 @@ public class ProjectOptimisticLockingTest extends OptimisticLockingTestCase
         updates.setAttachments(Collections.<NewAttachment> emptyList());
         updates.setAttachmentSessionKey(SESSION_KEY);
         logIntoCommonClientService();
-        TimeIntervalChecker timeIntervalChecker = new TimeIntervalChecker(1);
+        TimeIntervalChecker timeIntervalChecker = new TimeIntervalChecker();
 
         commonClientService.updateProject(updates);
 
         p = commonServer.getProjectInfo(systemSessionToken, projectIdentifier);
-        assertEquals(project1.getDescription() + " 2", p.getDescription());
+        assertEquals(toolBox.project1.getDescription() + " 2", p.getDescription());
         assertEquals("system", p.getRegistrator().getUserId());
         assertEquals("test", p.getModifier().getUserId());
         timeIntervalChecker.assertDateInInterval(p.getModificationDate());
@@ -111,7 +95,8 @@ public class ProjectOptimisticLockingTest extends OptimisticLockingTestCase
     @Test
     public void testUpdateProjectWithOldVersion()
     {
-        ProjectIdentifier projectIdentifier = createProjectIdentifier(project1.getIdentifier());
+        ProjectIdentifier projectIdentifier =
+                toolBox.createProjectIdentifier(toolBox.project1.getIdentifier());
         Project currentProject = commonServer.getProjectInfo(systemSessionToken, projectIdentifier);
         ProjectUpdates updates = new ProjectUpdates();
         updates.setVersion(currentProject.getVersion());
@@ -138,121 +123,37 @@ public class ProjectOptimisticLockingTest extends OptimisticLockingTestCase
     {
         String sessionToken = logIntoCommonClientService().getSessionID();
         NewExperiment experiment =
-                new NewExperiment(project1.getIdentifier() + "/POLT-1", EXPERIMENT_TYPE_CODE);
+                new NewExperiment(toolBox.project1.getIdentifier() + "/POLT-1",
+                        ToolBox.EXPERIMENT_TYPE_CODE);
         experiment.setAttachments(Collections.<NewAttachment> emptyList());
         experiment.setProperties(new IEntityProperty[]
             { new PropertyBuilder("DESCRIPTION").value("hello").getProperty() });
-        assertEquals("system", project1.getModifier().getUserId());
-        TimeIntervalChecker timeIntervalChecker = new TimeIntervalChecker(1);
+        assertEquals("system", toolBox.project1.getModifier().getUserId());
+        TimeIntervalChecker timeIntervalChecker = new TimeIntervalChecker();
 
         genericServer.registerExperiment(sessionToken, experiment,
                 Collections.<NewAttachment> emptyList());
 
-        checkModifierAndModificationDateOfProject1(timeIntervalChecker);
+        toolBox.checkModifierAndModificationDateOfProject1(timeIntervalChecker);
     }
 
     @Test
     public void testRegisterExperiments()
     {
-        assertEquals("system", project1.getModifier().getUserId());
+        assertEquals("system", toolBox.project1.getModifier().getUserId());
         AtomicEntityOperationDetailsBuilder builder = new AtomicEntityOperationDetailsBuilder();
-        builder.user(USER_ID);
-        builder.experiment(experiment(1)).experiment(experiment(2));
-        TimeIntervalChecker timeIntervalChecker = new TimeIntervalChecker(1);
+        builder.user(ToolBox.USER_ID);
+        builder.experiment(toolBox.experiment(1)).experiment(toolBox.experiment(2));
+        TimeIntervalChecker timeIntervalChecker = new TimeIntervalChecker();
 
         etlService.performEntityOperations(systemSessionToken, builder.getDetails());
 
         List<Experiment> experiments =
                 commonServer.listExperiments(systemSessionToken,
-                        new ExperimentTypeBuilder().code(EXPERIMENT_TYPE_CODE).getExperimentType(),
-                        createProjectIdentifier(project1.getIdentifier()));
-        assertEquals("[OLT-E1, OLT-E2]", extractCodes(experiments).toString());
-        checkModifierAndModificationDateOfProject1(timeIntervalChecker, USER_ID);
-    }
-
-    /*
-     * This test registers three experiments for the same project. Two of them are registered by the
-     * main thread using performEntityOperations(). A second thread registers an experiment between
-     * the registration of the two other experiments. This is done by using a
-     * IServiceConversationProgressListener together with two message channels to coordinate the
-     * order of actions in both threads.
-     */
-    @Test
-    public void testRegisterExperimentsInTwoThreads()
-    {
-        assertEquals("system", project1.getModifier().getUserId());
-        final StringBuilder stringBuilder = new StringBuilder();
-        final MessageChannel messageChannelMain =
-                new MessageChannelBuilder(10000).name("main").logger(operationLog).getChannel();
-        final MessageChannel messageChannelSecond =
-                new MessageChannelBuilder(10000).name("second").logger(operationLog).getChannel();
-        final IServiceConversationProgressListener listener =
-                new AbstractServiceConversationProgressListener(operationLog)
-                    {
-                        @Override
-                        public void handleProgress(String phaseName, int totalItemsToProcess,
-                                int numItemsProcessed)
-                        {
-                            stringBuilder.append(phaseName).append(" ").append(numItemsProcessed)
-                                    .append("/").append(totalItemsToProcess).append("\n");
-                            if (phaseName.equals(CREATE_EXPERIMENTS_PHASE)
-                                    && numItemsProcessed == 1 && totalItemsToProcess == 2)
-                            {
-                                messageChannelMain.send(FIRST_REGISTERED);
-                            }
-                        }
-                    };
-        TimeIntervalChecker timeIntervalChecker = new TimeIntervalChecker(1);
-
-        new Thread(new Runnable()
-            {
-                @Override
-                public void run()
-                {
-                    NewExperiment experiment3 = experiment(3);
-                    String sessionToken =
-                            genericServer.tryToAuthenticate("test", "a").getSessionToken();
-                    messageChannelMain.assertNextMessage(FIRST_REGISTERED);
-                    genericServer.registerExperiment(sessionToken, experiment3,
-                            Collections.<NewAttachment> emptyList());
-                    messageChannelSecond.send(REGISTERED);
-                }
-            }).start();
-
-        ServiceConversationsThreadContext.setProgressListener(listener);
-        AtomicEntityOperationDetailsBuilder builder = new AtomicEntityOperationDetailsBuilder();
-        builder.user(USER_ID);
-        builder.experiment(experiment(1)).experiment(experiment(2));
-        AtomicEntityOperationDetails details = builder.getDetails();
-
-        etlService.performEntityOperations(systemSessionToken, details);
-
-        messageChannelSecond.assertNextMessage(REGISTERED);
-
-        List<Experiment> experiments =
-                commonServer.listExperiments(systemSessionToken,
-                        new ExperimentTypeBuilder().code(EXPERIMENT_TYPE_CODE).getExperimentType(),
-                        createProjectIdentifier(project1.getIdentifier()));
-        assertEquals("[OLT-E1, OLT-E2, OLT-E3]", extractCodes(experiments).toString());
-        checkModifierAndModificationDateOfProject1(timeIntervalChecker);
-        assertEquals("authorize 1/2\n" + "authorize 2/2\n" + "createExperiments 1/2\n"
-                + "createExperiments 2/2\n", stringBuilder.toString());
+                        new ExperimentTypeBuilder().code(ToolBox.EXPERIMENT_TYPE_CODE)
+                                .getExperimentType(), toolBox
+                                .createProjectIdentifier(toolBox.project1.getIdentifier()));
+        assertEquals("[OLT-E1, OLT-E2]", toolBox.extractCodes(experiments).toString());
+        toolBox.checkModifierAndModificationDateOfProject1(timeIntervalChecker, ToolBox.USER_ID);
     }
-
-    private void checkModifierAndModificationDateOfProject1(TimeIntervalChecker timeIntervalChecker)
-    {
-        checkModifierAndModificationDateOfProject1(timeIntervalChecker, "test");
-    }
-
-    private void checkModifierAndModificationDateOfProject1(
-            TimeIntervalChecker timeIntervalChecker, String modifier)
-    {
-        ProjectIdentifier projectIdentifier = createProjectIdentifier(project1.getIdentifier());
-        Project p = commonServer.getProjectInfo(systemSessionToken, projectIdentifier);
-        assertEquals("system", p.getRegistrator().getUserId());
-        assertEquals(project1.getRegistrationDate(), p.getRegistrationDate());
-        assertEquals(modifier, p.getModifier().getUserId());
-        timeIntervalChecker.assertDateInInterval(p.getModificationDate());
-    }
-
 }
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/optimistic_locking/ToolBox.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/optimistic_locking/ToolBox.java
new file mode 100644
index 0000000000000000000000000000000000000000..2ac92f5a1c602ea45facb8b93d67c374dada3079
--- /dev/null
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/optimistic_locking/ToolBox.java
@@ -0,0 +1,358 @@
+/*
+ * Copyright 2012 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.systemtest.optimistic_locking;
+
+import static org.testng.AssertJUnit.assertEquals;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import ch.systemsx.cisd.openbis.generic.server.util.TimeIntervalChecker;
+import ch.systemsx.cisd.openbis.generic.shared.ICommonServer;
+import ch.systemsx.cisd.openbis.generic.shared.IETLLIMSService;
+import ch.systemsx.cisd.openbis.generic.shared.basic.ICodeHolder;
+import ch.systemsx.cisd.openbis.generic.shared.basic.IIdentifierHolder;
+import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetType;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Deletion;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DeletionType;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.FileFormatType;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Grantee;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityProperty;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ListSampleCriteria;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.LocatorType;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewAttachment;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewExperiment;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewSample;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Person;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Project;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.RoleWithHierarchy.RoleCode;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleType;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Space;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.builders.ExperimentTypeBuilder;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.builders.PropertyBuilder;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.builders.SampleTypeBuilder;
+import ch.systemsx.cisd.openbis.generic.shared.dto.NewDataSet;
+import ch.systemsx.cisd.openbis.generic.shared.dto.NewProperty;
+import ch.systemsx.cisd.openbis.generic.shared.dto.StorageFormat;
+import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.DatabaseInstanceIdentifier;
+import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifierFactory;
+import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ProjectIdentifier;
+import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ProjectIdentifierFactory;
+import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifierFactory;
+import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SpaceIdentifierFactory;
+import ch.systemsx.cisd.openbis.plugin.generic.shared.IGenericServer;
+
+/**
+ * @author Franz-Josef Elmer
+ */
+public class ToolBox
+{
+    public static final String USER_ID = "optimist";
+
+    public static final String SPACE_1 = "OPTIMISTIC_LOCKING_1";
+
+    public static final String SPACE_2 = "OPTIMISTIC_LOCKING_2";
+
+    public static final String EXPERIMENT_TYPE_CODE = "SIRNA_HCS";
+
+    public static final String SAMPLE_TYPE_CODE = "NORMAL";
+
+    public static final String DATA_STORE_CODE = "STANDARD";
+
+    public static final String REGISTERED = "registered";
+
+    public static final String FIRST_REGISTERED = "First registered";
+
+    public static final List<IEntityProperty> NO_PROPERTIES = Collections
+            .<IEntityProperty> emptyList();
+
+    public static final List<NewAttachment> NO_ATTACHMENTS = Collections
+            .<NewAttachment> emptyList();
+
+    private static final LocatorType LOCATOR_TYPE = new LocatorType(
+            LocatorType.DEFAULT_LOCATOR_TYPE_CODE);
+
+    private static final FileFormatType FILE_FORMAT_TYPE = new FileFormatType("XML");
+
+    private static final DataSetType DATA_SET_TYPE = new DataSetType("UNKNOWN");
+
+    private final ICommonServer commonServer;
+
+    private final IGenericServer genericServer;
+
+    private final IETLLIMSService etlService;
+
+    private final String systemSessionToken;
+
+    public Space space1;
+
+    public Space space2;
+
+    public Project project1;
+
+    public Project project2;
+
+    public ToolBox(ICommonServer commonServer, IGenericServer genericServer,
+            IETLLIMSService etlService, String systemSessionToken)
+    {
+        this.commonServer = commonServer;
+        this.genericServer = genericServer;
+        this.etlService = etlService;
+        this.systemSessionToken = systemSessionToken;
+
+    }
+
+    void createSpacesAndProjects()
+    {
+        space1 = findOrCreateSpace(SPACE_1);
+        space2 = findOrCreateSpace(SPACE_2);
+        project1 = findOrCreateProject("/" + SPACE_1 + "/P1");
+        project2 = findOrCreateProject("/" + SPACE_2 + "/P2");
+        createInstanceAdmin(USER_ID);
+    }
+
+    void deleteSpaces()
+    {
+        deleteSpace(space1);
+        deleteSpace(space2);
+    }
+
+    private void deleteSpace(Space space)
+    {
+        trashExperiments(space);
+        trashSamples(space);
+        emptyTrashCan();
+        deleteProjects(space);
+        commonServer.deleteSpaces(systemSessionToken, Arrays.asList(new TechId(space.getId())),
+                "cleanup");
+    }
+
+    private void deleteProjects(Space space)
+    {
+        List<Project> projects = commonServer.listProjects(systemSessionToken);
+        List<TechId> projectIds = new ArrayList<TechId>();
+        for (Project project : projects)
+        {
+            if (project.getSpace().getCode().equals(space.getCode()))
+            {
+                projectIds.add(new TechId(project));
+            }
+        }
+        commonServer.deleteProjects(systemSessionToken, projectIds, "cleanup");
+    }
+
+    private void emptyTrashCan()
+    {
+        List<Deletion> deletions = commonServer.listDeletions(systemSessionToken, false);
+        commonServer.deletePermanently(systemSessionToken, TechId.createList(deletions));
+    }
+
+    private void trashSamples(Space space)
+    {
+        ListSampleCriteria criteria = new ListSampleCriteria();
+        criteria.setSampleType(SampleType.createAllSampleType(Collections.<SampleType> emptyList(),
+                false));
+        criteria.setSpaceCode(space.getCode());
+        criteria.setIncludeSpace(true);
+        criteria.setIncludeInstance(false);
+        criteria.setExcludeWithoutExperiment(false);
+        List<Sample> samples = commonServer.listSamples(systemSessionToken, criteria);
+        commonServer.deleteSamples(systemSessionToken, TechId.createList(samples), "cleanup",
+                DeletionType.TRASH);
+    }
+
+    private void trashExperiments(Space space)
+    {
+        List<Experiment> experiments =
+                commonServer.listExperiments(systemSessionToken,
+                        new ExperimentTypeBuilder().code(EXPERIMENT_TYPE_CODE).getExperimentType(),
+                        new SpaceIdentifierFactory(space.getIdentifier()).createIdentifier());
+        commonServer.deleteExperiments(systemSessionToken, TechId.createList(experiments),
+                "cleanup", DeletionType.TRASH);
+    }
+
+    public void createInstanceAdmin(String userId)
+    {
+        List<Person> persons = commonServer.listPersons(systemSessionToken);
+        for (Person person : persons)
+        {
+            if (person.getUserId().equals(userId))
+            {
+                return;
+            }
+        }
+        commonServer.registerPerson(systemSessionToken, userId);
+        commonServer.registerInstanceRole(systemSessionToken, RoleCode.ADMIN,
+                Grantee.createPerson(userId));
+    }
+
+    public Project findOrCreateProject(String projectIdentifier)
+    {
+        Project project = tryToFindProject(projectIdentifier);
+        if (project != null)
+        {
+            return project;
+        }
+        commonServer.registerProject(systemSessionToken, new ProjectIdentifierFactory(
+                projectIdentifier).createIdentifier(), "A test project", null, Collections
+                .<NewAttachment> emptyList());
+        return tryToFindProject(projectIdentifier);
+    }
+
+    public Project tryToFindProject(String projectIdentifier)
+    {
+        List<Project> projects = commonServer.listProjects(systemSessionToken);
+        for (Project project : projects)
+        {
+            if (project.getIdentifier().equals(projectIdentifier))
+            {
+                return project;
+            }
+        }
+        return null;
+    }
+
+    public Space findOrCreateSpace(String spaceCode)
+    {
+        Space space = tryToFindSpace(spaceCode);
+        if (space != null)
+        {
+            return space;
+        }
+        commonServer.registerSpace(systemSessionToken, spaceCode, "A test space");
+        return tryToFindSpace(spaceCode);
+    }
+
+    public Space tryToFindSpace(String spaceCode)
+    {
+        DatabaseInstanceIdentifier identifier = new DatabaseInstanceIdentifier(null);
+        List<Space> spaces = commonServer.listSpaces(systemSessionToken, identifier);
+        for (Space space : spaces)
+        {
+            if (space.getCode().equals(spaceCode))
+            {
+                return space;
+            }
+        }
+        return null;
+    }
+
+    NewExperiment experiment(int number)
+    {
+        NewExperiment experiment =
+                new NewExperiment(project1.getIdentifier() + "/OLT-E" + number,
+                        EXPERIMENT_TYPE_CODE);
+        experiment.setAttachments(Collections.<NewAttachment> emptyList());
+        experiment.setProperties(new IEntityProperty[]
+            { new PropertyBuilder("DESCRIPTION").value("hello " + number).getProperty() });
+        return experiment;
+    }
+
+    public List<String> extractCodes(List<? extends ICodeHolder> codeHolders)
+    {
+        List<String> result = new ArrayList<String>();
+        for (ICodeHolder codeHolder : codeHolders)
+        {
+            result.add(codeHolder.getCode());
+        }
+        Collections.sort(result);
+        return result;
+    }
+
+    public ProjectIdentifier createProjectIdentifier(String identifier)
+    {
+        return new ProjectIdentifierFactory(identifier).createIdentifier();
+    }
+
+    public Experiment createAndLoadExperiment(int number)
+    {
+        NewExperiment experiment = experiment(number);
+        genericServer.registerExperiment(systemSessionToken, experiment, NO_ATTACHMENTS);
+        return loadExperiment(experiment);
+    }
+
+    public Experiment loadExperiment(final IIdentifierHolder experiment)
+    {
+        return commonServer.getExperimentInfo(systemSessionToken,
+                ExperimentIdentifierFactory.parse(experiment.getIdentifier()));
+    }
+
+    public NewSample sample(int number, IIdentifierHolder experiment)
+    {
+        NewSample sample = sample(number);
+        sample.setExperimentIdentifier(experiment.getIdentifier());
+        return sample;
+    }
+
+    public NewSample sample(int number)
+    {
+        NewSample sample = new NewSample();
+        sample.setIdentifier("/" + ToolBox.SPACE_1 + "/OLT-S" + number);
+        sample.setSampleType(new SampleTypeBuilder().code(SAMPLE_TYPE_CODE).getSampleType());
+        return sample;
+    }
+
+    public Sample loadSample(IIdentifierHolder sample)
+    {
+        return etlService.tryGetSampleWithExperiment(systemSessionToken,
+                SampleIdentifierFactory.parse(sample.getIdentifier()));
+    }
+
+    public NewDataSet dataSet(String code, Experiment experiment)
+    {
+        NewDataSet dataSet = dataSet(code);
+        dataSet.setExperimentIdentifierOrNull(ExperimentIdentifierFactory.parse(experiment
+                .getIdentifier()));
+        return dataSet;
+    }
+
+    private NewDataSet dataSet(String code)
+    {
+        NewDataSet dataSet = new NewDataSet();
+        dataSet.setCode(code);
+        dataSet.setDataSetType(DATA_SET_TYPE);
+        dataSet.setFileFormatType(FILE_FORMAT_TYPE);
+        dataSet.setDataSetProperties(Collections.<NewProperty> emptyList());
+        dataSet.setLocation("a/b/c/" + code);
+        dataSet.setLocatorType(LOCATOR_TYPE);
+        dataSet.setStorageFormat(StorageFormat.PROPRIETARY);
+        dataSet.setDataStoreCode(DATA_STORE_CODE);
+        return dataSet;
+    }
+
+    public void checkModifierAndModificationDateOfProject1(TimeIntervalChecker timeIntervalChecker)
+    {
+        checkModifierAndModificationDateOfProject1(timeIntervalChecker, "test");
+    }
+
+    public void checkModifierAndModificationDateOfProject1(TimeIntervalChecker timeIntervalChecker,
+            String modifier)
+    {
+        ProjectIdentifier projectIdentifier = createProjectIdentifier(project1.getIdentifier());
+        Project p = commonServer.getProjectInfo(systemSessionToken, projectIdentifier);
+        assertEquals("system", p.getRegistrator().getUserId());
+        assertEquals(project1.getRegistrationDate(), p.getRegistrationDate());
+        assertEquals(modifier, p.getModifier().getUserId());
+        timeIntervalChecker.assertDateInInterval(p.getModificationDate());
+    }
+
+}