diff --git a/rtd_phosphonetx/etc/service.properties b/rtd_phosphonetx/etc/service.properties
index b3ff87fa062ef46397721ad20baa563932d13039..5cb41163842ac67f1dacc71ce0ab41cd83621879 100644
--- a/rtd_phosphonetx/etc/service.properties
+++ b/rtd_phosphonetx/etc/service.properties
@@ -113,6 +113,16 @@ demo-reporter.class = ch.systemsx.cisd.openbis.dss.generic.server.plugins.demo.D
 # The property file. Its content will be passed as a parameter to the plugin.
 demo-reporter.properties-file = 
 
+# Comma separated names of processing plugins. Each plugin should have configuration properties prefixed with its name.
+processing-plugins = copy-data-sets
+
+# The configuration of the processing plugin is the same as the reporting plugins configuration. 
+copy-data-sets.label = Data Set Copier
+copy-data-sets.dataset-types = UNKNOWN
+copy-data-sets.class = ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.DataSetCopier
+#copy-data-sets.destination =  /Volumes/share-1-\$/user/cisd/felmer/phosphonetx/ 
+copy-data-sets.destination =  vesuvio:tmp/LMS-1267 
+
 data-set-validators = val1
 
 val1.data-set-type = HCS_IMAGE_ANALYSIS_DATA
diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/RawDataService.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/RawDataService.java
index 5eb5d23bb1eb17955d596338ba3f3f239d86acf6..3fd32b1a160d8c63a705f4730ab625fea03e96ef 100644
--- a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/RawDataService.java
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/RawDataService.java
@@ -16,26 +16,17 @@
 
 package ch.systemsx.cisd.openbis.plugin.phosphonetx.server;
 
-import java.util.ArrayList;
 import java.util.List;
 
-import javax.annotation.Resource;
-
-import ch.rinn.restrictions.Private;
 import ch.systemsx.cisd.authentication.ISessionManager;
 import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.openbis.generic.server.AbstractServer;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDAOFactory;
-import ch.systemsx.cisd.openbis.generic.shared.ICommonServer;
-import ch.systemsx.cisd.openbis.generic.shared.authorization.validator.GroupValidator;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Group;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ListSampleCriteria;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
-import ch.systemsx.cisd.openbis.generic.shared.dto.PersonPE;
-import ch.systemsx.cisd.openbis.generic.shared.dto.SampleTypePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.Session;
-import ch.systemsx.cisd.openbis.generic.shared.translator.SampleTypeTranslator;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SessionContextDTO;
 import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.IRawDataService;
+import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.IRawDataServiceInternal;
 
 /**
  * Imlementation of {@link IRawDataService}.
@@ -44,22 +35,17 @@ import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.IRawDataService;
  */
 public class RawDataService extends AbstractServer<IRawDataService> implements IRawDataService
 {
-    @Private static final String GROUP_CODE = "MS_DATA";
-
-    @Private static final String RAW_DATA_SAMPLE_TYPE = "MS_INJECTION";
-    
-    @Resource(name = ch.systemsx.cisd.openbis.generic.shared.ResourceNames.COMMON_SERVER)
-    private ICommonServer commonServer;
+    private IRawDataServiceInternal service;
 
     public RawDataService()
     {
     }
 
-    public RawDataService(ISessionManager<Session> sessionManager, IDAOFactory daoFactory,
-            ICommonServer commonServer)
+    public RawDataService(final ISessionManager<Session> sessionManager, final IDAOFactory daoFactory,
+            IRawDataServiceInternal service)
     {
         super(sessionManager, daoFactory);
-        this.commonServer = commonServer;
+        this.service = service;
     }
     
     public IRawDataService createLogger(boolean invocationSuccessful, long elapsedTime)
@@ -70,34 +56,38 @@ public class RawDataService extends AbstractServer<IRawDataService> implements I
     public List<Sample> listRawDataSamples(String sessionToken, String userID)
     {
         checkSession(sessionToken);
-        
-        PersonPE person = getDAOFactory().getPersonDAO().tryFindPersonByUserId(userID);
-        if (person == null)
+        SessionContextDTO session = login(userID);
+        try
         {
-            throw new UserFailureException("Unknown user ID: " + userID);
-        }
-        ListSampleCriteria criteria = new ListSampleCriteria();
-        SampleTypePE sampleTypePE =
-                getDAOFactory().getSampleTypeDAO().tryFindSampleTypeByCode(RAW_DATA_SAMPLE_TYPE);
-        criteria.setSampleType(SampleTypeTranslator.translate(sampleTypePE, null));
-        criteria.setIncludeGroup(true);
-        criteria.setGroupCode(GROUP_CODE);
-        List<Sample> samples = commonServer.listSamples(sessionToken, criteria);
-        List<Sample> filteredList = new ArrayList<Sample>();
-        GroupValidator validator = new GroupValidator();
-        for (Sample sample : samples)
+            return service.listRawDataSamples(session.getSessionToken());
+            
+        } finally
         {
-            Sample parent = sample.getGeneratedFrom();
-            if (parent != null)
-            {
-                Group group = parent.getGroup();
-                if (group == null || validator.doValidation(person, group))
-                {
-                    filteredList.add(sample);
-                }
-            }
+            service.logout(session.getSessionToken());
         }
-        return filteredList;
     }
 
+    public void copyRawData(String sessionToken, String userID, long[] rawDataSampleIDs)
+    {
+        checkSession(sessionToken);
+        SessionContextDTO session = login(userID);
+        try
+        {
+            service.copyRawData(session.getSessionToken(), rawDataSampleIDs);
+        } finally
+        {
+            service.logout(session.getSessionToken());
+        }
+    }
+    
+    private SessionContextDTO login(String userID)
+    {
+        SessionContextDTO session = service.tryToAuthenticate(userID, "dummy-password");
+        if (session == null)
+        {
+            throw new UserFailureException("Unknown user ID: " + userID);
+        }
+        return session;
+    }
+    
 }
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
new file mode 100644
index 0000000000000000000000000000000000000000..9480b1c67f0b53b01e35bd609665383efd16a5ed
--- /dev/null
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/RawDataServiceInternal.java
@@ -0,0 +1,159 @@
+/*
+ * 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.plugin.phosphonetx.server;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import ch.rinn.restrictions.Private;
+import ch.systemsx.cisd.authentication.ISessionManager;
+import ch.systemsx.cisd.common.exceptions.EnvironmentFailureException;
+import ch.systemsx.cisd.common.exceptions.UserFailureException;
+import ch.systemsx.cisd.openbis.generic.server.AbstractServer;
+import ch.systemsx.cisd.openbis.generic.server.business.bo.ICommonBusinessObjectFactory;
+import ch.systemsx.cisd.openbis.generic.server.business.bo.IExternalDataTable;
+import ch.systemsx.cisd.openbis.generic.server.business.bo.samplelister.ISampleLister;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDAOFactory;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.IExternalDataDAO;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.ISampleDAO;
+import ch.systemsx.cisd.openbis.generic.shared.authorization.validator.IValidator;
+import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataStoreServiceKind;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ListOrSearchSampleCriteria;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ListSampleCriteria;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DataStorePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DataStoreServicePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.ExternalDataPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.PersonPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SampleTypePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.Session;
+import ch.systemsx.cisd.openbis.generic.shared.translator.SampleTypeTranslator;
+import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.IRawDataServiceInternal;
+import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.authorization.validator.RawDataSampleValidator;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+public class RawDataServiceInternal extends AbstractServer<IRawDataServiceInternal> implements IRawDataServiceInternal
+{
+    @Private static final String COPY_PROCESSING_KEY = "copy-data-sets";
+
+    @Private static final String GROUP_CODE = "MS_DATA";
+
+    @Private static final String RAW_DATA_SAMPLE_TYPE = "MS_INJECTION";
+    
+    private static final IValidator<Sample> RAW_DATA_SAMPLE_VALIDATOR = new RawDataSampleValidator();
+
+    private ICommonBusinessObjectFactory businessObjectFactory;
+
+    public RawDataServiceInternal()
+    {
+    }
+
+    public RawDataServiceInternal(ISessionManager<Session> sessionManager, IDAOFactory daoFactory,
+            ICommonBusinessObjectFactory businessObjectFactory)
+    {
+        super(sessionManager, daoFactory);
+        this.businessObjectFactory = businessObjectFactory;
+    }
+    
+
+    public IRawDataServiceInternal createLogger(boolean invocationSuccessful, long elapsedTime)
+    {
+        return new RawDataServiceInternalLogger(getSessionManager(), invocationSuccessful, elapsedTime);
+    }
+    
+    public List<Sample> listRawDataSamples(String sessionToken)
+    {
+        return loadAllRawDataSamples(getSession(sessionToken));
+    }
+    
+    public void copyRawData(String sessionToken, long[] rawDataSampleIDs)
+    {
+        Session session = getSession(sessionToken);
+        PersonPE person = session.tryGetPerson();
+        
+        List<Sample> samples = loadAllRawDataSamples(session);
+        Set<Long> sampleIDs = new HashSet<Long>();
+        for (Sample sample : samples)
+        {
+            if (RAW_DATA_SAMPLE_VALIDATOR.isValid(person, sample))
+            {
+                sampleIDs.add(sample.getId());
+            }
+        }
+        
+        ISampleDAO sampleDAO = getDAOFactory().getSampleDAO();
+        IExternalDataDAO externalDataDAO = getDAOFactory().getExternalDataDAO();
+        List<String> dataSetCodes = new ArrayList<String>();
+        for (long id : rawDataSampleIDs)
+        {
+            if (sampleIDs.contains(id) == false)
+            {
+                throw new UserFailureException("Invalid or unauthorized access on sample with ID: "
+                        + id);
+            }
+            SamplePE sample = sampleDAO.getByTechId(new TechId(id));
+            List<ExternalDataPE> dataSets = externalDataDAO.listExternalData(sample);
+            for (ExternalDataPE dataSet : dataSets)
+            {
+                dataSetCodes.add(dataSet.getCode());
+            }
+        }
+        String dataStoreServerCode = findDataStoreServer();
+        IExternalDataTable externalDataTable =
+                businessObjectFactory.createExternalDataTable(session);
+        externalDataTable.processDatasets(COPY_PROCESSING_KEY, dataStoreServerCode, dataSetCodes);
+    }
+
+    private List<Sample> loadAllRawDataSamples(Session session)
+    {
+        ISampleLister sampleLister = businessObjectFactory.createSampleLister(session);
+        ListSampleCriteria criteria = new ListSampleCriteria();
+        SampleTypePE sampleTypePE =
+            getDAOFactory().getSampleTypeDAO().tryFindSampleTypeByCode(RAW_DATA_SAMPLE_TYPE);
+        criteria.setSampleType(SampleTypeTranslator.translate(sampleTypePE, null));
+        criteria.setIncludeGroup(true);
+        criteria.setGroupCode(GROUP_CODE);
+        return sampleLister.list(new ListOrSearchSampleCriteria(criteria));
+    }
+    
+    private String findDataStoreServer()
+    {
+        List<DataStorePE> dataStores = getDAOFactory().getDataStoreDAO().listDataStores();
+        for (DataStorePE dataStore : dataStores)
+        {
+            Set<DataStoreServicePE> services = dataStore.getServices();
+            for (DataStoreServicePE dataStoreService : services)
+            {
+                if (DataStoreServiceKind.PROCESSING.equals(dataStoreService.getKind())
+                        && COPY_PROCESSING_KEY.equals(dataStoreService.getKey()))
+                {
+                    return dataStore.getCode();
+                }
+            }
+        }
+        throw new EnvironmentFailureException("No data store processing service with key '"
+                + COPY_PROCESSING_KEY + "' found.");
+    }
+}
diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/RawDataServiceInternalLogger.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/RawDataServiceInternalLogger.java
new file mode 100644
index 0000000000000000000000000000000000000000..98fbf7a477259a4542975b59d461cbab124e98f2
--- /dev/null
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/RawDataServiceInternalLogger.java
@@ -0,0 +1,53 @@
+/*
+ * 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.plugin.phosphonetx.server;
+
+import java.util.List;
+
+import ch.systemsx.cisd.authentication.ISessionManager;
+import ch.systemsx.cisd.openbis.generic.server.AbstractServerLogger;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
+import ch.systemsx.cisd.openbis.generic.shared.dto.Session;
+import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.IRawDataServiceInternal;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+class RawDataServiceInternalLogger extends AbstractServerLogger implements IRawDataServiceInternal
+{
+
+    RawDataServiceInternalLogger(ISessionManager<Session> sessionManager,
+            boolean invocationSuccessful, long elapsedTime)
+    {
+        super(sessionManager, invocationSuccessful, elapsedTime);
+    }
+
+    public List<Sample> listRawDataSamples(String sessionToken)
+    {
+        logAccess(sessionToken, "list_raw_data_samples");
+        return null;
+    }
+    
+    public void copyRawData(String sessionToken, long[] rawDataSampleIDs)
+    {
+        int numberOfDataSets = rawDataSampleIDs == null ? 0 : rawDataSampleIDs.length;
+        logAccess(sessionToken, "copy_raw_data", "NUMBER_OF_DATA_SETS(%s)", numberOfDataSets);
+    }
+
+}
diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/RawDataServiceLogger.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/RawDataServiceLogger.java
index 04a028cec3bfef5bbd71f5a6a2c5e8bfe998e81a..32d98dff7e08d92f3c549f3de83f87794d3589e0 100644
--- a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/RawDataServiceLogger.java
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/RawDataServiceLogger.java
@@ -29,7 +29,7 @@ import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.IRawDataService;
  *
  * @author Franz-Josef Elmer
  */
-public class RawDataServiceLogger extends AbstractServerLogger implements IRawDataService
+class RawDataServiceLogger extends AbstractServerLogger implements IRawDataService
 {
 
     RawDataServiceLogger(ISessionManager<Session> sessionManager,
@@ -44,4 +44,11 @@ public class RawDataServiceLogger extends AbstractServerLogger implements IRawDa
         return null;
     }
 
+    public void copyRawData(String sessionToken, String userID, long[] rawDataSampleIDs)
+    {
+        int numberOfDataSets = rawDataSampleIDs == null ? 0 : rawDataSampleIDs.length;
+        logAccess(sessionToken, "copy_raw_data", "USER_ID(%s) NUMBER_OF_DATA_SETS(%s)", userID,
+                numberOfDataSets);
+    }
+
 }
diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/shared/IRawDataService.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/shared/IRawDataService.java
index df2cc2540db8fa4dadf5427090b556e6e61a3dcb..542e60a5b70c42a76f6b2a90f95832a312073afe 100644
--- a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/shared/IRawDataService.java
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/shared/IRawDataService.java
@@ -33,10 +33,14 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
 public interface IRawDataService extends IServer
 {
     /**
-     * Returns all samples of type MS_INJECTION in group MS_DATA which have a parent sample the
-     * specified user is allow to read.
+     * Returns all samples of type MS_INJECTION in group MS_DATA which have a parent sample which
+     * the specified user is allow to read.
      */
     @Transactional(readOnly = true)
     @RolesAllowed(RoleSet.INSTANCE_ADMIN_OBSERVER)
     public List<Sample> listRawDataSamples(String sessionToken, String userID);
+    
+    @Transactional(readOnly = true)
+    @RolesAllowed(RoleSet.INSTANCE_ADMIN_OBSERVER)
+    public void copyRawData(String sessionToken, String userID, long[] rawDataSampleIDs);
 }
diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/shared/IRawDataServiceInternal.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/shared/IRawDataServiceInternal.java
new file mode 100644
index 0000000000000000000000000000000000000000..f0b3483c468d880bcf06393f08ba2fcf71361d55
--- /dev/null
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/shared/IRawDataServiceInternal.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.plugin.phosphonetx.shared;
+
+import java.util.List;
+
+import org.springframework.transaction.annotation.Transactional;
+
+import ch.systemsx.cisd.openbis.generic.shared.IServer;
+import ch.systemsx.cisd.openbis.generic.shared.authorization.annotation.ReturnValueFilter;
+import ch.systemsx.cisd.openbis.generic.shared.authorization.annotation.RoleSet;
+import ch.systemsx.cisd.openbis.generic.shared.authorization.annotation.RolesAllowed;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
+import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.authorization.validator.RawDataSampleValidator;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+public interface IRawDataServiceInternal extends IServer
+{
+    /**
+     * Returns all samples of type MS_INJECTION in group MS_DATA which have a parent sample which
+     * the specified user is allow to read.
+     */
+    @Transactional(readOnly = true)
+    @RolesAllowed(RoleSet.USER)
+    @ReturnValueFilter(validatorClass = RawDataSampleValidator.class)
+    public List<Sample> listRawDataSamples(String sessionToken);
+    
+    @Transactional(readOnly = true)
+    @RolesAllowed(RoleSet.USER)
+    public void copyRawData(String sessionToken, long[] rawDataSampleIDs);
+}
\ No newline at end of file
diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/shared/authorization/validator/RawDataSampleValidator.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/shared/authorization/validator/RawDataSampleValidator.java
new file mode 100644
index 0000000000000000000000000000000000000000..6918f0fac9eae54c68011dabe5eeff424f89ac28
--- /dev/null
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/shared/authorization/validator/RawDataSampleValidator.java
@@ -0,0 +1,31 @@
+package ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.authorization.validator;
+
+import ch.systemsx.cisd.openbis.generic.shared.authorization.validator.GroupValidator;
+import ch.systemsx.cisd.openbis.generic.shared.authorization.validator.IValidator;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Group;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
+import ch.systemsx.cisd.openbis.generic.shared.dto.PersonPE;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+public final class RawDataSampleValidator implements IValidator<Sample>
+{
+    private IValidator<Group> validator = new GroupValidator();
+
+    public boolean isValid(PersonPE person, Sample sample)
+    {
+        Sample parent = sample.getGeneratedFrom();
+        if (parent != null)
+        {
+            Group group = parent.getGroup();
+            if (group == null || validator.isValid(person, group))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+}
\ No newline at end of file
diff --git a/rtd_phosphonetx/source/java/phosphonetx-applicationContext.xml b/rtd_phosphonetx/source/java/phosphonetx-applicationContext.xml
index 75d1796c11a7069e0b1b1b0ce05ae161b8aa5dcb..49fe1a591d1ed9507d5d83d34a29244040d303ab 100644
--- a/rtd_phosphonetx/source/java/phosphonetx-applicationContext.xml
+++ b/rtd_phosphonetx/source/java/phosphonetx-applicationContext.xml
@@ -41,7 +41,7 @@
     </bean>      
     
     <!-- 
-        // Raw Data Server with interceptors for translating results
+        // Raw Data Server 
     -->
     
     <bean id="phosphonetx-raw-data-service" class="org.springframework.aop.framework.ProxyFactoryBean">
@@ -54,7 +54,7 @@
             <bean class="ch.systemsx.cisd.openbis.plugin.phosphonetx.server.RawDataService">
                 <constructor-arg ref="session-manager" />
                 <constructor-arg ref="dao-factory" />
-                <constructor-arg ref="common-server" />
+                <constructor-arg ref="phosphonetx-raw-data-service-internal" />
             </bean>
         </property>
         <property name="interceptorNames">
@@ -64,4 +64,28 @@
         </property>
     </bean>
     
+    <bean id="phosphonetx-raw-data-service-internal" 
+          class="ch.systemsx.cisd.openbis.plugin.phosphonetx.server.RawDataServiceInternal">
+        <constructor-arg>
+            <bean class="ch.systemsx.cisd.authentication.DefaultSessionManager">
+                <constructor-arg>
+                    <bean class="ch.systemsx.cisd.openbis.generic.server.SessionFactory" />
+                </constructor-arg>
+                <constructor-arg>
+                    <bean class="ch.systemsx.cisd.openbis.generic.server.LogMessagePrefixGenerator" />
+                </constructor-arg>
+                <constructor-arg ref="dummy-authentication-service" />
+                <constructor-arg>
+                    <bean class="ch.systemsx.cisd.common.servlet.RequestContextProviderAdapter">
+                        <constructor-arg ref="request-context-provider" />
+                    </bean>
+                </constructor-arg>
+                <constructor-arg value="${session-timeout}" />
+            </bean>
+        </constructor-arg>
+        <constructor-arg ref="dao-factory"/>
+        <constructor-arg ref="common-business-object-factory" />
+    </bean>
+
+    
 </beans>
\ No newline at end of file
diff --git a/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/RawDataTestClient.java b/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/RawDataTestClient.java
index b96531f519a29f7277bca526c3897deec7089d6b..de9cb66793ad26ddd3e5cb252aff36c832e17d6c 100644
--- a/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/RawDataTestClient.java
+++ b/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/RawDataTestClient.java
@@ -18,6 +18,7 @@ package ch.systemsx.cisd.openbis.plugin.phosphonetx;
 
 import java.util.List;
 
+import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.common.spring.HttpInvokerUtils;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
 import ch.systemsx.cisd.openbis.generic.shared.dto.SessionContextDTO;
@@ -37,17 +38,35 @@ public class RawDataTestClient
     {
         IRawDataService service = HttpInvokerUtils.createServiceStub(IRawDataService.class, SERVICE_PATH, 5);
         
-        SessionContextDTO session = service.tryToAuthenticate("test_b", "t");
         for (String user : new String[] {"test", "test_a", "test_b", "test_c"})
         {
-            List<Sample> samples = service.listRawDataSamples(session.getSessionToken(), user);
-            System.out.println("User: " + user);
-            for (Sample sample : samples)
+            try
+            {
+                System.out.println("User: " + user);
+                SessionContextDTO session = service.tryToAuthenticate("test_b", "t");
+                String sessionToken = session.getSessionToken();
+                List<Sample> samples = service.listRawDataSamples(sessionToken, user);
+                for (Sample sample : samples)
+                {
+                    System.out.println("  " + sample.getCode()+" -> "+sample.getGeneratedFrom().getIdentifier());
+                }
+            } catch (UserFailureException ex)
             {
-                System.out.println("  " + sample.getCode()+" -> "+sample.getGeneratedFrom().getIdentifier());
+                System.out.println(" Exception: " + ex);
             }
             
         }
-   
+        System.out.println("--------------------");
+        SessionContextDTO session = service.tryToAuthenticate("test_b", "t");
+        String sessionToken = session.getSessionToken();
+        
+        List<Sample> samples = service.listRawDataSamples(sessionToken, "test_a");
+        long[] ids = new long[samples.size()];
+        for (int i = 0; i < samples.size(); i++)
+        {
+            Sample sample = samples.get(i);
+            ids[i] = sample.getId();
+        }
+        service.copyRawData(sessionToken, "test_a", ids);
     }
 }
diff --git a/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/RawDataServiceInternalTest.java b/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/RawDataServiceInternalTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..866bfec3698d73568aa435d204cbc646341b3922
--- /dev/null
+++ b/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/RawDataServiceInternalTest.java
@@ -0,0 +1,204 @@
+/*
+ * 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.plugin.phosphonetx.server;
+
+import static ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataStoreServiceKind.PROCESSING;
+import static ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataStoreServiceKind.QUERIES;
+import static ch.systemsx.cisd.openbis.plugin.phosphonetx.server.RawDataServiceInternal.COPY_PROCESSING_KEY;
+import static ch.systemsx.cisd.openbis.plugin.phosphonetx.server.RawDataServiceInternal.GROUP_CODE;
+import static ch.systemsx.cisd.openbis.plugin.phosphonetx.server.RawDataServiceInternal.RAW_DATA_SAMPLE_TYPE;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedHashSet;
+import java.util.List;
+
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.jmock.Expectations;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import ch.rinn.restrictions.Friend;
+import ch.systemsx.cisd.openbis.generic.server.business.bo.ICommonBusinessObjectFactory;
+import ch.systemsx.cisd.openbis.generic.server.business.bo.samplelister.ISampleLister;
+import ch.systemsx.cisd.openbis.generic.shared.AbstractServerTestCase;
+import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataStoreServiceKind;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ListOrSearchSampleCriteria;
+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.dto.DataStorePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DataStoreServicePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.ExternalDataPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SampleTypePE;
+import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.IRawDataServiceInternal;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+@Friend(toClasses=RawDataServiceInternal.class)
+public class RawDataServiceInternalTest extends AbstractServerTestCase
+{
+    private IRawDataServiceInternal service;
+    private ICommonBusinessObjectFactory boFactory;
+    private ISampleLister sampleLister;
+
+    @Override
+    @BeforeMethod
+    public final void setUp()
+    {
+        super.setUp();
+        boFactory = context.mock(ICommonBusinessObjectFactory.class);
+        sampleLister = context.mock(ISampleLister.class);
+        service = new RawDataServiceInternal(sessionManager, daoFactory, boFactory);
+    }
+    
+    @Test
+    public void testListRawDataSamples()
+    {
+        prepareGetSession();
+        prepareListRawDataSamples(42L);
+        
+        List<Sample> samples = service.listRawDataSamples(SESSION_TOKEN);
+
+        assertEquals(42L, samples.get(0).getId().longValue());
+        assertEquals(1, samples.size());
+        context.assertIsSatisfied();
+    }
+    
+    @Test
+    public void testCopyRawData()
+    {
+        prepareGetSession();
+        prepareListRawDataSamples(1L, 2L, 3L, 42L);
+        final long[] ids = new long[] {2, 3};
+        context.checking(new Expectations()
+            {
+                {
+                    for (long id : ids)
+                    {
+                        one(sampleDAO).getByTechId(new TechId(id));
+                        SamplePE sample = new SamplePE();
+                        sample.setId(id);
+                        sample.setCode("s" + id);
+                        will(returnValue(sample));
+                        
+                        one(externalDataDAO).listExternalData(sample);
+                        List<ExternalDataPE> dataSets = new ArrayList<ExternalDataPE>();
+                        for (int i = 0; i < (int) (id % 3); i++)
+                        {
+                            ExternalDataPE dataSet = new ExternalDataPE();
+                            dataSet.setCode("ds" + id + "." + i);
+                            dataSets.add(dataSet);
+                        }
+                        will(returnValue(dataSets ));
+                    }
+                    
+                    one(dataStoreDAO).listDataStores();
+                    DataStorePE s1 = store("s1", service("a", PROCESSING), service(COPY_PROCESSING_KEY, QUERIES));
+                    DataStorePE s2 = store("s2", service(COPY_PROCESSING_KEY, PROCESSING));
+                    will(returnValue(Arrays.asList(s1, s2)));
+                    
+                    one(boFactory).createExternalDataTable(SESSION);
+                    will(returnValue(externalDataTable));
+                    
+                    List<String> dataSetCodes = Arrays.asList("ds2.0", "ds2.1");
+                    one(externalDataTable).processDatasets(COPY_PROCESSING_KEY, "s2", dataSetCodes);
+                }
+                
+            });
+        
+        service.copyRawData(SESSION_TOKEN, ids);
+        
+        context.assertIsSatisfied();
+    }
+
+    private void prepareListRawDataSamples(final Long... sampleIDs)
+    {
+        context.checking(new Expectations()
+            {
+                {
+                    one(boFactory).createSampleLister(SESSION);
+                    will(returnValue(sampleLister));
+
+                    one(sampleTypeDAO).tryFindSampleTypeByCode(RAW_DATA_SAMPLE_TYPE);
+                    final SampleTypePE sampleType = new SampleTypePE();
+                    sampleType.setCode(RAW_DATA_SAMPLE_TYPE);
+                    sampleType.setId(20100104l);
+                    sampleType.setListable(Boolean.TRUE);
+                    sampleType.setAutoGeneratedCode(Boolean.FALSE);
+                    sampleType.setGeneratedFromHierarchyDepth(0);
+                    sampleType.setContainerHierarchyDepth(0);
+                    will(returnValue(sampleType));
+
+                    one(sampleLister).list(with(new BaseMatcher<ListOrSearchSampleCriteria>()
+                        {
+                            public boolean matches(Object item)
+                            {
+                                if (item instanceof ListOrSearchSampleCriteria)
+                                {
+                                    ListOrSearchSampleCriteria criteria =
+                                            (ListOrSearchSampleCriteria) item;
+                                    assertEquals(GROUP_CODE, criteria.getGroupCode());
+                                    assertEquals(true, criteria.isIncludeGroup());
+                                    SampleType type = criteria.getSampleType();
+                                    assertEquals(RAW_DATA_SAMPLE_TYPE, type.getCode());
+                                    assertEquals(sampleType.getId(), type.getId());
+                                    return true;
+                                }
+                                return false;
+                            }
+
+                            public void describeTo(Description description)
+                            {
+                                description.appendValue(sampleType);
+                            }
+                        }));
+                    List<Sample> samples = new ArrayList<Sample>();
+                    for (Long id : sampleIDs)
+                    {
+                        Sample sample = new Sample();
+                        sample.setId(id);
+                        Sample parent = new Sample();
+                        sample.setGeneratedFrom(parent);
+                        samples.add(sample);
+                    }
+                    will(returnValue(samples));
+                }
+            });
+    }
+
+    private DataStorePE store(String code, DataStoreServicePE... services)
+    {
+        DataStorePE store = new DataStorePE();
+        store.setCode(code);
+        store.setServices(new LinkedHashSet<DataStoreServicePE>(Arrays.asList(services)));
+        return store;
+    }
+    
+    private DataStoreServicePE service(String key, DataStoreServiceKind kind)
+    {
+        DataStoreServicePE dataStoreService = new DataStoreServicePE();
+        dataStoreService.setKey(key);
+        dataStoreService.setKind(kind);
+        return dataStoreService;
+    }
+}
diff --git a/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/RawDataServiceTest.java b/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/RawDataServiceTest.java
deleted file mode 100644
index 13951e4662c793eded77b0e22d9f86a9d8bef76e..0000000000000000000000000000000000000000
--- a/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/RawDataServiceTest.java
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- * 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.plugin.phosphonetx.server;
-
-import static ch.systemsx.cisd.openbis.plugin.phosphonetx.server.RawDataService.GROUP_CODE;
-import static ch.systemsx.cisd.openbis.plugin.phosphonetx.server.RawDataService.RAW_DATA_SAMPLE_TYPE;
-
-import java.util.Arrays;
-import java.util.LinkedHashSet;
-import java.util.List;
-
-import org.hamcrest.BaseMatcher;
-import org.hamcrest.Description;
-import org.jmock.Expectations;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import ch.rinn.restrictions.Friend;
-import ch.systemsx.cisd.common.exceptions.UserFailureException;
-import ch.systemsx.cisd.openbis.generic.shared.AbstractServerTestCase;
-import ch.systemsx.cisd.openbis.generic.shared.ICommonServer;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DatabaseInstance;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Group;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ListSampleCriteria;
-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.dto.DatabaseInstancePE;
-import ch.systemsx.cisd.openbis.generic.shared.dto.GroupPE;
-import ch.systemsx.cisd.openbis.generic.shared.dto.PersonPE;
-import ch.systemsx.cisd.openbis.generic.shared.dto.RoleAssignmentPE;
-import ch.systemsx.cisd.openbis.generic.shared.dto.SampleTypePE;
-import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.DatabaseInstanceIdentifier;
-import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.GroupIdentifier;
-import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier;
-import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifierFactory;
-
-/**
- * 
- *
- * @author Franz-Josef Elmer
- */
-@Friend(toClasses=RawDataService.class)
-public class RawDataServiceTest extends AbstractServerTestCase
-{
-    private static final String USER_ID = "a-user";
-    private static final Sample NO_PARENT = create("no-parent", null);
-    private static final Sample WITH_INSTANCE_PARENT = create("with-instance-parent", "t:/parent");
-    private static final Sample WITH_PARENT_IN_G1 = create("with-parent-in-g1", "t:/g1/parent");
-    private static final Sample WITH_PARENT_IN_G2 = create("with-parent-in-g2", "t:/g2/parent");
-    
-    private static Sample create(String sampleCode, String parentSampleIdentifierOrNull)
-    {
-        Sample sample = new Sample();
-        sample.setCode(sampleCode);
-        if (parentSampleIdentifierOrNull != null)
-        {
-            Sample parent = new Sample();
-            parent.setIdentifier(parentSampleIdentifierOrNull);
-            SampleIdentifier identifier = SampleIdentifierFactory.parse(parentSampleIdentifierOrNull);
-            parent.setCode(identifier.getSampleCode());
-            GroupIdentifier groupLevel = identifier.getGroupLevel();
-            if (groupLevel != null)
-            {
-                Group group = new Group();
-                group.setCode(groupLevel.getGroupCode());
-                group.setInstance(createDatabaseInstance(groupLevel.getDatabaseInstanceCode()));
-                parent.setGroup(group);
-            }
-            DatabaseInstanceIdentifier databaseInstanceLevel = identifier.getDatabaseInstanceLevel();
-            if (databaseInstanceLevel != null)
-            {
-                String code = databaseInstanceLevel.getDatabaseInstanceCode();
-                DatabaseInstance databaseInstance = createDatabaseInstance(code);
-                parent.setDatabaseInstance(databaseInstance);
-            }
-            sample.setGeneratedFrom(parent);
-        }
-        return sample;
-    }
-
-    private static DatabaseInstance createDatabaseInstance(String code)
-    {
-        DatabaseInstance databaseInstance = new DatabaseInstance();
-        databaseInstance.setCode(code);
-        databaseInstance.setUuid(code);
-        return databaseInstance;
-    }
-    
-    private ICommonServer commonServer;
-    private RawDataService rawDataService;
-
-    @Override
-    @BeforeMethod
-    public final void setUp()
-    {
-        super.setUp();
-        commonServer = context.mock(ICommonServer.class);
-        rawDataService = new RawDataService(sessionManager, daoFactory, commonServer);
-    }
-
-    @Test
-    public void testListRawDataSamplesForUnknownUser()
-    {
-        prepareGetSession();
-        context.checking(new Expectations()
-            {
-                {
-                    one(personDAO).tryFindPersonByUserId(USER_ID);
-                }
-            });
-        
-        try
-        {
-            rawDataService.listRawDataSamples(SESSION_TOKEN, USER_ID);
-            fail("UserFailureException expected.");
-        } catch (UserFailureException ex)
-        {
-            assertEquals("Unknown user ID: " + USER_ID, ex.getMessage());
-        }
-
-        context.assertIsSatisfied();
-    }
-
-    @Test
-    public void testListRawDataSamplesForUserWithNoRoles()
-    {
-        prepareGetSession();
-        prepareListRawDataSamples();
-        
-        List<Sample> samples = rawDataService.listRawDataSamples(SESSION_TOKEN, USER_ID);
-
-        assertSame(WITH_INSTANCE_PARENT, samples.get(0));
-        assertEquals(1, samples.size());
-        context.assertIsSatisfied();
-    }
-    
-    @Test
-    public void testListRawDataSamplesForUserWithRightsForGroupG1()
-    {
-        prepareGetSession();
-        prepareListRawDataSamples(createRole("G1", "T"));
-        
-        List<Sample> samples = rawDataService.listRawDataSamples(SESSION_TOKEN, USER_ID);
-        
-        assertSame(WITH_INSTANCE_PARENT, samples.get(0));
-        assertSame(WITH_PARENT_IN_G1, samples.get(1));
-        assertEquals(2, samples.size());
-        context.assertIsSatisfied();
-    }
-    
-    @Test
-    public void testListRawDataSamplesForUserWithRightsForGroupG1AndG2()
-    {
-        prepareGetSession();
-        prepareListRawDataSamples(createRole("G1", "T"), createRole("G2", "T"));
-        
-        List<Sample> samples = rawDataService.listRawDataSamples(SESSION_TOKEN, USER_ID);
-        
-        assertSame(WITH_INSTANCE_PARENT, samples.get(0));
-        assertSame(WITH_PARENT_IN_G1, samples.get(1));
-        assertSame(WITH_PARENT_IN_G2, samples.get(2));
-        assertEquals(3, samples.size());
-        context.assertIsSatisfied();
-    }
-
-    @Test
-    public void testListRawDataSamplesForUserWithRightsForGroupG1ButWrongInstance()
-    {
-        prepareGetSession();
-        prepareListRawDataSamples(createRole("G1", "X"));
-        
-        List<Sample> samples = rawDataService.listRawDataSamples(SESSION_TOKEN, USER_ID);
-        
-        assertSame(WITH_INSTANCE_PARENT, samples.get(0));
-        assertEquals(1, samples.size());
-        context.assertIsSatisfied();
-    }
-    
-    @Test
-    public void testListRawDataSamplesForUserWithRightsForInstanceT()
-    {
-        prepareGetSession();
-        prepareListRawDataSamples(createRole(null, "T"));
-        
-        List<Sample> samples = rawDataService.listRawDataSamples(SESSION_TOKEN, USER_ID);
-        
-        assertSame(WITH_INSTANCE_PARENT, samples.get(0));
-        assertSame(WITH_PARENT_IN_G1, samples.get(1));
-        assertSame(WITH_PARENT_IN_G2, samples.get(2));
-        assertEquals(3, samples.size());
-        context.assertIsSatisfied();
-    }
-    
-    @Test
-    public void testListRawDataSamplesForUserWithRightsForInstanceX()
-    {
-        prepareGetSession();
-        prepareListRawDataSamples(createRole(null, "X"));
-        
-        List<Sample> samples = rawDataService.listRawDataSamples(SESSION_TOKEN, USER_ID);
-        
-        assertSame(WITH_INSTANCE_PARENT, samples.get(0));
-        assertEquals(1, samples.size());
-        context.assertIsSatisfied();
-    }
-    
-    private void prepareListRawDataSamples(final RoleAssignmentPE... roles)
-    {
-        context.checking(new Expectations()
-            {
-                {
-                    one(personDAO).tryFindPersonByUserId(USER_ID);
-                    PersonPE person = new PersonPE();
-                    person.setRoleAssignments(new LinkedHashSet<RoleAssignmentPE>(Arrays.asList(roles)));
-                    will(returnValue(person));
-
-                    one(sampleTypeDAO).tryFindSampleTypeByCode(RAW_DATA_SAMPLE_TYPE);
-                    final SampleTypePE sampleType = new SampleTypePE();
-                    sampleType.setCode(RAW_DATA_SAMPLE_TYPE);
-                    sampleType.setId(20100104l);
-                    sampleType.setListable(Boolean.TRUE);
-                    sampleType.setAutoGeneratedCode(Boolean.FALSE);
-                    sampleType.setGeneratedFromHierarchyDepth(0);
-                    sampleType.setContainerHierarchyDepth(0);
-                    will(returnValue(sampleType));
-
-                    one(commonServer).listSamples(with(SESSION_TOKEN),
-                            with(new BaseMatcher<ListSampleCriteria>()
-                                {
-                                    public boolean matches(Object item)
-                                    {
-                                        if (item instanceof ListSampleCriteria)
-                                        {
-                                            ListSampleCriteria criteria = (ListSampleCriteria) item;
-                                            assertEquals(GROUP_CODE, criteria.getGroupCode());
-                                            assertEquals(true, criteria.isIncludeGroup());
-                                            SampleType type = criteria.getSampleType();
-                                            assertEquals(RAW_DATA_SAMPLE_TYPE, type.getCode());
-                                            assertEquals(sampleType.getId(), type.getId());
-                                            return true;
-                                        }
-                                        return false;
-                                    }
-
-                                    public void describeTo(Description description)
-                                    {
-                                        description.appendValue(sampleType);
-                                    }
-                                }));
-                    will(returnValue(Arrays.asList(NO_PARENT, WITH_INSTANCE_PARENT,
-                            WITH_PARENT_IN_G1, WITH_PARENT_IN_G2)));
-                }
-            });
-    }
-    
-    private RoleAssignmentPE createRole(String groupCodeOrNull, String dataBaseInstanceUUID)
-    {
-        RoleAssignmentPE role = new RoleAssignmentPE();
-        if (groupCodeOrNull == null)
-        {
-            DatabaseInstancePE databaseInstance = new DatabaseInstancePE();
-            databaseInstance.setUuid(dataBaseInstanceUUID);
-            role.setDatabaseInstance(databaseInstance);
-        } else
-        {
-            GroupPE group = new GroupPE();
-            group.setCode(groupCodeOrNull);
-            DatabaseInstancePE databaseInstance = new DatabaseInstancePE();
-            databaseInstance.setUuid(dataBaseInstanceUUID);
-            group.setDatabaseInstance(databaseInstance);
-            role.setGroup(group);
-        }
-        return role;
-    }
-}
diff --git a/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/shared/authorization/validator/RawDataSampleValidatorTest.java b/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/shared/authorization/validator/RawDataSampleValidatorTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..9cc8266ec6f93a8a031f5ff5efc059c13b9c64d3
--- /dev/null
+++ b/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/shared/authorization/validator/RawDataSampleValidatorTest.java
@@ -0,0 +1,181 @@
+/*
+ * 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.plugin.phosphonetx.shared.authorization.validator;
+
+import java.util.Arrays;
+import java.util.LinkedHashSet;
+
+import org.testng.AssertJUnit;
+import org.testng.annotations.Test;
+
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DatabaseInstance;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Group;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DatabaseInstancePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.GroupPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.PersonPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.RoleAssignmentPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.DatabaseInstanceIdentifier;
+import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.GroupIdentifier;
+import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier;
+import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifierFactory;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+public class RawDataSampleValidatorTest extends AssertJUnit
+{
+    private static final Sample NO_PARENT = create("no-parent", null);
+    private static final Sample WITH_INSTANCE_PARENT = create("with-instance-parent", "t:/parent");
+    private static final Sample WITH_PARENT_IN_G1 = create("with-parent-in-g1", "t:/g1/parent");
+    private static final Sample WITH_PARENT_IN_G2 = create("with-parent-in-g2", "t:/g2/parent");
+    
+    private RawDataSampleValidator validator = new RawDataSampleValidator();
+    
+    private static Sample create(String sampleCode, String parentSampleIdentifierOrNull)
+    {
+        Sample sample = new Sample();
+        sample.setCode(sampleCode);
+        if (parentSampleIdentifierOrNull != null)
+        {
+            Sample parent = new Sample();
+            parent.setIdentifier(parentSampleIdentifierOrNull);
+            SampleIdentifier identifier = SampleIdentifierFactory.parse(parentSampleIdentifierOrNull);
+            parent.setCode(identifier.getSampleCode());
+            GroupIdentifier groupLevel = identifier.getGroupLevel();
+            if (groupLevel != null)
+            {
+                Group group = new Group();
+                group.setCode(groupLevel.getGroupCode());
+                group.setInstance(createDatabaseInstance(groupLevel.getDatabaseInstanceCode()));
+                parent.setGroup(group);
+            }
+            DatabaseInstanceIdentifier databaseInstanceLevel = identifier.getDatabaseInstanceLevel();
+            if (databaseInstanceLevel != null)
+            {
+                String code = databaseInstanceLevel.getDatabaseInstanceCode();
+                DatabaseInstance databaseInstance = createDatabaseInstance(code);
+                parent.setDatabaseInstance(databaseInstance);
+            }
+            sample.setGeneratedFrom(parent);
+        }
+        return sample;
+    }
+
+    private static DatabaseInstance createDatabaseInstance(String code)
+    {
+        DatabaseInstance databaseInstance = new DatabaseInstance();
+        databaseInstance.setCode(code);
+        databaseInstance.setUuid(code);
+        return databaseInstance;
+    }
+    
+    @Test
+    public void testUserWithNoRights()
+    {
+        PersonPE person = createPersonWithRoles();
+        
+        assertEquals(false, validator.isValid(person, NO_PARENT));
+        assertEquals(true, validator.isValid(person, WITH_INSTANCE_PARENT));
+        assertEquals(false, validator.isValid(person, WITH_PARENT_IN_G1));
+        assertEquals(false, validator.isValid(person, WITH_PARENT_IN_G2));
+    }
+    
+    @Test
+    public void testUserWithRightsForGroupG1()
+    {
+        PersonPE person = createPersonWithRoles(createRole("G1", "T"));
+        
+        assertEquals(false, validator.isValid(person, NO_PARENT));
+        assertEquals(true, validator.isValid(person, WITH_INSTANCE_PARENT));
+        assertEquals(true, validator.isValid(person, WITH_PARENT_IN_G1));
+        assertEquals(false, validator.isValid(person, WITH_PARENT_IN_G2));
+    }
+    
+    @Test
+    public void testUserWithRightsForGroupG1AndG2()
+    {
+        PersonPE person = createPersonWithRoles(createRole("G1", "T"), createRole("G2", "T"));
+        
+        assertEquals(false, validator.isValid(person, NO_PARENT));
+        assertEquals(true, validator.isValid(person, WITH_INSTANCE_PARENT));
+        assertEquals(true, validator.isValid(person, WITH_PARENT_IN_G1));
+        assertEquals(true, validator.isValid(person, WITH_PARENT_IN_G2));
+    }
+    
+    @Test
+    public void testUserWithRightsForGroupG1ButWrongInstance()
+    {
+        PersonPE person = createPersonWithRoles(createRole("G1", "X"));
+        
+        assertEquals(false, validator.isValid(person, NO_PARENT));
+        assertEquals(true, validator.isValid(person, WITH_INSTANCE_PARENT));
+        assertEquals(false, validator.isValid(person, WITH_PARENT_IN_G1));
+        assertEquals(false, validator.isValid(person, WITH_PARENT_IN_G2));
+    }
+    
+    @Test
+    public void testUserWithRightsForForInstanceT()
+    {
+        PersonPE person = createPersonWithRoles(createRole(null, "T"));
+        
+        assertEquals(false, validator.isValid(person, NO_PARENT));
+        assertEquals(true, validator.isValid(person, WITH_INSTANCE_PARENT));
+        assertEquals(true, validator.isValid(person, WITH_PARENT_IN_G1));
+        assertEquals(true, validator.isValid(person, WITH_PARENT_IN_G2));
+    }
+    
+    @Test
+    public void testUserWithRightsForForInstanceX()
+    {
+        PersonPE person = createPersonWithRoles(createRole(null, "X"));
+        
+        assertEquals(false, validator.isValid(person, NO_PARENT));
+        assertEquals(true, validator.isValid(person, WITH_INSTANCE_PARENT));
+        assertEquals(false, validator.isValid(person, WITH_PARENT_IN_G1));
+        assertEquals(false, validator.isValid(person, WITH_PARENT_IN_G2));
+    }
+    
+    private PersonPE createPersonWithRoles(RoleAssignmentPE... roles)
+    {
+        PersonPE person = new PersonPE();
+        person.setRoleAssignments(new LinkedHashSet<RoleAssignmentPE>(Arrays.asList(roles)));
+        return person;
+    }
+    
+    private RoleAssignmentPE createRole(String groupCodeOrNull, String dataBaseInstanceUUID)
+    {
+        RoleAssignmentPE role = new RoleAssignmentPE();
+        if (groupCodeOrNull == null)
+        {
+            DatabaseInstancePE databaseInstance = new DatabaseInstancePE();
+            databaseInstance.setUuid(dataBaseInstanceUUID);
+            role.setDatabaseInstance(databaseInstance);
+        } else
+        {
+            GroupPE group = new GroupPE();
+            group.setCode(groupCodeOrNull);
+            DatabaseInstancePE databaseInstance = new DatabaseInstancePE();
+            databaseInstance.setUuid(dataBaseInstanceUUID);
+            group.setDatabaseInstance(databaseInstance);
+            role.setGroup(group);
+        }
+        return role;
+    }
+}