diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/dss/phosphonetx/server/plugins/MsInjectionCopier.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/dss/phosphonetx/server/plugins/MsInjectionCopier.java
new file mode 100644
index 0000000000000000000000000000000000000000..425327175037945004da898ac644e8e34e508da4
--- /dev/null
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/dss/phosphonetx/server/plugins/MsInjectionCopier.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright 2010 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.dss.phosphonetx.server.plugins;
+
+import java.io.File;
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.log4j.Logger;
+
+import ch.systemsx.cisd.common.exceptions.Status;
+import ch.systemsx.cisd.common.filesystem.BooleanStatus;
+import ch.systemsx.cisd.common.filesystem.FileUtilities;
+import ch.systemsx.cisd.common.filesystem.IPathCopier;
+import ch.systemsx.cisd.common.filesystem.ssh.ISshCommandExecutor;
+import ch.systemsx.cisd.common.highwatermark.HostAwareFile;
+import ch.systemsx.cisd.common.highwatermark.HostAwareFileWithHighwaterMark;
+import ch.systemsx.cisd.common.logging.LogCategory;
+import ch.systemsx.cisd.common.logging.LogFactory;
+import ch.systemsx.cisd.common.process.ProcessResult;
+import ch.systemsx.cisd.common.utilities.PropertyUtils;
+import ch.systemsx.cisd.common.utilities.StringUtilities;
+import ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.Copier;
+import ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.DataSetCopier;
+import ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.IPathCopierFactory;
+import ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.ISshCommandExecutorFactory;
+import ch.systemsx.cisd.openbis.dss.generic.shared.IPostRegistrationDatasetHandler;
+import ch.systemsx.cisd.openbis.dss.generic.shared.dto.DataSetInformation;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+class MsInjectionCopier implements Serializable, IPostRegistrationDatasetHandler
+{
+    
+    private static final class ExceptionWithStatus extends RuntimeException
+    {
+        private static final long serialVersionUID = 1L;
+        private final Status status;
+
+        ExceptionWithStatus(Status status)
+        {
+            this.status = status;
+        }
+
+        public Status getStatus()
+        {
+            return status;
+        }
+    }
+    
+    private static interface IExecutor
+    {
+        BooleanStatus exists(File file);
+        void deleteFolder(File folder);
+        void copyDataSet(File dataSet, File destination);
+        void renameTo(File newFile, File oldFile);
+    }
+    
+    private static final class LocalExcecutor implements IExecutor
+    {
+        public BooleanStatus exists(File file)
+        {
+            return BooleanStatus.createFromBoolean(file.exists());
+        }
+
+        public void deleteFolder(File folder)
+        {
+            boolean successful = folder.delete();
+            if (successful == false)
+            {
+                operationLog.error("Deletion of '" + folder + "' failed for some unknown reason.");
+                throw new ExceptionWithStatus(Status.createError("couldn't delete"));
+            }
+        }
+
+        public void copyDataSet(File dataSet, File destination)
+        {
+            try
+            {
+                FileUtilities.copyFileTo(dataSet, destination, true);
+            } catch (Exception ex)
+            {
+                operationLog.error("Couldn't copy '" + dataSet + "' to '" + destination + "'.");
+                throw new ExceptionWithStatus(Status.createError("copy failed"));
+            }
+        }
+
+        public void renameTo(File newFile, File oldFile)
+        {
+            boolean result = oldFile.renameTo(newFile);
+            if (result == false)
+            {
+                operationLog.error("Couldn't rename '" + oldFile + "' to '" + newFile + "'.");
+                throw new ExceptionWithStatus(Status.createError("rename failed"));
+            }
+        }
+        
+    }
+    
+    private static final class RemoteExecutor implements IExecutor
+    {
+        private final ISshCommandExecutor executor;
+        private final IPathCopier copier;
+        private final String host;
+        private final String rsyncModuleNameOrNull;
+        private final String rsyncPasswordFileOrNull;
+
+        public RemoteExecutor(ISshCommandExecutor executor, IPathCopier copier, String host,
+                String rsyncModuleNameOrNull, String rsyncPasswordFileOrNull)
+        {
+            this.executor = executor;
+            this.copier = copier;
+            this.host = host;
+            this.rsyncModuleNameOrNull = rsyncModuleNameOrNull;
+            this.rsyncPasswordFileOrNull = rsyncPasswordFileOrNull;
+        }
+        
+        public BooleanStatus exists(File file)
+        {
+            return executor.exists(file, DataSetCopier.SSH_TIMEOUT_MILLIS);
+        }
+
+        public void deleteFolder(File folder)
+        {
+            ProcessResult result =
+                executor.tryExecuteCommandRemotely("delete " + folder.getPath(),
+                        DataSetCopier.SSH_TIMEOUT_MILLIS);
+            if (result.isOK() == false)
+            {
+                operationLog.error("Remote deletion of '" + folder
+                        + "' failed with exit value: " + result.getExitValue());
+                throw new ExceptionWithStatus(Status.createError("couldn't delete"));
+            }
+            List<String> output = result.getOutput();
+            if (output.isEmpty() == false)
+            {
+                operationLog.error("Remote deletion of '" + folder
+                        + "' seemed to be successful but produced following output:\n"
+                        + StringUtilities.concatenateWithNewLine(output));
+                throw new ExceptionWithStatus(Status.createError("deletion leads to a problem"));
+            }
+        }
+        
+        public void copyDataSet(File dataSet, File destination)
+        {
+            Status result =
+                    copier.copyToRemote(dataSet, destination, host, rsyncModuleNameOrNull,
+                            rsyncPasswordFileOrNull);
+            if (result.isError())
+            {
+                throw new ExceptionWithStatus(result);
+            }
+        }
+
+        public void renameTo(File newFile, File oldFile)
+        {
+            ProcessResult result =
+                    executor.tryExecuteCommandRemotely("mv " + oldFile.getPath() + " "
+                            + newFile.getPath(), DataSetCopier.SSH_TIMEOUT_MILLIS);
+            if (result.isOK() == false)
+            {
+                operationLog.error("Remote move of '" + oldFile
+                        + "' to '" + newFile + "' failed with exit value: " + result.getExitValue());
+                throw new ExceptionWithStatus(Status.createError("couldn't move"));
+            }
+            List<String> output = result.getOutput();
+            if (output.isEmpty() == false)
+            {
+                operationLog.error("Remote move of '" + oldFile
+                        + "' to '" + newFile 
+                        + "' seemed to be successful but produced following output:\n"
+                        + StringUtilities.concatenateWithNewLine(output));
+                throw new ExceptionWithStatus(Status.createError("moving leads to a problem"));
+            }
+        }
+    }
+
+    private static final long serialVersionUID = 1L;
+
+    private final static Logger operationLog =
+            LogFactory.getLogger(LogCategory.OPERATION, MsInjectionCopier.class);
+
+    private final IExecutor executor;
+
+    private final File destination;
+
+    MsInjectionCopier(Properties properties, IPathCopierFactory pathCopierFactory,
+            ISshCommandExecutorFactory sshCommandExecutorFactory)
+    {
+        String hostFile =
+                PropertyUtils.getMandatoryProperty(properties, DataSetCopier.DESTINATION_KEY);
+        HostAwareFile hostAwareFile = HostAwareFileWithHighwaterMark.create(hostFile, -1);
+        String hostOrNull = hostAwareFile.tryGetHost();
+        destination = hostAwareFile.getFile();
+        if (hostOrNull == null)
+        {
+            executor = new LocalExcecutor();
+        } else
+        {
+            File sshExecutable = Copier.getExecutable(properties, DataSetCopier.SSH_EXEC);
+            File rsyncExecutable = Copier.getExecutable(properties, DataSetCopier.RSYNC_EXEC);
+            IPathCopier copier = pathCopierFactory.create(rsyncExecutable, sshExecutable);
+            copier.check();
+            String rsyncModule = hostAwareFile.tryGetRsyncModule();
+            String rsyncPasswordFile =
+                    properties.getProperty(DataSetCopier.RSYNC_PASSWORD_FILE_KEY);
+            FileUtilities.checkPathCopier(copier, hostOrNull, null, rsyncModule, rsyncPasswordFile);
+            ISshCommandExecutor sshCommandExecutor =
+                    sshCommandExecutorFactory.create(sshExecutable, hostOrNull);
+            executor =
+                    new RemoteExecutor(sshCommandExecutor, copier, hostOrNull, rsyncModule,
+                            rsyncPasswordFile);
+        }
+    }
+
+    public void undoLastOperation()
+    {
+    }
+
+    public Status handle(File originalData, DataSetInformation dataSetInformation,
+            Map<String, String> parameterBindings)
+    {
+        try
+        {
+            String target = createTargetFolderName(dataSetInformation, parameterBindings);
+            File targetFolder = new File(destination, target);
+            deleteTargetFolder(targetFolder);
+            executor.copyDataSet(originalData, destination);
+            executor.renameTo(targetFolder, new File(destination, originalData.getName()));
+            return null;
+            
+        } catch (ExceptionWithStatus ex)
+        {
+            return ex.getStatus();
+        }
+    }
+
+    private String createTargetFolderName(DataSetInformation dataSetInformation,
+            Map<String, String> parameterBindings)
+    {
+        String dataSetTypeCode = dataSetInformation.getDataSetType().getCode();
+        String sampleCode = parameterBindings.get(dataSetInformation.getDataSetCode());
+        return (sampleCode == null ? "sample-unknown" : sampleCode) + "_" + dataSetTypeCode;
+    }
+    
+    private void deleteTargetFolder(File targetFolder)
+    {
+        BooleanStatus targetExists = executor.exists(targetFolder);
+        if (targetExists.isError())
+        {
+            operationLog.error("Could not check existence of '" + targetFolder + "': "
+                    + targetExists.tryGetMessage());
+            throw new ExceptionWithStatus(Status.createError("couldn't check existence"));
+        }
+        if (targetExists.isSuccess())
+        {
+            executor.deleteFolder(targetFolder);
+        }
+    }
+
+}
+
diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/dss/phosphonetx/server/plugins/MsInjectionDataSetCopier.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/dss/phosphonetx/server/plugins/MsInjectionDataSetCopier.java
new file mode 100644
index 0000000000000000000000000000000000000000..b89716caebfb8ae76582f848c7d4ea06a98a5fe6
--- /dev/null
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/dss/phosphonetx/server/plugins/MsInjectionDataSetCopier.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2010 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.dss.phosphonetx.server.plugins;
+
+import java.io.File;
+import java.util.Properties;
+
+import ch.rinn.restrictions.Private;
+import ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.AbstractDropboxProcessingPlugin;
+import ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.IPathCopierFactory;
+import ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.ISshCommandExecutorFactory;
+import ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.RsyncCopierFactory;
+import ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.SshCommandExecutorFactory;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+public class MsInjectionDataSetCopier extends AbstractDropboxProcessingPlugin
+{
+    private static final long serialVersionUID = 1L;
+    
+    public MsInjectionDataSetCopier(Properties properties, File storeRoot)
+    {
+        this(properties, storeRoot, new RsyncCopierFactory(), new SshCommandExecutorFactory());
+    }
+
+    @Private MsInjectionDataSetCopier(Properties properties, File storeRoot, IPathCopierFactory pathCopierFactory,
+            ISshCommandExecutorFactory sshCommandExecutorFactory)
+    {
+        super(properties, storeRoot, new MsInjectionCopier(properties, pathCopierFactory,
+                sshCommandExecutorFactory));
+    }
+}
diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/RawDataServiceInternal.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/RawDataServiceInternal.java
index c56856f69e52feaba2a14742d556ebf4c9d1f090..b98389ce70508e1832eef1b14f27e5304ca34f8a 100644
--- a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/RawDataServiceInternal.java
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/RawDataServiceInternal.java
@@ -102,6 +102,7 @@ public class RawDataServiceInternal extends AbstractServer<IRawDataServiceIntern
         List<MsInjectionSample> samples = loadAllRawDataSamples(session);
         Set<Long> sampleIDs = new HashSet<Long>();
         List<String> dataSetCodes = new ArrayList<String>();
+        Map<String, String> parameterBindings = new HashMap<String, String>();
         for (MsInjectionSample sample : samples)
         {
             if (RAW_DATA_SAMPLE_VALIDATOR.isValid(person, sample))
@@ -111,7 +112,9 @@ public class RawDataServiceInternal extends AbstractServer<IRawDataServiceIntern
                 ExternalData latestDataSet = latestDataSets.get(dataSetType);
                 if (latestDataSet != null)
                 {
-                    dataSetCodes.add(latestDataSet.getCode());
+                    String code = latestDataSet.getCode();
+                    dataSetCodes.add(code);
+                    parameterBindings.put(code, sample.getSample().getCode());
                 }
             }
         }
@@ -119,7 +122,6 @@ public class RawDataServiceInternal extends AbstractServer<IRawDataServiceIntern
         String dataStoreServerCode = findDataStoreServer(dataSetProcessingKey);
         IExternalDataTable externalDataTable =
                 businessObjectFactory.createExternalDataTable(session);
-        Map<String, String> parameterBindings = new HashMap<String, String>();
         externalDataTable.processDatasets(dataSetProcessingKey, dataStoreServerCode, dataSetCodes,
                 parameterBindings);
     }