diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/PredicateExecutor.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/PredicateExecutor.java
index d743e2fbe8062e4fbbc3132eb300f4915f097c91..7f6ca0454e4d87284a3bd3a9c6f87bc0a9302771 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/PredicateExecutor.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/PredicateExecutor.java
@@ -252,12 +252,28 @@ public final class PredicateExecutor
             Session sess = daoFactory.getSessionFactory().getCurrentSession();
             Query query = sess.getNamedQuery(DataSetAccessPE.DATASET_ACCESS_QUERY_NAME);
             query = query.setReadOnly(true);
-            List<DataSetAccessPE> results = query.setString(0, dataSetCode).list();
+            String[] codes =
+                { dataSetCode };
+            List<DataSetAccessPE> results =
+                    query.setParameterList(DataSetAccessPE.DATA_SET_CODES_PARAMETER_NAME, codes)
+                            .list();
             if (results.size() < 1)
                 return null;
             return results.get(0);
         }
 
+        @SuppressWarnings("unchecked")
+        public List<DataSetAccessPE> tryGetDatasetCollectionAccessData(List<String> dataSetCodes)
+        {
+            Session sess = daoFactory.getSessionFactory().getCurrentSession();
+            Query query = sess.getNamedQuery(DataSetAccessPE.DATASET_ACCESS_QUERY_NAME);
+            query = query.setReadOnly(true);
+            List<DataSetAccessPE> results =
+                    query.setParameterList(DataSetAccessPE.DATA_SET_CODES_PARAMETER_NAME,
+                            dataSetCodes).list();
+            return results;
+        }
+
         public GroupPE tryToGetGroup(SpaceOwnerKind kind, TechId techId)
         {
             switch (kind)
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/authorization/IAuthorizationDataProvider.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/authorization/IAuthorizationDataProvider.java
index 1753a1c5a3a0daf77b93d0863f285fd5f042e654..c7e3fb51d84a531426ee31382c372aa39ec4ef3d 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/authorization/IAuthorizationDataProvider.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/authorization/IAuthorizationDataProvider.java
@@ -48,10 +48,15 @@ public interface IAuthorizationDataProvider extends IDatabaseInstanceFinder
     public ProjectPE tryToGetProject(String dataSetCode);
 
     /**
-     * Returns the information necessary to determine if a user is allowed to access this dataset.
+     * Returns the information necessary to determine if a user is allowed to access this data set.
      */
     public DataSetAccessPE tryGetDatasetAccessData(String dataSetCode);
 
+    /**
+     * Returns the information necessary to determine if a user is allowed to access the data sets.
+     */
+    public List<DataSetAccessPE> tryGetDatasetCollectionAccessData(List<String> dataSetCodes);
+
     /**
      * Returns the group of an entity with given <var>entityKind</var> and <var>techId</var>
      * 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/authorization/predicate/DataSetCodeCollectionPredicate.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/authorization/predicate/DataSetCodeCollectionPredicate.java
new file mode 100644
index 0000000000000000000000000000000000000000..9324d3180b8b55fdecb5e70b34a14861b5f6586a
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/authorization/predicate/DataSetCodeCollectionPredicate.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2009 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.shared.authorization.predicate;
+
+import java.util.List;
+
+import ch.systemsx.cisd.common.exceptions.Status;
+import ch.systemsx.cisd.openbis.generic.shared.authorization.RoleWithIdentifier;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DataSetAccessPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.PersonPE;
+
+/**
+ * A {@link IPredicate} based on a list of data set codes.
+ * 
+ * @author Franz-Josef Elmer
+ */
+public class DataSetCodeCollectionPredicate extends AbstractGroupPredicate<List<String>>
+{
+    @Override
+    public String getCandidateDescription()
+    {
+        return "data set code";
+    }
+
+    @Override
+    Status doEvaluation(PersonPE person, List<RoleWithIdentifier> allowedRoles,
+            List<String> dataSetCodes)
+    {
+        assert initialized : "Predicate has not been initialized";
+
+        List<DataSetAccessPE> accessData =
+                authorizationDataProvider.tryGetDatasetCollectionAccessData(dataSetCodes);
+
+        if (accessData == null)
+        {
+            return Status.OK;
+        }
+
+        if (accessData.size() < dataSetCodes.size())
+        {
+            return Status.createError("Could not get access data for all datasets");
+        }
+
+        for (DataSetAccessPE accessDatum : accessData)
+        {
+            String dbInstanceUUID = accessDatum.getDatabaseInstanceUuid();
+            String dbInstanceCode = accessDatum.getDatabaseInstanceCode();
+            String groupCode = accessDatum.getGroupCode();
+            Status result =
+                    evaluate(person, allowedRoles, dbInstanceUUID, dbInstanceCode, groupCode);
+            if (result != Status.OK)
+            {
+                return result;
+            }
+        }
+
+        return Status.OK;
+    }
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/DataSetAccessPE.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/DataSetAccessPE.java
index f6937c57ab5bca4ae1b306ae9c6b60e2709576d4..4a9ba8d9b27d33b9e3ede098148f31cb60e44b95 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/DataSetAccessPE.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/DataSetAccessPE.java
@@ -43,7 +43,7 @@ import javax.persistence.SqlResultSetMapping;
         + " g, "
         + TableNames.DATABASE_INSTANCES_TABLE
         + " dbi "
-        + "where ds.code=? and e.id = ds.expe_id and p.id = e.proj_id and g.id = p.grou_id and dbi.id = g.dbin_id", resultSetMapping = "implicit")
+        + "where ds.code in (:codes) and e.id = ds.expe_id and p.id = e.proj_id and g.id = p.grou_id and dbi.id = g.dbin_id", resultSetMapping = "implicit")
 public class DataSetAccessPE
 {
     private String dataSetId;
@@ -58,6 +58,8 @@ public class DataSetAccessPE
 
     public final static String DATASET_ACCESS_QUERY_NAME = "dataset_access";
 
+    public final static String DATA_SET_CODES_PARAMETER_NAME = "codes";
+
     /**
      * A factory method that should only be used for testing.
      */