diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/DataSetStorageAlgorithm.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/DataSetStorageAlgorithm.java
index 28786b907c063b1643b8caf24fe60adc44cbbe02..3e8fb7de3ddf5a3b0d2127fbd619f30cd4e56e95 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/DataSetStorageAlgorithm.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/DataSetStorageAlgorithm.java
@@ -218,6 +218,8 @@ public class DataSetStorageAlgorithm<T extends DataSetInformation>
         data.setFileFormatType(registrationDetails.getFileFormatType());
         data.setMeasured(registrationDetails.isMeasuredData());
         data.setDataStoreCode(dataStoreCode);
+        data.setExperimentIdentifierOrNull(dataSetInformation.getExperimentIdentifier());
+        data.setSampleIdentifierOrNull(dataSetInformation.getSampleIdentifier());
 
         File dataFile = ((StoredState<T>) state).getDataFile();
 
diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/DataSetStorageAlgorithmRunner.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/DataSetStorageAlgorithmRunner.java
index 064b62ddb19d93c785ebe05e3bc9246cb6ea0706..6b95debfb66cb6f4935397a9b4f3b77a92a0d860 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/DataSetStorageAlgorithmRunner.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/DataSetStorageAlgorithmRunner.java
@@ -23,7 +23,6 @@ import java.util.List;
 import org.apache.log4j.Logger;
 
 import ch.systemsx.cisd.base.exceptions.InterruptedExceptionUnchecked;
-import ch.systemsx.cisd.common.exceptions.HighLevelException;
 import ch.systemsx.cisd.common.logging.LogCategory;
 import ch.systemsx.cisd.common.logging.LogFactory;
 import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService;
@@ -110,10 +109,6 @@ public class DataSetStorageAlgorithmRunner<T extends DataSetInformation>
             // Runs or throws a throwable
             runStorageProcessors();
 
-        } catch (final HighLevelException ex)
-        {
-            rollbackDuringStorageProcessorRun(ex);
-            return Collections.emptyList();
         } catch (final Throwable throwable)
         {
             rollbackDuringStorageProcessorRun(throwable);
@@ -125,10 +120,6 @@ public class DataSetStorageAlgorithmRunner<T extends DataSetInformation>
             // Runs or throw a throwable
             registerDataSetsInApplicationServer();
 
-        } catch (final HighLevelException ex)
-        {
-            rollbackDuringMetadataRegistration(ex);
-            return Collections.emptyList();
         } catch (final Throwable throwable)
         {
             rollbackDuringMetadataRegistration(throwable);
diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/DefaultEntityOperationService.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/DefaultEntityOperationService.java
index 834443b9f15fc6967b1e3139206133a4a53fda01..6a39aadc6186725818548315448676656434cab2 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/DefaultEntityOperationService.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/DefaultEntityOperationService.java
@@ -24,12 +24,10 @@ import ch.systemsx.cisd.openbis.dss.generic.shared.dto.AtomicEntityOperationDeta
 import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation;
 import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetRegistrationInformation;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.AtomicEntityOperationResult;
-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.NewExperiment;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
-import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifier;
-import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifierFactory;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewSample;
+import ch.systemsx.cisd.openbis.generic.shared.dto.NewExternalData;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SampleUpdatesDTO;
 
 public class DefaultEntityOperationService<T extends DataSetInformation> implements
         IEntityOperationService<T>
@@ -44,36 +42,29 @@ public class DefaultEntityOperationService<T extends DataSetInformation> impleme
     public AtomicEntityOperationResult performOperationsInApplcationServer(
             AtomicEntityOperationDetails<T> registrationDetails)
     {
-        ArrayList<Experiment> experimentsCreated = new ArrayList<Experiment>();
-        ArrayList<Sample> samplesUpdated = new ArrayList<Sample>();
-        ArrayList<Sample> samplesCreated = new ArrayList<Sample>();
-        ArrayList<ExternalData> dataSetsCreated = new ArrayList<ExternalData>();
-
         IEncapsulatedOpenBISService openBisService =
                 registrator.getGlobalState().getOpenBisService();
-        List<NewExperiment> experimentRegistrations =
-                registrationDetails.getExperimentRegistrations();
-        for (NewExperiment experiment : experimentRegistrations)
-        {
-            openBisService.registerExperiment(experiment);
-            ExperimentIdentifier experimentIdentifier =
-                    new ExperimentIdentifierFactory(experiment.getIdentifier()).createIdentifier();
-            experimentsCreated.add(openBisService.tryToGetExperiment(experimentIdentifier));
-        }
 
-        List<DataSetRegistrationInformation<T>> dataSetRegistrations =
-                registrationDetails.getDataSetRegistrations();
-        for (DataSetRegistrationInformation<T> dataSetRegistration : dataSetRegistrations)
+        return openBisService.performEntityOperations(convert(registrationDetails));
+    }
+
+    private ch.systemsx.cisd.openbis.generic.shared.dto.AtomicEntityOperationDetails convert(
+            AtomicEntityOperationDetails<T> details)
+    {
+
+        List<NewExperiment> experimentRegistrations = details.getExperimentRegistrations();
+        List<SampleUpdatesDTO> sampleUpdates = details.getSampleUpdates();
+        List<NewSample> sampleRegistrations = details.getSampleRegistrations();
+        List<NewExternalData> dataSetRegistrations = new ArrayList<NewExternalData>();
+
+        for (DataSetRegistrationInformation<?> dsRegistration : details.getDataSetRegistrations())
         {
-            openBisService.registerDataSet(dataSetRegistration.getDataSetInformation(),
-                    dataSetRegistration.getExternalData());
-            dataSetsCreated.add(openBisService.tryGetDataSet(dataSetRegistration
-                    .getDataSetInformation().getDataSetCode()));
+            NewExternalData newExternalData = dsRegistration.getExternalData();
+            dataSetRegistrations.add(newExternalData);
         }
 
-        return new AtomicEntityOperationResult(experimentsCreated, samplesUpdated, samplesCreated,
-                dataSetsCreated);
-
+        return new ch.systemsx.cisd.openbis.generic.shared.dto.AtomicEntityOperationDetails(
+                experimentRegistrations, sampleUpdates, sampleRegistrations, dataSetRegistrations);
     }
 
 }
\ No newline at end of file
diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/IExperiment.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/IExperiment.java
index 9a123ffc7d697ddf095d33e29c1b1f334ef0811b..ec38be0b6ae227cd1ea962f23b4e1eb64b923afa 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/IExperiment.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/IExperiment.java
@@ -23,4 +23,20 @@ package ch.systemsx.cisd.etlserver.registrator.api.v1;
  */
 public interface IExperiment extends IExperimentImmutable
 {
+    /**
+     * Set the value for a property.
+     * 
+     * @throws IllegalArgumentException if no property for code <code>propertyCode</code> is found.
+     */
+    void setPropertyValue(String propertyCode, String propertyValue);
+
+    /**
+     * Set the code for this experiment.
+     */
+    void setCode(String code);
+
+    /**
+     * Set the experiment type for this experiment.
+     */
+    void setType(String experimentType);
 }
diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/IExperimentImmutable.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/IExperimentImmutable.java
index ddc8bda7414540ca12687d0661a8268e00db5e76..f48b20aeb9c318196e4ecbe8d32218093093093d 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/IExperimentImmutable.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/IExperimentImmutable.java
@@ -17,14 +17,35 @@
 package ch.systemsx.cisd.etlserver.registrator.api.v1;
 
 /**
- * Read-only interface to an existing experiment. 
- *
+ * Read-only interface to an existing experiment.
+ * 
  * @author Chandrasekhar Ramakrishnan
  */
 public interface IExperimentImmutable
 {
+    /**
+     * Return the experiment identifier of this experiment.
+     */
+    String getExperimentIdentifier();
+
     /**
      * Return true if the experiment is in openBIS.
      */
     boolean isExistingExperiment();
+
+    /**
+     * Return the code for this experiment. May be null.
+     */
+    String getCode();
+
+    /**
+     * Return the type for this experiment. May be null.
+     */
+    String getType();
+
+    /**
+     * Return the value of a property specified by a code. May return null of no such property with
+     * code <code>propertyCode</code> is found.
+     */
+    String getPropertyValue(String propertyCode);
 }
diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/ISample.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/ISample.java
index ab82ffb1f34bc855ad9d366a7c20a64dc2a45521..216ffab8151b620b5006cc786b5817a83b2a5623 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/ISample.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/ISample.java
@@ -22,4 +22,26 @@ package ch.systemsx.cisd.etlserver.registrator.api.v1;
 public interface ISample extends ISampleImmutable
 {
 
+    /**
+     * Set the experiment for this sample. The experiment need not be immutable, but the immutable
+     * one is the superclass.
+     */
+    void setExperiment(IExperimentImmutable experiment);
+
+    /**
+     * Set the code for this sample.
+     */
+    void setCode(String code);
+
+    /**
+     * Set the type for this sample.
+     */
+    void setType(String type);
+
+    /**
+     * Set the value for a property.
+     * 
+     * @throws IllegalArgumentException if no property for code <code>propertyCode</code> is found.
+     */
+    void setPropertyValue(String propertyCode, String propertyValue);
 }
diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/ISampleImmutable.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/ISampleImmutable.java
index 3fbfe8a323872df0e69d88d865e2b3c735a71db2..aa0554ada301eecc71291ef1f83fb6003b5c1b9d 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/ISampleImmutable.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/ISampleImmutable.java
@@ -23,8 +23,35 @@ package ch.systemsx.cisd.etlserver.registrator.api.v1;
  */
 public interface ISampleImmutable
 {
+    /**
+     * Return the identifier for this sample.
+     */
+    String getSampleIdentifier();
+
+    /**
+     * Return the code for this sample. May be null.
+     */
+    String getCode();
+
+    /**
+     * Return the experiment for this sample. May be null.
+     */
+    IExperimentImmutable getExperiment();
+
+    /**
+     * Return the type for this sample. May be null.
+     */
+    String getType();
+
     /**
      * Return true if the sample exists in the database.
      */
     boolean isExistingSample();
+
+    /**
+     * Return the value of a property specified by a code. May return null of no such property with
+     * code <code>propertyCode</code> is found.
+     */
+    String getPropertyValue(String propertyCode);
+
 }
diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/impl/AbstractTransactionState.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/impl/AbstractTransactionState.java
index b8adafbba62b81d40e35753df97d2f9170b9cbcf..f4675b3d48c50f6e49032890f09510ab421dfa52 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/impl/AbstractTransactionState.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/impl/AbstractTransactionState.java
@@ -18,8 +18,10 @@ package ch.systemsx.cisd.etlserver.registrator.api.v1.impl;
 
 import java.io.File;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
+import ch.systemsx.cisd.common.exceptions.NotImplementedException;
 import ch.systemsx.cisd.common.filesystem.FileUtilities;
 import ch.systemsx.cisd.etlserver.registrator.DataSetRegistrationDetails;
 import ch.systemsx.cisd.etlserver.registrator.DataSetRegistrationService;
@@ -33,10 +35,16 @@ import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService;
 import ch.systemsx.cisd.openbis.dss.generic.shared.dto.AtomicEntityOperationDetails;
 import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation;
 import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetRegistrationInformation;
+import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityProperty;
+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.dto.ExperimentUpdatesDTO;
 import ch.systemsx.cisd.openbis.generic.shared.dto.SampleUpdatesDTO;
+import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifierFactory;
+import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier;
+import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifierFactory;
 
 /**
  * Abstract superclass for the states a DataSetRegistrationTransaction can be in.
@@ -86,6 +94,10 @@ abstract class AbstractTransactionState<T extends DataSetInformation>
 
         private final List<Experiment> experimentsToBeRegistered = new ArrayList<Experiment>();
 
+        private final List<Sample> samplesToBeRegistered = new ArrayList<Sample>();
+
+        private final List<Sample> samplesToBeUpdated = new ArrayList<Sample>();
+
         public LiveTransactionState(DataSetRegistrationTransaction<T> parent,
                 RollbackStack rollbackStack, File workingDirectory, File stagingDirectory,
                 DataSetRegistrationService<T> registrationService,
@@ -134,26 +146,39 @@ abstract class AbstractTransactionState<T extends DataSetInformation>
 
         public ISample getSampleForUpdate(String sampleIdentifierString)
         {
-            // TODO Auto-generated method stub
-            return null;
+            SampleIdentifier sampleIdentifier =
+                    new SampleIdentifierFactory(sampleIdentifierString).createIdentifier();
+            ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample sample =
+                    openBisService.tryGetSampleWithExperiment(sampleIdentifier);
+            // TODO KE: Ask Sekhar if we should throw an exception or simply return NULL
+            if (sample == null)
+            {
+                throw new IllegalArgumentException("Could not find sample with identifier"
+                        + sampleIdentifierString);
+            }
+            Sample result = new Sample(sample);
+            samplesToBeUpdated.add(result);
+            return result;
         }
 
         public ISample createNewSample(String sampleIdentifierString)
         {
-            // TODO Auto-generated method stub
-            return null;
+            // TODO KE: should we create a new method with a more sensible name (createPermId())
+            String permId = openBisService.createDataSetCode();
+            Sample sample = new Sample(sampleIdentifierString, permId);
+            samplesToBeRegistered.add(sample);
+            return sample;
         }
 
         public IExperiment getExperimentForUpdate(String experimentIdentifierString)
         {
-            // TODO Auto-generated method stub
-            return null;
+            throw new NotImplementedException();
         }
 
         public IExperiment createNewExperiment(String experimentIdentifierString)
         {
-            String permID = openBisService.createDataSetCode();
-            Experiment experiment = new Experiment(experimentIdentifierString, permID);
+            String permId = openBisService.createDataSetCode();
+            Experiment experiment = new Experiment(experimentIdentifierString, permId);
             experimentsToBeRegistered.add(experiment);
             return experiment;
         }
@@ -275,11 +300,14 @@ abstract class AbstractTransactionState<T extends DataSetInformation>
         AtomicEntityOperationDetails<T> createEntityOperationDetails(
                 List<DataSetRegistrationInformation<T>> dataSetRegistrations)
         {
-            ArrayList<NewExperiment> experimentRegistrations = new ArrayList<NewExperiment>();
-            ArrayList<ExperimentUpdatesDTO> experimentUpdates =
+
+            List<NewExperiment> experimentRegistrations = convertExperimentsToBeRegistered();
+            List<SampleUpdatesDTO> sampleUpdates = convertSamplesToBeUpdated();
+            List<NewSample> sampleRegistrations = convertSamplesToBeRegistered();
+
+            // experiment updates not yet supported
+            List<ExperimentUpdatesDTO> experimentUpdates =
                     new ArrayList<ExperimentUpdatesDTO>();
-            ArrayList<SampleUpdatesDTO> sampleUpdates = new ArrayList<SampleUpdatesDTO>();
-            ArrayList<NewSample> sampleRegistrations = new ArrayList<NewSample>();
 
             AtomicEntityOperationDetails<T> registrationDetails =
                     new AtomicEntityOperationDetails<T>(experimentUpdates,
@@ -288,6 +316,60 @@ abstract class AbstractTransactionState<T extends DataSetInformation>
             return registrationDetails;
         }
 
+        private List<NewExperiment> convertExperimentsToBeRegistered() {
+            List<NewExperiment> result = new ArrayList<NewExperiment>();
+            for (Experiment apiExperiment : experimentsToBeRegistered) {
+                ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment experiment = apiExperiment.getExperiment();
+                NewExperiment newExperiment = new NewExperiment();
+                newExperiment.setIdentifier(experiment.getIdentifier());
+                newExperiment.setPermID(experiment.getPermId());
+                IEntityProperty[] properties =
+                        experiment.getProperties().toArray(new IEntityProperty[0]);
+                newExperiment.setProperties(properties);
+                result.add(newExperiment);
+            }
+            return result;
+        }
+
+        private List<NewSample> convertSamplesToBeRegistered()
+        {
+            List<NewSample> result = new ArrayList<NewSample>();
+            for (Sample apiSample : samplesToBeRegistered)
+            {
+                ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample sample =
+                        apiSample.getSample();
+                NewSample newSample = new NewSample();
+                newSample.setIdentifier(sample.getIdentifier());
+                newSample.setPermID(sample.getPermId());
+                IEntityProperty[] properties =
+                        sample.getProperties().toArray(new IEntityProperty[0]);
+                newSample.setProperties(properties);
+                newSample.setExperimentIdentifier(sample.getExperiment().getIdentifier());
+            }
+            return result;
+        }
+
+        private List<SampleUpdatesDTO> convertSamplesToBeUpdated() {
+            List<SampleUpdatesDTO> result = new ArrayList<SampleUpdatesDTO>();
+            for (Sample apiSample : samplesToBeRegistered) {
+                ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample sample =
+                    apiSample.getSample();
+                
+                List<NewAttachment> attachments = Collections.emptyList();
+                SampleUpdatesDTO sampleUpdate = new SampleUpdatesDTO(TechId.create(sample), // db id
+                        sample.getProperties(), // List<IEntityProperty>
+                        ExperimentIdentifierFactory.parse(sample.getExperiment().getIdentifier()), // ExperimentIdentifier
+                        attachments, // Collection<NewAttachment>
+                        sample.getModificationDate(), // Sample version
+                        SampleIdentifierFactory.parse(sample.getIdentifier()), // Sample Identifier
+                        sample.getContainer().getIdentifier(), // Container Identifier
+                        null // Parent Identifiers
+                        );
+                result.add(sampleUpdate);
+            }
+            return result;
+        }
+
         @Override
         public boolean isCommitted()
         {
diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/impl/DataSet.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/impl/DataSet.java
index b3a9b0aa3f91418f10fe4646bbd843b208928825..2c5449dd9030a4791d656c747d6b280a4226a0b9 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/impl/DataSet.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/impl/DataSet.java
@@ -27,6 +27,7 @@ import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.FileFormatType;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifier;
+import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifierFactory;
 
 /**
  * A generic class that represents a data set for the registration API. Can be subclassed.
@@ -148,7 +149,7 @@ public class DataSet<T extends DataSetInformation> implements IDataSet
     protected void setExperiment(ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment exp)
     {
         registrationDetails.getDataSetInformation().setExperiment(exp);
-        ExperimentIdentifier experimentId = new ExperimentIdentifier(exp);
+        ExperimentIdentifier experimentId = ExperimentIdentifierFactory.parse(exp.getIdentifier());
         registrationDetails.getDataSetInformation().setExperimentIdentifier(experimentId);
     }
 }
diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/impl/DataSetRegistrationTransaction.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/impl/DataSetRegistrationTransaction.java
index 427ad66fe7ccdde4b165c9a7bfa5ebe704ce454e..4ead56eec83e8ea6bd2197ec284a6729b9f150a2 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/impl/DataSetRegistrationTransaction.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/impl/DataSetRegistrationTransaction.java
@@ -179,7 +179,7 @@ public class DataSetRegistrationTransaction<T extends DataSetInformation> implem
     {
         SampleIdentifier sampleIdentifier =
                 new SampleIdentifierFactory(sampleIdentifierString).createIdentifier();
-        return new Sample(openBisService.tryGetSampleWithExperiment(sampleIdentifier));
+        return new SampleImmutable(openBisService.tryGetSampleWithExperiment(sampleIdentifier));
     }
 
     public ISample getSampleForUpdate(String sampleIdentifierString)
diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/impl/Experiment.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/impl/Experiment.java
index 4b2437c6a130c6c9bf3d5288d04ba773d12b398c..15f720caef3e3fb06d8c028b554583c9811ee17e 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/impl/Experiment.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/impl/Experiment.java
@@ -16,7 +16,13 @@
 
 package ch.systemsx.cisd.etlserver.registrator.api.v1.impl;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import ch.systemsx.cisd.etlserver.registrator.api.v1.IExperiment;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExperimentType;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityProperty;
+import ch.systemsx.cisd.openbis.generic.shared.util.EntityHelper;
 
 /**
  * Implementation of {@link IExperiment}.
@@ -31,6 +37,9 @@ class Experiment extends ExperimentImmutable implements IExperiment
         ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment experiment = getExperiment();
         experiment.setIdentifier(identifier);
         experiment.setPermId(permID);
+
+        List<IEntityProperty> properties = new ArrayList<IEntityProperty>();
+        experiment.setProperties(properties);
     }
 
     @Override
@@ -39,6 +48,22 @@ class Experiment extends ExperimentImmutable implements IExperiment
         return false;
     }
     
+    public void setCode(String code)
+    {
+        getExperiment().setCode(code);
+    }
+
+    public void setPropertyValue(String propertyCode, String propertyValue)
+    {
+        EntityHelper.createOrUpdateProperty(getExperiment(), propertyCode, propertyValue);
+    }
 
+    public void setType(String experimentType)
+    {
+        ExperimentType type = new ExperimentType();
+        type.setCode(experimentType);
+
+        getExperiment().setExperimentType(type);
+    }
 
 }
diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/impl/ExperimentImmutable.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/impl/ExperimentImmutable.java
index 63afb7afa132ea7456b84ba37e483b5645098bb4..b49cd4ceeea9e1d5281263ec9a7528ad9d05409d 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/impl/ExperimentImmutable.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/impl/ExperimentImmutable.java
@@ -18,6 +18,7 @@ package ch.systemsx.cisd.etlserver.registrator.api.v1.impl;
 
 import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.etlserver.registrator.api.v1.IExperimentImmutable;
+import ch.systemsx.cisd.openbis.generic.shared.util.EntityHelper;
 
 /**
  * @author Chandrasekhar Ramakrishnan
@@ -26,14 +27,15 @@ class ExperimentImmutable implements IExperimentImmutable
 {
     private final ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment experiment;
 
-    public ExperimentImmutable(ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment experiment)
+    public ExperimentImmutable(
+            ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment experiment)
     {
         this.experiment = experiment;
     }
 
-    ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment getExperiment()
+    public String getExperimentIdentifier()
     {
-        return experiment;
+        return experiment.getIdentifier();
     }
 
     public boolean isExistingExperiment()
@@ -51,4 +53,29 @@ class ExperimentImmutable implements IExperimentImmutable
             throw new UserFailureException("Experiment does not exist.");
         }
     }
+
+    public ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment getExperiment()
+    {
+        return experiment;
+    }
+
+    public String getPropertyValue(String propertyCode)
+    {
+        return EntityHelper.tryFindPropertyValue(experiment, propertyCode);
+    }
+
+    public String getCode()
+    {
+        return experiment.getCode();
+    }
+
+    public String getType()
+    {
+        if (experiment.getExperimentType() != null)
+        {
+            return experiment.getExperimentType().getCode();
+        }
+        return null;
+    }
+
 }
diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/impl/Sample.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/impl/Sample.java
index 103c64301cb261d6134217009e9148a0be63314c..4c7206be08c2e8e3cf947d62b2bc347c8d826194 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/impl/Sample.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/impl/Sample.java
@@ -16,40 +16,51 @@
 
 package ch.systemsx.cisd.etlserver.registrator.api.v1.impl;
 
-import ch.systemsx.cisd.common.exceptions.UserFailureException;
+import ch.systemsx.cisd.etlserver.registrator.api.v1.IExperimentImmutable;
 import ch.systemsx.cisd.etlserver.registrator.api.v1.ISample;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleType;
+import ch.systemsx.cisd.openbis.generic.shared.util.EntityHelper;
 
 /**
  * @author Chandrasekhar Ramakrishnan
  */
-public class Sample implements ISample
+public class Sample extends SampleImmutable implements ISample
 {
-    private final ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample sample;
+
+    public Sample(String sampleIdentifier, String permId)
+    {
+        super(new ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample());
+        getSample().setIdentifier(sampleIdentifier);
+        getSample().setPermId(permId);
+    }
 
     public Sample(ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample sample)
     {
-        this.sample = sample;
+        super(sample);
     }
 
-    public ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample getSample()
+    public void setExperiment(IExperimentImmutable experiment)
     {
-        return sample;
+        ExperimentImmutable exp = (ExperimentImmutable) experiment;
+        getSample().setExperiment(exp.getExperiment());
     }
 
-    public boolean isExistingSample()
+    public void setCode(String code)
     {
-        return null != sample;
+        getSample().setCode(code);
     }
 
-    /**
-     * Throw an exception if the sample does not exist
-     */
-    protected void checkExists()
+    public void setPropertyValue(String propertyCode, String propertyValue)
     {
-        if (false == isExistingSample())
-        {
-            throw new UserFailureException("Sample does not exist.");
-        }
+        EntityHelper.createOrUpdateProperty(getSample(), propertyCode, propertyValue);
+    }
+
+    public void setType(String type)
+    {
+        SampleType sampleType = new SampleType();
+        sampleType.setCode(type);
+
+        getSample().setSampleType(sampleType);
     }
 
 }
diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/impl/SampleImmutable.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/impl/SampleImmutable.java
new file mode 100644
index 0000000000000000000000000000000000000000..efdb2918242abc4002945d71afdb0ff77deddcca
--- /dev/null
+++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/registrator/api/v1/impl/SampleImmutable.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2011 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.etlserver.registrator.api.v1.impl;
+
+import ch.systemsx.cisd.common.exceptions.UserFailureException;
+import ch.systemsx.cisd.etlserver.registrator.api.v1.IExperimentImmutable;
+import ch.systemsx.cisd.etlserver.registrator.api.v1.ISampleImmutable;
+import ch.systemsx.cisd.openbis.generic.shared.util.EntityHelper;
+
+/**
+ * @author Chandrasekhar Ramakrishnan
+ */
+public class SampleImmutable implements ISampleImmutable
+{
+    private final ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample sample;
+
+    public SampleImmutable(ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample sample)
+    {
+        this.sample = sample;
+    }
+
+    public IExperimentImmutable getExperiment()
+    {
+        ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment experiment =
+                sample.getExperiment();
+        return (null != experiment) ? new ExperimentImmutable(experiment) : null;
+    }
+
+    public String getSampleIdentifier()
+    {
+        return sample.getIdentifier();
+    }
+
+    public String getCode()
+    {
+        return sample.getCode();
+    }
+
+    public ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample getSample()
+    {
+        return sample;
+    }
+
+    public boolean isExistingSample()
+    {
+        return null != sample;
+    }
+
+    /**
+     * Throw an exception if the sample does not exist
+     */
+    protected void checkExists()
+    {
+        if (false == isExistingSample())
+        {
+            throw new UserFailureException("Sample does not exist.");
+        }
+    }
+
+    public String getPropertyValue(String propertyCode)
+    {
+        return EntityHelper.tryFindPropertyValue(sample, propertyCode);
+    }
+
+    public String getType()
+    {
+        if (sample.getSampleType() != null)
+        {
+            return sample.getSampleType().getCode();
+        }
+        return null;
+    }
+
+}
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/EncapsulatedOpenBISService.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/EncapsulatedOpenBISService.java
index 745dcdf7e6bbf60b0c1ea947ad114e8cdc460d93..051194a64574d8dfc7766baa8bcabeb70d45a6dd 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/EncapsulatedOpenBISService.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/EncapsulatedOpenBISService.java
@@ -34,6 +34,7 @@ import ch.systemsx.cisd.openbis.generic.shared.ResourceNames;
 import ch.systemsx.cisd.openbis.generic.shared.api.v1.OpenBisServiceFactory;
 import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ArchiverDataSetCriteria;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.AtomicEntityOperationResult;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetArchivingStatus;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetTypeWithVocabularyTerms;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DatabaseInstance;
@@ -50,6 +51,7 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Person;
 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.VocabularyTerm;
+import ch.systemsx.cisd.openbis.generic.shared.dto.AtomicEntityOperationDetails;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ListSamplesByPropertyCriteria;
 import ch.systemsx.cisd.openbis.generic.shared.dto.NewExternalData;
 import ch.systemsx.cisd.openbis.generic.shared.dto.NewProperty;
@@ -465,5 +467,11 @@ public final class EncapsulatedOpenBISService implements IEncapsulatedOpenBISSer
             dataSetOrNull.setShareId(Constants.DEFAULT_SHARE_ID);
         }
     }
+
+    public AtomicEntityOperationResult performEntityOperations(
+            AtomicEntityOperationDetails operationDetails)
+    {
+        return service.performEntityOperations(session.getToken(), operationDetails);
+    }
     
 }
\ No newline at end of file
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/IEncapsulatedOpenBISService.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/IEncapsulatedOpenBISService.java
index 4963b869a2c782a0834171a682333a51793e116d..26d60b20f4dc6a22bf88c19ca446de6961ae793b 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/IEncapsulatedOpenBISService.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/shared/IEncapsulatedOpenBISService.java
@@ -23,6 +23,7 @@ import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation;
 import ch.systemsx.cisd.openbis.generic.shared.IETLLIMSService;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ArchiverDataSetCriteria;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.AtomicEntityOperationResult;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetArchivingStatus;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetTypeWithVocabularyTerms;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DatabaseInstance;
@@ -39,6 +40,7 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Person;
 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.VocabularyTerm;
+import ch.systemsx.cisd.openbis.generic.shared.dto.AtomicEntityOperationDetails;
 import ch.systemsx.cisd.openbis.generic.shared.dto.ListSamplesByPropertyCriteria;
 import ch.systemsx.cisd.openbis.generic.shared.dto.NewExternalData;
 import ch.systemsx.cisd.openbis.generic.shared.dto.NewProperty;
@@ -367,4 +369,12 @@ public interface IEncapsulatedOpenBISService
     @ManagedAuthentication
     public Sample updateSampleAndRegisterDataSet(SampleUpdatesDTO newSample,
             NewExternalData externalData);
+
+    /**
+     * {@link IETLLIMSService#performEntityOperations(String, AtomicEntityOperationDetails)}
+     */
+    @ManagedAuthentication
+    public AtomicEntityOperationResult performEntityOperations(
+            AtomicEntityOperationDetails operationDetails);
+
 }
\ No newline at end of file
diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/JythonTopLevelDataSetRegistratorTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/JythonTopLevelDataSetRegistratorTest.java
index 3f2fc3bfc837c393e6ce3032a456d2011f6450df..a091d4f2fb8e29b5ec911f6ae6c9dbc7ff484f8d 100644
--- a/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/JythonTopLevelDataSetRegistratorTest.java
+++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/JythonTopLevelDataSetRegistratorTest.java
@@ -65,11 +65,11 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.AtomicEntityOperationRe
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DatabaseInstance;
 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.Person;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.builders.ExperimentBuilder;
 import ch.systemsx.cisd.openbis.generic.shared.dto.NewExternalData;
 import ch.systemsx.cisd.openbis.generic.shared.dto.StorageFormat;
+import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifier;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifierFactory;
 
 /**
@@ -88,6 +88,8 @@ public class JythonTopLevelDataSetRegistratorTest extends AbstractFileSystemTest
 
     private static final DataSetType DATA_SET_TYPE = new DataSetType("O1");
 
+    private static final String EXPERIMENT_PERM_ID = "experiment-perm-id";
+
     private JythonTopLevelDataSetHandler<DataSetInformation> handler;
 
     private Mockery context;
@@ -152,9 +154,8 @@ public class JythonTopLevelDataSetRegistratorTest extends AbstractFileSystemTest
         createData();
         ExperimentBuilder builder = new ExperimentBuilder().identifier("/SPACE/PROJECT/EXP");
         final Experiment experiment = builder.getExperiment();
-        final RecordingMatcher<DataSetInformation> dataSetInfo =
-                new RecordingMatcher<DataSetInformation>();
-        final RecordingMatcher<NewExternalData> dataSet = new RecordingMatcher<NewExternalData>();
+        final RecordingMatcher<ch.systemsx.cisd.openbis.generic.shared.dto.AtomicEntityOperationDetails> atomicatOperationDetails =
+                new RecordingMatcher<ch.systemsx.cisd.openbis.generic.shared.dto.AtomicEntityOperationDetails>();
         context.checking(new Expectations()
             {
                 {
@@ -167,30 +168,28 @@ public class JythonTopLevelDataSetRegistratorTest extends AbstractFileSystemTest
 
                     one(dataSetValidator).assertValidDataSet(DATA_SET_TYPE,
                             new File(new File(stagingDir, DATA_SET_CODE), "sub_data_set_1"));
-                    one(openBisService).registerDataSet(with(dataSetInfo), with(dataSet));
-                    one(openBisService).tryGetDataSet(DATA_SET_CODE);
-                    ExternalData externalData = new ExternalData();
-                    externalData.setCode(DATA_SET_CODE);
-                    will(returnValue(externalData));
+                    one(openBisService).performEntityOperations(with(atomicatOperationDetails));
+                    will(returnValue(new AtomicEntityOperationResult()));
                 }
             });
 
         handler.handle(markerFile);
 
         assertEquals(1, MockStorageProcessor.instance.incomingDirs.size());
-        assertEquals(DATA_SET_CODE, dataSetInfo.recordedObject().getDataSetCode());
-        assertEquals(DATA_SET_TYPE, dataSetInfo.recordedObject().getDataSetType());
-        assertEquals(experiment.getIdentifier(), dataSetInfo.recordedObject()
-                .getExperimentIdentifier().toString());
-        assertEquals(DATA_SET_CODE, dataSet.recordedObject().getCode());
-        assertEquals(DATA_SET_TYPE, dataSet.recordedObject().getDataSetType());
+        assertEquals(1, atomicatOperationDetails.recordedObject().getDataSetRegistrations().size());
+
+        NewExternalData dataSet =
+                atomicatOperationDetails.recordedObject().getDataSetRegistrations().get(0);
+
+        assertEquals(DATA_SET_CODE, dataSet.getCode());
+        assertEquals(DATA_SET_TYPE, dataSet.getDataSetType());
         File datasetLocation =
                 DatasetLocationUtil.getDatasetLocationPath(workingDirectory, DATA_SET_CODE,
                         ch.systemsx.cisd.openbis.dss.generic.shared.Constants.DEFAULT_SHARE_ID,
                         DATABASE_INSTANCE_UUID);
         assertEquals(FileUtilities.getRelativeFile(new File(workingDirectory,
-                ch.systemsx.cisd.openbis.dss.generic.shared.Constants.DEFAULT_SHARE_ID), datasetLocation), dataSet.recordedObject()
-                .getLocation());
+                ch.systemsx.cisd.openbis.dss.generic.shared.Constants.DEFAULT_SHARE_ID),
+                datasetLocation), dataSet.getLocation());
         assertEquals(1, MockStorageProcessor.instance.calledCommitCount);
         assertEquals(datasetLocation, MockStorageProcessor.instance.rootDirs.get(0));
         File incomingDir = MockStorageProcessor.instance.incomingDirs.get(0);
@@ -271,8 +270,9 @@ public class JythonTopLevelDataSetRegistratorTest extends AbstractFileSystemTest
 
                     one(dataSetValidator).assertValidDataSet(DATA_SET_TYPE,
                             new File(new File(stagingDir, DATA_SET_CODE), "sub_data_set_1"));
-                    one(openBisService).registerDataSet(with(new IsAnything<DataSetInformation>()),
-                            with(new IsAnything<NewExternalData>()));
+                    one(openBisService)
+                            .performEntityOperations(
+                                    with(new IsAnything<ch.systemsx.cisd.openbis.generic.shared.dto.AtomicEntityOperationDetails>()));
                     will(throwException(new AssertionError("Fail")));
                 }
             });
@@ -300,11 +300,10 @@ public class JythonTopLevelDataSetRegistratorTest extends AbstractFileSystemTest
     }
 
     @Test
-    public void testTwoSimpleTransactions()
+    public void testTwoSimpleDataSets()
     {
         setUpHomeDataBaseExpectations();
-        Properties properties =
-                createThreadProperties(SCRIPTS_FOLDER + "two-simple-transactions.py");
+        Properties properties = createThreadProperties(SCRIPTS_FOLDER + "two-simple-datasets.py");
         final File stagingDir = new File(workingDirectory, "staging");
         properties.setProperty(DataSetRegistrationService.STAGING_DIR, stagingDir.getPath());
         createHandler(properties, false, true);
@@ -313,12 +312,8 @@ public class JythonTopLevelDataSetRegistratorTest extends AbstractFileSystemTest
         final Experiment experiment1 = builder1.getExperiment();
         ExperimentBuilder builder2 = new ExperimentBuilder().identifier("/SPACE/PROJECT/EXP2");
         final Experiment experiment2 = builder2.getExperiment();
-        final RecordingMatcher<DataSetInformation> dataSetInfo1 =
-                new RecordingMatcher<DataSetInformation>();
-        final RecordingMatcher<NewExternalData> dataSet1 = new RecordingMatcher<NewExternalData>();
-        final RecordingMatcher<DataSetInformation> dataSetInfo2 =
-                new RecordingMatcher<DataSetInformation>();
-        final RecordingMatcher<NewExternalData> dataSet2 = new RecordingMatcher<NewExternalData>();
+        final RecordingMatcher<ch.systemsx.cisd.openbis.generic.shared.dto.AtomicEntityOperationDetails> operations =
+                new RecordingMatcher<ch.systemsx.cisd.openbis.generic.shared.dto.AtomicEntityOperationDetails>();
         context.checking(new Expectations()
             {
                 {
@@ -332,12 +327,6 @@ public class JythonTopLevelDataSetRegistratorTest extends AbstractFileSystemTest
 
                     one(dataSetValidator).assertValidDataSet(DATA_SET_TYPE,
                             new File(new File(stagingDir, DATA_SET_CODE + 1), "sub_data_set_1"));
-                    one(openBisService).registerDataSet(with(dataSetInfo1), with(dataSet1));
-
-                    one(openBisService).tryGetDataSet(DATA_SET_CODE + 1);
-                    ExternalData externalData = new ExternalData();
-                    externalData.setCode(DATA_SET_CODE + 1);
-                    will(returnValue(externalData));
 
                     one(openBisService).createDataSetCode();
                     will(returnValue(DATA_SET_CODE + 2));
@@ -349,12 +338,9 @@ public class JythonTopLevelDataSetRegistratorTest extends AbstractFileSystemTest
 
                     one(dataSetValidator).assertValidDataSet(DATA_SET_TYPE,
                             new File(new File(stagingDir, DATA_SET_CODE + 2), "sub_data_set_2"));
-                    one(openBisService).registerDataSet(with(dataSetInfo2), with(dataSet2));
 
-                    one(openBisService).tryGetDataSet(DATA_SET_CODE + 2);
-                    externalData = new ExternalData();
-                    externalData.setCode(DATA_SET_CODE + 2);
-                    will(returnValue(externalData));
+                    one(openBisService).performEntityOperations(with(operations));
+                    will(returnValue(new AtomicEntityOperationResult()));
                 }
             });
 
@@ -362,17 +348,21 @@ public class JythonTopLevelDataSetRegistratorTest extends AbstractFileSystemTest
 
         assertEquals(2, MockStorageProcessor.instance.incomingDirs.size());
         assertEquals(2, MockStorageProcessor.instance.calledCommitCount);
-        assertEquals(DATA_SET_CODE + 1, dataSetInfo1.recordedObject().getDataSetCode());
-        assertEquals(DATA_SET_TYPE, dataSetInfo1.recordedObject().getDataSetType());
-        assertEquals(experiment1.getIdentifier(), dataSetInfo1.recordedObject()
-                .getExperimentIdentifier().toString());
-        assertEquals(DATA_SET_CODE + 1, dataSet1.recordedObject().getCode());
-        assertEquals(DATA_SET_TYPE, dataSet1.recordedObject().getDataSetType());
+        assertEquals(2, operations.recordedObject().getDataSetRegistrations().size());
+
+        NewExternalData dataSet1 = operations.recordedObject().getDataSetRegistrations().get(0);
+        NewExternalData dataSet2 = operations.recordedObject().getDataSetRegistrations().get(1);
+
+        assertEquals(experiment1.getIdentifier(), dataSet1.getExperimentIdentifierOrNull()
+                .toString());
+        assertEquals(DATA_SET_CODE + 1, dataSet1.getCode());
+        assertEquals(DATA_SET_TYPE, dataSet1.getDataSetType());
         File datasetLocation1 =
                 DatasetLocationUtil.getDatasetLocationPath(workingDirectory, DATA_SET_CODE + 1,
                         ch.systemsx.cisd.openbis.dss.generic.shared.Constants.DEFAULT_SHARE_ID, DATABASE_INSTANCE_UUID);
         assertEquals(FileUtilities.getRelativeFile(new File(workingDirectory,
-                ch.systemsx.cisd.openbis.dss.generic.shared.Constants.DEFAULT_SHARE_ID), datasetLocation1), dataSet1.recordedObject()
+                ch.systemsx.cisd.openbis.dss.generic.shared.Constants.DEFAULT_SHARE_ID),
+                datasetLocation1), dataSet1
                 .getLocation());
         assertEquals(datasetLocation1, MockStorageProcessor.instance.rootDirs.get(0));
         File incomingDir1 = MockStorageProcessor.instance.incomingDirs.get(0);
@@ -380,17 +370,16 @@ public class JythonTopLevelDataSetRegistratorTest extends AbstractFileSystemTest
                 incomingDir1);
         assertEquals("hello world1",
                 FileUtilities.loadToString(new File(datasetLocation1, "read1.me")).trim());
-        assertEquals(DATA_SET_CODE + 2, dataSetInfo2.recordedObject().getDataSetCode());
-        assertEquals(DATA_SET_TYPE, dataSetInfo2.recordedObject().getDataSetType());
-        assertEquals(experiment2.getIdentifier(), dataSetInfo2.recordedObject()
-                .getExperimentIdentifier().toString());
-        assertEquals(DATA_SET_CODE + 2, dataSet2.recordedObject().getCode());
-        assertEquals(DATA_SET_TYPE, dataSet2.recordedObject().getDataSetType());
+        assertEquals(experiment2.getIdentifier(), dataSet2.getExperimentIdentifierOrNull()
+                .toString());
+        assertEquals(DATA_SET_CODE + 2, dataSet2.getCode());
+        assertEquals(DATA_SET_TYPE, dataSet2.getDataSetType());
         File datasetLocation2 =
                 DatasetLocationUtil.getDatasetLocationPath(workingDirectory, DATA_SET_CODE + 2,
                         ch.systemsx.cisd.openbis.dss.generic.shared.Constants.DEFAULT_SHARE_ID, DATABASE_INSTANCE_UUID);
         assertEquals(FileUtilities.getRelativeFile(new File(workingDirectory,
-                ch.systemsx.cisd.openbis.dss.generic.shared.Constants.DEFAULT_SHARE_ID), datasetLocation2), dataSet2.recordedObject()
+                ch.systemsx.cisd.openbis.dss.generic.shared.Constants.DEFAULT_SHARE_ID),
+                datasetLocation2), dataSet2
                 .getLocation());
         assertEquals(datasetLocation2, MockStorageProcessor.instance.rootDirs.get(1));
         File incomingDir2 = MockStorageProcessor.instance.incomingDirs.get(1);
@@ -427,6 +416,66 @@ public class JythonTopLevelDataSetRegistratorTest extends AbstractFileSystemTest
                 MockStorageProcessor.instance.dataSetInfoString);
     }
 
+    // TODO KE: 2011-02-11 Make this test run
+    //@Test
+    public void testTransactionWithNewExperiment()
+    {
+        setUpHomeDataBaseExpectations();
+        Properties properties =
+                createThreadProperties(SCRIPTS_FOLDER + "transaction-with-new-experiment.py");
+        final File stagingDir = new File(workingDirectory, "staging");
+        properties.setProperty(DataSetRegistrationService.STAGING_DIR, stagingDir.getPath());
+        createHandler(properties, false, true);
+        createData();
+        final ExperimentIdentifier experimentIdentifier =
+                ExperimentIdentifierFactory.parse("/SPACE/PROJECT/EXP");
+        final RecordingMatcher<ch.systemsx.cisd.openbis.generic.shared.dto.AtomicEntityOperationDetails> atomicatOperationDetails =
+                new RecordingMatcher<ch.systemsx.cisd.openbis.generic.shared.dto.AtomicEntityOperationDetails>();
+        context.checking(new Expectations()
+            {
+                {
+                    one(openBisService).createDataSetCode();
+                    will(returnValue(DATA_SET_CODE));
+
+                    one(openBisService).createDataSetCode();
+                    will(returnValue(EXPERIMENT_PERM_ID));
+
+                    one(openBisService).tryToGetExperiment(experimentIdentifier);
+                    will(returnValue(null));
+
+                    one(dataSetValidator).assertValidDataSet(DATA_SET_TYPE,
+                            new File(new File(stagingDir, DATA_SET_CODE), "sub_data_set_1"));
+                    one(openBisService).performEntityOperations(with(atomicatOperationDetails));
+                    will(returnValue(new AtomicEntityOperationResult()));
+                }
+            });
+
+        handler.handle(markerFile);
+
+        assertEquals(1, MockStorageProcessor.instance.incomingDirs.size());
+        assertEquals(1, atomicatOperationDetails.recordedObject().getDataSetRegistrations().size());
+
+        NewExternalData dataSet =
+                atomicatOperationDetails.recordedObject().getDataSetRegistrations().get(0);
+
+        assertEquals(DATA_SET_CODE, dataSet.getCode());
+        assertEquals(DATA_SET_TYPE, dataSet.getDataSetType());
+        File datasetLocation =
+                DatasetLocationUtil.getDatasetLocationPath(workingDirectory, DATA_SET_CODE,
+                        ch.systemsx.cisd.openbis.dss.generic.shared.Constants.DEFAULT_SHARE_ID,
+                        DATABASE_INSTANCE_UUID);
+        assertEquals(FileUtilities.getRelativeFile(new File(workingDirectory,
+                ch.systemsx.cisd.openbis.dss.generic.shared.Constants.DEFAULT_SHARE_ID),
+                datasetLocation),
+
+        dataSet.getLocation());
+        assertEquals(1, MockStorageProcessor.instance.calledCommitCount);
+        assertEquals(datasetLocation, MockStorageProcessor.instance.rootDirs.get(0));
+        File incomingDir = MockStorageProcessor.instance.incomingDirs.get(0);
+        assertEquals(new File(new File(stagingDir, DATA_SET_CODE), "sub_data_set_1"), incomingDir);
+        context.assertIsSatisfied();
+    }
+
     @Test
     public void testScriptDies()
     {
diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/api/v1/impl/DataSetRegistrationTransactionTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/api/v1/impl/DataSetRegistrationTransactionTest.java
index 8f77056b5b4607c2b8a578ab28e15d29148b6fc6..af63e7a9649b732b7420c410cfaf75ea4ce59a99 100644
--- a/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/api/v1/impl/DataSetRegistrationTransactionTest.java
+++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/api/v1/impl/DataSetRegistrationTransactionTest.java
@@ -50,13 +50,14 @@ import ch.systemsx.cisd.etlserver.registrator.api.v1.IExperimentImmutable;
 import ch.systemsx.cisd.etlserver.validation.IDataSetValidator;
 import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService;
 import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.AtomicEntityOperationResult;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DatabaseInstance;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment;
 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.Space;
-import ch.systemsx.cisd.openbis.generic.shared.dto.NewExternalData;
+import ch.systemsx.cisd.openbis.generic.shared.dto.AtomicEntityOperationDetails;
 import ch.systemsx.cisd.openbis.generic.shared.dto.StorageFormat;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifierFactory;
 
@@ -157,7 +158,6 @@ public class DataSetRegistrationTransactionTest extends AbstractFileSystemTestCa
         rollbackQueueFiles = listRollbackQueueFiles();
         assertEquals(0, rollbackQueueFiles.length);
 
-        // Commented out for the moment.
         context.assertIsSatisfied();
     }
 
@@ -365,14 +365,15 @@ public class DataSetRegistrationTransactionTest extends AbstractFileSystemTestCa
                                         .createIdentifier());
                         will(returnValue(experiment));
 
-                        exactly(1).of(openBisService).registerDataSet(
-                                with(any(DataSetInformation.class)),
-                                with(any(NewExternalData.class)));
+                        exactly(1).of(openBisService).performEntityOperations(
+                                with(any(AtomicEntityOperationDetails.class)));
+                        will(returnValue(new AtomicEntityOperationResult()));
                     }
                 }
             });
     }
 
+
     private void setUpDataSetValidatorExpectations()
     {
         File dataSetDir = new File(stagingDirectory, DATA_SET_CODE + "1");
diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/transaction-with-new-experiment.py b/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/transaction-with-new-experiment.py
index 735a44c0d4e662391c451232e56b8875ec7fb97f..02b475407c86f4a260eaec9bb5266ded9aba880a 100644
--- a/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/transaction-with-new-experiment.py
+++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/transaction-with-new-experiment.py
@@ -2,5 +2,9 @@ transaction = service.transaction(incoming, factory)
 dataSet = transaction.createNewDataSet()
 transaction.moveFile(incoming.getPath() + '/sub_data_set_1', dataSet)
 dataSet.setDataSetType('O1')
-dataSet.setExperiment(transaction.createNewExperiment('/SPACE/PROJECT/EXP'))
+
+experiment = transaction.createNewExperiment('/SPACE/PROJECT/EXP')
+experiment.setPropertyValue('propCode', 'propValue')
+
+dataSet.setExperiment(experiment)
 
diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/two-simple-transactions.py b/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/two-simple-datasets.py
similarity index 100%
rename from datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/two-simple-transactions.py
rename to datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/registrator/two-simple-datasets.py
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/AtomicEntityOperationResult.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/AtomicEntityOperationResult.java
index 7a108148702c8cc50711853e20cf80674bea1622..f1a6c9ae2cea059ff62c4423fcd9a5e6d4b893a4 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/AtomicEntityOperationResult.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/AtomicEntityOperationResult.java
@@ -18,6 +18,7 @@ package ch.systemsx.cisd.openbis.generic.shared.basic.dto;
 
 import java.io.Serializable;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -39,6 +40,12 @@ public class AtomicEntityOperationResult implements Serializable
 
     private final ArrayList<ExternalData> dataSetsCreated;
 
+    public AtomicEntityOperationResult()
+    {
+        this(Collections.<Experiment> emptyList(), Collections.<Sample> emptyList(), Collections
+                .<Sample> emptyList(), Collections.<ExternalData> emptyList());
+    }
+
     public AtomicEntityOperationResult(List<Experiment> experimentsCreated,
             List<Sample> samplesUpdated, List<Sample> samplesCreated,
             List<ExternalData> dataSetsCreated)
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/identifier/ExperimentIdentifierFactory.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/identifier/ExperimentIdentifierFactory.java
index 5f7164e03f6d8a2c3e21c3c0aa4b0ca5f174ed28..c8802de02ca94978502069f40c2e2bfbd109956e 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/identifier/ExperimentIdentifierFactory.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/identifier/ExperimentIdentifierFactory.java
@@ -38,10 +38,10 @@ public final class ExperimentIdentifierFactory extends AbstractIdentifierFactory
 
     public final ExperimentIdentifier createIdentifier() throws UserFailureException
     {
-        return parseIdentifier(getTextToParse());
+        return parse(getTextToParse());
     }
 
-    private static ExperimentIdentifier parseIdentifier(final String text)
+    public static ExperimentIdentifier parse(final String text)
     {
         final TokenLexer lexer = new TokenLexer(text);
         final ProjectIdentifier parentIdentifier = ProjectIdentifierFactory.parseIdentifier(lexer);
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/util/EntityHelper.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/util/EntityHelper.java
index 4fc488fb6382a3b10b757d527de5a15a9e5c3c9c..af5e44824649a80868df28d8ed31d4634ca92250 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/util/EntityHelper.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/util/EntityHelper.java
@@ -18,8 +18,10 @@ package ch.systemsx.cisd.openbis.generic.shared.util;
 
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.EntityKind;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.EntityProperty;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.EntityType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExperimentType;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityPropertiesHolder;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityProperty;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.MaterialType;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.PropertyType;
@@ -77,15 +79,12 @@ public class EntityHelper
     /**
      * does the same as {@link #tryFindProperty(Iterable, String)} but with arrays.
      */
-    // TODO 2011-01-13 KE : could we scratch the usage of arrays and only have lists ?
-    // if so, we could delete this method
     public static IEntityProperty tryFindProperty(IEntityProperty[] properties,
             final String propertyCode)
     {
         for (final IEntityProperty property : properties)
         {
             final PropertyType propertyType = property.getPropertyType();
-            // TODO KE : ugly, why is the extracting logic not uppercasing ??
             if (propertyType.getCode().equalsIgnoreCase(propertyCode))
             {
                 return property;
@@ -93,4 +92,44 @@ public class EntityHelper
         }
         return null;
     }
+
+    public static String tryFindPropertyValue(IEntityPropertiesHolder holder, String propertyCode)
+    {
+        IEntityProperty property = null;
+
+        if (holder.getProperties() != null)
+        {
+            property = EntityHelper.tryFindProperty(holder.getProperties(), propertyCode);
+        }
+
+        return (property != null) ? property.tryGetOriginalValue() : null;
+    }
+
+    /**
+     * Tries to set the value for a given property in an {@link IEntityPropertiesHolder} instance.
+     * Creates a new property if no property for the specified code is found.
+     */
+    public static void createOrUpdateProperty(IEntityPropertiesHolder holder, String propertyCode,
+            String propertyValue)
+    {
+        IEntityProperty property = tryFindProperty(holder.getProperties(), propertyCode);
+
+        if (property == null) {
+            property = createNewProperty(propertyCode);
+            holder.getProperties().add(property);
+        }
+        property.setValue(propertyValue);
+    }
+
+
+    private static IEntityProperty createNewProperty(String propertyCode)
+    {
+        IEntityProperty property;
+        property = new EntityProperty();
+        PropertyType propertyType = new PropertyType();
+        propertyType.setCode(propertyCode);
+        property.setPropertyType(propertyType);
+        return property;
+    }
+
 }