diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java
index e21ed5eeae6ef856988b130f28a0f467a9120221..5c09d2b7ae42421dd823d7c66c58c028b6c06fd9 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java
@@ -75,6 +75,7 @@ import ch.systemsx.cisd.openbis.generic.server.authorization.predicate.SampleTec
 import ch.systemsx.cisd.openbis.generic.server.authorization.predicate.SampleUpdatesPredicate;
 import ch.systemsx.cisd.openbis.generic.server.authorization.predicate.SpaceIdentifierPredicate;
 import ch.systemsx.cisd.openbis.generic.server.authorization.validator.DeletionValidator;
+import ch.systemsx.cisd.openbis.generic.server.authorization.validator.ExperimentByIdentiferValidator;
 import ch.systemsx.cisd.openbis.generic.server.authorization.validator.ExpressionValidator;
 import ch.systemsx.cisd.openbis.generic.server.authorization.validator.ExternalDataValidator;
 import ch.systemsx.cisd.openbis.generic.server.authorization.validator.MatchingEntityValidator;
@@ -1416,6 +1417,20 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
 
     }
 
+    @Override
+    @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
+    @ReturnValueFilter(validatorClass = ExperimentByIdentiferValidator.class)
+    public List<Experiment> searchForExperiments(String sessionToken,
+            DetailedSearchCriteria criteria)
+    {
+        final Session session = getSession(sessionToken);
+        SearchHelper searchHelper =
+                new SearchHelper(session, businessObjectFactory, getDAOFactory());
+        String userId = session.getUserName();
+        List<ExperimentPE> experiments = searchHelper.searchForExperiments(userId, criteria);
+        return translateExperiments(sessionToken, experiments);
+    }
+
     @Override
     @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
     @ReturnValueFilter(validatorClass = ExternalDataValidator.class)
@@ -3478,8 +3493,8 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
         if (defaultPutDataStoreServerCodeOrNull == null)
         {
             throw ConfigurationFailureException
-                    .fromTemplate
-                    ("There are %d Data Store Servers registered in openBIS, but property dss-rpc.put.dss-code is not set.",
+                    .fromTemplate(
+                            "There are %d Data Store Servers registered in openBIS, but property dss-rpc.put.dss-code is not set.",
                             dataStores.size());
         }
         for (DataStorePE store : dataStores)
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServerLogger.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServerLogger.java
index a1df72d1564cbd8a297a4ed92e47bcfcec6dfda0..32f00e6e4cbbabc005a6ac14f04e51ffe75812c2 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServerLogger.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServerLogger.java
@@ -631,6 +631,14 @@ final class CommonServerLogger extends AbstractServerLogger implements ICommonSe
                 projectIdentifier, abbreviate(attachments));
     }
 
+    @Override
+    public List<Experiment> searchForExperiments(String sessionToken,
+            DetailedSearchCriteria criteria)
+    {
+        logAccess(sessionToken, "search_for_experiments", "criteria(%s)", criteria);
+        return null;
+    }
+
     @Override
     public List<ExternalData> searchForDataSets(String sessionToken, DetailedSearchCriteria criteria)
     {
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/SearchHelper.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/SearchHelper.java
index c0057edf7d440febbaa271911874d4e5e7a70e97..3f5fda76bac2becd1e3903dc3d9659d1b77f3cb6 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/SearchHelper.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/SearchHelper.java
@@ -19,10 +19,12 @@ package ch.systemsx.cisd.openbis.generic.server;
 import java.util.List;
 
 import ch.systemsx.cisd.openbis.generic.server.business.bo.ICommonBusinessObjectFactory;
+import ch.systemsx.cisd.openbis.generic.server.business.bo.IExperimentTable;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.datasetlister.IDatasetLister;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.materiallister.IMaterialLister;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.samplelister.ISampleLister;
 import ch.systemsx.cisd.openbis.generic.server.business.search.DataSetSearchManager;
+import ch.systemsx.cisd.openbis.generic.server.business.search.ExperimentSearchManager;
 import ch.systemsx.cisd.openbis.generic.server.business.search.MaterialSearchManager;
 import ch.systemsx.cisd.openbis.generic.server.business.search.SampleSearchManager;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDAOFactory;
@@ -31,6 +33,7 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DetailedSearchCriteria;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Material;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
+import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.Session;
 
 /**
@@ -89,4 +92,13 @@ class SearchHelper
         return new MaterialSearchManager(searchDAO, materialLister).searchForMaterials(userId,
                 detailedSearchCriteria);
     }
+
+    public List<ExperimentPE> searchForExperiments(String userId,
+            DetailedSearchCriteria detailedSearchCriteria)
+    {
+        IHibernateSearchDAO searchDAO = daoFactory.getHibernateSearchDAO();
+        IExperimentTable experimentTable = businessObjectFactory.createExperimentTable(session);
+        return new ExperimentSearchManager(searchDAO, experimentTable).searchForExperiments(userId,
+                detailedSearchCriteria);
+    }
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationService.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationService.java
index b04b45e4ccf48f4e6dc76eed53f5a7e4cdde4310..29db281fdfadf5a5966e8ea2df4a82e5f375c7a6 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationService.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationService.java
@@ -120,7 +120,7 @@ import ch.systemsx.cisd.openbis.generic.shared.util.HibernateUtils;
 public class GeneralInformationService extends AbstractServer<IGeneralInformationService> implements
         IGeneralInformationService
 {
-    public static final int MINOR_VERSION = 20;
+    public static final int MINOR_VERSION = 21;
 
     @Resource(name = ch.systemsx.cisd.openbis.generic.shared.ResourceNames.COMMON_SERVER)
     private ICommonServer commonServer;
@@ -957,6 +957,22 @@ public class GeneralInformationService extends AbstractServer<IGeneralInformatio
         return Translator.translateExperiments(experiments);
     }
 
+    @Override
+    @Transactional(readOnly = true)
+    @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
+    @ReturnValueFilter(validatorClass = ExperimentByIdentiferValidator.class)
+    public List<Experiment> searchForExperiments(String sessionToken, SearchCriteria searchCriteria)
+    {
+        checkSession(sessionToken);
+
+        DetailedSearchCriteria detailedSearchCriteria =
+                SearchCriteriaToDetailedSearchCriteriaTranslator.convert(getDAOFactory(),
+                        SearchableEntityKind.EXPERIMENT, searchCriteria);
+        List<ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment> experiments =
+                commonServer.searchForExperiments(sessionToken, detailedSearchCriteria);
+        return Translator.translateExperiments(experiments);
+    }
+
     @Override
     @Transactional(readOnly = true)
     @RolesAllowed(RoleWithHierarchy.SPACE_OBSERVER)
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationServiceLogger.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationServiceLogger.java
index 608b0dfb4b87f77fe6be86692ddb4ecc771e4c4e..31172b3ef92f3b875b981a4dce3323abb0cffff1 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationServiceLogger.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/api/v1/GeneralInformationServiceLogger.java
@@ -297,6 +297,13 @@ class GeneralInformationServiceLogger extends AbstractServerLogger implements
         return null;
     }
 
+    @Override
+    public List<Experiment> searchForExperiments(String sessionToken, SearchCriteria searchCriteria)
+    {
+        logAccess(sessionToken, "search-for-experiments", "SEARCH_CRITERIA(%s)", searchCriteria);
+        return null;
+    }
+
     @Override
     public List<Experiment> filterExperimentsVisibleToUser(String sessionToken,
             List<Experiment> allExperiments, String userId)
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ExperimentTable.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ExperimentTable.java
index 1430f1805efa1fb86a0e5f1b540b008a64021d23..15d9937e7170ed9162dbc4bc27c843e8a629cbc5 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ExperimentTable.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ExperimentTable.java
@@ -85,6 +85,12 @@ public final class ExperimentTable extends AbstractBusinessObject implements IEx
     // IExperimentTable
     //
 
+    @Override
+    public void loadByIds(Collection<Long> experimentIds)
+    {
+        experiments = getExperimentDAO().listByIDs(experimentIds);
+    }
+
     @Override
     public final void load(final String experimentTypeCode,
             final ProjectIdentifier projectIdentifier)
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/IExperimentTable.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/IExperimentTable.java
index da93f0993481e70fc2aaf4fe19f046e4eee42826..30d9d78940a690d92c5474f226c0827a89f57301 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/IExperimentTable.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/IExperimentTable.java
@@ -35,6 +35,11 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SpaceIdentifier;
  */
 public interface IExperimentTable
 {
+    /**
+     * Loads all experiments specified by their ids.
+     */
+    public void loadByIds(Collection<Long> experimentIds);
+
     /**
      * Loads all experiments of given type and from given project together with all their
      * properties.
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/search/ExperimentSearchManager.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/search/ExperimentSearchManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..f833fe22094af1a36bc775557af3c8549d20e982
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/search/ExperimentSearchManager.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2013 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.generic.server.business.search;
+
+import static ch.systemsx.cisd.openbis.generic.shared.dto.properties.EntityKind.EXPERIMENT;
+
+import java.util.Collections;
+import java.util.List;
+
+import ch.systemsx.cisd.openbis.generic.server.business.bo.IExperimentTable;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.IHibernateSearchDAO;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DetailedSearchAssociationCriteria;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DetailedSearchCriteria;
+import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentPE;
+
+/**
+ * Search manager for experiments.
+ * 
+ * @author Franz-Josef Elmer
+ */
+public class ExperimentSearchManager extends AbstractSearchManager<IExperimentTable>
+{
+
+    public ExperimentSearchManager(IHibernateSearchDAO searchDAO, IExperimentTable lister)
+    {
+        super(searchDAO, lister);
+    }
+
+    public List<ExperimentPE> searchForExperiments(String userId, DetailedSearchCriteria criteria)
+    {
+        List<Long> experimentIds =
+                searchDAO.searchForEntityIds(userId, criteria, EXPERIMENT,
+                        Collections.<DetailedSearchAssociationCriteria> emptyList());
+        lister.loadByIds(experimentIds);
+        return lister.getExperiments();
+    }
+
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/ICommonServer.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/ICommonServer.java
index b9cfa0e0749c6dd63a0c9a9f4ca1064a7e30a4bf..7e55bcb392332305265913a4f39cd1dd325e43c5 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/ICommonServer.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/ICommonServer.java
@@ -615,7 +615,14 @@ public interface ICommonServer extends IServer
             String description, String leaderId, Collection<NewAttachment> attachments);
 
     /**
-     * Searches for samples that fulfill the specified search criteria.
+     * Searches for experiments that fulfill the specified search criteria.
+     */
+    @Transactional(readOnly = true)
+    public List<Experiment> searchForExperiments(String sessionToken,
+            DetailedSearchCriteria criteria);
+
+    /**
+     * Searches for data sets that fulfill the specified search criteria.
      */
     @Transactional(readOnly = true)
     public List<ExternalData> searchForDataSets(String sessionToken, DetailedSearchCriteria criteria);
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/remoteapitest/api/v1/GeneralInformationServiceJsonApiTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/remoteapitest/api/v1/GeneralInformationServiceJsonApiTest.java
index 7d1d6a8fbbcc16a514fae641534ef9f78474698d..c4bbdbbf07107371b81332efbe9e7de71661e1e2 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/remoteapitest/api/v1/GeneralInformationServiceJsonApiTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/remoteapitest/api/v1/GeneralInformationServiceJsonApiTest.java
@@ -16,7 +16,7 @@
 
 package ch.systemsx.cisd.openbis.remoteapitest.api.v1;
 
-import static junit.framework.Assert.assertEquals;
+import static org.testng.AssertJUnit.assertEquals;
 import static org.testng.AssertJUnit.assertNotNull;
 import static org.testng.AssertJUnit.assertTrue;
 import static org.testng.AssertJUnit.fail;
@@ -29,6 +29,7 @@ import java.util.Comparator;
 import java.util.EnumSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Set;
 
 import org.testng.annotations.AfterMethod;
@@ -150,6 +151,32 @@ public class GeneralInformationServiceJsonApiTest extends RemoteApiTestCase
         fail("result didn't contain project " + expectedSampleIdentifier);
     }
 
+    @Test
+    public void testSearchForExperiments()
+    {
+        SearchCriteria searchCriteria = new SearchCriteria();
+        searchCriteria.addMatchClause(MatchClause.createPropertyMatch("GENDER", "FEMALE"));
+
+        List<Experiment> experiments =
+                generalInformationService.searchForExperiments(sessionToken, searchCriteria);
+
+        assertEquals("/CISD/NEMO/EXP-TEST-2", experiments.get(0).getIdentifier());
+        assertEquals("SIRNA_HCS", experiments.get(0).getExperimentTypeCode());
+        List<Entry<String, String>> list =
+                new ArrayList<Entry<String, String>>(experiments.get(0).getProperties().entrySet());
+        Collections.sort(list, new Comparator<Entry<String, String>>()
+            {
+                @Override
+                public int compare(Entry<String, String> e1, Entry<String, String> e2)
+                {
+                    return e1.getKey().compareTo(e2.getKey());
+                }
+            });
+        assertEquals("[DESCRIPTION=very important expertiment, GENDER=FEMALE, "
+                + "PURCHASE_DATE=2009-02-09 00:00:00 +0100]", list.toString());
+        assertEquals(1, experiments.size());
+    }
+
     @Test
     public void testSearchForSamples()
     {
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/api/v1/GeneralInformationServiceTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/api/v1/GeneralInformationServiceTest.java
index dc72fd147bb7486aa59cbd25af975ce0a384e9ea..388df743eef71bff144c84a782fcd877a4f0b944 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/api/v1/GeneralInformationServiceTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/api/v1/GeneralInformationServiceTest.java
@@ -31,6 +31,7 @@ import java.util.Date;
 import java.util.EnumSet;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map.Entry;
 
 import org.springframework.beans.factory.annotation.Autowired;
 import org.testng.annotations.AfterMethod;
@@ -1153,6 +1154,58 @@ public class GeneralInformationServiceTest extends SystemTestCase
                 dataSets.toString());
     }
 
+    @Test
+    public void testSearchForExperimentsByCode()
+    {
+        SearchCriteria searchCriteria = new SearchCriteria();
+        searchCriteria.addMatchClause(MatchClause.createAttributeMatch(MatchClauseAttribute.CODE,
+                "EXP1*"));
+
+        List<Experiment> experiments =
+                generalInformationService.searchForExperiments(sessionToken, searchCriteria);
+
+        assertEntities("[/CISD/NEMO/EXP1, /CISD/NEMO/EXP10, /CISD/NEMO/EXP11]", experiments);
+    }
+
+    @Test
+    public void testSearchForExperimentsByProject()
+    {
+        SearchCriteria searchCriteria = new SearchCriteria();
+        searchCriteria.addMatchClause(MatchClause.createAttributeMatch(
+                MatchClauseAttribute.PROJECT, "NOE"));
+
+        List<Experiment> experiments =
+                generalInformationService.searchForExperiments(sessionToken, searchCriteria);
+
+        assertEntities("[/CISD/NOE/EXP-TEST-2]", experiments);
+    }
+
+    @Test
+    public void testSearchForExperimentsByProperty()
+    {
+        SearchCriteria searchCriteria = new SearchCriteria();
+        searchCriteria.addMatchClause(MatchClause.createPropertyMatch("GENDER", "FEMALE"));
+
+        List<Experiment> experiments =
+                generalInformationService.searchForExperiments(sessionToken, searchCriteria);
+
+        assertEquals("/CISD/NEMO/EXP-TEST-2", experiments.get(0).getIdentifier());
+        assertEquals("SIRNA_HCS", experiments.get(0).getExperimentTypeCode());
+        List<Entry<String, String>> list =
+                new ArrayList<Entry<String, String>>(experiments.get(0).getProperties().entrySet());
+        Collections.sort(list, new Comparator<Entry<String, String>>()
+            {
+                @Override
+                public int compare(Entry<String, String> e1, Entry<String, String> e2)
+                {
+                    return e1.getKey().compareTo(e2.getKey());
+                }
+            });
+        assertEquals("[DESCRIPTION=very important expertiment, GENDER=FEMALE, "
+                + "PURCHASE_DATE=2009-02-09 00:00:00 +0100]", list.toString());
+        assertEquals(1, experiments.size());
+    }
+
     @Test
     public void testGetDefaultPutDataStoreBaseURL()
     {
diff --git a/openbis_api/source/java/ch/systemsx/cisd/openbis/generic/shared/api/v1/IGeneralInformationService.java b/openbis_api/source/java/ch/systemsx/cisd/openbis/generic/shared/api/v1/IGeneralInformationService.java
index 800f30a27252bab2da81e3f46e24df98028d782c..3fd3e8b30a64615039b3c7f245320491c9d74d84 100644
--- a/openbis_api/source/java/ch/systemsx/cisd/openbis/generic/shared/api/v1/IGeneralInformationService.java
+++ b/openbis_api/source/java/ch/systemsx/cisd/openbis/generic/shared/api/v1/IGeneralInformationService.java
@@ -439,6 +439,14 @@ public interface IGeneralInformationService extends IRpcService
      * @since 1.9
      */
     public List<Experiment> listExperiments(String sessionToken, List<String> experimentIdentifiers);
+    
+    /**
+     * Returns all experiments matching specified search criteria. Note, that sub criterias are not
+     * supported. 
+     * 
+     * @since 1.21
+     */
+    public List<Experiment> searchForExperiments(String sessionToken, SearchCriteria searchCriteria);
 
     /**
      * Returns all available projects.