From c1cf9b40f9dc661695f73e2c4b9bd94f3757f7d7 Mon Sep 17 00:00:00 2001
From: pkupczyk <piotr.kupczyk@id.ethz.ch>
Date: Fri, 4 May 2018 21:17:28 +0200
Subject: [PATCH] SSDM-5852 : V3 API Query - non-existent database handling and
 database provider initialization

---
 .../query/AbstractExecuteExecutor.java        |  4 --
 .../query/MapQueryDatabaseByIdExecutor.java   |  6 +--
 .../query/QueryAuthorizationExecutor.java     | 22 ++++++++
 .../query/UpdateQueryDatabaseExecutor.java    |  4 +-
 .../query/QueryAuthorizationRecord.java       |  2 +
 .../query/QueryAuthorizationValidator.java    | 21 +++++---
 .../asapi/v3/translator/query/QueryQuery.java |  2 +-
 ...baseDefinitionProviderAutoInitialized.java | 53 +++++++++++++++++++
 ...baseDefinitionProviderAutoInitialized.java | 31 +++++++++++
 .../asapi/v3/AbstractQueryTest.java           | 34 ++++++++++++
 .../systemtest/asapi/v3/DeleteQueryTest.java  | 16 ++++++
 .../systemtest/asapi/v3/ExecuteQueryTest.java | 17 ++++++
 .../systemtest/asapi/v3/ExecuteSqlTest.java   | 14 +++++
 .../systemtest/asapi/v3/GetQueryTest.java     | 14 +++++
 .../systemtest/asapi/v3/SearchQueryTest.java  | 14 +++++
 .../systemtest/asapi/v3/UpdateQueryTest.java  | 19 +++++++
 16 files changed, 255 insertions(+), 18 deletions(-)
 create mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/plugin/query/server/QueryDatabaseDefinitionProviderAutoInitialized.java
 create mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/plugin/query/shared/IQueryDatabaseDefinitionProviderAutoInitialized.java

diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/query/AbstractExecuteExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/query/AbstractExecuteExecutor.java
index 830b6be38a8..b3e50e589cf 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/query/AbstractExecuteExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/query/AbstractExecuteExecutor.java
@@ -34,7 +34,6 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.QueryPE;
 import ch.systemsx.cisd.openbis.plugin.query.server.DAO;
 import ch.systemsx.cisd.openbis.plugin.query.server.authorization.QueryAccessController;
 import ch.systemsx.cisd.openbis.plugin.query.shared.DatabaseDefinition;
-import ch.systemsx.cisd.openbis.plugin.query.shared.IQueryDatabaseDefinitionProvider;
 import ch.systemsx.cisd.openbis.plugin.query.shared.basic.dto.QueryParameterBindings;
 
 /**
@@ -52,9 +51,6 @@ public class AbstractExecuteExecutor
     @Autowired
     protected IMapQueryDatabaseByIdExecutor mapQueryDatabaseByIdExecutor;
 
-    @Autowired
-    protected IQueryDatabaseDefinitionProvider databaseDefinitionProvider;
-
     @Autowired
     protected IDAOFactory daoFactory;
 
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/query/MapQueryDatabaseByIdExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/query/MapQueryDatabaseByIdExecutor.java
index f8651504425..fdcf5f77f60 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/query/MapQueryDatabaseByIdExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/query/MapQueryDatabaseByIdExecutor.java
@@ -28,7 +28,7 @@ import ch.ethz.sis.openbis.generic.asapi.v3.dto.query.id.QueryDatabaseName;
 import ch.ethz.sis.openbis.generic.asapi.v3.exceptions.UnsupportedObjectIdException;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.IOperationContext;
 import ch.systemsx.cisd.openbis.plugin.query.shared.DatabaseDefinition;
-import ch.systemsx.cisd.openbis.plugin.query.shared.IQueryDatabaseDefinitionProvider;
+import ch.systemsx.cisd.openbis.plugin.query.shared.IQueryDatabaseDefinitionProviderAutoInitialized;
 
 /**
  * @author pkupczyk
@@ -38,13 +38,11 @@ public class MapQueryDatabaseByIdExecutor implements IMapQueryDatabaseByIdExecut
 {
 
     @Autowired
-    private IQueryDatabaseDefinitionProvider databaseProvider;
+    private IQueryDatabaseDefinitionProviderAutoInitialized databaseProvider;
 
     @Override
     public Map<IQueryDatabaseId, DatabaseDefinition> map(IOperationContext context, Collection<? extends IQueryDatabaseId> ids)
     {
-        databaseProvider.initDatabaseDefinitions();
-
         Map<IQueryDatabaseId, DatabaseDefinition> result = new LinkedHashMap<IQueryDatabaseId, DatabaseDefinition>();
 
         for (IQueryDatabaseId id : ids)
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/query/QueryAuthorizationExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/query/QueryAuthorizationExecutor.java
index 3429ebfc9d3..bf8ff10501d 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/query/QueryAuthorizationExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/query/QueryAuthorizationExecutor.java
@@ -16,10 +16,12 @@
 
 package ch.ethz.sis.openbis.generic.server.asapi.v3.executor.query;
 
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.query.id.IQueryId;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.query.id.QueryDatabaseName;
+import ch.ethz.sis.openbis.generic.asapi.v3.exceptions.ObjectNotFoundException;
 import ch.ethz.sis.openbis.generic.asapi.v3.exceptions.UnauthorizedObjectAccessException;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.IOperationContext;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.helper.roleassignment.RoleAssignmentUtils;
@@ -33,6 +35,7 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.RoleWithHierarchy;
 import ch.systemsx.cisd.openbis.generic.shared.dto.QueryPE;
 import ch.systemsx.cisd.openbis.plugin.query.server.authorization.QueryAccessController;
 import ch.systemsx.cisd.openbis.plugin.query.shared.DatabaseDefinition;
+import ch.systemsx.cisd.openbis.plugin.query.shared.IQueryDatabaseDefinitionProviderAutoInitialized;
 
 /**
  * @author pkupczyk
@@ -41,6 +44,9 @@ import ch.systemsx.cisd.openbis.plugin.query.shared.DatabaseDefinition;
 public class QueryAuthorizationExecutor implements IQueryAuthorizationExecutor
 {
 
+    @Autowired
+    private IQueryDatabaseDefinitionProviderAutoInitialized databaseProvider;
+
     @Override
     @RolesAllowed({ RoleWithHierarchy.PROJECT_OBSERVER, RoleWithHierarchy.SPACE_ETL_SERVER })
     @Capability("CREATE_QUERY")
@@ -72,6 +78,8 @@ public class QueryAuthorizationExecutor implements IQueryAuthorizationExecutor
     @RolesAllowed({ RoleWithHierarchy.PROJECT_OBSERVER, RoleWithHierarchy.SPACE_ETL_SERVER })
     public void canExecute(IOperationContext context, IQueryId id, QueryPE query)
     {
+        checkDatabaseExists(query.getQueryDatabaseKey());
+
         if (query.isPublic() || context.getSession().tryGetPerson().equals(query.getRegistrator())
                 || RoleAssignmentUtils.isInstanceAdmin(context.getSession().tryGetPerson()))
         {
@@ -92,6 +100,8 @@ public class QueryAuthorizationExecutor implements IQueryAuthorizationExecutor
     @RolesAllowed({ RoleWithHierarchy.PROJECT_OBSERVER, RoleWithHierarchy.SPACE_ETL_SERVER })
     public void canExecute(IOperationContext context, String sql, DatabaseDefinition database)
     {
+        checkDatabaseExists(database.getKey());
+
         try
         {
             QueryAccessController.checkWriteAccess(context.getSession(), database.getKey(), "create and perform");
@@ -117,6 +127,8 @@ public class QueryAuthorizationExecutor implements IQueryAuthorizationExecutor
 
     private void canWrite(IOperationContext context, IQueryId id, QueryPE query, String operation)
     {
+        checkDatabaseExists(query.getQueryDatabaseKey());
+
         if (query.isPublic() || context.getSession().tryGetPerson().equals(query.getRegistrator())
                 || RoleAssignmentUtils.isInstanceAdmin(context.getSession().tryGetPerson()))
         {
@@ -133,4 +145,14 @@ public class QueryAuthorizationExecutor implements IQueryAuthorizationExecutor
         }
     }
 
+    private void checkDatabaseExists(String databaseKey)
+    {
+        DatabaseDefinition database = databaseProvider.getDefinition(databaseKey);
+
+        if (database == null)
+        {
+            throw new ObjectNotFoundException(new QueryDatabaseName(databaseKey));
+        }
+    }
+
 }
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/query/UpdateQueryDatabaseExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/query/UpdateQueryDatabaseExecutor.java
index 3d4159ebfff..daaf94e5c57 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/query/UpdateQueryDatabaseExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/query/UpdateQueryDatabaseExecutor.java
@@ -30,7 +30,7 @@ import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.IOperationContext;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.entity.AbstractUpdateEntityToOneRelationExecutor;
 import ch.systemsx.cisd.openbis.generic.shared.dto.QueryPE;
 import ch.systemsx.cisd.openbis.plugin.query.shared.DatabaseDefinition;
-import ch.systemsx.cisd.openbis.plugin.query.shared.IQueryDatabaseDefinitionProvider;
+import ch.systemsx.cisd.openbis.plugin.query.shared.IQueryDatabaseDefinitionProviderAutoInitialized;
 
 /**
  * @author pkupczyk
@@ -44,7 +44,7 @@ public class UpdateQueryDatabaseExecutor extends AbstractUpdateEntityToOneRelati
     private IMapQueryDatabaseByIdExecutor mapQueryDatabaseByIdExecutor;
 
     @Autowired
-    private IQueryDatabaseDefinitionProvider databaseDefinitionProvider;
+    private IQueryDatabaseDefinitionProviderAutoInitialized databaseDefinitionProvider;
 
     @Override
     protected String getRelationName()
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/query/QueryAuthorizationRecord.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/query/QueryAuthorizationRecord.java
index 46aeca3d430..c33cdcb891d 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/query/QueryAuthorizationRecord.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/query/QueryAuthorizationRecord.java
@@ -26,6 +26,8 @@ public class QueryAuthorizationRecord
 
     public boolean isPublic;
 
+    public String databaseKey;
+
     public Long registratorId;
 
 }
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/query/QueryAuthorizationValidator.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/query/QueryAuthorizationValidator.java
index 0e0b00739e7..728e63aafb5 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/query/QueryAuthorizationValidator.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/query/QueryAuthorizationValidator.java
@@ -21,10 +21,13 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
 import ch.ethz.sis.openbis.generic.server.asapi.v3.helper.roleassignment.RoleAssignmentUtils;
 import ch.systemsx.cisd.openbis.generic.shared.dto.PersonPE;
+import ch.systemsx.cisd.openbis.plugin.query.shared.DatabaseDefinition;
+import ch.systemsx.cisd.openbis.plugin.query.shared.IQueryDatabaseDefinitionProviderAutoInitialized;
 
 import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
 import net.lemnik.eodsql.QueryTool;
@@ -36,23 +39,27 @@ import net.lemnik.eodsql.QueryTool;
 public class QueryAuthorizationValidator implements IQueryAuthorizationValidator
 {
 
+    @Autowired
+    private IQueryDatabaseDefinitionProviderAutoInitialized databaseProvider;
+
     @Override
     public Set<Long> validate(PersonPE person, Collection<Long> queryIds)
     {
-        if (RoleAssignmentUtils.isInstanceAdmin(person))
-        {
-            return new HashSet<Long>(queryIds);
-        }
-
+        boolean isInstanceAdmin = RoleAssignmentUtils.isInstanceAdmin(person);
         QueryQuery query = QueryTool.getManagedQuery(QueryQuery.class);
         List<QueryAuthorizationRecord> records = query.getAuthorizations(new LongOpenHashSet(queryIds));
         Set<Long> result = new HashSet<Long>();
 
         for (QueryAuthorizationRecord record : records)
         {
-            if (record.isPublic || record.registratorId.equals(person.getId()))
+            DatabaseDefinition database = databaseProvider.getDefinition(record.databaseKey);
+
+            if (database != null)
             {
-                result.add(record.id);
+                if (record.isPublic || record.registratorId.equals(person.getId()) || isInstanceAdmin)
+                {
+                    result.add(record.id);
+                }
             }
         }
 
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/query/QueryQuery.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/query/QueryQuery.java
index 6c37c7e0f58..f87a63d47e0 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/query/QueryQuery.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/query/QueryQuery.java
@@ -39,7 +39,7 @@ public interface QueryQuery extends ObjectQuery
             LongSetMapper.class }, fetchSize = FETCH_SIZE)
     public List<ObjectRelationRecord> getRegistratorIds(LongSet queryIds);
 
-    @Select(sql = "select q.id, q.is_public as isPublic, q.pers_id_registerer as registratorId from queries q where q.id = any(?{1})", parameterBindings = {
+    @Select(sql = "select q.id, q.is_public as isPublic, q.db_key as databaseKey, q.pers_id_registerer as registratorId from queries q where q.id = any(?{1})", parameterBindings = {
             LongSetMapper.class }, fetchSize = FETCH_SIZE)
     public List<QueryAuthorizationRecord> getAuthorizations(LongSet queryIds);
 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/query/server/QueryDatabaseDefinitionProviderAutoInitialized.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/query/server/QueryDatabaseDefinitionProviderAutoInitialized.java
new file mode 100644
index 00000000000..fd1491e62c4
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/query/server/QueryDatabaseDefinitionProviderAutoInitialized.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2018 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.plugin.query.server;
+
+import java.util.Collection;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import ch.systemsx.cisd.common.exceptions.UserFailureException;
+import ch.systemsx.cisd.openbis.plugin.query.shared.DatabaseDefinition;
+import ch.systemsx.cisd.openbis.plugin.query.shared.IQueryDatabaseDefinitionProvider;
+import ch.systemsx.cisd.openbis.plugin.query.shared.IQueryDatabaseDefinitionProviderAutoInitialized;
+
+/**
+ * @author pkupczyk
+ */
+@Component
+public class QueryDatabaseDefinitionProviderAutoInitialized implements IQueryDatabaseDefinitionProviderAutoInitialized
+{
+
+    @Autowired
+    private IQueryDatabaseDefinitionProvider databaseProvider;
+
+    @Override
+    public DatabaseDefinition getDefinition(String dbKey) throws UserFailureException
+    {
+        databaseProvider.initDatabaseDefinitions();
+        return databaseProvider.getDefinition(dbKey);
+    }
+
+    @Override
+    public Collection<DatabaseDefinition> getAllDefinitions() throws UserFailureException
+    {
+        databaseProvider.initDatabaseDefinitions();
+        return databaseProvider.getAllDefinitions();
+    }
+
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/query/shared/IQueryDatabaseDefinitionProviderAutoInitialized.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/query/shared/IQueryDatabaseDefinitionProviderAutoInitialized.java
new file mode 100644
index 00000000000..dda27704d8f
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/query/shared/IQueryDatabaseDefinitionProviderAutoInitialized.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2010 ETH Zuerich, CISD
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.systemsx.cisd.openbis.plugin.query.shared;
+
+import java.util.Collection;
+
+import ch.systemsx.cisd.common.exceptions.UserFailureException;
+
+/**
+ * @author pkupczyk
+ */
+public interface IQueryDatabaseDefinitionProviderAutoInitialized
+{
+    DatabaseDefinition getDefinition(String dbKey) throws UserFailureException;
+
+    Collection<DatabaseDefinition> getAllDefinitions() throws UserFailureException;
+}
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/AbstractQueryTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/AbstractQueryTest.java
index 92b6f06e038..560a24a9abb 100644
--- a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/AbstractQueryTest.java
+++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/AbstractQueryTest.java
@@ -47,6 +47,8 @@ import ch.ethz.sis.openbis.generic.asapi.v3.dto.query.update.QueryUpdate;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.roleassignment.Role;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.roleassignment.create.RoleAssignmentCreation;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.space.id.ISpaceId;
+import ch.systemsx.cisd.openbis.generic.shared.dto.PersonPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.QueryPE;
 
 /**
  * @author pkupczyk
@@ -147,6 +149,38 @@ public class AbstractQueryTest extends AbstractTest
         return getQuery(user, password, ids.get(0));
     }
 
+    protected QueryPE createQueryWithExistingDB(String user)
+    {
+        PersonPE registrator = daoFactory.getPersonDAO().tryFindPersonByUserId(user);
+
+        QueryPE queryPE = new QueryPE();
+        queryPE.setName("my-database-exists");
+        queryPE.setQueryType(ch.systemsx.cisd.openbis.generic.shared.basic.dto.QueryType.GENERIC);
+        queryPE.setQueryDatabaseKey(DB_OPENBIS_METADATA);
+        queryPE.setExpression(SELECT_SPACE_CODES_SQL);
+        queryPE.setRegistrator(registrator);
+
+        daoFactory.getQueryDAO().createQuery(queryPE);
+
+        return queryPE;
+    }
+
+    protected QueryPE createQueryWithNonExistentDB(String user)
+    {
+        PersonPE registrator = daoFactory.getPersonDAO().tryFindPersonByUserId(user);
+
+        QueryPE queryPE = new QueryPE();
+        queryPE.setName("my-database-does-not-exist");
+        queryPE.setQueryType(ch.systemsx.cisd.openbis.generic.shared.basic.dto.QueryType.GENERIC);
+        queryPE.setQueryDatabaseKey("idontexist");
+        queryPE.setExpression(SELECT_SPACE_CODES_SQL);
+        queryPE.setRegistrator(registrator);
+
+        daoFactory.getQueryDAO().createQuery(queryPE);
+
+        return queryPE;
+    }
+
     protected Query getQuery(String user, String password, IQueryId queryId)
     {
         String sessionToken = v3api.login(user, password);
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/DeleteQueryTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/DeleteQueryTest.java
index d456bebc77e..286e6d8c916 100644
--- a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/DeleteQueryTest.java
+++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/DeleteQueryTest.java
@@ -32,6 +32,7 @@ import ch.ethz.sis.openbis.generic.asapi.v3.dto.query.id.QueryDatabaseName;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.query.id.QueryName;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.query.id.QueryTechId;
 import ch.systemsx.cisd.common.action.IDelegatedAction;
+import ch.systemsx.cisd.openbis.generic.shared.dto.QueryPE;
 
 /**
  * @author pkupczyk
@@ -81,6 +82,21 @@ public class DeleteQueryTest extends AbstractQueryTest
             }, "Deletion options cannot be null");
     }
 
+    @Test
+    public void testDeleteWithQueryThatBelongsToNonexistentDatabase()
+    {
+        QueryPE queryWithNonExistentDB = createQueryWithNonExistentDB(TEST_USER);
+
+        assertObjectNotFoundException(new IDelegatedAction()
+            {
+                @Override
+                public void execute()
+                {
+                    deleteQuery(TEST_USER, PASSWORD, new QueryName(queryWithNonExistentDB.getName()));
+                }
+            }, new QueryDatabaseName("idontexist"));
+    }
+
     @Test(dataProvider = PROVIDER_TRUE_FALSE)
     public void testDeleteWithOwner(boolean isPublic)
     {
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/ExecuteQueryTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/ExecuteQueryTest.java
index 8703a235f77..35571eca81c 100644
--- a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/ExecuteQueryTest.java
+++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/ExecuteQueryTest.java
@@ -29,9 +29,11 @@ import ch.ethz.sis.openbis.generic.asapi.v3.dto.query.Query;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.query.create.QueryCreation;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.query.id.IQueryDatabaseId;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.query.id.QueryDatabaseName;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.query.id.QueryName;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.roleassignment.Role;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.space.id.SpacePermId;
 import ch.systemsx.cisd.common.action.IDelegatedAction;
+import ch.systemsx.cisd.openbis.generic.shared.dto.QueryPE;
 
 /**
  * @author pkupczyk
@@ -127,6 +129,21 @@ public class ExecuteQueryTest extends AbstractQueryTest
         assertEquals(result.getRows().get(11).get(1).toString(), "/TEST-SPACE/TEST-PROJECT/EXP-SPACE-TEST");
     }
 
+    @Test
+    public void testExecuteWithQueryThatBelongsToNonexistentDatabase()
+    {
+        QueryPE queryWithNonExistentDB = createQueryWithNonExistentDB(TEST_USER);
+
+        assertObjectNotFoundException(new IDelegatedAction()
+            {
+                @Override
+                public void execute()
+                {
+                    executeQuery(TEST_USER, PASSWORD, new QueryName(queryWithNonExistentDB.getName()), null);
+                }
+            }, new QueryDatabaseName("idontexist"));
+    }
+
     @Test(dataProvider = PROVIDER_TRUE_FALSE)
     public void testExecuteWithOwner(boolean isPublic)
     {
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/ExecuteSqlTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/ExecuteSqlTest.java
index 07a3536fcc4..184517bda91 100644
--- a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/ExecuteSqlTest.java
+++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/ExecuteSqlTest.java
@@ -25,6 +25,7 @@ import org.testng.annotations.Test;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.TableModel;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.person.Person;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.project.id.ProjectIdentifier;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.query.id.QueryDatabaseName;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.roleassignment.Role;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.space.id.SpacePermId;
 import ch.systemsx.cisd.common.action.IDelegatedAction;
@@ -83,6 +84,19 @@ public class ExecuteSqlTest extends AbstractQueryTest
             }, "Unknown variable 'code'");
     }
 
+    @Test
+    public void testExecuteWithDatabaseNonexistent()
+    {
+        assertObjectNotFoundException(new IDelegatedAction()
+            {
+                @Override
+                public void execute()
+                {
+                    executeSql(TEST_USER, PASSWORD, SELECT_SPACE_CODES_SQL, new QueryDatabaseName("idontexist"), null);
+                }
+            }, new QueryDatabaseName("idontexist"));
+    }
+
     @Test
     public void testExecuteWithDatabaseWithSpaceNullUsingSpaceObserver()
     {
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/GetQueryTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/GetQueryTest.java
index 6ee05ae66c0..bd81b1beebe 100644
--- a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/GetQueryTest.java
+++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/GetQueryTest.java
@@ -36,6 +36,7 @@ import ch.ethz.sis.openbis.generic.asapi.v3.dto.query.id.QueryDatabaseName;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.query.id.QueryName;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.query.id.QueryTechId;
 import ch.systemsx.cisd.common.action.IDelegatedAction;
+import ch.systemsx.cisd.openbis.generic.shared.dto.QueryPE;
 import ch.systemsx.cisd.openbis.systemtest.authorization.ProjectAuthorizationUser;
 
 /**
@@ -231,6 +232,19 @@ public class GetQueryTest extends AbstractQueryTest
         assertEquals(query.getRegistrator().getUserId(), TEST_USER);
     }
 
+    @Test
+    public void testGetWithQueryThatBelongsToNonexistentDatabase()
+    {
+        QueryPE queryWithExistingDB = createQueryWithExistingDB(TEST_USER);
+        QueryPE queryWithNonExistentDB = createQueryWithNonExistentDB(TEST_USER);
+
+        Query query = getQuery(TEST_USER, PASSWORD, new QueryName(queryWithExistingDB.getName()));
+        assertEquals(query.getName(), queryWithExistingDB.getName());
+
+        query = getQuery(TEST_USER, PASSWORD, new QueryName(queryWithNonExistentDB.getName()));
+        assertNull(query);
+    }
+
     @Test(dataProvider = PROVIDER_TRUE_FALSE)
     public void testGetWithOwner(boolean isPublic)
     {
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/SearchQueryTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/SearchQueryTest.java
index c041ee4bd73..28f084c4ac0 100644
--- a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/SearchQueryTest.java
+++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/SearchQueryTest.java
@@ -31,6 +31,7 @@ import ch.ethz.sis.openbis.generic.asapi.v3.dto.query.id.QueryName;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.query.id.QueryTechId;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.query.search.QuerySearchCriteria;
 import ch.systemsx.cisd.common.action.IDelegatedAction;
+import ch.systemsx.cisd.openbis.generic.shared.dto.QueryPE;
 import ch.systemsx.cisd.openbis.systemtest.authorization.ProjectAuthorizationUser;
 
 /**
@@ -144,6 +145,19 @@ public class SearchQueryTest extends AbstractQueryTest
         testSearch(TEST_USER, criteria);
     }
 
+    @Test
+    public void testSearchWithQueryThatBelongsToNonexistentDatabase()
+    {
+        QueryPE queryWithExistingDB = createQueryWithExistingDB(TEST_USER);
+        QueryPE queryWithNonExistentDB = createQueryWithNonExistentDB(TEST_USER);
+
+        QuerySearchCriteria criteria = new QuerySearchCriteria();
+        criteria.withOrOperator();
+        criteria.withName().thatEquals(queryWithExistingDB.getName());
+        criteria.withName().thatEquals(queryWithNonExistentDB.getName());
+        testSearch(TEST_USER, criteria, queryWithExistingDB.getName());
+    }
+
     @Test
     public void testSearchWithNameThatEquals()
     {
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/UpdateQueryTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/UpdateQueryTest.java
index 6e7a2fe6bda..d29b7466f77 100644
--- a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/UpdateQueryTest.java
+++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/UpdateQueryTest.java
@@ -27,6 +27,7 @@ import ch.ethz.sis.openbis.generic.asapi.v3.dto.query.id.QueryDatabaseName;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.query.id.QueryName;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.query.update.QueryUpdate;
 import ch.systemsx.cisd.common.action.IDelegatedAction;
+import ch.systemsx.cisd.openbis.generic.shared.dto.QueryPE;
 
 /**
  * @author pkupczyk
@@ -172,6 +173,24 @@ public class UpdateQueryTest extends AbstractQueryTest
             }, update.getDatabaseId().getValue());
     }
 
+    @Test
+    public void testUpdateWithQueryThatBelongsToNonexistentDatabase()
+    {
+        QueryPE queryWithNonExistentDB = createQueryWithNonExistentDB(TEST_USER);
+
+        QueryUpdate update = new QueryUpdate();
+        update.setQueryId(new QueryName(queryWithNonExistentDB.getName()));
+
+        assertObjectNotFoundException(new IDelegatedAction()
+            {
+                @Override
+                public void execute()
+                {
+                    updateQuery(TEST_USER, PASSWORD, update);
+                }
+            }, new QueryDatabaseName("idontexist"));
+    }
+
     @Test
     public void testUpdateWithQueryTypeNull()
     {
-- 
GitLab