diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/FullSampleIdentifier.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/FullSampleIdentifier.java
index ba2b50955a1a53da8680a26022788e6c7aed18d9..441695289f1781ab2fd53d7c048cf9f5463450a9 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/FullSampleIdentifier.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/FullSampleIdentifier.java
@@ -16,6 +16,10 @@
 
 package ch.ethz.sis.openbis.generic.server.api.v3.executor.sample;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+
 import org.apache.commons.lang.StringUtils;
 
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.sample.SampleIdentifier;
@@ -26,7 +30,7 @@ import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.sample.SampleIdentifier;
  * 
  * @author Franz-Josef Elmer
  */
-class FullSampleIdentifier
+public class FullSampleIdentifier
 {
     private static final String CODE_CHAR_PATTERN = "a-zA-Z0-9_\\-\\.";
     private static final String CODE_CHARS = "[" + CODE_CHAR_PATTERN + "]+";
@@ -35,7 +39,7 @@ class FullSampleIdentifier
     private SampleIdentifierParts sampleIdentifierParts;
     private String sampleCode;
     
-    FullSampleIdentifier(String sampleIdentifier)
+    public FullSampleIdentifier(String sampleIdentifier, String homeSpaceCodeOrNull)
     {
         String[] parts = extractParts(sampleIdentifier);
         String spaceCode = null;
@@ -56,35 +60,58 @@ class FullSampleIdentifier
             projectCode = parts[2];
             code = parts[3];
         }
+        if (spaceCode != null && spaceCode.isEmpty() && homeSpaceCodeOrNull != null)
+        {
+            spaceCode = homeSpaceCodeOrNull;
+        }
         
-        String[] splittedCode = splitCode(code, sampleIdentifier);
-        if (splittedCode.length == 2)
+        List<String> splittedCode = splitCode(code, sampleIdentifier);
+        if (splittedCode.size() == 2)
         {
-            containerCode = splittedCode[0];
-            plainSampleCode = splittedCode[1];
+            containerCode = splittedCode.get(0);
+            plainSampleCode = splittedCode.get(1);
         } else {
-            plainSampleCode = splittedCode[0];
+            plainSampleCode = splittedCode.get(0);
         }
         
         //Code format validation
-        verifyCodePattern(spaceCode);
-        verifyCodePattern(projectCode);
-        verifyCodePattern(containerCode);
-        verifyCodePattern(plainSampleCode);
+        verifyCodePattern(spaceCode, "Space code");
+        verifyCodePattern(projectCode, "Project code");
+        verifyCodePattern(containerCode, "Container sample code");
+        verifyCodePattern(plainSampleCode, containerCode == null ? "Sample code" : "Sample subcode");
             
         sampleCode = plainSampleCode;
         sampleIdentifierParts = new SampleIdentifierParts(spaceCode, projectCode, containerCode);
         
     }
 
-    private String[] splitCode(String code, String sampleIdentifier)
+    private List<String> splitCode(String code, String sampleIdentifier)
     {
-        String[] splittedCode = code.split(":");
-        if (splittedCode.length > 2)
+        String delim = ":";
+        StringTokenizer tokenizer = new StringTokenizer(code, delim, true);
+        int numberOfDelims = 0;
+        List<String> tokens = new ArrayList<>(); 
+        while (tokenizer.hasMoreTokens())
+        {
+            String token = tokenizer.nextToken();
+            if (delim.equals(token))
+            {
+                numberOfDelims++;
+            } else
+            {
+                tokens.add(token);
+            }
+        }
+        if (numberOfDelims > 1)
+        {
+            throw new IllegalArgumentException("Sample code can not contain more than one '" + delim + "': " 
+                    + sampleIdentifier);
+        }
+        if (numberOfDelims != tokens.size() - 1)
         {
-            throw new IllegalArgumentException("Sample code can not contain more than one ':': " + sampleIdentifier);
+            throw new IllegalArgumentException("Sample code starts or ends with '" + delim + "': " + sampleIdentifier);
         }
-        return splittedCode;
+        return tokens;
     }
 
     private String[] extractParts(String sampleIdentifier)
@@ -110,19 +137,29 @@ class FullSampleIdentifier
         return parts;
     }
 
-    private void verifyCodePattern(String code) {
-        if(code != null && code.matches(CODE_PATTERN) == false) {
-            throw new IllegalArgumentException("Code field containing other characters than letters, numbers, '_', '-' and '.': " + code);
+    private void verifyCodePattern(String code, String partName)
+    {
+        if (code == null)
+        {
+            return;
         }
-    }
-    
+        if (code.length() == 0)
+        {
+            throw new IllegalArgumentException(partName + " can not be an empty string.");
+        }
+        if (code.matches(CODE_PATTERN) == false)
+        {
+            throw new IllegalArgumentException(partName + " containing other characters than letters, numbers, "
+                    + "'_', '-' and '.': " + code);
+        }
+    }    
     
-    SampleIdentifierParts getParts()
+    public SampleIdentifierParts getParts()
     {
         return sampleIdentifierParts;
     }
 
-    String getSampleCode()
+    public String getSampleCode()
     {
         return sampleCode;
     }
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/ListSampleTechIdByIdentifier.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/ListSampleTechIdByIdentifier.java
index 366cf9f11f03d5bd502d6870bac01be42b0fc8ff..a1fd1e470f13179c6efa16172134c66efa9d3126 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/ListSampleTechIdByIdentifier.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/ListSampleTechIdByIdentifier.java
@@ -27,8 +27,6 @@ import net.lemnik.eodsql.QueryTool;
 import ch.ethz.sis.openbis.generic.server.api.v3.executor.common.TechIdStringIdentifierRecord;
 import ch.ethz.sis.openbis.generic.server.api.v3.helper.common.AbstractListTechIdById;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.sample.SampleIdentifier;
-import ch.systemsx.cisd.openbis.generic.shared.basic.CodeConverter;
-import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifierFactory;
 
 /**
  * 
@@ -53,37 +51,7 @@ public class ListSampleTechIdByIdentifier extends AbstractListTechIdById<SampleI
     @Override
     protected Map<Long, SampleIdentifier> createIdsByTechIdsMap(List<SampleIdentifier> ids)
     {
-        Map<SampleIdentifierParts, Map<String, SampleIdentifier>> groupedIdentifiers = new HashMap<>();
-        for (SampleIdentifier sampleIdentifier : ids)
-        {
-            ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier sampleIdentifier2 
-                = SampleIdentifierFactory.parse(sampleIdentifier.getIdentifier());
-            String spaceCode = null;
-            if (sampleIdentifier2.isSpaceLevel())
-            {
-                if (sampleIdentifier2.isInsideHomeSpace())
-                {
-                    if (homeSpaceCodeOrNull == null)
-                    {
-                        continue;
-                    }
-                    spaceCode = homeSpaceCodeOrNull;
-                } else
-                {
-                    spaceCode = CodeConverter.tryToDatabase(sampleIdentifier2.getSpaceLevel().getSpaceCode());
-                }
-            }
-            String sampleSubCode = CodeConverter.tryToDatabase(sampleIdentifier2.getSampleSubCode());
-            String containerCode = CodeConverter.tryToDatabase(sampleIdentifier2.tryGetContainerCode());
-            SampleIdentifierParts key = new SampleIdentifierParts(spaceCode, null, containerCode);
-            Map<String, SampleIdentifier> identifiersByCode = groupedIdentifiers.get(key);
-            if (identifiersByCode == null)
-            {
-                identifiersByCode = new HashMap<>();
-                groupedIdentifiers.put(key, identifiersByCode);
-            }
-            identifiersByCode.put(sampleSubCode, sampleIdentifier);
-        }
+        Map<SampleIdentifierParts, Map<String, SampleIdentifier>> groupedIdentifiers = groupIdentifiers(ids);
         
         Map<Long, SampleIdentifier> result = new HashMap<>();
         SampleQuery query = QueryTool.getManagedQuery(SampleQuery.class);
@@ -100,11 +68,32 @@ public class ListSampleTechIdByIdentifier extends AbstractListTechIdById<SampleI
         }
         return result;
     }
-    
+
+    private Map<SampleIdentifierParts, Map<String, SampleIdentifier>> groupIdentifiers(List<SampleIdentifier> ids)
+    {
+        Map<SampleIdentifierParts, Map<String, SampleIdentifier>> groupedIdentifiers = new HashMap<>();
+        for (SampleIdentifier sampleIdentifier : ids)
+        {
+            FullSampleIdentifier fullSampleIdentifier = new FullSampleIdentifier(sampleIdentifier.getIdentifier(), 
+                    homeSpaceCodeOrNull);
+            
+            SampleIdentifierParts key = fullSampleIdentifier.getParts();
+            Map<String, SampleIdentifier> identifiersByCode = groupedIdentifiers.get(key);
+            if (identifiersByCode == null)
+            {
+                identifiersByCode = new HashMap<>();
+                groupedIdentifiers.put(key, identifiersByCode);
+            }
+            identifiersByCode.put(fullSampleIdentifier.getSampleCode(), sampleIdentifier);
+        }
+        return groupedIdentifiers;
+    }
+
     private List<TechIdStringIdentifierRecord> list(SampleQuery query, SampleIdentifierParts key, Collection<String> codes)
     {
         String[] codesArray = codes.toArray(new String[codes.size()]);
         String spaceCode = key.getSpaceCodeOrNull();
+        String projectCode = key.getProjectCodeOrNull();
         String containerCode = key.getContainerCodeOrNull();
         if (spaceCode == null)
         {
@@ -114,11 +103,19 @@ public class ListSampleTechIdByIdentifier extends AbstractListTechIdById<SampleI
             }
             return query.listSharedSampleTechIdsByContainerCodeAndCodes(containerCode, codesArray);
         }
+        if (projectCode == null)
+        {
+            if (containerCode == null)
+            {
+                return query.listSpaceSampleTechIdsByCodes(spaceCode, codesArray);
+            }
+            return query.listSpaceSampleTechIdsByContainerCodeAndCodes(spaceCode, containerCode, codesArray);
+        }
         if (containerCode == null)
         {
-            return query.listSpaceSampleTechIdsByCodes(spaceCode, codesArray);
+            return query.listProjectSampleTechIdsByCodes(spaceCode, projectCode, codesArray);
         }
-        return query.listSpaceSampleTechIdsByContainerCodeAndCodes(spaceCode, containerCode, codesArray);
+        return query.listProjectSampleTechIdsByContainerCodeAndCodes(spaceCode, projectCode, containerCode, codesArray);
     }
 
 }
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/MapSampleByIdExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/MapSampleByIdExecutor.java
index 7b3cda71f60bb9007473e1f329e28b8640e08a8a..b521033dd4a5e21b82a5f9de9f6342dd8b7a4a42 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/MapSampleByIdExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/MapSampleByIdExecutor.java
@@ -29,8 +29,8 @@ import ch.ethz.sis.openbis.generic.server.api.v3.helper.sample.ListSampleByPermI
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.sample.ISampleId;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDAOFactory;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.ISampleDAO;
-import ch.systemsx.cisd.openbis.generic.server.dataaccess.ISpaceDAO;
 import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SpacePE;
 
 /**
  * @author pkupczyk
@@ -38,22 +38,19 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE;
 @Component
 public class MapSampleByIdExecutor extends AbstractMapObjectByIdExecutor<ISampleId, SamplePE> implements IMapSampleByIdExecutor
 {
-
-    private ISpaceDAO spaceDAO;
-
     private ISampleDAO sampleDAO;
 
     @Override
     protected void addListers(IOperationContext context, List<IListObjectById<? extends ISampleId, SamplePE>> listers)
     {
         listers.add(new ListSampleByPermId(sampleDAO));
-        listers.add(new ListSampleByIdentifier(spaceDAO, sampleDAO, context.getSession().tryGetHomeGroup()));
+        SpacePE space = context.getSession().tryGetHomeGroup();
+        listers.add(new ListSampleByIdentifier(sampleDAO, space));
     }
 
     @Autowired
     private void setDAOFactory(IDAOFactory daoFactory)
     {
-        spaceDAO = daoFactory.getSpaceDAO();
         sampleDAO = daoFactory.getSampleDAO();
     }
 
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/SampleIdentifierParts.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/SampleIdentifierParts.java
index 61302519b06e6ba661900518a0ddad2ac413fd82..35e1fd85e35fccd8074c66698152f8f9bdacc5b0 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/SampleIdentifierParts.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/SampleIdentifierParts.java
@@ -16,7 +16,7 @@
 
 package ch.ethz.sis.openbis.generic.server.api.v3.executor.sample;
 
-final class SampleIdentifierParts
+public final class SampleIdentifierParts
 {
     private String spaceCodeOrNull;
     private String projectCodeOrNull;
@@ -73,13 +73,6 @@ final class SampleIdentifierParts
                 + calcHashCode(containerCodeOrNull);
     }
     
-    @Override
-    public String toString()
-    {
-        // TODO Auto-generated method stub
-        return super.toString();
-    }
-
     private int calcHashCode(String str)
     {
         return str == null ? 0 : str.hashCode();
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/SampleQuery.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/SampleQuery.java
index d1e0f3727ab7bed5904d2eda5f9ea8605fffc253..034ba69d0db097e01efd3aafd17abe0c899f2e19 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/SampleQuery.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/SampleQuery.java
@@ -48,14 +48,29 @@ public interface SampleQuery extends ObjectQuery
             String[] codes);
     
     @Select(sql = "select s.id, s.code as identifier from samples s join spaces sp on s.space_id = sp.id "
-            + "where sp.code = ?{1} and samp_id_part_of is null and s.code = any(?{2})", parameterBindings =
-            { TypeMapper.class, StringArrayMapper.class }, fetchSize = FETCH_SIZE)
+            + "where sp.code = ?{1} and proj_id is null and samp_id_part_of is null and s.code = any(?{2})", 
+            parameterBindings = { TypeMapper.class, StringArrayMapper.class }, fetchSize = FETCH_SIZE)
     public List<TechIdStringIdentifierRecord> listSpaceSampleTechIdsByCodes(String spaceCode, String[] codes);
     
     @Select(sql = "select s.id, s.code as identifier from samples s join spaces sp on s.space_id = sp.id "
             + "join samples cs on s.samp_id_part_of = cs.id "
-            + "where sp.code = ?{1}  and cs.code = ?{2} and s.code = any(?{3})", parameterBindings =
+            + "where sp.code = ?{1} and proj_id is null and cs.code = ?{2} and s.code = any(?{3})", parameterBindings =
         { TypeMapper.class, TypeMapper.class, StringArrayMapper.class }, fetchSize = FETCH_SIZE)
     public List<TechIdStringIdentifierRecord> listSpaceSampleTechIdsByContainerCodeAndCodes(String spaceCode, 
             String containerCode, String[] codes);
+    
+    @Select(sql = "select s.id, s.code as identifier from samples s join spaces sp on s.space_id = sp.id "
+            + "join projects p on s.proj_id = p.id "
+            + "where sp.code = ?{1} and samp_id_part_of is null and p.code = ?{2} and s.code = any(?{3})", parameterBindings =
+        { TypeMapper.class, TypeMapper.class, StringArrayMapper.class }, fetchSize = FETCH_SIZE)
+    public List<TechIdStringIdentifierRecord> listProjectSampleTechIdsByCodes(String spaceCode, 
+            String projectCode, String[] codes);
+    
+    @Select(sql = "select s.id, s.code as identifier from samples s join spaces sp on s.space_id = sp.id "
+            + "join projects p on s.proj_id = p.id "
+            + "join samples cs on s.samp_id_part_of = cs.id "
+            + "where sp.code = ?{1} and p.code = ?{2} and cs.code = ?{3} and s.code = any(?{4})", parameterBindings =
+        { TypeMapper.class, TypeMapper.class, TypeMapper.class, StringArrayMapper.class }, fetchSize = FETCH_SIZE)
+    public List<TechIdStringIdentifierRecord> listProjectSampleTechIdsByContainerCodeAndCodes(String spaceCode, 
+            String projectCode, String containerCode, String[] codes);
 }
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/helper/sample/ListSampleByIdentifier.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/helper/sample/ListSampleByIdentifier.java
index d98f8f55342a866d73aac95c3bccb7f4f91ec262..e87fde0892b256ab083e569ccf5508372b4ad233 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/helper/sample/ListSampleByIdentifier.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/helper/sample/ListSampleByIdentifier.java
@@ -16,24 +16,14 @@
 
 package ch.ethz.sis.openbis.generic.server.api.v3.helper.sample;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
 
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.sample.ListSampleTechIdByIdentifier;
 import ch.ethz.sis.openbis.generic.server.api.v3.helper.common.AbstractListObjectById;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.sample.SampleIdentifier;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.ISampleDAO;
-import ch.systemsx.cisd.openbis.generic.server.dataaccess.ISpaceDAO;
 import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.SpacePE;
-import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifierFactory;
-import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SpaceIdentifier;
 
 /**
  * @author Franz-Josef Elmer
@@ -42,17 +32,15 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SpaceIdentifier;
 public class ListSampleByIdentifier extends AbstractListObjectById<SampleIdentifier, SamplePE>
 {
 
-    private ISpaceDAO spaceDAO;
-
     private ISampleDAO sampleDAO;
 
-    private SpacePE homeSpaceOrNull;
+    private ListSampleTechIdByIdentifier techIdByIdentifier;
 
-    public ListSampleByIdentifier(ISpaceDAO spaceDAO, ISampleDAO sampleDAO, SpacePE homeSpaceOrNull)
+    public ListSampleByIdentifier(ISampleDAO sampleDAO, SpacePE homeSpaceOrNull)
     {
-        this.spaceDAO = spaceDAO;
         this.sampleDAO = sampleDAO;
-        this.homeSpaceOrNull = homeSpaceOrNull;
+        String homeSpaceCodeOrNull = homeSpaceOrNull == null ? null : homeSpaceOrNull.getCode();
+        techIdByIdentifier = new ListSampleTechIdByIdentifier(homeSpaceCodeOrNull);
     }
 
     @Override
@@ -64,178 +52,13 @@ public class ListSampleByIdentifier extends AbstractListObjectById<SampleIdentif
     @Override
     public SampleIdentifier createId(SamplePE sample)
     {
-        return new SampleIdentifier(sample.getIdentifier());
+        return techIdByIdentifier.createId(sample.getId());
     }
 
     @Override
     public List<SamplePE> listByIds(List<SampleIdentifier> ids)
     {
-        Map<SampleIdentifier, ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier> idMap = getIdMap(ids);
-        Map<String, SpacePE> spaceMap = getSpaceMap(idMap.values());
-
-        Map<Key, List<String>> sampleCodesBySpaceAndContainer = new HashMap<ListSampleByIdentifier.Key, List<String>>();
-
-        for (SampleIdentifier id : ids)
-        {
-            ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier sid = idMap.get(id);
-
-            if (sid.isDatabaseInstanceLevel())
-            {
-                addToMap(sampleCodesBySpaceAndContainer, null, sid);
-            } else if (sid.isSpaceLevel())
-            {
-                SpaceIdentifier spaceIdentifier = sid.getSpaceLevel();
-                if (sid.isInsideHomeSpace() == false)
-                {
-                    String spaceCode = spaceIdentifier.getSpaceCode();
-                    SpacePE space = spaceMap.get(spaceCode);
-                    if (space != null)
-                    {
-                        addToMap(sampleCodesBySpaceAndContainer, space, sid);
-                    }
-                } else if (homeSpaceOrNull != null)
-                {
-                    addToMap(sampleCodesBySpaceAndContainer, homeSpaceOrNull, sid);
-                }
-            } else
-            {
-                assert false;
-            }
-        }
-        List<SamplePE> result = new ArrayList<SamplePE>();
-        Set<Entry<Key, List<String>>> entrySet = sampleCodesBySpaceAndContainer.entrySet();
-
-        for (Entry<Key, List<String>> entry : entrySet)
-        {
-            Key key = entry.getKey();
-            List<String> sampleCodes = entry.getValue();
-            SpacePE space = key.getSpace();
-            String containerId = key.getContainerId();
-            if (space == null)
-            {
-                result.addAll(sampleDAO.listByCodesAndDatabaseInstance(sampleCodes, containerId));
-            } else
-            {
-                result.addAll(sampleDAO.listByCodesAndSpace(sampleCodes, containerId, space));
-            }
-        }
-        return result;
-    }
-
-    private Map<SampleIdentifier, ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier> getIdMap(List<SampleIdentifier> ids)
-    {
-        Map<SampleIdentifier, ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier> sidMap =
-                new HashMap<SampleIdentifier, ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier>();
-
-        for (SampleIdentifier id : ids)
-        {
-            ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier sid = SampleIdentifierFactory.parse(id.getIdentifier());
-            sidMap.put(id, sid);
-        }
-
-        return sidMap;
-    }
-
-    private Map<String, SpacePE> getSpaceMap(Collection<ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier> ids)
-    {
-        Set<String> spaceCodes = new HashSet<String>();
-
-        for (ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier id : ids)
-        {
-            if (id.isSpaceLevel())
-            {
-                spaceCodes.add(id.getSpaceLevel().getSpaceCode());
-            }
-        }
-
-        if (false == spaceCodes.isEmpty())
-        {
-            List<SpacePE> spaces = spaceDAO.tryFindSpaceByCodes(new ArrayList<String>(spaceCodes));
-            Map<String, SpacePE> spaceMap = new HashMap<String, SpacePE>();
-
-            for (SpacePE space : spaces)
-            {
-                spaceMap.put(space.getCode(), space);
-            }
-
-            return spaceMap;
-        } else
-        {
-            return Collections.emptyMap();
-        }
-    }
-
-    private void addToMap(Map<Key, List<String>> sampleCodesBySpaceAndContainer, SpacePE space,
-            ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier sampleIdentifier)
-    {
-        Key key = new Key(space, sampleIdentifier.tryGetContainerCode());
-        List<String> list = sampleCodesBySpaceAndContainer.get(key);
-        if (list == null)
-        {
-            list = new ArrayList<String>();
-            sampleCodesBySpaceAndContainer.put(key, list);
-        }
-        list.add(sampleIdentifier.getSampleSubCode());
-    }
-
-    private static final class Key
-    {
-        final SpacePE space;
-
-        final String containerId;
-
-        public Key(SpacePE space, String containerId)
-        {
-            super();
-            this.space = space;
-            this.containerId = containerId;
-        }
-
-        public SpacePE getSpace()
-        {
-            return space;
-        }
-
-        public String getContainerId()
-        {
-            return containerId;
-        }
-
-        @Override
-        public int hashCode()
-        {
-            final int prime = 31;
-            int result = 1;
-            result = prime * result + ((containerId == null) ? 0 : containerId.hashCode());
-            result = prime * result + ((space == null) ? 0 : space.hashCode());
-            return result;
-        }
-
-        @Override
-        public boolean equals(Object obj)
-        {
-            if (this == obj)
-                return true;
-            if (obj == null)
-                return false;
-            if (getClass() != obj.getClass())
-                return false;
-            Key other = (Key) obj;
-            if (containerId == null)
-            {
-                if (other.containerId != null)
-                    return false;
-            } else if (!containerId.equals(other.containerId))
-                return false;
-            if (space == null)
-            {
-                if (other.space != null)
-                    return false;
-            } else if (!space.equals(other.space))
-                return false;
-            return true;
-        }
-
+        return sampleDAO.listByIDs(techIdByIdentifier.listByIds(ids));
     }
 
 }
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/FullSampleIdentifierTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/FullSampleIdentifierTest.java
index a0e592afda4732eb7dc22252ff74f0b071ab27d4..f74dfa8e1e18498a67e58d5f919f9ade3c46f727 100644
--- a/openbis/sourceTest/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/FullSampleIdentifierTest.java
+++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/FullSampleIdentifierTest.java
@@ -33,11 +33,15 @@ public class FullSampleIdentifierTest
     public void testHappyCases()
     {
         assertSampId("/S1");
+        assertSampId("/C1:S1");
         assertSampId("/SPACE1/S2");
         assertSampId("/SPACE1/S2:A02");
         assertSampId("/SPACE1/PROJECT1/S1");
         assertSampId("/SPACE1/PROJECT1/S1:A02");
-        
+        assertSampIdWithHomeSpace("/HS/S1", "//S1", "HS");
+        assertSampIdWithHomeSpace("/HS/C1:S1", "//C1:S1", "HS");
+        assertSampIdWithHomeSpace("/HS/PROJECT1/S1", "//PROJECT1/S1", "HS");
+        assertSampIdWithHomeSpace("/HS/PROJECT1/C1:S1", "//PROJECT1/C1:S1", "HS");
     }
     
     @Test
@@ -53,18 +57,30 @@ public class FullSampleIdentifierTest
         assertInvalidSampId("Sample identifier don't contain any codes: //", "//");
         assertInvalidSampId("Sample identifier don't contain any codes: /", "/");
         
-        assertInvalidSampId("Code field containing other characters than letters, numbers, '_', '-' and '.': S1&*", "/S1&*");
-        assertInvalidSampId("Code field containing other characters than letters, numbers, '_', '-' and '.': SPA&CE1", "/SPA&CE1/S2");
-        assertInvalidSampId("Code field containing other characters than letters, numbers, '_', '-' and '.': S^2", "/SPACE1/S^2:A02");
-        assertInvalidSampId("Code field containing other characters than letters, numbers, '_', '-' and '.': PRO<>JECT1", "/SPACE1/PRO<>JECT1/S1");
-        assertInvalidSampId("Code field containing other characters than letters, numbers, '_', '-' and '.': A0(2", "/SPACE1/PROJECT1/S1:A0(2");
+        assertInvalidSampId("Space code can not be an empty string.", "//S1");
+        assertInvalidSampId("Project code can not be an empty string.", "/S//S1");
+        assertInvalidSampId("Sample code starts or ends with ':': /S/:S1", "/S/:S1");
+        assertInvalidSampId("Sample code starts or ends with ':': /S/C1:", "/S/C1:");
+        assertInvalidSampId("Sample code can not contain more than one ':': /S/C1:S1:", "/S/C1:S1:");
+        
+        String prefix = " containing other characters than letters, numbers, '_', '-' and '.': ";
+        assertInvalidSampId("Sample code" + prefix + "S1&*", "/S1&*");
+        assertInvalidSampId("Space code" + prefix + "SPA&CE1", "/SPA&CE1/S2");
+        assertInvalidSampId("Container sample code" + prefix + "S^2", "/SPACE1/S^2:A02");
+        assertInvalidSampId("Project code" + prefix + "PRO<>JECT1", "/SPACE1/PRO<>JECT1/S1");
+        assertInvalidSampId("Sample subcode" + prefix + "A0(2", "/SPACE1/PROJECT1/S1:A0(2");
     }
     
     private void assertInvalidSampId(String expectedErrorMsg, String identifier)
+    {
+        assertInvalidSampId(expectedErrorMsg, identifier, null);
+    }
+    
+    private void assertInvalidSampId(String expectedErrorMsg, String identifier, String homeSpaceOrNull)
     {
         try
         {
-            new FullSampleIdentifier(identifier);
+            new FullSampleIdentifier(identifier, homeSpaceOrNull);
             fail("IllegalArgumentException expected");
         } catch (IllegalArgumentException ex)
         {
@@ -74,7 +90,12 @@ public class FullSampleIdentifierTest
     
     private void assertSampId(String identifier)
     {
-        assertEquals(new FullSampleIdentifier(identifier).toString(), identifier);
+        assertEquals(new FullSampleIdentifier(identifier, null).toString(), identifier);
+    }
+    
+    private void assertSampIdWithHomeSpace(String expectedIdentifier, String identifier, String homeSpace)
+    {
+        assertEquals(new FullSampleIdentifier(identifier, homeSpace).toString(), expectedIdentifier);
     }
 
 }
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/ProjectSampleTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/ProjectSampleTest.java
index 552841cce6494506c82ab05915c2c9cb254bbb9e..04e6bdcde47902394b08b4b934e537dbb858c189 100644
--- a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/ProjectSampleTest.java
+++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/ProjectSampleTest.java
@@ -34,7 +34,6 @@ import org.springframework.test.context.transaction.TransactionConfiguration;
 import org.springframework.transaction.annotation.Propagation;
 import org.springframework.transaction.annotation.Transactional;
 import org.testng.annotations.BeforeClass;
-import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 import ch.ethz.sis.openbis.generic.shared.api.v3.IApplicationServerApi;
@@ -48,11 +47,11 @@ import ch.ethz.sis.openbis.generic.shared.api.v3.dto.entity.space.SpaceCreation;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.fetchoptions.project.ProjectFetchOptions;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.fetchoptions.sample.SampleFetchOptions;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.entitytype.EntityTypePermId;
-import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.experiment.ExperimentPermId;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.experiment.IExperimentId;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.project.IProjectId;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.project.ProjectPermId;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.sample.ISampleId;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.sample.SampleIdentifier;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.sample.SamplePermId;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.space.ISpaceId;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.space.SpacePermId;
@@ -74,18 +73,8 @@ import ch.systemsx.cisd.openbis.systemtest.base.BaseTest;
 @Test(groups = "project-samples")
 public class ProjectSampleTest extends BaseTest
 {
-    private static final String[] SEARCH_METHODS 
-        = {"testSearchForSamplesWithProject", "testSearchForSamplesWithCodeAndWithProject"};
     private static final Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION, ProjectSampleTest.class);
     private static final EntityTypePermId ENTITY_TYPE_UNKNOWN = new EntityTypePermId("UNKNOWN");
-    private static final String TEST_USER = "test";
-    private static final String PASSWORD = "password";
-
-    private static final String SYSTEM_USER = "system";
-    private static final String NOT_EXISTING_USER = "notexistinguser";
-    private static final String TEST_SPACE_USER = "test_space";
-    private static final String TEST_POWER_USER_CISD = "test_role";
-    private static final String TEST_GROUP_OBSERVER = "observer";
     
     @Autowired
     protected IApplicationServerApi v3api;
@@ -96,11 +85,6 @@ public class ProjectSampleTest extends BaseTest
     private ProjectPermId project2inSpace1;
     private ProjectPermId project1InSpace2;
     private ProjectPermId project2InSpace2;
-    private ExperimentPermId experimentInProject1InSpace1;
-    private SamplePermId sharedSample1;
-    private SamplePermId sharedSample2;
-    private SamplePermId sample1InSpace1;
-    private SamplePermId sample2InSpace1;
     
     @BeforeClass
     public void createData()
@@ -113,13 +97,8 @@ public class ProjectSampleTest extends BaseTest
         project2inSpace1 = projects.get(1);
         project1InSpace2 = createProjects(systemSessionToken, space2, "PROJECT1").get(0);
         project2InSpace2 = createProjects(systemSessionToken, space2, "PROJECT2").get(0);
-        experimentInProject1InSpace1 = createExperiments(systemSessionToken, project1inSpace1, "EXP1").get(0);
-        List<SamplePermId> sharedSamples = createSamples(systemSessionToken, null, null, null, "SHARED1", "SHARED2");
-        sharedSample1 = sharedSamples.get(0);
-        sharedSample2 = sharedSamples.get(1);
-        List<SamplePermId> spaceSamples = createSamples(systemSessionToken, space1, null, null, "SAMPLE1", "SAMPLE2");
-        sample1InSpace1 = spaceSamples.get(0);
-        sample2InSpace1 = spaceSamples.get(1);
+        createSamples(systemSessionToken, null, null, null, "SHARED1", "SHARED2");
+        createSamples(systemSessionToken, space1, null, null, "SAMPLE1", "SAMPLE2");
         createSamples(systemSessionToken, space1, project1inSpace1, null, "SAMPLE3", "SAMPLE4");
         createSamples(systemSessionToken, space2, project2InSpace2, null, "SAMPLE5", "SAMPLE6");
         waitAtLeastASecond(); // to allow checks on modification time stamps 
@@ -131,6 +110,7 @@ public class ProjectSampleTest extends BaseTest
     @Test(enabled = false)
     public void cleanDatabase()
     {
+        // super method deletes samples, experiments and data sets from the database
     }
 
     private List<SpacePermId> createSpaces(String sessionToken, String...spaceCodes)
@@ -158,20 +138,6 @@ public class ProjectSampleTest extends BaseTest
         return v3api.createProjects(sessionToken, newProjects);
     }
     
-    private List<ExperimentPermId> createExperiments(String sessionToken, IProjectId projectId, String...experimentCodes)
-    {
-        List<ExperimentCreation> newExperiments = new ArrayList<ExperimentCreation>();
-        for (String code : experimentCodes)
-        {
-            ExperimentCreation experiment = new ExperimentCreation();
-            experiment.setTypeId(ENTITY_TYPE_UNKNOWN);
-            experiment.setProjectId(projectId);
-            experiment.setCode(code);
-            newExperiments.add(experiment);
-        }
-        return v3api.createExperiments(sessionToken, newExperiments);
-    }
-    
     private List<SamplePermId> createSamples(String sessionToken, ISpaceId spaceOrNull, 
             IProjectId projectOrNull, IExperimentId experimentOrNull, String...codes)
     {
@@ -190,9 +156,9 @@ public class ProjectSampleTest extends BaseTest
     }
     
     @Test
-    public void testCreateSampleAndMapSamples()
+    public void testCreateSampleAndMapSamplesByPermId()
     {
-        String sampleCode = createUniqueCode();
+        String sampleCode = createUniqueCode("S");
         SampleCreation sampleCreation = new SampleCreation();
         sampleCreation.setCode(sampleCode);
         sampleCreation.setTypeId(ENTITY_TYPE_UNKNOWN);
@@ -208,10 +174,11 @@ public class ProjectSampleTest extends BaseTest
         assertEquals(sample.getIdentifier().getIdentifier(), "/SPACE1/PROJECT1/" + sampleCode);
         assertEquals(sample.getProject().getIdentifier().getIdentifier(), "/SPACE1/PROJECT1");
     }
+    
     @Test
-    public void testCreateThreeSamplesWithSameCodeInDifferentProjectOfSameSpace()
+    public void testCreateThreeSamplesWithSameCodeInDifferentProjectOfSameSpaceAndMapSamplesByIdentifier()
     {
-        String sampleCode = createUniqueCode();
+        String sampleCode = createUniqueCode("S");
         SampleCreation s1 = new SampleCreation();
         s1.setCode(sampleCode);
         s1.setTypeId(ENTITY_TYPE_UNKNOWN);
@@ -227,23 +194,56 @@ public class ProjectSampleTest extends BaseTest
         s3.setTypeId(ENTITY_TYPE_UNKNOWN);
         s3.setSpaceId(space1);
         
-        List<SamplePermId> ids = v3api.createSamples(systemSessionToken, Arrays.asList(s1, s2, s3));
+        v3api.createSamples(systemSessionToken, Arrays.asList(s1, s2, s3));
         
         SampleFetchOptions fetchOptions = new SampleFetchOptions();
         fetchOptions.withProject();
+        List<ISampleId> ids = new ArrayList<>();
+        ids.add(new SampleIdentifier("/SPACE1/PROJECT1/" + sampleCode));
+        ids.add(new SampleIdentifier("/SPACE1/PROJECT2/" + sampleCode));
+        ids.add(new SampleIdentifier("/SPACE1/" + sampleCode));
         Map<ISampleId, Sample> samples = v3api.mapSamples(systemSessionToken, ids, fetchOptions);
         assertEquals(samples.get(ids.get(0)).getProject().getIdentifier().toString(), "/SPACE1/PROJECT1");
         assertEquals(samples.get(ids.get(1)).getProject().getIdentifier().toString(), "/SPACE1/PROJECT2");
         assertEquals(samples.get(ids.get(2)).getProject(), null);
     }
+    
+    @Test
+    public void testCreateProjectSampleWithComponent()
+    {
+        String sampleCode = createUniqueCode("S");
+        SampleCreation s1 = new SampleCreation();
+        s1.setCode(sampleCode);
+        s1.setTypeId(ENTITY_TYPE_UNKNOWN);
+        s1.setSpaceId(space1);
+        s1.setProjectId(project1inSpace1);
+        SamplePermId s1PermId = v3api.createSamples(systemSessionToken, Arrays.asList(s1)).get(0);
+        SampleCreation s2 = new SampleCreation();
+        s2.setCode("A01");
+        s2.setTypeId(ENTITY_TYPE_UNKNOWN);
+        s2.setSpaceId(space1);
+        s2.setProjectId(project1inSpace1);
+        s2.setContainerId(s1PermId);
+        v3api.createSamples(systemSessionToken, Arrays.asList(s2)).get(0);
+        
+        SampleFetchOptions fetchOptions = new SampleFetchOptions();
+        fetchOptions.withProject();
+        fetchOptions.withContainer();
+        List<ISampleId> ids = new ArrayList<>();
+        ids.add(new SampleIdentifier("/SPACE1/PROJECT1/" + sampleCode));
+        ids.add(new SampleIdentifier("/SPACE1/PROJECT1/" + sampleCode + ":A01"));
+        Map<ISampleId, Sample> samples = v3api.mapSamples(systemSessionToken, ids, fetchOptions);
+        assertEquals(samples.get(ids.get(0)).getProject().getIdentifier().toString(), "/SPACE1/PROJECT1");
+        assertEquals(samples.get(ids.get(1)).getProject().getIdentifier().toString(), "/SPACE1/PROJECT1");
+    }
 
     @Test
     public void testAssignSpaceSampleToAProject()
     {
-        String sampleCode = createUniqueCode();
+        String sampleCode = createUniqueCode("S");
         SamplePermId spaceSample = createSamples(systemSessionToken, space1, null, null, sampleCode).get(0);
         SampleUpdate sampleUpdate = new SampleUpdate();
-        sampleUpdate.setSampleId(spaceSample);
+        sampleUpdate.setSampleId(new SampleIdentifier("/SPACE1/" + sampleCode));
         sampleUpdate.setProjectId(project1inSpace1);
         Date now = new Date();
         
@@ -264,10 +264,10 @@ public class ProjectSampleTest extends BaseTest
     @Test
     public void testAssignProjectSampleToADifferentProjectInTheSameSpace()
     {
-        String sampleCode = createUniqueCode();
+        String sampleCode = createUniqueCode("S");
         SamplePermId spaceSample = createSamples(systemSessionToken, space1, project1inSpace1, null, sampleCode).get(0);
         SampleUpdate sampleUpdate = new SampleUpdate();
-        sampleUpdate.setSampleId(spaceSample);
+        sampleUpdate.setSampleId(new SampleIdentifier("/SPACE1/PROJECT1/" + sampleCode));
         sampleUpdate.setProjectId(project2inSpace1);
         Date now = new Date();
         
@@ -288,7 +288,7 @@ public class ProjectSampleTest extends BaseTest
     @Test
     public void testAssignProjectSampleToAProjectInADifferentSpace()
     {
-        String sampleCode = createUniqueCode();
+        String sampleCode = createUniqueCode("S");
         SamplePermId spaceSample = createSamples(systemSessionToken, space1, project1inSpace1, null, sampleCode).get(0);
         SampleUpdate sampleUpdate = new SampleUpdate();
         sampleUpdate.setSampleId(spaceSample);
@@ -313,7 +313,7 @@ public class ProjectSampleTest extends BaseTest
     @Test
     public void testUnassignProjectSampleFromProject()
     {
-        String sampleCode = createUniqueCode();
+        String sampleCode = createUniqueCode("S");
         SamplePermId spaceSample = createSamples(systemSessionToken, space1, project1inSpace1, null, sampleCode).get(0);
         SampleUpdate sampleUpdate = new SampleUpdate();
         sampleUpdate.setSampleId(spaceSample);
@@ -390,7 +390,8 @@ public class ProjectSampleTest extends BaseTest
         creation.setTypeId(ENTITY_TYPE_UNKNOWN);
         creation.setSpaceId(space1);
         creation.setProjectId(project2inSpace1);
-        creation.setExperimentId(experimentInProject1InSpace1);
+        String expCode = createUniqueCode("E");
+        creation.setExperimentId(createExperimentInProject1OfSpace1(expCode));
         
         assertUserFailureException(new IDelegatedAction()
         {
@@ -402,7 +403,7 @@ public class ProjectSampleTest extends BaseTest
         }, "Sample project must be the same as experiment project. "
                 + "Sample: /SPACE1/SAMPLE_WITH_INCONSISTENT_PROJECT_AND_EXPERIMENT, "
                 + "Project: /SPACE1/PROJECT2, "
-                + "Experiment: /SPACE1/PROJECT1/EXP1 "
+                + "Experiment: /SPACE1/PROJECT1/" + expCode + " "
                 + "(Context: [verify experiment for sample SAMPLE_WITH_INCONSISTENT_PROJECT_AND_EXPERIMENT])");
     }
     
@@ -410,8 +411,10 @@ public class ProjectSampleTest extends BaseTest
     @Transactional(propagation = Propagation.NEVER)
     public void testAssignSpaceSampleToProjectInDifferentSpace()
     {
+        String code = createUniqueCode("S");
+        ISampleId sampleId = createSamples(systemSessionToken, space1, null, null, code).get(0);
         final SampleUpdate sampleUpdate = new SampleUpdate();
-        sampleUpdate.setSampleId(sample1InSpace1);
+        sampleUpdate.setSampleId(sampleId);
         sampleUpdate.setProjectId(project2InSpace2);
 
         assertUserFailureException(new IDelegatedAction()
@@ -422,17 +425,19 @@ public class ProjectSampleTest extends BaseTest
                 v3api.updateSamples(systemSessionToken, Collections.singletonList(sampleUpdate));
             }
         }, "Sample space must be the same as project space. "
-                + "Sample: /SPACE1/SAMPLE1, "
+                + "Sample: /SPACE1/" + code + ", "
                 + "Project: /SPACE2/PROJECT2 "
-                + "(Context: [verify project for sample SAMPLE1])");
+                + "(Context: [verify project for sample " + code + "])");
     }
     
     @Test
     @Transactional(propagation = Propagation.NEVER)
     public void testAssignSampleOfAnExperimentToProjectDifferentToTheExperimentProject()
     {
-        String sampleCode = createUniqueCode();
-        SamplePermId sample = createSamples(systemSessionToken, space1, null, experimentInProject1InSpace1, sampleCode).get(0);
+        String sampleCode = createUniqueCode("S");
+        String expCode = createUniqueCode("E");
+        IExperimentId experiment = createExperimentInProject1OfSpace1(expCode);
+        SamplePermId sample = createSamples(systemSessionToken, space1, null, experiment, sampleCode).get(0);
         final SampleUpdate sampleUpdate = new SampleUpdate();
         sampleUpdate.setSampleId(sample);
         sampleUpdate.setProjectId(project2inSpace1);
@@ -447,7 +452,7 @@ public class ProjectSampleTest extends BaseTest
         }, "Sample project must be the same as experiment project. "
                 + "Sample: /SPACE1/" + sampleCode + ", "
                 + "Project: /SPACE1/PROJECT2, "
-                + "Experiment: /SPACE1/PROJECT1/EXP1 "
+                + "Experiment: /SPACE1/PROJECT1/" + expCode + " "
                 + "(Context: [verify experiment for sample " + sampleCode + "])");
         
     }
@@ -456,8 +461,10 @@ public class ProjectSampleTest extends BaseTest
     @Transactional(propagation = Propagation.NEVER)
     public void testAssignSharedSampleToProject()
     {
+        String code = createUniqueCode("S");
+        ISampleId sharedSample = createSamples(systemSessionToken, null, null, null, code).get(0);
         final SampleUpdate sampleUpdate = new SampleUpdate();
-        sampleUpdate.setSampleId(sharedSample1);
+        sampleUpdate.setSampleId(sharedSample);
         sampleUpdate.setProjectId(project1inSpace1);
         
         assertUserFailureException(new IDelegatedAction()
@@ -468,9 +475,9 @@ public class ProjectSampleTest extends BaseTest
                 v3api.updateSamples(systemSessionToken, Collections.singletonList(sampleUpdate));
             }
         }, "Shared samples cannot be attached to projects. "
-                + "Sample: /SHARED1, "
+                + "Sample: /" + code + ", "
                 + "Project: /SPACE1/PROJECT1 "
-                + "(Context: [verify project for sample SHARED1])");
+                + "(Context: [verify project for sample " + code + "])");
     }
     
     @Test(priority = -1)
@@ -583,10 +590,19 @@ public class ProjectSampleTest extends BaseTest
         assertEquals(renderedReferenceDate.compareTo(renderedActualDate) <= 0, true,
                 renderedActualDate + " > " + renderedReferenceDate);
     }
+    
+    private IExperimentId createExperimentInProject1OfSpace1(String code)
+    {
+        ExperimentCreation experiment = new ExperimentCreation();
+        experiment.setCode(code);
+        experiment.setTypeId(ENTITY_TYPE_UNKNOWN);
+        experiment.setProjectId(project1inSpace1);
+        return v3api.createExperiments(systemSessionToken, Arrays.asList(experiment)).get(0);
+    }
 
-    private String createUniqueCode()
+    private String createUniqueCode(String prefix)
     {
-        return "S-" + System.currentTimeMillis();
+        return prefix + "-" + System.currentTimeMillis();
     }
     
     private void waitAtLeastASecond()