diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/ApplicationServerApi.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/ApplicationServerApi.java
index 903afb8c4b01c634d7783713f643f672c8444100..5087462811db56906e7c7b0cc5607ac8f4770f12 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/ApplicationServerApi.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/ApplicationServerApi.java
@@ -17,7 +17,6 @@
 package ch.ethz.sis.openbis.generic.server.api.v3;
 
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 
@@ -34,22 +33,19 @@ import ch.ethz.sis.openbis.generic.server.api.v3.executor.deletion.IRevertDeleti
 import ch.ethz.sis.openbis.generic.server.api.v3.executor.experiment.ICreateExperimentExecutor;
 import ch.ethz.sis.openbis.generic.server.api.v3.executor.experiment.IDeleteExperimentExecutor;
 import ch.ethz.sis.openbis.generic.server.api.v3.executor.experiment.IMapExperimentByIdExecutor;
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.experiment.ISearchExperimentExecutor;
 import ch.ethz.sis.openbis.generic.server.api.v3.executor.experiment.IUpdateExperimentExecutor;
 import ch.ethz.sis.openbis.generic.server.api.v3.executor.sample.ICreateSampleExecutor;
 import ch.ethz.sis.openbis.generic.server.api.v3.executor.sample.IDeleteSampleExecutor;
 import ch.ethz.sis.openbis.generic.server.api.v3.executor.sample.IMapSampleByIdExecutor;
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.sample.ISearchSampleExecutor;
 import ch.ethz.sis.openbis.generic.server.api.v3.executor.sample.IUpdateSampleExecutor;
 import ch.ethz.sis.openbis.generic.server.api.v3.translator.TranslationContext;
-import ch.ethz.sis.openbis.generic.server.api.v3.translator.common.MapTranslator;
 import ch.ethz.sis.openbis.generic.server.api.v3.translator.common.IdentityTranslator;
+import ch.ethz.sis.openbis.generic.server.api.v3.translator.common.MapTranslator;
 import ch.ethz.sis.openbis.generic.server.api.v3.translator.entity.deletion.DeletionTranslator;
 import ch.ethz.sis.openbis.generic.server.api.v3.translator.entity.experiment.ExperimentTranslator;
 import ch.ethz.sis.openbis.generic.server.api.v3.translator.entity.sample.SampleTranslator;
-import ch.ethz.sis.openbis.generic.server.api.v3.translator.search.EntityAttributeProviderFactory;
-import ch.ethz.sis.openbis.generic.server.api.v3.translator.search.ISearchCriterionTranslator;
-import ch.ethz.sis.openbis.generic.server.api.v3.translator.search.SearchCriterionTranslationResult;
-import ch.ethz.sis.openbis.generic.server.api.v3.translator.search.SearchCriterionTranslatorFactory;
-import ch.ethz.sis.openbis.generic.server.api.v3.translator.search.SearchTranslationContext;
 import ch.ethz.sis.openbis.generic.server.api.v3.utils.ExceptionUtils;
 import ch.ethz.sis.openbis.generic.shared.api.v3.IApplicationServerApi;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.deletion.Deletion;
@@ -81,8 +77,6 @@ import ch.systemsx.cisd.openbis.generic.server.authorization.annotation.RolesAll
 import ch.systemsx.cisd.openbis.generic.server.business.IPropertiesBatchManager;
 import ch.systemsx.cisd.openbis.generic.server.business.IRelationshipService;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.ICommonBusinessObjectFactory;
-import ch.systemsx.cisd.openbis.generic.server.business.search.ExperimentSearchManager;
-import ch.systemsx.cisd.openbis.generic.server.business.search.SampleSearchManager;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDAOFactory;
 import ch.systemsx.cisd.openbis.generic.server.plugin.IDataSetTypeSlaveServerPlugin;
 import ch.systemsx.cisd.openbis.generic.server.plugin.ISampleTypeSlaveServerPlugin;
@@ -113,6 +107,9 @@ public class ApplicationServerApi extends AbstractServer<IApplicationServerApi>
     @Resource(name = ComponentNames.RELATIONSHIP_SERVICE)
     private IRelationshipService relationshipService;
 
+    @Autowired
+    private ISearchExperimentExecutor searchExperimentExecutor;
+
     @Autowired
     private IMapExperimentByIdExecutor mapExperimentByIdExecutor;
 
@@ -125,6 +122,9 @@ public class ApplicationServerApi extends AbstractServer<IApplicationServerApi>
     @Autowired
     private IDeleteExperimentExecutor deleteExperimentExecutor;
 
+    @Autowired
+    private ISearchSampleExecutor searchSampleExecutor;
+
     @Autowired
     private IMapSampleByIdExecutor mapSampleByIdExecutor;
 
@@ -326,23 +326,19 @@ public class ApplicationServerApi extends AbstractServer<IApplicationServerApi>
             ExperimentFetchOptions fetchOptions)
     {
         Session session = getSession(sessionToken);
+        OperationContext context = new OperationContext(session);
 
-        ISearchCriterionTranslator translator =
-                new SearchCriterionTranslatorFactory(getDAOFactory(), new EntityAttributeProviderFactory()).getTranslator(searchCriterion);
-        SearchCriterionTranslationResult translationResult = translator.translate(new SearchTranslationContext(session), searchCriterion);
-
-        ExperimentSearchManager searchManager =
-                new ExperimentSearchManager(getDAOFactory().getHibernateSearchDAO(),
-                        getBusinessObjectFactory().createExperimentTable(session));
-
-        Collection<Long> experimentIds =
-                searchManager.searchForExperimentIDs(session.getUserName(), translationResult.getCriteria());
-
-        List<ExperimentPE> experiments = getDAOFactory().getExperimentDAO().listByIDs(experimentIds);
+        try
+        {
+            List<ExperimentPE> experiments = searchExperimentExecutor.search(context, searchCriterion);
 
-        Map<ExperimentPE, Experiment> translatedMap =
-                new ExperimentTranslator(new TranslationContext(session), managedPropertyEvaluatorFactory, fetchOptions).translate(experiments);
-        return new ArrayList<Experiment>(translatedMap.values());
+            Map<ExperimentPE, Experiment> translatedMap =
+                    new ExperimentTranslator(new TranslationContext(session), managedPropertyEvaluatorFactory, fetchOptions).translate(experiments);
+            return new ArrayList<Experiment>(translatedMap.values());
+        } catch (Throwable t)
+        {
+            throw ExceptionUtils.create(context, t);
+        }
     }
 
     @Override
@@ -351,23 +347,19 @@ public class ApplicationServerApi extends AbstractServer<IApplicationServerApi>
     public List<Sample> searchSamples(String sessionToken, SampleSearchCriterion searchCriterion, SampleFetchOptions fetchOptions)
     {
         Session session = getSession(sessionToken);
+        OperationContext context = new OperationContext(session);
 
-        ISearchCriterionTranslator translator =
-                new SearchCriterionTranslatorFactory(getDAOFactory(), new EntityAttributeProviderFactory()).getTranslator(searchCriterion);
-        SearchCriterionTranslationResult translationResult = translator.translate(new SearchTranslationContext(session), searchCriterion);
-
-        SampleSearchManager searchManager =
-                new SampleSearchManager(getDAOFactory().getHibernateSearchDAO(),
-                        getBusinessObjectFactory().createSampleLister(session));
-
-        Collection<Long> sampleIds =
-                searchManager.searchForSampleIDs(session.getUserName(), translationResult.getCriteria());
-
-        List<SamplePE> samples = getDAOFactory().getSampleDAO().listByIDs(sampleIds);
+        try
+        {
+            List<SamplePE> samples = searchSampleExecutor.search(context, searchCriterion);
 
-        Map<SamplePE, Sample> translatedMap =
-                new SampleTranslator(new TranslationContext(session), managedPropertyEvaluatorFactory, fetchOptions).translate(samples);
-        return new ArrayList<Sample>(translatedMap.values());
+            Map<SamplePE, Sample> translatedMap =
+                    new SampleTranslator(new TranslationContext(session), managedPropertyEvaluatorFactory, fetchOptions).translate(samples);
+            return new ArrayList<Sample>(translatedMap.values());
+        } catch (Throwable t)
+        {
+            throw ExceptionUtils.create(context, t);
+        }
     }
 
     @Override
@@ -488,11 +480,6 @@ public class ApplicationServerApi extends AbstractServer<IApplicationServerApi>
         return new ApplicationServerApiLogger(sessionManager, context);
     }
 
-    private ICommonBusinessObjectFactory getBusinessObjectFactory()
-    {
-        return businessObjectFactory;
-    }
-
     @Override
     public int getMajorVersion()
     {
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/common/AbstractSearchObjectExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/common/AbstractSearchObjectExecutor.java
new file mode 100644
index 0000000000000000000000000000000000000000..7542408ec08afbbfd368e468bf32a1e4b1d49f5a
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/common/AbstractSearchObjectExecutor.java
@@ -0,0 +1,591 @@
+/*
+ * Copyright 2014 ETH Zuerich, Scientific IT Services
+ *
+ * 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.ethz.sis.openbis.generic.server.api.v3.executor.common;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Stack;
+
+import javax.annotation.Resource;
+
+import org.springframework.beans.factory.annotation.Autowired;
+
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.IOperationContext;
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.entity.IMapEntityTypeByIdExecutor;
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.experiment.IMapExperimentByIdExecutor;
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.project.IMapProjectByIdExecutor;
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.sample.IMapSampleByIdExecutor;
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.space.IMapSpaceByIdExecutor;
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.tag.IMapTagByIdExecutor;
+import ch.ethz.sis.openbis.generic.server.api.v3.translator.search.EntityAttributeProviderFactory;
+import ch.ethz.sis.openbis.generic.server.api.v3.translator.search.ISearchCriterionTranslator;
+import ch.ethz.sis.openbis.generic.server.api.v3.translator.search.SearchCriterionTranslationResult;
+import ch.ethz.sis.openbis.generic.server.api.v3.translator.search.SearchCriterionTranslatorFactory;
+import ch.ethz.sis.openbis.generic.server.api.v3.translator.search.SearchTranslationContext;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.entitytype.IEntityTypeId;
+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.sample.ISampleId;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.space.ISpaceId;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.tag.ITagId;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.AbstractCompositeSearchCriterion;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.AbstractObjectSearchCriterion;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.CodeSearchCriterion;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.EntityTypeSearchCriterion;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.ExperimentSearchCriterion;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.ISearchCriterion;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.IdSearchCriterion;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.PermIdSearchCriterion;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.SampleSearchCriterion;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.TagSearchCriterion;
+import ch.systemsx.cisd.openbis.generic.server.ComponentNames;
+import ch.systemsx.cisd.openbis.generic.server.business.bo.ICommonBusinessObjectFactory;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDAOFactory;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DetailedSearchCriteria;
+import ch.systemsx.cisd.openbis.generic.shared.dto.EntityTypePE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.MetaprojectPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.ProjectPE;
+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.properties.EntityKind;
+
+/**
+ * @author pkupczyk
+ */
+public abstract class AbstractSearchObjectExecutor<CRITERION extends AbstractObjectSearchCriterion<?>, OBJECT> implements
+        ISearchObjectExecutor<CRITERION, OBJECT>
+{
+
+    @Autowired
+    private IMapSpaceByIdExecutor mapSpaceByIdExecutor;
+
+    @Autowired
+    private IMapProjectByIdExecutor mapProjectByIdExecutor;
+
+    @Autowired
+    private IMapExperimentByIdExecutor mapExperimentByIdExecutor;
+
+    @Autowired
+    private IMapSampleByIdExecutor mapSampleByIdExecutor;
+
+    @Autowired
+    private IMapEntityTypeByIdExecutor mapEntityTypeByIdExecutor;
+
+    @Autowired
+    private IMapTagByIdExecutor mapTagByIdExecutor;
+
+    @Resource(name = ComponentNames.COMMON_BUSINESS_OBJECT_FACTORY)
+    protected ICommonBusinessObjectFactory businessObjectFactory;
+
+    @Autowired
+    protected IDAOFactory daoFactory;
+
+    protected abstract List<OBJECT> doSearch(IOperationContext context, DetailedSearchCriteria criteria);
+
+    @Override
+    public List<OBJECT> search(IOperationContext context, CRITERION criterion)
+    {
+        if (context == null)
+        {
+            throw new IllegalArgumentException("Context cannot be null");
+        }
+        if (criterion == null)
+        {
+            throw new IllegalArgumentException("Criterion cannot be null");
+        }
+
+        replaceCriteria(context, criterion);
+
+        ISearchCriterionTranslator translator =
+                new SearchCriterionTranslatorFactory(daoFactory, new EntityAttributeProviderFactory()).getTranslator(criterion);
+        SearchCriterionTranslationResult translationResult = translator.translate(new SearchTranslationContext(context.getSession()), criterion);
+
+        return doSearch(context, translationResult.getCriteria());
+    }
+
+    private void replaceCriteria(IOperationContext context, AbstractCompositeSearchCriterion criterion)
+    {
+        List<ICriterionReplacer> replacers = new LinkedList<ICriterionReplacer>();
+        replacers.add(new SpaceIdCriterionReplacer());
+        replacers.add(new ProjectIdCriterionReplacer());
+        replacers.add(new ExperimentIdCriterionReplacer());
+        replacers.add(new ExperimentTypeIdCriterionReplacer());
+        replacers.add(new SampleIdCriterionReplacer());
+        replacers.add(new SampleTypeIdCriterionReplacer());
+        replacers.add(new TagIdCriterionReplacer());
+
+        Map<ICriterionReplacer, Set<ISearchCriterion>> toReplaceMap = new HashMap<ICriterionReplacer, Set<ISearchCriterion>>();
+        collectCriteriaToReplace(context, new Stack<ISearchCriterion>(), criterion, replacers, toReplaceMap);
+
+        if (false == toReplaceMap.isEmpty())
+        {
+            Map<ISearchCriterion, ISearchCriterion> replacementMap = createCriteriaReplacements(context, toReplaceMap);
+            replaceCriteria(criterion, replacementMap);
+        }
+    }
+
+    private void collectCriteriaToReplace(IOperationContext context, Stack<ISearchCriterion> parentCriteria,
+            AbstractCompositeSearchCriterion criterion,
+            List<ICriterionReplacer> replacers, Map<ICriterionReplacer, Set<ISearchCriterion>> toReplaceMap)
+    {
+        parentCriteria.push(criterion);
+
+        for (ISearchCriterion subCriterion : criterion.getCriteria())
+        {
+            if (subCriterion instanceof AbstractCompositeSearchCriterion)
+            {
+                collectCriteriaToReplace(context, parentCriteria, (AbstractCompositeSearchCriterion) subCriterion, replacers, toReplaceMap);
+            } else
+            {
+                for (ICriterionReplacer replacer : replacers)
+                {
+                    if (replacer.canReplace(context, parentCriteria, subCriterion))
+                    {
+                        Set<ISearchCriterion> toReplace = toReplaceMap.get(replacer);
+                        if (toReplace == null)
+                        {
+                            toReplace = new HashSet<ISearchCriterion>();
+                            toReplaceMap.put(replacer, toReplace);
+                        }
+                        toReplace.add(subCriterion);
+                        break;
+                    }
+                }
+            }
+        }
+
+        parentCriteria.pop();
+    }
+
+    private Map<ISearchCriterion, ISearchCriterion> createCriteriaReplacements(IOperationContext context,
+            Map<ICriterionReplacer, Set<ISearchCriterion>> toReplaceMap)
+    {
+        Map<ISearchCriterion, ISearchCriterion> result = new HashMap<ISearchCriterion, ISearchCriterion>();
+
+        for (ICriterionReplacer replacer : toReplaceMap.keySet())
+        {
+            Set<ISearchCriterion> toReplace = toReplaceMap.get(replacer);
+            Map<ISearchCriterion, ISearchCriterion> replaced = replacer.replace(context, toReplace);
+            result.putAll(replaced);
+        }
+
+        return result;
+    }
+
+    private void replaceCriteria(AbstractCompositeSearchCriterion criterion, Map<ISearchCriterion, ISearchCriterion> replacementMap)
+    {
+        List<ISearchCriterion> newSubCriteria = new LinkedList<ISearchCriterion>();
+
+        for (ISearchCriterion subCriterion : criterion.getCriteria())
+        {
+            ISearchCriterion newSubCriterion = subCriterion;
+
+            if (subCriterion instanceof AbstractCompositeSearchCriterion)
+            {
+                replaceCriteria((AbstractCompositeSearchCriterion) subCriterion, replacementMap);
+            } else if (replacementMap.containsKey(subCriterion))
+            {
+                newSubCriterion = replacementMap.get(subCriterion);
+            }
+
+            newSubCriteria.add(newSubCriterion);
+        }
+
+        criterion.setCriteria(newSubCriteria);
+    }
+
+    private interface ICriterionReplacer
+    {
+
+        public boolean canReplace(IOperationContext context, Stack<ISearchCriterion> parentCriteria, ISearchCriterion criterion);
+
+        public Map<ISearchCriterion, ISearchCriterion> replace(IOperationContext context, Collection<ISearchCriterion> criteria);
+
+    }
+
+    private class SpaceIdCriterionReplacer implements ICriterionReplacer
+    {
+
+        @Override
+        public boolean canReplace(IOperationContext context, Stack<ISearchCriterion> parentCriteria, ISearchCriterion criterion)
+        {
+            if (criterion instanceof IdSearchCriterion<?>)
+            {
+                return ((IdSearchCriterion<?>) criterion).getId() instanceof ISpaceId;
+            } else
+            {
+                return false;
+            }
+        }
+
+        @Override
+        public Map<ISearchCriterion, ISearchCriterion> replace(IOperationContext context, Collection<ISearchCriterion> criteria)
+        {
+            Set<ISpaceId> spaceIds = new HashSet<ISpaceId>();
+
+            for (ISearchCriterion criterion : criteria)
+            {
+                IdSearchCriterion<?> idCriterion = (IdSearchCriterion<?>) criterion;
+                spaceIds.add((ISpaceId) idCriterion.getId());
+            }
+
+            Map<ISearchCriterion, ISearchCriterion> criterionMap = new HashMap<ISearchCriterion, ISearchCriterion>();
+            Map<ISpaceId, SpacePE> spaceMap = mapSpaceByIdExecutor.map(context, spaceIds);
+
+            for (ISearchCriterion criterion : criteria)
+            {
+                IdSearchCriterion<?> idCriterion = (IdSearchCriterion<?>) criterion;
+                SpacePE space = spaceMap.get(idCriterion.getId());
+
+                if (space == null)
+                {
+                    CodeSearchCriterion replacement = new CodeSearchCriterion();
+                    replacement.thatEquals("#");
+                    criterionMap.put(criterion, replacement);
+                } else
+                {
+                    CodeSearchCriterion replacement = new CodeSearchCriterion();
+                    replacement.thatEquals(space.getCode());
+                    criterionMap.put(criterion, replacement);
+                }
+            }
+
+            return criterionMap;
+        }
+
+    }
+
+    private class ProjectIdCriterionReplacer implements ICriterionReplacer
+    {
+
+        @Override
+        public boolean canReplace(IOperationContext context, Stack<ISearchCriterion> parentCriteria, ISearchCriterion criterion)
+        {
+            if (criterion instanceof IdSearchCriterion<?>)
+            {
+                return ((IdSearchCriterion<?>) criterion).getId() instanceof IProjectId;
+            } else
+            {
+                return false;
+            }
+        }
+
+        @Override
+        public Map<ISearchCriterion, ISearchCriterion> replace(IOperationContext context, Collection<ISearchCriterion> criteria)
+        {
+            Set<IProjectId> projectIds = new HashSet<IProjectId>();
+
+            for (ISearchCriterion criterion : criteria)
+            {
+                IdSearchCriterion<?> idCriterion = (IdSearchCriterion<?>) criterion;
+                projectIds.add((IProjectId) idCriterion.getId());
+            }
+
+            Map<ISearchCriterion, ISearchCriterion> criterionMap = new HashMap<ISearchCriterion, ISearchCriterion>();
+            Map<IProjectId, ProjectPE> projectMap = mapProjectByIdExecutor.map(context, projectIds);
+
+            for (ISearchCriterion criterion : criteria)
+            {
+                IdSearchCriterion<?> idCriterion = (IdSearchCriterion<?>) criterion;
+                ProjectPE project = projectMap.get(idCriterion.getId());
+
+                if (project == null)
+                {
+                    PermIdSearchCriterion replacement = new PermIdSearchCriterion();
+                    replacement.thatEquals("#");
+                    criterionMap.put(criterion, replacement);
+                } else
+                {
+                    PermIdSearchCriterion replacement = new PermIdSearchCriterion();
+                    replacement.thatEquals(project.getPermId());
+                    criterionMap.put(criterion, replacement);
+                }
+            }
+
+            return criterionMap;
+        }
+
+    }
+
+    private class ExperimentIdCriterionReplacer implements ICriterionReplacer
+    {
+
+        @Override
+        public boolean canReplace(IOperationContext context, Stack<ISearchCriterion> parentCriteria, ISearchCriterion criterion)
+        {
+            if (criterion instanceof IdSearchCriterion<?>)
+            {
+                return ((IdSearchCriterion<?>) criterion).getId() instanceof IExperimentId;
+            } else
+            {
+                return false;
+            }
+        }
+
+        @Override
+        public Map<ISearchCriterion, ISearchCriterion> replace(IOperationContext context, Collection<ISearchCriterion> criteria)
+        {
+            Set<IExperimentId> experimentIds = new HashSet<IExperimentId>();
+
+            for (ISearchCriterion criterion : criteria)
+            {
+                IdSearchCriterion<?> idCriterion = (IdSearchCriterion<?>) criterion;
+                experimentIds.add((IExperimentId) idCriterion.getId());
+            }
+
+            Map<ISearchCriterion, ISearchCriterion> criterionMap = new HashMap<ISearchCriterion, ISearchCriterion>();
+            Map<IExperimentId, ExperimentPE> experimentMap = mapExperimentByIdExecutor.map(context, experimentIds);
+
+            for (ISearchCriterion criterion : criteria)
+            {
+                IdSearchCriterion<?> idCriterion = (IdSearchCriterion<?>) criterion;
+                ExperimentPE experiment = experimentMap.get(idCriterion.getId());
+
+                if (experiment == null)
+                {
+                    PermIdSearchCriterion replacement = new PermIdSearchCriterion();
+                    replacement.thatEquals("#");
+                    criterionMap.put(criterion, replacement);
+                } else
+                {
+                    PermIdSearchCriterion replacement = new PermIdSearchCriterion();
+                    replacement.thatEquals(experiment.getPermId());
+                    criterionMap.put(criterion, replacement);
+                }
+            }
+
+            return criterionMap;
+        }
+
+    }
+
+    private class SampleIdCriterionReplacer implements ICriterionReplacer
+    {
+
+        @Override
+        public boolean canReplace(IOperationContext context, Stack<ISearchCriterion> parentCriteria, ISearchCriterion criterion)
+        {
+            if (criterion instanceof IdSearchCriterion<?>)
+            {
+                return ((IdSearchCriterion<?>) criterion).getId() instanceof ISampleId;
+            } else
+            {
+                return false;
+            }
+        }
+
+        @Override
+        public Map<ISearchCriterion, ISearchCriterion> replace(IOperationContext context, Collection<ISearchCriterion> criteria)
+        {
+            Set<ISampleId> sampleIds = new HashSet<ISampleId>();
+
+            for (ISearchCriterion criterion : criteria)
+            {
+                IdSearchCriterion<?> idCriterion = (IdSearchCriterion<?>) criterion;
+                sampleIds.add((ISampleId) idCriterion.getId());
+            }
+
+            Map<ISearchCriterion, ISearchCriterion> criterionMap = new HashMap<ISearchCriterion, ISearchCriterion>();
+            Map<ISampleId, SamplePE> sampleMap = mapSampleByIdExecutor.map(context, sampleIds);
+
+            for (ISearchCriterion criterion : criteria)
+            {
+                IdSearchCriterion<?> idCriterion = (IdSearchCriterion<?>) criterion;
+                SamplePE sample = sampleMap.get(idCriterion.getId());
+
+                if (sample == null)
+                {
+                    PermIdSearchCriterion replacement = new PermIdSearchCriterion();
+                    replacement.thatEquals("#");
+                    criterionMap.put(criterion, replacement);
+                } else
+                {
+                    PermIdSearchCriterion replacement = new PermIdSearchCriterion();
+                    replacement.thatEquals(sample.getPermId());
+                    criterionMap.put(criterion, replacement);
+                }
+            }
+
+            return criterionMap;
+        }
+
+    }
+
+    private class ExperimentTypeIdCriterionReplacer implements ICriterionReplacer
+    {
+
+        @Override
+        public boolean canReplace(IOperationContext context, Stack<ISearchCriterion> parentCriteria, ISearchCriterion criterion)
+        {
+            Stack<ISearchCriterion> parentCriteriaCopy = new Stack<ISearchCriterion>();
+            parentCriteriaCopy.addAll(parentCriteria);
+
+            ISearchCriterion parentCriterion = parentCriteriaCopy.isEmpty() ? null : parentCriteriaCopy.pop();
+            ISearchCriterion grandParentCriterion = parentCriteriaCopy.isEmpty() ? null : parentCriteriaCopy.pop();
+
+            return criterion instanceof IdSearchCriterion<?> && parentCriterion instanceof EntityTypeSearchCriterion
+                    && grandParentCriterion instanceof ExperimentSearchCriterion;
+        }
+
+        @Override
+        public Map<ISearchCriterion, ISearchCriterion> replace(IOperationContext context, Collection<ISearchCriterion> criteria)
+        {
+            Set<IEntityTypeId> typeIds = new HashSet<IEntityTypeId>();
+
+            for (ISearchCriterion criterion : criteria)
+            {
+                IdSearchCriterion<?> idCriterion = (IdSearchCriterion<?>) criterion;
+                typeIds.add((IEntityTypeId) idCriterion.getId());
+            }
+
+            Map<ISearchCriterion, ISearchCriterion> criterionMap = new HashMap<ISearchCriterion, ISearchCriterion>();
+            Map<IEntityTypeId, EntityTypePE> typeMap = mapEntityTypeByIdExecutor.map(context, EntityKind.EXPERIMENT, typeIds);
+
+            for (ISearchCriterion criterion : criteria)
+            {
+                IdSearchCriterion<?> idCriterion = (IdSearchCriterion<?>) criterion;
+                EntityTypePE type = typeMap.get(idCriterion.getId());
+
+                if (type == null)
+                {
+                    CodeSearchCriterion replacement = new CodeSearchCriterion();
+                    replacement.thatEquals("#");
+                    criterionMap.put(criterion, replacement);
+                } else
+                {
+                    CodeSearchCriterion replacement = new CodeSearchCriterion();
+                    replacement.thatEquals(type.getCode());
+                    criterionMap.put(criterion, replacement);
+                }
+            }
+
+            return criterionMap;
+        }
+
+    }
+
+    private class SampleTypeIdCriterionReplacer implements ICriterionReplacer
+    {
+
+        @Override
+        public boolean canReplace(IOperationContext context, Stack<ISearchCriterion> parentCriteria, ISearchCriterion criterion)
+        {
+            Stack<ISearchCriterion> parentCriteriaCopy = new Stack<ISearchCriterion>();
+            parentCriteriaCopy.addAll(parentCriteria);
+
+            ISearchCriterion parentCriterion = parentCriteriaCopy.isEmpty() ? null : parentCriteriaCopy.pop();
+            ISearchCriterion grandParentCriterion = parentCriteriaCopy.isEmpty() ? null : parentCriteriaCopy.pop();
+
+            return criterion instanceof IdSearchCriterion<?> && parentCriterion instanceof EntityTypeSearchCriterion
+                    && grandParentCriterion instanceof SampleSearchCriterion;
+        }
+
+        @Override
+        public Map<ISearchCriterion, ISearchCriterion> replace(IOperationContext context, Collection<ISearchCriterion> criteria)
+        {
+            Set<IEntityTypeId> typeIds = new HashSet<IEntityTypeId>();
+
+            for (ISearchCriterion criterion : criteria)
+            {
+                IdSearchCriterion<?> idCriterion = (IdSearchCriterion<?>) criterion;
+                typeIds.add((IEntityTypeId) idCriterion.getId());
+            }
+
+            Map<ISearchCriterion, ISearchCriterion> criterionMap = new HashMap<ISearchCriterion, ISearchCriterion>();
+            Map<IEntityTypeId, EntityTypePE> typeMap = mapEntityTypeByIdExecutor.map(context, EntityKind.SAMPLE, typeIds);
+
+            for (ISearchCriterion criterion : criteria)
+            {
+                IdSearchCriterion<?> idCriterion = (IdSearchCriterion<?>) criterion;
+                EntityTypePE type = typeMap.get(idCriterion.getId());
+
+                if (type == null)
+                {
+                    CodeSearchCriterion replacement = new CodeSearchCriterion();
+                    replacement.thatEquals("#");
+                    criterionMap.put(criterion, replacement);
+                } else
+                {
+                    CodeSearchCriterion replacement = new CodeSearchCriterion();
+                    replacement.thatEquals(type.getCode());
+                    criterionMap.put(criterion, replacement);
+                }
+            }
+
+            return criterionMap;
+        }
+
+    }
+
+    private class TagIdCriterionReplacer implements ICriterionReplacer
+    {
+
+        @Override
+        public boolean canReplace(IOperationContext context, Stack<ISearchCriterion> parentCriteria, ISearchCriterion criterion)
+        {
+            Stack<ISearchCriterion> parentCriteriaCopy = new Stack<ISearchCriterion>();
+            parentCriteriaCopy.addAll(parentCriteria);
+
+            ISearchCriterion parentCriterion = parentCriteriaCopy.isEmpty() ? null : parentCriteriaCopy.pop();
+
+            return criterion instanceof IdSearchCriterion<?> && parentCriterion instanceof TagSearchCriterion;
+        }
+
+        @Override
+        public Map<ISearchCriterion, ISearchCriterion> replace(IOperationContext context, Collection<ISearchCriterion> criteria)
+        {
+            Set<ITagId> tagIds = new HashSet<ITagId>();
+
+            for (ISearchCriterion criterion : criteria)
+            {
+                IdSearchCriterion<?> idCriterion = (IdSearchCriterion<?>) criterion;
+                tagIds.add((ITagId) idCriterion.getId());
+            }
+
+            Map<ISearchCriterion, ISearchCriterion> criterionMap = new HashMap<ISearchCriterion, ISearchCriterion>();
+            Map<ITagId, MetaprojectPE> tagMap = mapTagByIdExecutor.map(context, tagIds);
+
+            for (ISearchCriterion criterion : criteria)
+            {
+                IdSearchCriterion<?> idCriterion = (IdSearchCriterion<?>) criterion;
+                MetaprojectPE tag = tagMap.get(idCriterion.getId());
+
+                if (tag == null)
+                {
+                    CodeSearchCriterion replacement = new CodeSearchCriterion();
+                    replacement.thatEquals("#");
+                    criterionMap.put(criterion, replacement);
+                } else
+                {
+                    CodeSearchCriterion replacement = new CodeSearchCriterion();
+                    replacement.thatEquals(tag.getName());
+                    criterionMap.put(criterion, replacement);
+                }
+            }
+
+            return criterionMap;
+        }
+
+    }
+
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/common/ISearchObjectExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/common/ISearchObjectExecutor.java
new file mode 100644
index 0000000000000000000000000000000000000000..65a987f53c19ae1a5bed7b0ab832c7777aa7bb4f
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/common/ISearchObjectExecutor.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2014 ETH Zuerich, Scientific IT Services
+ *
+ * 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.ethz.sis.openbis.generic.server.api.v3.executor.common;
+
+import java.util.List;
+
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.IOperationContext;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.AbstractObjectSearchCriterion;
+
+/**
+ * @author pkupczyk
+ */
+public interface ISearchObjectExecutor<CRITERION extends AbstractObjectSearchCriterion<?>, OBJECT>
+{
+
+    public List<OBJECT> search(IOperationContext context, CRITERION criterion);
+
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/experiment/ISearchExperimentExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/experiment/ISearchExperimentExecutor.java
new file mode 100644
index 0000000000000000000000000000000000000000..d9bd108dbaeba270bfe5599450207708103703ac
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/experiment/ISearchExperimentExecutor.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2014 ETH Zuerich, Scientific IT Services
+ *
+ * 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.ethz.sis.openbis.generic.server.api.v3.executor.experiment;
+
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.common.ISearchObjectExecutor;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.ExperimentSearchCriterion;
+import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentPE;
+
+/**
+ * @author pkupczyk
+ */
+public interface ISearchExperimentExecutor extends ISearchObjectExecutor<ExperimentSearchCriterion, ExperimentPE>
+{
+
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/experiment/SearchExperimentExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/experiment/SearchExperimentExecutor.java
new file mode 100644
index 0000000000000000000000000000000000000000..9f74200065a6e0ad5897bc910eac5e0cd44c2226
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/experiment/SearchExperimentExecutor.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2014 ETH Zuerich, Scientific IT Services
+ *
+ * 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.ethz.sis.openbis.generic.server.api.v3.executor.experiment;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.springframework.stereotype.Component;
+
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.IOperationContext;
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.common.AbstractSearchObjectExecutor;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.ExperimentSearchCriterion;
+import ch.systemsx.cisd.openbis.generic.server.business.search.ExperimentSearchManager;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DetailedSearchCriteria;
+import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentPE;
+
+/**
+ * @author pkupczyk
+ */
+@Component
+public class SearchExperimentExecutor extends AbstractSearchObjectExecutor<ExperimentSearchCriterion, ExperimentPE> implements
+        ISearchExperimentExecutor
+{
+
+    @Override
+    protected List<ExperimentPE> doSearch(IOperationContext context, DetailedSearchCriteria criteria)
+    {
+        ExperimentSearchManager searchManager =
+                new ExperimentSearchManager(daoFactory.getHibernateSearchDAO(),
+                        businessObjectFactory.createExperimentTable(context.getSession()));
+
+        Collection<Long> experimentIds =
+                searchManager.searchForExperimentIDs(context.getSession().getUserName(), criteria);
+
+        return daoFactory.getExperimentDAO().listByIDs(experimentIds);
+    }
+
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/ISearchSampleExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/ISearchSampleExecutor.java
new file mode 100644
index 0000000000000000000000000000000000000000..a997aa9ac58d667a3c6d1dcf7ed9ccf05f356976
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/ISearchSampleExecutor.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2014 ETH Zuerich, Scientific IT Services
+ *
+ * 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.ethz.sis.openbis.generic.server.api.v3.executor.sample;
+
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.common.ISearchObjectExecutor;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.SampleSearchCriterion;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE;
+
+/**
+ * @author pkupczyk
+ */
+public interface ISearchSampleExecutor extends ISearchObjectExecutor<SampleSearchCriterion, SamplePE>
+{
+
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/SearchSampleExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/SearchSampleExecutor.java
new file mode 100644
index 0000000000000000000000000000000000000000..a2fe5b91e0f2b174087694b86c3d77e9fbd0987a
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/SearchSampleExecutor.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2014 ETH Zuerich, Scientific IT Services
+ *
+ * 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.ethz.sis.openbis.generic.server.api.v3.executor.sample;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.springframework.stereotype.Component;
+
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.IOperationContext;
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.common.AbstractSearchObjectExecutor;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.SampleSearchCriterion;
+import ch.systemsx.cisd.openbis.generic.server.business.search.SampleSearchManager;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DetailedSearchCriteria;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE;
+
+/**
+ * @author pkupczyk
+ */
+@Component
+public class SearchSampleExecutor extends AbstractSearchObjectExecutor<SampleSearchCriterion, SamplePE> implements ISearchSampleExecutor
+{
+
+    @Override
+    protected List<SamplePE> doSearch(IOperationContext context, DetailedSearchCriteria criteria)
+    {
+        SampleSearchManager searchManager =
+                new SampleSearchManager(daoFactory.getHibernateSearchDAO(), businessObjectFactory.createSampleLister(context.getSession()));
+
+        Collection<Long> sampleIds =
+                searchManager.searchForSampleIDs(context.getSession().getUserName(), criteria);
+
+        return daoFactory.getSampleDAO().listByIDs(sampleIds);
+    }
+
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/AddTagToEntityExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/AddTagToEntityExecutor.java
index a82a831896f3d25091b817a4668da32b53fdb467..bdfbfa3ac5d082ef252ef5d34a1d427e486d1229 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/AddTagToEntityExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/AddTagToEntityExecutor.java
@@ -35,7 +35,7 @@ public class AddTagToEntityExecutor implements IAddTagToEntityExecutor
 {
 
     @Autowired
-    private IGetTagMapExecutor getTagMapExecutor;
+    private IMapTagByIdExecutor mapTagByIdExecutor;
 
     @Autowired
     private ICreateTagExecutor createTagExecutor;
@@ -45,9 +45,9 @@ public class AddTagToEntityExecutor implements IAddTagToEntityExecutor
     {
     }
 
-    public AddTagToEntityExecutor(IGetTagMapExecutor getTagMapExecutor, ICreateTagExecutor createTagExecutor)
+    public AddTagToEntityExecutor(IMapTagByIdExecutor mapTagByIdExecutor, ICreateTagExecutor createTagExecutor)
     {
-        this.getTagMapExecutor = getTagMapExecutor;
+        this.mapTagByIdExecutor = mapTagByIdExecutor;
         this.createTagExecutor = createTagExecutor;
     }
 
@@ -59,7 +59,7 @@ public class AddTagToEntityExecutor implements IAddTagToEntityExecutor
             return;
         }
 
-        Map<ITagId, MetaprojectPE> tagMap = getTagMapExecutor.getTagMap(context, tagIds);
+        Map<ITagId, MetaprojectPE> tagMap = mapTagByIdExecutor.map(context, tagIds);
 
         for (ITagId tagId : tagIds)
         {
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/CreateTagExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/CreateTagExecutor.java
index 6c56d85ba1e33fac4075356e6b5e1174fafccf2d..ec924385c8f948b6df13192262c8c52e70427934 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/CreateTagExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/CreateTagExecutor.java
@@ -37,24 +37,24 @@ public class CreateTagExecutor implements ICreateTagExecutor
     private IDAOFactory daoFactory;
 
     @Autowired
-    private IGetTagNameExecutor getTagNameExecutor;
+    private IGetTagCodeExecutor getTagCodeExecutor;
 
     @SuppressWarnings("unused")
     private CreateTagExecutor()
     {
     }
 
-    public CreateTagExecutor(IDAOFactory daoFactory, IGetTagNameExecutor getTagNameExecutor)
+    public CreateTagExecutor(IDAOFactory daoFactory, IGetTagCodeExecutor getTagCodeExecutor)
     {
         this.daoFactory = daoFactory;
-        this.getTagNameExecutor = getTagNameExecutor;
+        this.getTagCodeExecutor = getTagCodeExecutor;
     }
 
     @Override
     public MetaprojectPE createTag(IOperationContext context, ITagId tagId)
     {
         MetaprojectPE tag = new MetaprojectPE();
-        tag.setName(getTagNameExecutor.getTagName(context, tagId));
+        tag.setName(getTagCodeExecutor.getTagCode(context, tagId));
         tag.setOwner(context.getSession().tryGetPerson());
         tag.setCreationDate(new Date());
         daoFactory.getMetaprojectDAO().createOrUpdateMetaproject(tag, context.getSession().tryGetPerson());
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/GetTagNameExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/GetTagCodeExecutor.java
similarity index 86%
rename from openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/GetTagNameExecutor.java
rename to openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/GetTagCodeExecutor.java
index 03532fab2df89761af4851658a7febd12f145dea..f21ed2ac3d255b2f941879f9b869f6a47db59be4 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/GetTagNameExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/GetTagCodeExecutor.java
@@ -20,7 +20,7 @@ import org.springframework.stereotype.Component;
 
 import ch.ethz.sis.openbis.generic.server.api.v3.executor.IOperationContext;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.tag.ITagId;
-import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.tag.TagNameId;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.tag.TagCodeId;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.tag.TagPermId;
 import ch.ethz.sis.openbis.generic.shared.api.v3.exceptions.UnauthorizedObjectAccessException;
 import ch.systemsx.cisd.common.exceptions.NotImplementedException;
@@ -30,19 +30,19 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.MetaprojectIdentifier;
  * @author pkupczyk
  */
 @Component
-public class GetTagNameExecutor implements IGetTagNameExecutor
+public class GetTagCodeExecutor implements IGetTagCodeExecutor
 {
 
-    public GetTagNameExecutor()
+    public GetTagCodeExecutor()
     {
     }
 
     @Override
-    public String getTagName(IOperationContext context, ITagId tagId)
+    public String getTagCode(IOperationContext context, ITagId tagId)
     {
-        if (tagId instanceof TagNameId)
+        if (tagId instanceof TagCodeId)
         {
-            return ((TagNameId) tagId).getName();
+            return ((TagCodeId) tagId).getCode();
         }
         if (tagId instanceof TagPermId)
         {
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/IGetTagNameExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/IGetTagCodeExecutor.java
similarity index 89%
rename from openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/IGetTagNameExecutor.java
rename to openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/IGetTagCodeExecutor.java
index 32a6150962e4c669fa7d03c4495ac46bce4b942e..0de25ef008a8b53af3f10efd836b42e76773e26d 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/IGetTagNameExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/IGetTagCodeExecutor.java
@@ -22,9 +22,9 @@ import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.tag.ITagId;
 /**
  * @author pkupczyk
  */
-public interface IGetTagNameExecutor
+public interface IGetTagCodeExecutor
 {
 
-    public String getTagName(IOperationContext context, ITagId tagId);
+    public String getTagCode(IOperationContext context, ITagId tagId);
 
 }
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/IGetTagMapExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/IMapTagByIdExecutor.java
similarity index 74%
rename from openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/IGetTagMapExecutor.java
rename to openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/IMapTagByIdExecutor.java
index d45ef71915528e37a9144a8c6c01a99ba1b38005..4ce7b3ff9db89716bc632b49f4c1105b683f3f0e 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/IGetTagMapExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/IMapTagByIdExecutor.java
@@ -16,19 +16,14 @@
 
 package ch.ethz.sis.openbis.generic.server.api.v3.executor.tag;
 
-import java.util.Collection;
-import java.util.Map;
-
-import ch.ethz.sis.openbis.generic.server.api.v3.executor.IOperationContext;
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.common.IMapObjectByIdExecutor;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.tag.ITagId;
 import ch.systemsx.cisd.openbis.generic.shared.dto.MetaprojectPE;
 
 /**
  * @author pkupczyk
  */
-public interface IGetTagMapExecutor
+public interface IMapTagByIdExecutor extends IMapObjectByIdExecutor<ITagId, MetaprojectPE>
 {
 
-    public Map<ITagId, MetaprojectPE> getTagMap(IOperationContext context, Collection<? extends ITagId> tagIds);
-
 }
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/GetTagMapExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/MapTagByIdExecutor.java
similarity index 78%
rename from openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/GetTagMapExecutor.java
rename to openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/MapTagByIdExecutor.java
index 1d80330634956a4dca50ddf62c5b4b5b3b95d52b..7d9e979fb5aa3eddfb1a370c46bbf1042254f314 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/GetTagMapExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/MapTagByIdExecutor.java
@@ -32,28 +32,28 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.MetaprojectPE;
  * @author pkupczyk
  */
 @Component
-public class GetTagMapExecutor implements IGetTagMapExecutor
+public class MapTagByIdExecutor implements IMapTagByIdExecutor
 {
 
     @Autowired
     private IDAOFactory daoFactory;
 
     @Autowired
-    private IGetTagNameExecutor getTagNameExecutor;
+    private IGetTagCodeExecutor getTagCodeExecutor;
 
     @SuppressWarnings("unused")
-    private GetTagMapExecutor()
+    private MapTagByIdExecutor()
     {
     }
 
-    public GetTagMapExecutor(IDAOFactory daoFactory, IGetTagNameExecutor getTagNameExecutor)
+    public MapTagByIdExecutor(IDAOFactory daoFactory, IGetTagCodeExecutor getTagCodeExecutor)
     {
         this.daoFactory = daoFactory;
-        this.getTagNameExecutor = getTagNameExecutor;
+        this.getTagCodeExecutor = getTagCodeExecutor;
     }
 
     @Override
-    public Map<ITagId, MetaprojectPE> getTagMap(IOperationContext context, Collection<? extends ITagId> tagIds)
+    public Map<ITagId, MetaprojectPE> map(IOperationContext context, Collection<? extends ITagId> tagIds)
     {
         Map<ITagId, MetaprojectPE> map = new HashMap<ITagId, MetaprojectPE>();
 
@@ -61,10 +61,10 @@ public class GetTagMapExecutor implements IGetTagMapExecutor
         {
             for (ITagId tagId : tagIds)
             {
-                String name = getTagNameExecutor.getTagName(context, tagId);
+                String code = getTagCodeExecutor.getTagCode(context, tagId);
                 MetaprojectPE tag =
                         daoFactory.getMetaprojectDAO()
-                                .tryFindByOwnerAndName(context.getSession().tryGetPerson().getUserId(), name);
+                                .tryFindByOwnerAndName(context.getSession().tryGetPerson().getUserId(), code);
                 if (tag != null)
                 {
                     map.put(tagId, tag);
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/RemoveTagFromEntityExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/RemoveTagFromEntityExecutor.java
index 896976275162ccb5196347f66981cd1432b7e49a..0ba4ac938ea8168774f59989a94794013172c21c 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/RemoveTagFromEntityExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/RemoveTagFromEntityExecutor.java
@@ -35,22 +35,22 @@ public class RemoveTagFromEntityExecutor implements IRemoveTagFromEntityExecutor
 {
 
     @Autowired
-    private IGetTagMapExecutor getTagMapExecutor;
+    private IMapTagByIdExecutor mapTagByIdExecutor;
 
     @SuppressWarnings("unused")
     private RemoveTagFromEntityExecutor()
     {
     }
 
-    public RemoveTagFromEntityExecutor(IGetTagMapExecutor getTagMapExecutor)
+    public RemoveTagFromEntityExecutor(IMapTagByIdExecutor mapTagByIdExecutor)
     {
-        this.getTagMapExecutor = getTagMapExecutor;
+        this.mapTagByIdExecutor = mapTagByIdExecutor;
     }
 
     @Override
     public void removeTag(IOperationContext context, IEntityWithMetaprojects entity, Collection<? extends ITagId> tagIds)
     {
-        Map<ITagId, MetaprojectPE> tagMap = getTagMapExecutor.getTagMap(context, tagIds);
+        Map<ITagId, MetaprojectPE> tagMap = mapTagByIdExecutor.map(context, tagIds);
 
         for (MetaprojectPE tag : tagMap.values())
         {
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/SetTagForEntityExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/SetTagForEntityExecutor.java
index f6e4baf17e1106c710a9331cb10a511eef518c1a..5854cbed1435864122dd26011f2b527e1d383280 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/SetTagForEntityExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/SetTagForEntityExecutor.java
@@ -37,7 +37,7 @@ public class SetTagForEntityExecutor implements ISetTagForEntityExecutor
 {
 
     @Autowired
-    private IGetTagMapExecutor getTagMapExecutor;
+    private IMapTagByIdExecutor mapTagByIdExecutor;
 
     @Autowired
     private ICreateTagExecutor createTagExecutor;
@@ -47,16 +47,16 @@ public class SetTagForEntityExecutor implements ISetTagForEntityExecutor
     {
     }
 
-    public SetTagForEntityExecutor(IGetTagMapExecutor getTagMapExecutor, ICreateTagExecutor createTagExecutor)
+    public SetTagForEntityExecutor(IMapTagByIdExecutor mapTagByIdExecutor, ICreateTagExecutor createTagExecutor)
     {
-        this.getTagMapExecutor = getTagMapExecutor;
+        this.mapTagByIdExecutor = mapTagByIdExecutor;
         this.createTagExecutor = createTagExecutor;
     }
 
     @Override
     public void setTags(IOperationContext context, IEntityWithMetaprojects entity, Collection<? extends ITagId> tagIds)
     {
-        Map<ITagId, MetaprojectPE> tagMap = getTagMapExecutor.getTagMap(context, tagIds);
+        Map<ITagId, MetaprojectPE> tagMap = mapTagByIdExecutor.map(context, tagIds);
         Set<MetaprojectPE> tags = new HashSet<MetaprojectPE>(tagMap.values());
 
         for (MetaprojectPE existingTag : entity.getMetaprojects())
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/translator/entity/tag/TagTranslator.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/translator/entity/tag/TagTranslator.java
index 6e15712d6541355056a846da4f2f8250ad7de06a..a36bd82bdf09c80b512c06b2e351919e37f1896c 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/translator/entity/tag/TagTranslator.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/translator/entity/tag/TagTranslator.java
@@ -49,7 +49,7 @@ public class TagTranslator extends AbstractCachingTranslator<MetaprojectPE, Tag,
         Tag result = new Tag();
 
         result.setPermId(new TagPermId(tag.getIdentifier()));
-        result.setName(tag.getName());
+        result.setCode(tag.getName());
         result.setDescription(tag.getDescription());
         result.setPrivate(tag.isPrivate());
         result.setRegistrationDate(tag.getCreationDate());
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/translator/search/AbstractCompositeSearchCriterionTranslator.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/translator/search/AbstractCompositeSearchCriterionTranslator.java
index 2fe623bbe727f848f6fe12c51360b128ff66c58c..3dced12c5a04793220e2fe2767e133bda4f0ceab 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/translator/search/AbstractCompositeSearchCriterionTranslator.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/translator/search/AbstractCompositeSearchCriterionTranslator.java
@@ -55,7 +55,7 @@ public abstract class AbstractCompositeSearchCriterionTranslator extends Abstrac
 
         if (criterion instanceof AbstractEntitySearchCriterion)
         {
-            detailedSearchCriteria.setConnection(translateOperator(((AbstractEntitySearchCriterion) compositeCriterion).getOperator()));
+            detailedSearchCriteria.setConnection(translateOperator(((AbstractEntitySearchCriterion<?>) compositeCriterion).getOperator()));
         }
 
         List<DetailedSearchCriterion> detailedCriterionList = new ArrayList<DetailedSearchCriterion>();
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/translator/search/ProjectSearchCriterionTranslator.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/translator/search/ProjectSearchCriterionTranslator.java
index 4c10d892c20f848530eb44d5279579f5d8634950..7c77fdd36f69de242dda044532bce2cdd51f2b54 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/translator/search/ProjectSearchCriterionTranslator.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/translator/search/ProjectSearchCriterionTranslator.java
@@ -18,6 +18,7 @@ package ch.ethz.sis.openbis.generic.server.api.v3.translator.search;
 
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.CodeSearchCriterion;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.ISearchCriterion;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.PermIdSearchCriterion;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.ProjectSearchCriterion;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.SpaceSearchCriterion;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDAOFactory;
@@ -60,6 +61,9 @@ public class ProjectSearchCriterionTranslator extends AbstractFieldFromComposite
         if (subCriterion instanceof CodeSearchCriterion)
         {
             return DetailedSearchField.createAttributeField(ExperimentAttributeSearchFieldKind.PROJECT);
+        } else if (subCriterion instanceof PermIdSearchCriterion)
+        {
+            return DetailedSearchField.createAttributeField(ExperimentAttributeSearchFieldKind.PROJECT_PERM_ID);
         } else if (subCriterion instanceof SpaceSearchCriterion)
         {
             return DetailedSearchField.createAttributeField(ExperimentAttributeSearchFieldKind.PROJECT_SPACE);
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/SearchCriteriaToDetailedSearchCriteriaTranslator.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/SearchCriteriaToDetailedSearchCriteriaTranslator.java
index fcc2fccc7935f3e4477275485db5428421f71313..33bab57d4da3bbefffd2a484d8cc7a2d9a81c5a5 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/SearchCriteriaToDetailedSearchCriteriaTranslator.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/SearchCriteriaToDetailedSearchCriteriaTranslator.java
@@ -50,8 +50,8 @@ import ch.systemsx.cisd.openbis.generic.shared.translator.DtoConverters;
 /**
  * Converts {@link SearchCriteria} objects to {@link DetailedSearchCriteria} objects.
  * <p>
- * Clients of this class need to provide a translator from {@link MatchClauseAttribute} to
- * {@link IAttributeSearchFieldKind} appropriate to the entity they are searching for.
+ * Clients of this class need to provide a translator from {@link MatchClauseAttribute} to {@link IAttributeSearchFieldKind} appropriate to the entity
+ * they are searching for.
  * 
  * @author Chandrasekhar Ramakrishnan
  */
@@ -136,8 +136,7 @@ public class SearchCriteriaToDetailedSearchCriteriaTranslator
     private final DetailedSearchCriteria newDetailedSearchCriteria;
 
     /**
-     * Interface for a translator from {@link MatchClauseAttribute} to
-     * {@link IAttributeSearchFieldKind}.
+     * Interface for a translator from {@link MatchClauseAttribute} to {@link IAttributeSearchFieldKind}.
      * 
      * @author Chandrasekhar Ramakrishnan
      */
@@ -227,6 +226,9 @@ public class SearchCriteriaToDetailedSearchCriteriaTranslator
                 case PROJECT:
                     ans = ExperimentAttributeSearchFieldKind.PROJECT;
                     break;
+                case PROJECT_PERM_ID:
+                    ans = ExperimentAttributeSearchFieldKind.PROJECT_PERM_ID;
+                    break;
                 case METAPROJECT:
                     ans = ExperimentAttributeSearchFieldKind.METAPROJECT;
                     break;
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/detailed/IndexFieldNameHelper.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/detailed/IndexFieldNameHelper.java
index 09587831d27baa9770ee1e549fea01aed9eca2f3..a8496b1a09e8b04a49f7de8b9490aae13dd19aaa 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/detailed/IndexFieldNameHelper.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/search/detailed/IndexFieldNameHelper.java
@@ -17,6 +17,7 @@
 package ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.detailed;
 
 import static ch.systemsx.cisd.openbis.generic.shared.dto.hibernate.SearchFieldConstants.CODE;
+import static ch.systemsx.cisd.openbis.generic.shared.dto.hibernate.SearchFieldConstants.PERM_ID;
 
 import ch.systemsx.cisd.common.exceptions.InternalErr;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.AssociatedEntityKind;
@@ -154,6 +155,8 @@ class IndexFieldNameHelper
                 return SearchFieldConstants.PERM_ID;
             case PROJECT:
                 return SearchFieldConstants.PREFIX_PROJECT + CODE;
+            case PROJECT_PERM_ID:
+                return SearchFieldConstants.PREFIX_PROJECT + PERM_ID;
             case PROJECT_SPACE:
                 return SearchFieldConstants.PREFIX_PROJECT + SearchFieldConstants.PREFIX_SPACE
                         + CODE;
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/ExperimentAttributeSearchFieldKind.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/ExperimentAttributeSearchFieldKind.java
index 7861c131dc6ac93ad3264408674428ce8c31bb42..49e8065a40e5ce600a2075009d950c01e467fb24 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/ExperimentAttributeSearchFieldKind.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/ExperimentAttributeSearchFieldKind.java
@@ -33,6 +33,8 @@ public enum ExperimentAttributeSearchFieldKind implements Serializable, IAttribu
 
     PROJECT("Project"),
 
+    PROJECT_PERM_ID("Project Perm Id"),
+
     PROJECT_SPACE("Space"),
 
     METAPROJECT("Metaproject"),
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/generic/server/api/v3/AbstractApplicationServerApiTestCase.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/generic/server/api/v3/AbstractApplicationServerApiTestCase.java
index 23cb6b87f50bc495786267250cc1c506cff36d43..c218a5791f9d41d4beaa64225203130e20a22435 100644
--- a/openbis/sourceTest/java/ch/ethz/sis/openbis/generic/server/api/v3/AbstractApplicationServerApiTestCase.java
+++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/generic/server/api/v3/AbstractApplicationServerApiTestCase.java
@@ -259,12 +259,12 @@ public abstract class AbstractApplicationServerApiTestCase extends AbstractServe
             });
     }
 
-    protected void prepareFindTag(final String userId, final String tagName, final MetaprojectPE tag)
+    protected void prepareFindTag(final String userId, final String tagCode, final MetaprojectPE tag)
     {
         context.checking(new Expectations()
             {
                 {
-                    allowing(metaprojectDAO).tryFindByOwnerAndName(userId, tagName);
+                    allowing(metaprojectDAO).tryFindByOwnerAndName(userId, tagCode);
                     will(returnValue(tag));
                 }
             });
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/generic/server/api/v3/ExperimentServerApiTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/generic/server/api/v3/ExperimentServerApiTest.java
index 67a1a6fcdd4c173a20698dbdce5b911234ef3694..a6134eb8ba0e821577da236c00319e8396aef6f5 100644
--- a/openbis/sourceTest/java/ch/ethz/sis/openbis/generic/server/api/v3/ExperimentServerApiTest.java
+++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/generic/server/api/v3/ExperimentServerApiTest.java
@@ -32,7 +32,7 @@ import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.experiment.ExperimentPer
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.project.ProjectIdentifier;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.project.ProjectPermId;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.tag.ITagId;
-import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.tag.TagNameId;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.tag.TagCodeId;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.tag.TagPermId;
 import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.common.test.RecordingMatcher;
@@ -56,9 +56,9 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.properties.EntityKind;
  */
 public class ExperimentServerApiTest extends AbstractApplicationServerApiTestCase
 {
-    private static final TagNameId TAG_NAME_ID = new TagNameId("red");
+    private static final TagCodeId TAG_CODE_ID = new TagCodeId("red");
 
-    private static final TagNameId UNKNOWN_TAG_NAME_ID = new TagNameId("unknown");
+    private static final TagCodeId UNKNOWN_TAG_CODE_ID = new TagCodeId("unknown");
 
     private static final String UNKNOWN_PROJECT_CODE = "UNKNOWN";
 
@@ -97,11 +97,11 @@ public class ExperimentServerApiTest extends AbstractApplicationServerApiTestCas
         dataType.setCode(DataTypeCode.VARCHAR);
         propertyType1.setType(dataType);
         tag = new MetaprojectPE();
-        tag.setName(TAG_NAME_ID.getName());
+        tag.setName(TAG_CODE_ID.getCode());
         tag.setOwner(person);
     }
 
-    @Test(enabled=false)
+    @Test(enabled = false)
     public void testCreateExperimentWithUnspecifiedType()
     {
         prepareCreationEnvironment();
@@ -114,7 +114,7 @@ public class ExperimentServerApiTest extends AbstractApplicationServerApiTestCas
         context.assertIsSatisfied();
     }
 
-    @Test(enabled=false)
+    @Test(enabled = false)
     public void testCreateExperimentWithUnknownType()
     {
         prepareCreationEnvironment();
@@ -128,7 +128,7 @@ public class ExperimentServerApiTest extends AbstractApplicationServerApiTestCas
         context.assertIsSatisfied();
     }
 
-    @Test(enabled=false)
+    @Test(enabled = false)
     public void testCreateExperimentWithUnspecifiedProject()
     {
         prepareCreationEnvironment();
@@ -141,7 +141,7 @@ public class ExperimentServerApiTest extends AbstractApplicationServerApiTestCas
         context.assertIsSatisfied();
     }
 
-    @Test(enabled=false)
+    @Test(enabled = false)
     public void testCreateExperimentWithUnknownProjectIdentifier()
     {
         prepareCreationEnvironment();
@@ -155,7 +155,7 @@ public class ExperimentServerApiTest extends AbstractApplicationServerApiTestCas
         context.assertIsSatisfied();
     }
 
-    @Test(enabled=false)
+    @Test(enabled = false)
     public void testCreateExperimentWithUnknownProjectPermId()
     {
         prepareCreationEnvironment();
@@ -169,7 +169,7 @@ public class ExperimentServerApiTest extends AbstractApplicationServerApiTestCas
         context.assertIsSatisfied();
     }
 
-    @Test(enabled=false)
+    @Test(enabled = false)
     public void testCreateExperimentWithTagIdOfWrongOwner()
     {
         prepareCreationEnvironment();
@@ -183,7 +183,7 @@ public class ExperimentServerApiTest extends AbstractApplicationServerApiTestCas
         context.assertIsSatisfied();
     }
 
-    @Test(enabled=false)
+    @Test(enabled = false)
     public void testCreateExperimentWithAttachmentWithUnspecifiedFileName()
     {
         prepareCreationEnvironment();
@@ -196,7 +196,7 @@ public class ExperimentServerApiTest extends AbstractApplicationServerApiTestCas
         context.assertIsSatisfied();
     }
 
-    @Test(enabled=false)
+    @Test(enabled = false)
     public void testCreateExperimentWithAttachmentWithUnspecifiedContent()
     {
         prepareCreationEnvironment();
@@ -212,7 +212,7 @@ public class ExperimentServerApiTest extends AbstractApplicationServerApiTestCas
         context.assertIsSatisfied();
     }
 
-    @Test(enabled=false)
+    @Test(enabled = false)
     public void testCreateExperimentWithNoTagsAndAttachmentsSuccessfully()
     {
         RecordingMatcherRepository recorderRepository = prepareCreationEnvironment();
@@ -242,12 +242,12 @@ public class ExperimentServerApiTest extends AbstractApplicationServerApiTestCas
         context.assertIsSatisfied();
     }
 
-    @Test(enabled=false)
+    @Test(enabled = false)
     public void testCreateExperimentWithTagAndAttachmentSuccessfully()
     {
         RecordingMatcherRepository recorderRepository = prepareCreationEnvironment();
         ExperimentCreation experiment = experiment("EXP1");
-        experiment.setTagIds(Arrays.<ITagId> asList(TAG_NAME_ID));
+        experiment.setTagIds(Arrays.<ITagId> asList(TAG_CODE_ID));
         AttachmentCreation attachment = new AttachmentCreation();
         attachment.setFileName("manual.pdf");
         attachment.setTitle("Manual");
@@ -327,8 +327,8 @@ public class ExperimentServerApiTest extends AbstractApplicationServerApiTestCas
         prepareFindProject(SPACE_CODE, PROJECT_CODE, project);
         prepareFindProject(SPACE_CODE, UNKNOWN_PROJECT_CODE, null);
         prepareFindProject(UNKNOWN_PROJECT_PERM_ID.getPermId(), null);
-        prepareFindTag(session.getUserName(), TAG_NAME_ID.getName(), tag);
-        prepareFindTag(session.getUserName(), UNKNOWN_TAG_NAME_ID.getName(), null);
+        prepareFindTag(session.getUserName(), TAG_CODE_ID.getCode(), tag);
+        prepareFindTag(session.getUserName(), UNKNOWN_TAG_CODE_ID.getCode(), null);
         RecordingMatcherRepository repository = new RecordingMatcherRepository();
         prepareCreateAttachment(repository);
         final RecordingMatcher<ExperimentPE> experimentRecoder =
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/generic/server/api/v3/SampleServerApiTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/generic/server/api/v3/SampleServerApiTest.java
index ed704ef05ee2ad1003cd8b6c12e7357c21a689cd..05e845dc7824befdc2deb82910244f9accb6b00c 100644
--- a/openbis/sourceTest/java/ch/ethz/sis/openbis/generic/server/api/v3/SampleServerApiTest.java
+++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/generic/server/api/v3/SampleServerApiTest.java
@@ -33,7 +33,7 @@ import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.entitytype.EntityTypePer
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.experiment.ExperimentPermId;
 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.SpacePermId;
-import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.tag.TagNameId;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.tag.TagCodeId;
 import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.common.test.RecordingMatcher;
 import ch.systemsx.cisd.common.test.RecordingMatcherRepository;
@@ -62,9 +62,9 @@ public class SampleServerApiTest extends AbstractApplicationServerApiTestCase
 
     private static final String UNKNOWN_ENTITY_TYPE = "UNKNOWN_ENTITY_TYPE";
 
-    private static final TagNameId TAG_NAME_ID = new TagNameId("TAG_NAME_ID");
+    private static final TagCodeId TAG_CODE_ID = new TagCodeId("TAG_NAME_ID");
 
-    private static final TagNameId UNKNOWN_TAG_NAME_ID = new TagNameId("UNKNOWN_TAG_NAME_ID");
+    private static final TagCodeId UNKNOWN_TAG_CODE_ID = new TagCodeId("UNKNOWN_TAG_NAME_ID");
 
     private static final ExperimentPermId UNKNOWN_EXPERIMENT_ID = new ExperimentPermId("UNKNOWN_EXPERIMENT_ID");
 
@@ -306,8 +306,8 @@ public class SampleServerApiTest extends AbstractApplicationServerApiTestCase
 
         prepareFindPropertyTypeByCode(PROPERTY_TYPE_CODE, propertyType1);
 
-        prepareFindTag(session.getUserName(), TAG_NAME_ID.getName(), tag);
-        prepareFindTag(session.getUserName(), UNKNOWN_TAG_NAME_ID.getName(), null);
+        prepareFindTag(session.getUserName(), TAG_CODE_ID.getCode(), tag);
+        prepareFindTag(session.getUserName(), UNKNOWN_TAG_CODE_ID.getCode(), null);
 
         prepareFindExperiment(UNKNOWN_EXPERIMENT_ID.getPermId(), null);
         prepareFindExperiment(EXPERIMENT_ID.getPermId(), experiment);
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/GetTagNameExecutorTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/GetTagCodeExecutorTest.java
similarity index 81%
rename from openbis/sourceTest/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/GetTagNameExecutorTest.java
rename to openbis/sourceTest/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/GetTagCodeExecutorTest.java
index be93ab69bff80047448bda4bfce49542bd966b70..cfa59e2c7feda677cba11db2819d0e31142f6a5e 100644
--- a/openbis/sourceTest/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/GetTagNameExecutorTest.java
+++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/GetTagCodeExecutorTest.java
@@ -23,7 +23,7 @@ import org.testng.annotations.Test;
 
 import ch.ethz.sis.openbis.generic.server.api.v3.executor.AbstractExecutorTest;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.tag.ITagId;
-import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.tag.TagNameId;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.tag.TagCodeId;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.tag.TagPermId;
 import ch.ethz.sis.openbis.generic.shared.api.v3.exceptions.UnauthorizedObjectAccessException;
 import ch.systemsx.cisd.openbis.generic.shared.dto.Session;
@@ -31,7 +31,7 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.Session;
 /**
  * @author pkupczyk
  */
-public class GetTagNameExecutorTest extends AbstractExecutorTest
+public class GetTagCodeExecutorTest extends AbstractExecutorTest
 {
 
     @Test
@@ -48,8 +48,8 @@ public class GetTagNameExecutorTest extends AbstractExecutorTest
                 }
             });
 
-        String name = execute(new TagPermId("/" + session.tryGetPerson().getUserId() + "/TEST_PERM_ID"));
-        Assert.assertEquals("TEST_PERM_ID", name);
+        String code = execute(new TagPermId("/" + session.tryGetPerson().getUserId() + "/TEST_PERM_ID"));
+        Assert.assertEquals("TEST_PERM_ID", code);
     }
 
     @Test(expectedExceptions = { UnauthorizedObjectAccessException.class }, expectedExceptionsMessageRegExp = ".*/OTHER_USER/TEST_PERM_ID.*")
@@ -72,14 +72,14 @@ public class GetTagNameExecutorTest extends AbstractExecutorTest
     @Test
     public void testWithNameId()
     {
-        String name = execute(new TagNameId("TEST_NAME_ID"));
-        Assert.assertEquals("TEST_NAME_ID", name);
+        String code = execute(new TagCodeId("TEST_NAME_ID"));
+        Assert.assertEquals("TEST_NAME_ID", code);
     }
 
     private String execute(ITagId tagId)
     {
-        GetTagNameExecutor executor = new GetTagNameExecutor();
-        return executor.getTagName(operationContext, tagId);
+        GetTagCodeExecutor executor = new GetTagCodeExecutor();
+        return executor.getTagCode(operationContext, tagId);
     }
 
 }
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/GetTagMapExecutorTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/MapTagByIdExecutorTest.java
similarity index 83%
rename from openbis/sourceTest/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/GetTagMapExecutorTest.java
rename to openbis/sourceTest/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/MapTagByIdExecutorTest.java
index a23d2ab30275684e61e0c996cf42efdf8e4f08a9..6595495922131f054e3ac03e1f86c1d07daf0e9a 100644
--- a/openbis/sourceTest/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/GetTagMapExecutorTest.java
+++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/tag/MapTagByIdExecutorTest.java
@@ -27,10 +27,10 @@ import org.jmock.Expectations;
 import org.testng.annotations.Test;
 
 import ch.ethz.sis.openbis.generic.server.api.v3.executor.AbstractExecutorTest;
-import ch.ethz.sis.openbis.generic.server.api.v3.executor.tag.GetTagMapExecutor;
-import ch.ethz.sis.openbis.generic.server.api.v3.executor.tag.IGetTagNameExecutor;
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.tag.MapTagByIdExecutor;
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.tag.IGetTagCodeExecutor;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.tag.ITagId;
-import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.tag.TagNameId;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.tag.TagCodeId;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.tag.TagPermId;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IMetaprojectDAO;
 import ch.systemsx.cisd.openbis.generic.shared.dto.MetaprojectPE;
@@ -39,17 +39,17 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.Session;
 /**
  * @author pkupczyk
  */
-public class GetTagMapExecutorTest extends AbstractExecutorTest
+public class MapTagByIdExecutorTest extends AbstractExecutorTest
 {
 
     private IMetaprojectDAO metaprojectDao;
 
-    private IGetTagNameExecutor getTagNameExecutor;
+    private IGetTagCodeExecutor getTagCodeExecutor;
 
     @Override
     protected void init()
     {
-        getTagNameExecutor = context.mock(IGetTagNameExecutor.class);
+        getTagCodeExecutor = context.mock(IGetTagCodeExecutor.class);
         metaprojectDao = context.mock(IMetaprojectDAO.class);
     }
 
@@ -72,7 +72,7 @@ public class GetTagMapExecutorTest extends AbstractExecutorTest
     {
         final Session session = createSession();
 
-        final ITagId tagId1 = new TagNameId("TEST_TAG_1");
+        final ITagId tagId1 = new TagCodeId("TEST_TAG_1");
         final ITagId tagId2 = new TagPermId("/TEST_USER/TEST_TAG_2");
         final ITagId tagId3 = new TagPermId("/OTHER_USER/TEST_TAG_3");
 
@@ -97,13 +97,13 @@ public class GetTagMapExecutorTest extends AbstractExecutorTest
                     allowing(daoFactory).getMetaprojectDAO();
                     will(returnValue(metaprojectDao));
 
-                    one(getTagNameExecutor).getTagName(operationContext, tagId1);
+                    one(getTagCodeExecutor).getTagCode(operationContext, tagId1);
                     will(returnValue("TEST_TAG_1"));
 
-                    one(getTagNameExecutor).getTagName(operationContext, tagId2);
+                    one(getTagCodeExecutor).getTagCode(operationContext, tagId2);
                     will(returnValue("TEST_TAG_2"));
 
-                    one(getTagNameExecutor).getTagName(operationContext, tagId3);
+                    one(getTagCodeExecutor).getTagCode(operationContext, tagId3);
                     will(returnValue("TEST_TAG_3"));
 
                     one(metaprojectDao).tryFindByOwnerAndName("TEST_PERSON", "TEST_TAG_1");
@@ -126,8 +126,8 @@ public class GetTagMapExecutorTest extends AbstractExecutorTest
 
     private Map<ITagId, MetaprojectPE> execute(Collection<? extends ITagId> tagIds)
     {
-        GetTagMapExecutor executor = new GetTagMapExecutor(daoFactory, getTagNameExecutor);
-        return executor.getTagMap(operationContext, tagIds);
+        MapTagByIdExecutor executor = new MapTagByIdExecutor(daoFactory, getTagCodeExecutor);
+        return executor.map(operationContext, tagIds);
     }
 
 }
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/AbstractSampleTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/AbstractSampleTest.java
index 4ffd96719d46e450ad437ac7c16cd6a04d6c65b1..d229227bd6c41a1b7ecc4022ee1724bf17c8b7ff 100644
--- a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/AbstractSampleTest.java
+++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/AbstractSampleTest.java
@@ -51,14 +51,14 @@ public class AbstractSampleTest extends AbstractTest
         assertCollectionContainsOnly(actualSet, expectedIdentifiers);
     }
 
-    protected static void assertTags(Collection<Tag> tags, String... expectedTagNames)
+    protected static void assertTags(Collection<Tag> tags, String... expectedTagCodes)
     {
-        Set<String> tagNames = new HashSet<String>();
+        Set<String> tagCodes = new HashSet<String>();
         for (Tag tag : tags)
         {
-            tagNames.add(tag.getName());
+            tagCodes.add(tag.getCode());
         }
-        assertCollectionContainsOnly(tagNames, expectedTagNames);
+        assertCollectionContainsOnly(tagCodes, expectedTagCodes);
     }
 
 }
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/CreateExperimentTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/CreateExperimentTest.java
index 3029412f540c4dfd0f1240a74940ae700c3cd955..cd16cfd32b34c1f0dc157e706fb0f92897ecda1d 100644
--- a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/CreateExperimentTest.java
+++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/CreateExperimentTest.java
@@ -248,7 +248,7 @@ public class CreateExperimentTest extends AbstractExperimentTest
 
         Tag tag = experiment.getTags().iterator().next();
 
-        assertEquals(tag.getName(), "TEST_METAPROJECTS");
+        assertEquals(tag.getCode(), "TEST_METAPROJECTS");
         assertEquals(tag.getPermId().getPermId(), "/test/TEST_METAPROJECTS");
         assertTrue(tag.getRegistrationDate().getTime() < now.getTime());
     }
@@ -282,7 +282,7 @@ public class CreateExperimentTest extends AbstractExperimentTest
 
         Tag tag = experiment.getTags().iterator().next();
 
-        assertEquals(tag.getName(), "NEW_TAG_THAT_SHOULD_BE_CREATED");
+        assertEquals(tag.getCode(), "NEW_TAG_THAT_SHOULD_BE_CREATED");
         assertEquals(tag.getPermId().getPermId(), "/test/NEW_TAG_THAT_SHOULD_BE_CREATED");
         // there can be a 1 second rounding when converting database date to java date
         assertTrue(tag.getRegistrationDate().getTime() + 1000 >= now.getTime());
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/SearchExperimentTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/SearchExperimentTest.java
index c00f2d6d43dd9a49bd0e1f950def6eec53ef1115..2cbfec707bfaf3cf3439c31d38f2d8f8ee87798a 100644
--- a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/SearchExperimentTest.java
+++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/SearchExperimentTest.java
@@ -24,6 +24,12 @@ import org.testng.annotations.Test;
 
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.entity.experiment.Experiment;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.fetchoptions.experiment.ExperimentFetchOptions;
+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.ExperimentIdentifier;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.experiment.ExperimentPermId;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.project.ProjectIdentifier;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.project.ProjectPermId;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.space.SpacePermId;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.ExperimentSearchCriterion;
 
 /**
@@ -32,6 +38,22 @@ import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.ExperimentSearchCrit
 public class SearchExperimentTest extends AbstractExperimentTest
 {
 
+    @Test
+    public void testSearchWithIdSetToIdentifier()
+    {
+        ExperimentSearchCriterion criterion = new ExperimentSearchCriterion();
+        criterion.withId().thatEquals(new ExperimentIdentifier("/CISD/NEMO/EXP1"));
+        testSearch(TEST_USER, criterion, "/CISD/NEMO/EXP1");
+    }
+
+    @Test
+    public void testSearchWithIdSetToPermId()
+    {
+        ExperimentSearchCriterion criterion = new ExperimentSearchCriterion();
+        criterion.withId().thatEquals(new ExperimentPermId("200811050951882-1028"));
+        testSearch(TEST_USER, criterion, "/CISD/NEMO/EXP1");
+    }
+
     @Test
     public void testSearchWithPermId()
     {
@@ -48,6 +70,14 @@ public class SearchExperimentTest extends AbstractExperimentTest
         testSearch(TEST_USER, criterion, "/CISD/NEMO/EXP1", "/CISD/NEMO/EXP10", "/CISD/NEMO/EXP11");
     }
 
+    @Test
+    public void testSearchWithTypeWithIdSetToPermId()
+    {
+        ExperimentSearchCriterion criterion = new ExperimentSearchCriterion();
+        criterion.withType().withId().thatEquals(new EntityTypePermId("COMPOUND_HCS"));
+        testSearch(TEST_USER, criterion, "/CISD/NEMO/EXP-TEST-1", "/CISD/NOE/EXP-TEST-2");
+    }
+
     @Test
     public void testSearchWithTypeWithCode()
     {
@@ -56,6 +86,30 @@ public class SearchExperimentTest extends AbstractExperimentTest
         testSearch(TEST_USER, criterion, "/CISD/NEMO/EXP-TEST-1", "/CISD/NOE/EXP-TEST-2");
     }
 
+    @Test
+    public void testSearchWithProjectWithIdSetToIdentifier()
+    {
+        ExperimentSearchCriterion criterion = new ExperimentSearchCriterion();
+        criterion.withProject().withId().thatEquals(new ProjectIdentifier("/TEST-SPACE/NOE"));
+        testSearch(TEST_USER, criterion, "/TEST-SPACE/NOE/EXP-TEST-2", "/TEST-SPACE/NOE/EXPERIMENT-TO-DELETE");
+    }
+
+    @Test
+    public void testSearchWithProjectWithIdSetToPermId()
+    {
+        ExperimentSearchCriterion criterion = new ExperimentSearchCriterion();
+        criterion.withProject().withId().thatEquals(new ProjectPermId("20120814110011738-106"));
+        testSearch(TEST_USER, criterion, "/TEST-SPACE/NOE/EXP-TEST-2", "/TEST-SPACE/NOE/EXPERIMENT-TO-DELETE");
+    }
+
+    @Test
+    public void testSearchWithProjectWithPermId()
+    {
+        ExperimentSearchCriterion criterion = new ExperimentSearchCriterion();
+        criterion.withProject().withPermId().thatEquals("20120814110011738-106");
+        testSearch(TEST_USER, criterion, "/TEST-SPACE/NOE/EXP-TEST-2", "/TEST-SPACE/NOE/EXPERIMENT-TO-DELETE");
+    }
+
     @Test
     public void testSearchWithProjectWithCode()
     {
@@ -64,6 +118,15 @@ public class SearchExperimentTest extends AbstractExperimentTest
         testSearch(TEST_USER, criterion, "/CISD/NOE/EXP-TEST-2", "/TEST-SPACE/NOE/EXP-TEST-2", "/TEST-SPACE/NOE/EXPERIMENT-TO-DELETE");
     }
 
+    @Test
+    public void testSearchWithProjectWithSpaceWithIdSetToPermId()
+    {
+        ExperimentSearchCriterion criterion = new ExperimentSearchCriterion();
+        criterion.withProject().withSpace().withId().thatEquals(new SpacePermId("TEST-SPACE"));
+        testSearch(TEST_USER, criterion, "/TEST-SPACE/TEST-PROJECT/EXP-SPACE-TEST", "/TEST-SPACE/NOE/EXP-TEST-2",
+                "/TEST-SPACE/NOE/EXPERIMENT-TO-DELETE");
+    }
+
     @Test
     public void testSearchWithProjectWithSpaceWithCode()
     {
@@ -199,7 +262,7 @@ public class SearchExperimentTest extends AbstractExperimentTest
     }
 
     @Test
-    public void testSearchWithUnauthorizedSpace()
+    public void testSearchWithSpaceUnauthorized()
     {
         ExperimentSearchCriterion criterion = new ExperimentSearchCriterion();
         criterion.withPermId().thatEquals("200811050951882-1028");
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/SearchSampleTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/SearchSampleTest.java
index b0250dd199e62036202aa4faf2b31b2128c0ff8e..80c584da70e4be4c78541555d1464229bce1b62f 100644
--- a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/SearchSampleTest.java
+++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/SearchSampleTest.java
@@ -24,6 +24,16 @@ import org.testng.annotations.Test;
 
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.entity.sample.Sample;
 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.ExperimentIdentifier;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.experiment.ExperimentPermId;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.project.ProjectIdentifier;
+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.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.SpacePermId;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.tag.TagCodeId;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.tag.TagPermId;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.SampleSearchCriterion;
 
 /**
@@ -32,6 +42,32 @@ import ch.ethz.sis.openbis.generic.shared.api.v3.dto.search.SampleSearchCriterio
 public class SearchSampleTest extends AbstractSampleTest
 {
 
+    @Test
+    public void testSearchWithIdSetToIdentifier()
+    {
+        SampleSearchCriterion criterion = new SampleSearchCriterion();
+        criterion.withId().thatEquals(new SampleIdentifier("/CISD/CP-TEST-1"));
+        testSearch(TEST_USER, criterion, "/CISD/CP-TEST-1");
+    }
+
+    @Test
+    public void testSearchWithIdSetToPermId()
+    {
+        SampleSearchCriterion criterion = new SampleSearchCriterion();
+        criterion.withId().thatEquals(new SamplePermId("200902091219327-1025"));
+        testSearch(TEST_USER, criterion, "/CISD/CP-TEST-1");
+    }
+
+    @Test
+    public void testSearchWithMultipleIds()
+    {
+        SampleSearchCriterion criterion = new SampleSearchCriterion();
+        criterion.withOrOperator();
+        criterion.withId().thatEquals(new SampleIdentifier("/CISD/CP-TEST-1"));
+        criterion.withId().thatEquals(new SamplePermId("200902091250077-1026"));
+        testSearch(TEST_USER, criterion, "/CISD/CP-TEST-1", "/CISD/CP-TEST-2");
+    }
+
     @Test
     public void testSearchWithPermId()
     {
@@ -48,6 +84,46 @@ public class SearchSampleTest extends AbstractSampleTest
         testSearch(TEST_USER, criterion, "/CISD/RP1-A2X");
     }
 
+    @Test
+    public void testSearchWithSpaceWithIdSetToPermId()
+    {
+        SampleSearchCriterion criterion = new SampleSearchCriterion();
+        criterion.withSpace().withId().thatEquals(new SpacePermId("TEST-SPACE"));
+        testSearch(TEST_USER, criterion, 8);
+    }
+
+    @Test
+    public void testSearchWithSpaceWithCode()
+    {
+        SampleSearchCriterion criterion = new SampleSearchCriterion();
+        criterion.withSpace().withCode().thatEquals("TEST-SPACE");
+        testSearch(TEST_USER, criterion, 8);
+    }
+
+    @Test
+    public void testSearchWithSpaceWithPermId()
+    {
+        SampleSearchCriterion criterion = new SampleSearchCriterion();
+        criterion.withSpace().withPermId().thatEquals("TEST-SPACE");
+        testSearch(TEST_USER, criterion, 8);
+
+        criterion = new SampleSearchCriterion();
+        criterion.withSpace().withPermId().thatEquals("/TEST-SPACE");
+        testSearch(TEST_USER, criterion, 8);
+    }
+
+    @Test
+    public void testSearchWithSpaceUnauthorized()
+    {
+        SampleSearchCriterion criterion = new SampleSearchCriterion();
+        criterion.withPermId().thatEquals("200902091219327-1025");
+        testSearch(TEST_USER, criterion, 1);
+
+        criterion = new SampleSearchCriterion();
+        criterion.withPermId().thatEquals("200902091219327-1025");
+        testSearch(TEST_SPACE_USER, criterion, 0);
+    }
+
     @Test
     public void testSearchWithCodeInContainer()
     {
@@ -56,6 +132,14 @@ public class SearchSampleTest extends AbstractSampleTest
         testSearch(TEST_USER, criterion, "/CISD/PLATE_WELLSEARCH:WELL-A01");
     }
 
+    @Test
+    public void testSearchWithTypeIdSetToPermId()
+    {
+        SampleSearchCriterion criterion = new SampleSearchCriterion();
+        criterion.withType().withId().thatEquals(new EntityTypePermId("REINFECT_PLATE"));
+        testSearch(TEST_USER, criterion, "/CISD/RP1-A2X", "/CISD/RP1-B1X", "/CISD/RP2-A1X");
+    }
+
     @Test
     public void testSearchWithTypeWithCode()
     {
@@ -64,6 +148,30 @@ public class SearchSampleTest extends AbstractSampleTest
         testSearch(TEST_USER, criterion, "/CISD/RP1-A2X", "/CISD/RP1-B1X", "/CISD/RP2-A1X");
     }
 
+    @Test
+    public void testSearchWithTypeWithPermId()
+    {
+        SampleSearchCriterion criterion = new SampleSearchCriterion();
+        criterion.withType().withPermId().thatEquals("REINFECT_PLATE");
+        testSearch(TEST_USER, criterion, "/CISD/RP1-A2X", "/CISD/RP1-B1X", "/CISD/RP2-A1X");
+    }
+
+    @Test
+    public void testSearchWithExperimentWithIdSetToIdentifier()
+    {
+        SampleSearchCriterion criterion = new SampleSearchCriterion();
+        criterion.withExperiment().withId().thatEquals(new ExperimentIdentifier("/CISD/NEMO/EXP10"));
+        testSearch(TEST_USER, criterion, "/CISD/3VCP5");
+    }
+
+    @Test
+    public void testSearchWithExperimentWithIdSetToPermId()
+    {
+        SampleSearchCriterion criterion = new SampleSearchCriterion();
+        criterion.withExperiment().withId().thatEquals(new ExperimentPermId("200811050952663-1029"));
+        testSearch(TEST_USER, criterion, "/CISD/3VCP5");
+    }
+
     @Test
     public void testSearchWithExperimentWithPermId()
     {
@@ -80,6 +188,14 @@ public class SearchSampleTest extends AbstractSampleTest
         testSearch(TEST_USER, criterion, "/CISD/CP-TEST-1", "/CISD/DYNA-TEST-1");
     }
 
+    @Test
+    public void testSearchWithExperimentWithTypeIdSetToPermId()
+    {
+        SampleSearchCriterion criterion = new SampleSearchCriterion();
+        criterion.withExperiment().withType().withId().thatEquals(new EntityTypePermId("COMPOUND_HCS"));
+        testSearch(TEST_USER, criterion, "/CISD/CP-TEST-1", "/CISD/CP-TEST-2", "/CISD/DYNA-TEST-1");
+    }
+
     @Test
     public void testSearchWithExperimentWithTypeWithCode()
     {
@@ -88,6 +204,94 @@ public class SearchSampleTest extends AbstractSampleTest
         testSearch(TEST_USER, criterion, "/CISD/CP-TEST-1", "/CISD/CP-TEST-2", "/CISD/DYNA-TEST-1");
     }
 
+    @Test
+    public void testSearchWithExperimentWithTypeWithPermId()
+    {
+        SampleSearchCriterion criterion = new SampleSearchCriterion();
+        criterion.withExperiment().withType().withPermId().thatEquals("COMPOUND_HCS");
+        testSearch(TEST_USER, criterion, "/CISD/CP-TEST-1", "/CISD/CP-TEST-2", "/CISD/DYNA-TEST-1");
+    }
+
+    @Test
+    public void testSearchWithExperimentWithProjectWithIdSetToIdentifier()
+    {
+        SampleSearchCriterion criterion = new SampleSearchCriterion();
+        criterion.withExperiment().withProject().withId().thatEquals(new ProjectIdentifier("/TEST-SPACE/NOE"));
+        testSearch(TEST_USER, criterion, "/TEST-SPACE/CP-TEST-4");
+    }
+
+    @Test
+    public void testSearchWithExperimentWithProjectWithIdSetToPermId()
+    {
+        SampleSearchCriterion criterion = new SampleSearchCriterion();
+        criterion.withExperiment().withProject().withId().thatEquals(new ProjectPermId("20120814110011738-106"));
+        testSearch(TEST_USER, criterion, "/TEST-SPACE/CP-TEST-4");
+    }
+
+    @Test
+    public void testSearchWithExperimentWithProjectWithCode()
+    {
+        SampleSearchCriterion criterion = new SampleSearchCriterion();
+        criterion.withExperiment().withProject().withCode().thatEquals("NOE");
+        testSearch(TEST_USER, criterion, "/CISD/CP-TEST-2", "/TEST-SPACE/CP-TEST-4");
+    }
+
+    @Test
+    public void testSearchWithExperimentWithProjectWithPermId()
+    {
+        SampleSearchCriterion criterion = new SampleSearchCriterion();
+        criterion.withExperiment().withProject().withId().thatEquals(new ProjectPermId("20120814110011738-106"));
+        testSearch(TEST_USER, criterion, "/TEST-SPACE/CP-TEST-4");
+    }
+
+    @Test
+    public void testSearchWithExperimentWithProjectWithSpaceWithIdSetToPermId()
+    {
+        SampleSearchCriterion criterion = new SampleSearchCriterion();
+        criterion.withExperiment().withProject().withSpace().withId().thatEquals(new SpacePermId("TEST-SPACE"));
+        testSearch(TEST_USER, criterion, 8);
+
+        criterion = new SampleSearchCriterion();
+        criterion.withExperiment().withProject().withSpace().withId().thatEquals(new SpacePermId("/TEST-SPACE"));
+        testSearch(TEST_USER, criterion, 8);
+    }
+
+    @Test
+    public void testSearchWithExperimentWithProjectWithSpaceWithCode()
+    {
+        SampleSearchCriterion criterion = new SampleSearchCriterion();
+        criterion.withExperiment().withProject().withSpace().withCode().thatEquals("TEST-SPACE");
+        testSearch(TEST_USER, criterion, 8);
+    }
+
+    @Test
+    public void testSearchWithExperimentWithProjectWithSpaceWithPermId()
+    {
+        SampleSearchCriterion criterion = new SampleSearchCriterion();
+        criterion.withExperiment().withProject().withSpace().withPermId().thatEquals("TEST-SPACE");
+        testSearch(TEST_USER, criterion, 8);
+
+        criterion = new SampleSearchCriterion();
+        criterion.withExperiment().withProject().withSpace().withPermId().thatEquals("/TEST-SPACE");
+        testSearch(TEST_USER, criterion, 8);
+    }
+
+    @Test
+    public void testSearchWithParentWithIdSetToIdentifier()
+    {
+        SampleSearchCriterion criterion = new SampleSearchCriterion();
+        criterion.withParents().withId().thatEquals(new SampleIdentifier("/CISD/MP002-1"));
+        testSearch(TEST_USER, criterion, "/CISD/3V-125", "/CISD/3V-126");
+    }
+
+    @Test
+    public void testSearchWithParentWithIdSetToPermId()
+    {
+        SampleSearchCriterion criterion = new SampleSearchCriterion();
+        criterion.withParents().withId().thatEquals(new SamplePermId("200811050917877-331"));
+        testSearch(TEST_USER, criterion, "/CISD/3V-125", "/CISD/3V-126");
+    }
+
     @Test
     public void testSearchWithParentWithPermId()
     {
@@ -104,6 +308,22 @@ public class SearchSampleTest extends AbstractSampleTest
         testSearch(TEST_USER, criterion, "/CISD/3V-125", "/CISD/3V-126");
     }
 
+    @Test
+    public void testSearchWithChildrenWithIdSetToIdentifier()
+    {
+        SampleSearchCriterion criterion = new SampleSearchCriterion();
+        criterion.withChildren().withId().thatEquals(new SampleIdentifier("/CISD/3VCP6"));
+        testSearch(TEST_USER, criterion, "/CISD/3V-125", "/CISD/CL-3V:A02");
+    }
+
+    @Test
+    public void testSearchWithChildrenWithIdSetToPermId()
+    {
+        SampleSearchCriterion criterion = new SampleSearchCriterion();
+        criterion.withChildren().withId().thatEquals(new SamplePermId("200811050946559-980"));
+        testSearch(TEST_USER, criterion, "/CISD/3V-125", "/CISD/CL-3V:A02");
+    }
+
     @Test
     public void testSearchWithChildrenWithPermId()
     {
@@ -120,6 +340,22 @@ public class SearchSampleTest extends AbstractSampleTest
         testSearch(TEST_USER, criterion, "/CISD/3V-125", "/CISD/CL-3V:A02");
     }
 
+    @Test
+    public void testSearchWithContainerWithIdSetToPermId()
+    {
+        SampleSearchCriterion criterion = new SampleSearchCriterion();
+        criterion.withContainer().withId().thatEquals(new SamplePermId("200811050924274-994"));
+        testSearch(TEST_USER, criterion, "/CISD/B1B3:B01", "/CISD/B1B3:B03");
+    }
+
+    @Test
+    public void testSearchWithContainerWithIdSetToIdentifier()
+    {
+        SampleSearchCriterion criterion = new SampleSearchCriterion();
+        criterion.withContainer().withId().thatEquals(new SampleIdentifier("/CISD/B1B3"));
+        testSearch(TEST_USER, criterion, "/CISD/B1B3:B01", "/CISD/B1B3:B03");
+    }
+
     @Test
     public void testSearchWithContainerWithPermId()
     {
@@ -136,6 +372,22 @@ public class SearchSampleTest extends AbstractSampleTest
         testSearch(TEST_USER, criterion, "/CISD/B1B3:B01", "/CISD/B1B3:B03");
     }
 
+    @Test
+    public void testSearchWithTagWithIdSetToPermId()
+    {
+        SampleSearchCriterion criterion = new SampleSearchCriterion();
+        criterion.withTag().withId().thatEquals(new TagPermId("/test/TEST_METAPROJECTS"));
+        testSearch(TEST_USER, criterion, "/TEST-SPACE/EV-TEST");
+    }
+
+    @Test
+    public void testSearchWithTagWithIdSetToId()
+    {
+        SampleSearchCriterion criterion = new SampleSearchCriterion();
+        criterion.withTag().withId().thatEquals(new TagCodeId("TEST_METAPROJECTS"));
+        testSearch(TEST_USER, criterion, "/TEST-SPACE/EV-TEST");
+    }
+
     @Test
     public void testSearchWithTagWithCode()
     {
@@ -144,6 +396,22 @@ public class SearchSampleTest extends AbstractSampleTest
         testSearch(TEST_USER, criterion, "/TEST-SPACE/EV-TEST");
     }
 
+    @Test
+    public void testSearchWithTagWithPermId()
+    {
+        SampleSearchCriterion criterion = new SampleSearchCriterion();
+        criterion.withTag().withPermId().thatEquals("/test/TEST_METAPROJECTS");
+        testSearch(TEST_USER, criterion, "/TEST-SPACE/EV-TEST");
+    }
+
+    @Test
+    public void testSearchWithTagWithPermIdUnauthorized()
+    {
+        final SampleSearchCriterion criterion = new SampleSearchCriterion();
+        criterion.withTag().withCode().thatEquals("/test/TEST_METAPROJECTS");
+        testSearch(TEST_SPACE_USER, criterion, 0);
+    }
+
     @Test
     public void testSearchWithRegistrationDateThatEquals()
     {
@@ -204,18 +472,6 @@ public class SearchSampleTest extends AbstractSampleTest
         testSearch(TEST_USER, criterion, "/CISD/CP-TEST-1", "/CISD/CP-TEST-2");
     }
 
-    @Test
-    public void testSearchWithUnauthorizedSpace()
-    {
-        SampleSearchCriterion criterion = new SampleSearchCriterion();
-        criterion.withPermId().thatEquals("200902091219327-1025");
-        testSearch(TEST_USER, criterion, 1);
-
-        criterion = new SampleSearchCriterion();
-        criterion.withPermId().thatEquals("200902091219327-1025");
-        testSearch(TEST_SPACE_USER, criterion, 0);
-    }
-
     private void testSearch(String user, SampleSearchCriterion criterion, String... expectedIdentifiers)
     {
         String sessionToken = v3api.login(user, PASSWORD);
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/UpdateExperimentTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/UpdateExperimentTest.java
index 44edfe89bfc2cbf0fb9063624c3c40e7b702bb6a..2579bc9aafdc91f3753b50b5350f78c1a6eccab9 100644
--- a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/UpdateExperimentTest.java
+++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/UpdateExperimentTest.java
@@ -45,7 +45,7 @@ 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.SamplePermId;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.space.SpacePermId;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.tag.ITagId;
-import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.tag.TagNameId;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.tag.TagCodeId;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.tag.TagPermId;
 import ch.systemsx.cisd.common.action.IDelegatedAction;
 import ch.systemsx.cisd.common.test.AssertionUtil;
@@ -344,11 +344,11 @@ public class UpdateExperimentTest extends AbstractExperimentTest
     {
         String sessionToken = v3api.login(TEST_USER, PASSWORD);
 
-        ExperimentPermId experimentId = createExperimentWithTags(new TagNameId("TEST_TAG_1"));
+        ExperimentPermId experimentId = createExperimentWithTags(new TagCodeId("TEST_TAG_1"));
 
         ExperimentUpdate update = new ExperimentUpdate();
         update.setExperimentId(experimentId);
-        update.getTagIds().add(new TagNameId("TEST_TAG_2"));
+        update.getTagIds().add(new TagCodeId("TEST_TAG_2"));
 
         v3api.updateExperiments(sessionToken, Arrays.asList(update));
 
@@ -398,7 +398,7 @@ public class UpdateExperimentTest extends AbstractExperimentTest
     {
         String sessionToken = v3api.login(TEST_USER, PASSWORD);
 
-        ExperimentPermId experimentId = createExperimentWithTags(new TagNameId("TEST_TAG_1"), new TagPermId("/test/TEST_TAG_2"));
+        ExperimentPermId experimentId = createExperimentWithTags(new TagCodeId("TEST_TAG_1"), new TagPermId("/test/TEST_TAG_2"));
 
         ExperimentUpdate update = new ExperimentUpdate();
         update.setExperimentId(experimentId);
@@ -414,7 +414,7 @@ public class UpdateExperimentTest extends AbstractExperimentTest
     {
         String sessionToken = v3api.login(TEST_USER, PASSWORD);
 
-        ExperimentPermId experimentId = createExperimentWithTags(new TagNameId("TEST_TAG_1"), new TagPermId("/test/TEST_TAG_2"));
+        ExperimentPermId experimentId = createExperimentWithTags(new TagCodeId("TEST_TAG_1"), new TagPermId("/test/TEST_TAG_2"));
 
         ExperimentUpdate update = new ExperimentUpdate();
         update.setExperimentId(experimentId);
@@ -430,7 +430,7 @@ public class UpdateExperimentTest extends AbstractExperimentTest
     {
         String sessionToken = v3api.login(TEST_USER, PASSWORD);
 
-        ExperimentPermId experimentId = createExperimentWithTags(new TagNameId("TEST_TAG_1"), new TagPermId("/test/TEST_TAG_2"));
+        ExperimentPermId experimentId = createExperimentWithTags(new TagCodeId("TEST_TAG_1"), new TagPermId("/test/TEST_TAG_2"));
 
         ExperimentUpdate update = new ExperimentUpdate();
         update.setExperimentId(experimentId);
@@ -468,7 +468,7 @@ public class UpdateExperimentTest extends AbstractExperimentTest
     {
         String sessionToken = v3api.login(TEST_USER, PASSWORD);
 
-        ExperimentPermId experimentId = createExperimentWithTags(new TagNameId("TEST_TAG_1"));
+        ExperimentPermId experimentId = createExperimentWithTags(new TagCodeId("TEST_TAG_1"));
 
         ExperimentUpdate update = new ExperimentUpdate();
         update.setExperimentId(experimentId);
@@ -484,11 +484,11 @@ public class UpdateExperimentTest extends AbstractExperimentTest
     {
         String sessionToken = v3api.login(TEST_USER, PASSWORD);
 
-        ExperimentPermId experimentId = createExperimentWithTags(new TagNameId("TEST_TAG_1"));
+        ExperimentPermId experimentId = createExperimentWithTags(new TagCodeId("TEST_TAG_1"));
 
         ExperimentUpdate update = new ExperimentUpdate();
         update.setExperimentId(experimentId);
-        update.getTagIds().set(new TagNameId("THIS_TAG_DOES_NOT_EXIST"));
+        update.getTagIds().set(new TagCodeId("THIS_TAG_DOES_NOT_EXIST"));
 
         v3api.updateExperiments(sessionToken, Arrays.asList(update));
 
@@ -500,7 +500,7 @@ public class UpdateExperimentTest extends AbstractExperimentTest
     {
         final String sessionToken = v3api.login(TEST_USER, PASSWORD);
 
-        ExperimentPermId experimentId = createExperimentWithTags(new TagNameId("TEST_TAG_1"));
+        ExperimentPermId experimentId = createExperimentWithTags(new TagCodeId("TEST_TAG_1"));
 
         final ITagId tagId = new TagPermId("/test_space/TEST_METAPROJECTS");
         final ExperimentUpdate update = new ExperimentUpdate();
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/UpdateSampleTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/UpdateSampleTest.java
index a55e35ced01e54cce39507ae7624623893444bcc..46cd53973f5ea47ac1552d7976c2fb074417d650 100644
--- a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/UpdateSampleTest.java
+++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/UpdateSampleTest.java
@@ -44,7 +44,7 @@ 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;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.tag.ITagId;
-import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.tag.TagNameId;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.tag.TagCodeId;
 import ch.systemsx.cisd.common.action.IDelegatedAction;
 import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.common.test.AssertionUtil;
@@ -1135,9 +1135,9 @@ public class UpdateSampleTest extends AbstractSampleTest
         SampleCreation creation1 = masterPlateCreation("CISD", "SAMPLE_1_WITH_TAGS");
         SampleCreation creation2 = masterPlateCreation("CISD", "SAMPLE_2_WITH_TAGS");
 
-        ITagId tag1Id = new TagNameId("TEST_TAG_1");
-        ITagId tag2Id = new TagNameId("TEST_TAG_2");
-        ITagId tag3Id = new TagNameId("TEST_TAG_3");
+        ITagId tag1Id = new TagCodeId("TEST_TAG_1");
+        ITagId tag2Id = new TagCodeId("TEST_TAG_2");
+        ITagId tag3Id = new TagCodeId("TEST_TAG_3");
 
         creation1.setTagIds(Arrays.asList(tag3Id));
         creation2.setTagIds(Arrays.asList(tag1Id, tag2Id));
diff --git a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/entity/tag/Tag.java b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/entity/tag/Tag.java
index bc936f8778775804781f7ef541f5062b68f642e9..412931371826314ae1ade5e46c38a653085aadfd 100644
--- a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/entity/tag/Tag.java
+++ b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/entity/tag/Tag.java
@@ -40,12 +40,12 @@ public class Tag implements Serializable
     private TagPermId permId;
 
     @JsonProperty
-    private String name;
+    private String code;
 
     @JsonProperty
     private String description;
 
-    @JsonProperty(value="private")
+    @JsonProperty(value = "private")
     private Boolean isPrivate;
 
     @JsonProperty
@@ -77,14 +77,14 @@ public class Tag implements Serializable
     }
 
     @JsonIgnore
-    public String getName()
+    public String getCode()
     {
-        return name;
+        return code;
     }
 
-    public void setName(String name)
+    public void setCode(String code)
     {
-        this.name = name;
+        this.code = code;
     }
 
     @JsonIgnore
diff --git a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/generators/DtoGenerator.java b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/generators/DtoGenerator.java
index 80ea9b2fdd0b6308d0eab02486bf3c48b399553b..e9eb79a242ee6fbf4d75a1edf6c9180273061707 100644
--- a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/generators/DtoGenerator.java
+++ b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/generators/DtoGenerator.java
@@ -16,6 +16,7 @@ import ch.systemsx.cisd.base.annotation.JsonObject;
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
 
+@SuppressWarnings("hiding")
 public class DtoGenerator
 {
     private static final String PACKAGE_PREFIX = "ch.ethz.sis.openbis.generic.shared.api.v3.dto";
diff --git a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/generators/Generator.java b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/generators/Generator.java
index 16f14dc5918f208b7a3099b865b65a6582c3167f..df8223dba55325128ccc67b0017f57d8935cf22e 100644
--- a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/generators/Generator.java
+++ b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/generators/Generator.java
@@ -203,17 +203,17 @@ public class Generator extends AbstractGenerator
 
         return gen;
     }
-    
+
     private static DtoGenerator createTagGenerator()
     {
         DtoGenerator gen = new DtoGenerator("tag", "Tag", TagFetchOptions.class);
-        
+
         gen.addSimpleField(TagPermId.class, "permId");
-        gen.addSimpleField(String.class, "name");
+        gen.addSimpleField(String.class, "code");
         addDescription(gen);
         gen.addSimpleField(Boolean.class, "private", "isPrivate");
         addRegistrationDate(gen);
-        
+
         gen.addFetchedField(Person.class, "owner", "Owner", PersonFetchOptions.class);
 
         return gen;
diff --git a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/id/CreationId.java b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/id/CreationId.java
index 808fecc82220f998ec8818241907bce41d0e64b7..117724fc8049d81c3ce0abc7c4cda992d1f64c36 100644
--- a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/id/CreationId.java
+++ b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/id/CreationId.java
@@ -66,28 +66,35 @@ public class CreationId implements ISampleId, IDataSetId, IExperimentId, IProjec
     @Override
     public int hashCode()
     {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + ((creationId == null) ? 0 : creationId.hashCode());
-        return result;
+        return ((getCreationId() == null) ? 0 : getCreationId().hashCode());
     }
 
     @Override
     public boolean equals(Object obj)
     {
         if (this == obj)
+        {
             return true;
+        }
         if (obj == null)
+        {
             return false;
+        }
         if (getClass() != obj.getClass())
+        {
             return false;
+        }
         CreationId other = (CreationId) obj;
-        if (creationId == null)
+        if (getCreationId() == null)
         {
-            if (other.creationId != null)
+            if (other.getCreationId() != null)
+            {
                 return false;
-        } else if (!creationId.equals(other.creationId))
+            }
+        } else if (!getCreationId().equals(other.getCreationId()))
+        {
             return false;
+        }
         return true;
     }
 
diff --git a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/id/ObjectIdentifier.java b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/id/ObjectIdentifier.java
index 481c6ba66db342d713f2a84350f7c96b47fa9774..84f7b6f8f5c2ce54a75d5076c0786a12396da43c 100644
--- a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/id/ObjectIdentifier.java
+++ b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/id/ObjectIdentifier.java
@@ -69,7 +69,7 @@ public abstract class ObjectIdentifier implements IObjectId
     @Override
     public int hashCode()
     {
-        return ((identifier == null) ? 0 : identifier.hashCode());
+        return ((getIdentifier() == null) ? 0 : getIdentifier().hashCode());
     }
 
     @Override
@@ -88,7 +88,7 @@ public abstract class ObjectIdentifier implements IObjectId
             return false;
         }
         ObjectIdentifier other = (ObjectIdentifier) obj;
-        return identifier == null ? identifier == other.identifier : identifier.equals(other.identifier);
+        return getIdentifier() == null ? getIdentifier() == other.getIdentifier() : getIdentifier().equals(other.getIdentifier());
     }
 
 }
diff --git a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/id/ObjectPermId.java b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/id/ObjectPermId.java
index d3d70536bd03a85b984362133ca5a6070eb23dd8..357b0a8be0885cd435141d07ca63d50758f9a30c 100644
--- a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/id/ObjectPermId.java
+++ b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/id/ObjectPermId.java
@@ -69,7 +69,7 @@ public abstract class ObjectPermId implements IObjectId
     @Override
     public int hashCode()
     {
-        return ((permId == null) ? 0 : permId.hashCode());
+        return ((getPermId() == null) ? 0 : getPermId().hashCode());
     }
 
     @Override
@@ -88,13 +88,13 @@ public abstract class ObjectPermId implements IObjectId
             return false;
         }
         ObjectPermId other = (ObjectPermId) obj;
-        if (permId == null)
+        if (getPermId() == null)
         {
-            if (other.permId != null)
+            if (other.getPermId() != null)
             {
                 return false;
             }
-        } else if (!permId.equals(other.permId))
+        } else if (!getPermId().equals(other.getPermId()))
         {
             return false;
         }
diff --git a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/id/ObjectTechId.java b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/id/ObjectTechId.java
index 56ae35236b645f4232985d715a5d36571dd2cc37..8c95f7491bfe9d5e7d3654c2657946469a8d20ef 100644
--- a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/id/ObjectTechId.java
+++ b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/id/ObjectTechId.java
@@ -83,7 +83,7 @@ public class ObjectTechId implements IObjectId
     @Override
     public int hashCode()
     {
-        return ((techId == null) ? 0 : techId.hashCode());
+        return ((getTechId() == null) ? 0 : getTechId().hashCode());
     }
 
     @Override
@@ -102,13 +102,13 @@ public class ObjectTechId implements IObjectId
             return false;
         }
         ObjectTechId other = (ObjectTechId) obj;
-        if (techId == null)
+        if (getTechId() == null)
         {
-            if (other.techId != null)
+            if (other.getTechId() != null)
             {
                 return false;
             }
-        } else if (!techId.equals(other.techId))
+        } else if (!getTechId().equals(other.getTechId()))
         {
             return false;
         }
diff --git a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/id/space/SpacePermId.java b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/id/space/SpacePermId.java
index 9173dcaa4f94800ed6a4baa17220aec42b75ffe1..5b2e447076de05d560d50c0a4be79fc427dc6c0f 100644
--- a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/id/space/SpacePermId.java
+++ b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/id/space/SpacePermId.java
@@ -31,7 +31,7 @@ public class SpacePermId extends ObjectPermId implements ISpaceId
     private static final long serialVersionUID = 1L;
 
     /**
-     * @param permId Space perm id, e.g. "MY_SPACE".
+     * @param permId Space perm id, e.g. "/MY_SPACE" or "MY_SPACE".
      */
     public SpacePermId(String permId)
     {
@@ -48,4 +48,19 @@ public class SpacePermId extends ObjectPermId implements ISpaceId
         super();
     }
 
+    @Override
+    public String getPermId()
+    {
+        String permId = super.getPermId();
+
+        // support both "/MY_SPACE" and "MY_SPACE"
+        if (permId.startsWith("/"))
+        {
+            return permId.substring(1);
+        } else
+        {
+            return permId;
+        }
+    }
+
 }
diff --git a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/id/tag/TagNameId.java b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/id/tag/TagCodeId.java
similarity index 68%
rename from openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/id/tag/TagNameId.java
rename to openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/id/tag/TagCodeId.java
index 2ac32439551621d43c368798404f45710d60207f..354ffa48063aefd60cc62cdeac5d1a95021b6f10 100644
--- a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/id/tag/TagNameId.java
+++ b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/id/tag/TagCodeId.java
@@ -21,61 +21,61 @@ import java.io.Serializable;
 import ch.systemsx.cisd.base.annotation.JsonObject;
 
 /**
- * Tag name. 
+ * Tag code.
  * 
  * @author Franz-Josef Elmer
  * @author Jakub Straszewski
  */
-@JsonObject("TagNameId")
-public class TagNameId implements ITagId, Serializable
+@JsonObject("TagCodeId")
+public class TagCodeId implements ITagId, Serializable
 {
 
     private static final long serialVersionUID = 1L;
-    private String name;
+
+    private String code;
 
     /**
-     * @param name Tag name, e.g. "MY_TAG".
+     * @param code Tag code, e.g. "MY_TAG".
      */
-    public TagNameId(String name)
+    public TagCodeId(String code)
     {
-        setName(name);
-        
+        setCode(code);
     }
 
     //
     // JSON-RPC
     //
 
-    public String getName()
+    public String getCode()
     {
-        return name;
+        return code;
     }
 
     @SuppressWarnings("unused")
-    private TagNameId()
+    private TagCodeId()
     {
         super();
     }
-    
-    private void setName(String name)
+
+    private void setCode(String code)
     {
-        if (name == null)
+        if (code == null)
         {
-            throw new IllegalArgumentException("Name cannot be null");
+            throw new IllegalArgumentException("Code cannot be null");
         }
-        this.name = name;
+        this.code = code;
     }
 
     @Override
     public String toString()
     {
-        return getName();
+        return getCode();
     }
 
     @Override
     public int hashCode()
     {
-        return ((name == null) ? 0 : name.hashCode());
+        return ((code == null) ? 0 : code.hashCode());
     }
 
     @Override
@@ -93,8 +93,8 @@ public class TagNameId implements ITagId, Serializable
         {
             return false;
         }
-        TagNameId other = (TagNameId) obj;
-        return name == null ? name == other.name : name.equals(other.name);
+        TagCodeId other = (TagCodeId) obj;
+        return code == null ? code == other.code : code.equals(other.code);
     }
 
 }
diff --git a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/AbstractCompositeSearchCriterion.java b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/AbstractCompositeSearchCriterion.java
index 1a19f58333cf3b01c0bd53dad14f1de38104c2bd..adb3b181687b715c2bcb6af8bc5068e263587918 100644
--- a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/AbstractCompositeSearchCriterion.java
+++ b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/AbstractCompositeSearchCriterion.java
@@ -31,14 +31,14 @@ public abstract class AbstractCompositeSearchCriterion extends AbstractSearchCri
 
     private static final long serialVersionUID = 1L;
 
-    protected Collection<AbstractSearchCriterion> criteria = new LinkedList<AbstractSearchCriterion>();
+    protected Collection<ISearchCriterion> criteria = new LinkedList<ISearchCriterion>();
 
     public Collection<ISearchCriterion> getCriteria()
     {
         return Collections.<ISearchCriterion> unmodifiableCollection(criteria);
     }
 
-    public void setCriteria(Collection<AbstractSearchCriterion> criteria)
+    public void setCriteria(Collection<ISearchCriterion> criteria)
     {
         this.criteria = criteria;
     }
diff --git a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/AbstractEntitySearchCriterion.java b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/AbstractEntitySearchCriterion.java
index bddebf9f74373d0a402728aff24672ba56fd3480..780931886a53522b1c0441e795aa75c048212f55 100644
--- a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/AbstractEntitySearchCriterion.java
+++ b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/AbstractEntitySearchCriterion.java
@@ -16,13 +16,14 @@
 
 package ch.ethz.sis.openbis.generic.shared.api.v3.dto.search;
 
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.IObjectId;
 import ch.systemsx.cisd.base.annotation.JsonObject;
 
 /**
  * @author pkupczyk
  */
 @JsonObject("AbstractEntitySearchCriterion")
-public class AbstractEntitySearchCriterion extends AbstractCompositeSearchCriterion
+public class AbstractEntitySearchCriterion<ID extends IObjectId> extends AbstractObjectSearchCriterion<ID>
 {
 
     private static final long serialVersionUID = 1L;
diff --git a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/AbstractObjectSearchCriterion.java b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/AbstractObjectSearchCriterion.java
new file mode 100644
index 0000000000000000000000000000000000000000..828b121ba5e8aabd52de35b9fae7c77881ba8773
--- /dev/null
+++ b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/AbstractObjectSearchCriterion.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2014 ETH Zuerich, Scientific IT Services
+ *
+ * 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.ethz.sis.openbis.generic.shared.api.v3.dto.search;
+
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.IObjectId;
+import ch.systemsx.cisd.base.annotation.JsonObject;
+
+/**
+ * @author pkupczyk
+ */
+@JsonObject("AbstractObjectSearchCriterion")
+public class AbstractObjectSearchCriterion<ID extends IObjectId> extends AbstractCompositeSearchCriterion
+{
+
+    private static final long serialVersionUID = 1L;
+
+    public IdSearchCriterion<ID> withId()
+    {
+        return with(new IdSearchCriterion<ID>());
+    }
+
+}
diff --git a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/CodeSearchCriterion.java b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/CodeSearchCriterion.java
index 345107c83cfa861a82ff9d21f1dd90e0905f1e28..f93096da64d9691bc806e7fa78bd67d04e20bfff 100644
--- a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/CodeSearchCriterion.java
+++ b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/CodeSearchCriterion.java
@@ -27,7 +27,7 @@ public class CodeSearchCriterion extends StringFieldSearchCriterion
 
     private static final long serialVersionUID = 1L;
 
-    protected CodeSearchCriterion()
+    public CodeSearchCriterion()
     {
         super("code", SearchFieldType.ATTRIBUTE);
     }
diff --git a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/EntityTypeSearchCriterion.java b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/EntityTypeSearchCriterion.java
index 63d66350c6177a603cd3fd11bbed4d8b6e9b3064..260766bd636873fa4f8b0d41824b4fa6912c4c67 100644
--- a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/EntityTypeSearchCriterion.java
+++ b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/EntityTypeSearchCriterion.java
@@ -16,13 +16,14 @@
 
 package ch.ethz.sis.openbis.generic.shared.api.v3.dto.search;
 
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.entitytype.IEntityTypeId;
 import ch.systemsx.cisd.base.annotation.JsonObject;
 
 /**
  * @author pkupczyk
  */
 @JsonObject("EntityTypeSearchCriterion")
-public class EntityTypeSearchCriterion extends AbstractCompositeSearchCriterion
+public class EntityTypeSearchCriterion extends AbstractObjectSearchCriterion<IEntityTypeId>
 {
 
     private static final long serialVersionUID = 1L;
@@ -36,6 +37,11 @@ public class EntityTypeSearchCriterion extends AbstractCompositeSearchCriterion
         return with(new CodeSearchCriterion());
     }
 
+    public PermIdSearchCriterion withPermId()
+    {
+        return with(new PermIdSearchCriterion());
+    }
+
     @Override
     protected SearchCriterionToStringBuilder createBuilder()
     {
diff --git a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/ExperimentSearchCriterion.java b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/ExperimentSearchCriterion.java
index dc7683c81956cac5f9115900e7fdbfb3588e4519..0959494e5d589039b778502511572b3432aec5ca 100644
--- a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/ExperimentSearchCriterion.java
+++ b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/ExperimentSearchCriterion.java
@@ -16,13 +16,14 @@
 
 package ch.ethz.sis.openbis.generic.shared.api.v3.dto.search;
 
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.experiment.IExperimentId;
 import ch.systemsx.cisd.base.annotation.JsonObject;
 
 /**
  * @author pkupczyk
  */
 @JsonObject("ExperimentSearchCriterion")
-public class ExperimentSearchCriterion extends AbstractEntitySearchCriterion
+public class ExperimentSearchCriterion extends AbstractEntitySearchCriterion<IExperimentId>
 {
 
     private static final long serialVersionUID = 1L;
diff --git a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/IdSearchCriterion.java b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/IdSearchCriterion.java
new file mode 100644
index 0000000000000000000000000000000000000000..f58d16da06f4ca8b69ec4291ad67ac6648fdb37e
--- /dev/null
+++ b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/IdSearchCriterion.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2014 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.ethz.sis.openbis.generic.shared.api.v3.dto.search;
+
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.IObjectId;
+import ch.systemsx.cisd.base.annotation.JsonObject;
+
+/**
+ * @author pkupczyk
+ */
+@JsonObject("IdSearchCriterion")
+public class IdSearchCriterion<T extends IObjectId> extends AbstractSearchCriterion
+{
+
+    private static final long serialVersionUID = 1L;
+
+    private T id;
+
+    @SuppressWarnings("hiding")
+    public void thatEquals(T id)
+    {
+        this.id = id;
+    }
+
+    public T getId()
+    {
+        return id;
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return ((id == null) ? 0 : id.hashCode());
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (this == obj)
+        {
+            return true;
+        }
+        if (obj == null)
+        {
+            return false;
+        }
+        if (getClass() != obj.getClass())
+        {
+            return false;
+        }
+        IdSearchCriterion<?> other = (IdSearchCriterion<?>) obj;
+        return id == null ? id == other.id : id.equals(other.id);
+    }
+
+}
diff --git a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/PermIdSearchCriterion.java b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/PermIdSearchCriterion.java
index 4dd397b3acd4cf0e6cd7842a49fbcc0b12432f9d..7727e6337383f311db9a25597db66c722844a777 100644
--- a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/PermIdSearchCriterion.java
+++ b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/PermIdSearchCriterion.java
@@ -27,7 +27,7 @@ public class PermIdSearchCriterion extends StringFieldSearchCriterion
 
     private static final long serialVersionUID = 1L;
 
-    protected PermIdSearchCriterion()
+    public PermIdSearchCriterion()
     {
         super("perm id", SearchFieldType.ATTRIBUTE);
     }
diff --git a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/ProjectSearchCriterion.java b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/ProjectSearchCriterion.java
index 0a11c91d3779fe32124e3885cb43aa14eec175fb..c891f3ebc7df05871a973e1538e41feebf14be9a 100644
--- a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/ProjectSearchCriterion.java
+++ b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/ProjectSearchCriterion.java
@@ -16,13 +16,14 @@
 
 package ch.ethz.sis.openbis.generic.shared.api.v3.dto.search;
 
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.project.IProjectId;
 import ch.systemsx.cisd.base.annotation.JsonObject;
 
 /**
  * @author pkupczyk
  */
 @JsonObject("ProjectSearchCriterion")
-public class ProjectSearchCriterion extends AbstractCompositeSearchCriterion
+public class ProjectSearchCriterion extends AbstractObjectSearchCriterion<IProjectId>
 {
 
     private static final long serialVersionUID = 1L;
@@ -36,6 +37,11 @@ public class ProjectSearchCriterion extends AbstractCompositeSearchCriterion
         return with(new CodeSearchCriterion());
     }
 
+    public PermIdSearchCriterion withPermId()
+    {
+        return with(new PermIdSearchCriterion());
+    }
+
     public SpaceSearchCriterion withSpace()
     {
         return with(new SpaceSearchCriterion());
diff --git a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/SampleSearchCriterion.java b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/SampleSearchCriterion.java
index 3a59de5f7ee742b8f9dc695f1923dac5b8156fd3..fb463b0c8737323aed0d16bf720fdcc9b5a8cdc5 100644
--- a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/SampleSearchCriterion.java
+++ b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/SampleSearchCriterion.java
@@ -16,13 +16,14 @@
 
 package ch.ethz.sis.openbis.generic.shared.api.v3.dto.search;
 
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.sample.ISampleId;
 import ch.systemsx.cisd.base.annotation.JsonObject;
 
 /**
  * @author pkupczyk
  */
 @JsonObject("SampleSearchCriterion")
-public class SampleSearchCriterion extends AbstractEntitySearchCriterion
+public class SampleSearchCriterion extends AbstractEntitySearchCriterion<ISampleId>
 {
 
     private static final long serialVersionUID = 1L;
diff --git a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/SearchCriterionToStringBuilder.java b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/SearchCriterionToStringBuilder.java
index a9f5772176fb7db2d2f4b39c4e8fcc84ffdca8c0..f94011629fa94d88762ba14343d5db9910b13943 100644
--- a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/SearchCriterionToStringBuilder.java
+++ b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/SearchCriterionToStringBuilder.java
@@ -31,7 +31,7 @@ public class SearchCriterionToStringBuilder
 
     private SearchOperator operator;
 
-    private Collection<AbstractSearchCriterion> criteria;
+    private Collection<ISearchCriterion> criteria;
 
     public SearchCriterionToStringBuilder setName(String name)
     {
@@ -45,7 +45,7 @@ public class SearchCriterionToStringBuilder
         return this;
     }
 
-    public SearchCriterionToStringBuilder setCriteria(Collection<AbstractSearchCriterion> criteria)
+    public SearchCriterionToStringBuilder setCriteria(Collection<ISearchCriterion> criteria)
     {
         this.criteria = criteria;
         return this;
@@ -71,7 +71,7 @@ public class SearchCriterionToStringBuilder
             sb.append(indentation + "with operator '" + operator + "'\n");
         }
 
-        for (AbstractSearchCriterion criterion : criteria)
+        for (ISearchCriterion criterion : criteria)
         {
             if (criterion instanceof AbstractCompositeSearchCriterion)
             {
diff --git a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/SpaceSearchCriterion.java b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/SpaceSearchCriterion.java
index 62c1ec5fddec89c3d8c3dad63d287658f868654b..3bebea35220d5f982f5d1b8e79706d55b8792f98 100644
--- a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/SpaceSearchCriterion.java
+++ b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/SpaceSearchCriterion.java
@@ -16,13 +16,14 @@
 
 package ch.ethz.sis.openbis.generic.shared.api.v3.dto.search;
 
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.space.ISpaceId;
 import ch.systemsx.cisd.base.annotation.JsonObject;
 
 /**
  * @author pkupczyk
  */
 @JsonObject("SpaceSearchCriterion")
-public class SpaceSearchCriterion extends AbstractCompositeSearchCriterion
+public class SpaceSearchCriterion extends AbstractObjectSearchCriterion<ISpaceId>
 {
 
     private static final long serialVersionUID = 1L;
@@ -36,6 +37,11 @@ public class SpaceSearchCriterion extends AbstractCompositeSearchCriterion
         return with(new CodeSearchCriterion());
     }
 
+    public PermIdSearchCriterion withPermId()
+    {
+        return with(new PermIdSearchCriterion());
+    }
+
     @Override
     protected SearchCriterionToStringBuilder createBuilder()
     {
diff --git a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/TagSearchCriterion.java b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/TagSearchCriterion.java
index 6d9afb34205502aa0325dc3ee8db6fcd8f7ff2ce..e8c94a412a9bffbafd67cfd3548f249278d1760d 100644
--- a/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/TagSearchCriterion.java
+++ b/openbis_api/source/java/ch/ethz/sis/openbis/generic/shared/api/v3/dto/search/TagSearchCriterion.java
@@ -16,13 +16,14 @@
 
 package ch.ethz.sis.openbis.generic.shared.api.v3.dto.search;
 
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.tag.ITagId;
 import ch.systemsx.cisd.base.annotation.JsonObject;
 
 /**
  * @author pkupczyk
  */
 @JsonObject("TagSearchCriterion")
-public class TagSearchCriterion extends AbstractCompositeSearchCriterion
+public class TagSearchCriterion extends AbstractObjectSearchCriterion<ITagId>
 {
 
     private static final long serialVersionUID = 1L;
@@ -36,6 +37,11 @@ public class TagSearchCriterion extends AbstractCompositeSearchCriterion
         return with(new CodeSearchCriterion());
     }
 
+    public PermIdSearchCriterion withPermId()
+    {
+        return with(new PermIdSearchCriterion());
+    }
+
     @Override
     protected SearchCriterionToStringBuilder createBuilder()
     {
diff --git a/openbis_api/source/java/ch/systemsx/cisd/openbis/generic/shared/api/v1/dto/SearchCriteria.java b/openbis_api/source/java/ch/systemsx/cisd/openbis/generic/shared/api/v1/dto/SearchCriteria.java
index 3bbff24f327a1b2eace8d822ea6dba0fc9c64fe1..733b2492629dd3a3cb199896ee26ce207bd3fc31 100644
--- a/openbis_api/source/java/ch/systemsx/cisd/openbis/generic/shared/api/v1/dto/SearchCriteria.java
+++ b/openbis_api/source/java/ch/systemsx/cisd/openbis/generic/shared/api/v1/dto/SearchCriteria.java
@@ -29,12 +29,10 @@ import org.apache.commons.lang.builder.ToStringStyle;
 import ch.systemsx.cisd.base.annotation.JsonObject;
 
 /**
- * A (mutable) object representing the specification of a search. A search is specified by
- * MatchClause objects and an operator for combining match clauses. Additionally sub criteria can be
- * added for entities connected with the main entity object.
+ * A (mutable) object representing the specification of a search. A search is specified by MatchClause objects and an operator for combining match
+ * clauses. Additionally sub criteria can be added for entities connected with the main entity object.
  * <p>
- * A MatchClause is made up of a property or attribute to compare against and a desired value for
- * that property or attribute.
+ * A MatchClause is made up of a property or attribute to compare against and a desired value for that property or attribute.
  * <p>
  * Example:<br>
  * <blockquote> Match all of the following clauses:
@@ -93,7 +91,7 @@ public class SearchCriteria implements Serializable
         // for sample or experiment
         SPACE,
         // for experiment
-        PROJECT,
+        PROJECT, PROJECT_PERM_ID,
         // for all types of entities
         METAPROJECT
     }
@@ -166,8 +164,7 @@ public class SearchCriteria implements Serializable
         }
 
         /**
-         * Factory method to create a MatchClause matching against registration or modification
-         * date.
+         * Factory method to create a MatchClause matching against registration or modification date.
          * 
          * @param attribute The attribute to compare against
          * @param mode The kind of comparison (<=, ==, >=)
@@ -201,8 +198,7 @@ public class SearchCriteria implements Serializable
         }
 
         /**
-         * Returns a String where those characters that Lucene expects to be escaped are escaped by
-         * a preceding <code>\</code>.
+         * Returns a String where those characters that Lucene expects to be escaped are escaped by a preceding <code>\</code>.
          * <p>
          * Copy of Lucene's <code>QueryParser.escape()</code> method.
          */
@@ -605,8 +601,7 @@ public class SearchCriteria implements Serializable
     }
 
     /**
-     * Gets the operator for combining MatchClause objects. Default value is {@link SearchOperator}
-     * .MATCH_ALL_CRITERIA.
+     * Gets the operator for combining MatchClause objects. Default value is {@link SearchOperator} .MATCH_ALL_CRITERIA.
      */
     public SearchOperator getOperator()
     {