Add query reference web-service.

Change-Id: Ic8e8818ea7ade9e1c330ddcb9e9e6851c62adfd1
diff --git a/full/Changes b/full/Changes
index 2c91a36..f77d0fa 100644
--- a/full/Changes
+++ b/full/Changes
@@ -15,6 +15,8 @@
    - Fixed running pipe and updated tests with mockserver (margaretha)
 01/02/2021
    - Updated methods dependent to Antrl4-maven-plugin libraries (margaretha)   
+05/02/2021
+   - Add query reference web-service (diewald,margaretha)   
 
 # version 0.62.4
 24/01/2020
diff --git a/full/src/main/java/de/ids_mannheim/korap/config/NamedVCLoader.java b/full/src/main/java/de/ids_mannheim/korap/config/NamedVCLoader.java
index eaa462e..57d1d9b 100644
--- a/full/src/main/java/de/ids_mannheim/korap/config/NamedVCLoader.java
+++ b/full/src/main/java/de/ids_mannheim/korap/config/NamedVCLoader.java
@@ -17,7 +17,8 @@
 import org.springframework.stereotype.Component;
 
 import de.ids_mannheim.korap.KrillCollection;
-import de.ids_mannheim.korap.constant.VirtualCorpusType;
+import de.ids_mannheim.korap.constant.QueryType;
+import de.ids_mannheim.korap.constant.ResourceType;
 import de.ids_mannheim.korap.entity.VirtualCorpus;
 import de.ids_mannheim.korap.exceptions.KustvaktException;
 import de.ids_mannheim.korap.service.VirtualCorpusService;
@@ -59,8 +60,9 @@
         String json = IOUtils.toString(is, "utf-8");
         if (json != null) {
             cacheVC(json, filename);
-            vcService.storeVC(filename, VirtualCorpusType.SYSTEM, json, null,
-                    null, null, true, "system");
+            vcService.storeVC(filename, ResourceType.SYSTEM,
+                    QueryType.VIRTUAL_CORPUS, json, null, null, null, true,
+                    "system");
         }
     }
 
@@ -100,8 +102,9 @@
                     // ignore
                     if (DEBUG) jlog.debug(e);
                 }
-                vcService.storeVC(filename, VirtualCorpusType.SYSTEM, json,
-                        null, null, null, true, "system");
+                vcService.storeVC(filename, ResourceType.SYSTEM,
+                        QueryType.VIRTUAL_CORPUS, json, null, null, null, true,
+                        "system");
             }
         }
     }
diff --git a/full/src/main/java/de/ids_mannheim/korap/constant/QueryType.java b/full/src/main/java/de/ids_mannheim/korap/constant/QueryType.java
new file mode 100644
index 0000000..d223056
--- /dev/null
+++ b/full/src/main/java/de/ids_mannheim/korap/constant/QueryType.java
@@ -0,0 +1,7 @@
+package de.ids_mannheim.korap.constant;
+
+public enum QueryType {
+
+    QUERY,
+    VIRTUAL_CORPUS;
+}
diff --git a/full/src/main/java/de/ids_mannheim/korap/constant/VirtualCorpusType.java b/full/src/main/java/de/ids_mannheim/korap/constant/ResourceType.java
similarity index 95%
rename from full/src/main/java/de/ids_mannheim/korap/constant/VirtualCorpusType.java
rename to full/src/main/java/de/ids_mannheim/korap/constant/ResourceType.java
index 0aea814..27cd9b8 100644
--- a/full/src/main/java/de/ids_mannheim/korap/constant/VirtualCorpusType.java
+++ b/full/src/main/java/de/ids_mannheim/korap/constant/ResourceType.java
@@ -12,7 +12,7 @@
  *   This should probably be renamed to something like RessourceType,
  *   as QueryReferences will use the same types.
  */
-public enum VirtualCorpusType {
+public enum ResourceType {
     /**
      * available for all
      */
diff --git a/full/src/main/java/de/ids_mannheim/korap/dao/QueryReferenceDao.java b/full/src/main/java/de/ids_mannheim/korap/dao/QueryReferenceDao.java
index 2d849b6..0cb4ae7 100644
--- a/full/src/main/java/de/ids_mannheim/korap/dao/QueryReferenceDao.java
+++ b/full/src/main/java/de/ids_mannheim/korap/dao/QueryReferenceDao.java
@@ -17,7 +17,7 @@
 import de.ids_mannheim.korap.exceptions.KustvaktException;
 import de.ids_mannheim.korap.exceptions.StatusCodes;
 
-import de.ids_mannheim.korap.constant.VirtualCorpusType;
+import de.ids_mannheim.korap.constant.ResourceType;
 import de.ids_mannheim.korap.utils.ParameterChecker;
 
 import de.ids_mannheim.korap.entity.QueryReference;
@@ -47,7 +47,7 @@
      */
     public int createQuery(
         String qName,
-        VirtualCorpusType type,
+        ResourceType type,
         // CorpusAccess requiredAccess,
         String koralQuery,
         String definition,
diff --git a/full/src/main/java/de/ids_mannheim/korap/dao/VirtualCorpusDao.java b/full/src/main/java/de/ids_mannheim/korap/dao/VirtualCorpusDao.java
index f367571..bbd9f2c 100644
--- a/full/src/main/java/de/ids_mannheim/korap/dao/VirtualCorpusDao.java
+++ b/full/src/main/java/de/ids_mannheim/korap/dao/VirtualCorpusDao.java
@@ -21,9 +21,10 @@
 import org.springframework.transaction.annotation.Transactional;
 
 import de.ids_mannheim.korap.constant.GroupMemberStatus;
+import de.ids_mannheim.korap.constant.QueryType;
 import de.ids_mannheim.korap.constant.UserGroupStatus;
 import de.ids_mannheim.korap.constant.VirtualCorpusAccessStatus;
-import de.ids_mannheim.korap.constant.VirtualCorpusType;
+import de.ids_mannheim.korap.constant.ResourceType;
 import de.ids_mannheim.korap.entity.UserGroup;
 import de.ids_mannheim.korap.entity.UserGroupMember;
 import de.ids_mannheim.korap.entity.UserGroupMember_;
@@ -52,14 +53,15 @@
     @PersistenceContext
     private EntityManager entityManager;
 
-    public int createVirtualCorpus (String name, VirtualCorpusType type,
-            CorpusAccess requiredAccess, String koralQuery, String definition,
-            String description, String status, boolean isCached,
-            String createdBy) throws KustvaktException {
+    public int createVirtualCorpus (String name, ResourceType type,
+            QueryType queryType, CorpusAccess requiredAccess, String koralQuery,
+            String definition, String description, String status,
+            boolean isCached, String createdBy) throws KustvaktException {
 
         VirtualCorpus vc = new VirtualCorpus();
         vc.setName(name);
         vc.setType(type);
+        vc.setQueryType(queryType);
         vc.setRequiredAccess(requiredAccess);
         vc.setKoralQuery(koralQuery);
         vc.setDefinition(definition);
@@ -73,7 +75,7 @@
     }
 
     public void editVirtualCorpus (VirtualCorpus vc, String name,
-            VirtualCorpusType type, CorpusAccess requiredAccess,
+            ResourceType type, CorpusAccess requiredAccess,
             String koralQuery, String definition, String description,
             String status, boolean isCached) throws KustvaktException {
 
@@ -121,14 +123,14 @@
      * retrieves virtual corpora of all users.
      * 
      * @param type
-     *            {@link VirtualCorpusType}
+     *            {@link ResourceType}
      * @param createdBy
      *            username of the virtual corpus creator
      * @return a list of {@link VirtualCorpus}
      * @throws KustvaktException
      */
     @SuppressWarnings("unchecked")
-    public List<VirtualCorpus> retrieveVCByType (VirtualCorpusType type,
+    public List<VirtualCorpus> retrieveVCByType (ResourceType type,
             String createdBy) throws KustvaktException {
 
         CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
@@ -246,7 +248,7 @@
 
     @SuppressWarnings("unchecked")
     public List<VirtualCorpus> retrieveOwnerVCByType (String userId,
-            VirtualCorpusType type) throws KustvaktException {
+            ResourceType type) throws KustvaktException {
         ParameterChecker.checkStringValue(userId, "userId");
 
         CriteriaBuilder builder = entityManager.getCriteriaBuilder();
@@ -322,7 +324,7 @@
                 builder.equal(virtualCorpus.get(VirtualCorpus_.createdBy),
                         userId),
                 builder.equal(virtualCorpus.get(VirtualCorpus_.type),
-                        VirtualCorpusType.SYSTEM));
+                        ResourceType.SYSTEM));
 
         query.select(virtualCorpus);
         query.where(predicate);
diff --git a/full/src/main/java/de/ids_mannheim/korap/dto/VirtualCorpusDto.java b/full/src/main/java/de/ids_mannheim/korap/dto/VirtualCorpusDto.java
index ae530c2..878dcf4 100644
--- a/full/src/main/java/de/ids_mannheim/korap/dto/VirtualCorpusDto.java
+++ b/full/src/main/java/de/ids_mannheim/korap/dto/VirtualCorpusDto.java
@@ -1,5 +1,8 @@
 package de.ids_mannheim.korap.dto;
 
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+
 import de.ids_mannheim.korap.entity.VirtualCorpus;
 import lombok.Getter;
 import lombok.Setter;
@@ -12,6 +15,7 @@
  */
 @Getter
 @Setter
+@JsonInclude(Include.NON_DEFAULT)
 public class VirtualCorpusDto {
 
     private int id;
diff --git a/full/src/main/java/de/ids_mannheim/korap/dto/converter/VirtualCorpusConverter.java b/full/src/main/java/de/ids_mannheim/korap/dto/converter/VirtualCorpusConverter.java
index f9872f7..fb16932 100644
--- a/full/src/main/java/de/ids_mannheim/korap/dto/converter/VirtualCorpusConverter.java
+++ b/full/src/main/java/de/ids_mannheim/korap/dto/converter/VirtualCorpusConverter.java
@@ -33,12 +33,13 @@
         dto.setType(vc.getType().displayName());
         dto.setKoralQuery(vc.getKoralQuery());
 
-        JsonNode node = JsonUtils.readTree(statistics);
-        dto.setNumberOfDoc(node.at("/documents").asInt());
-        dto.setNumberOfParagraphs(node.at("/paragraphs").asInt());
-        dto.setNumberOfSentences(node.at("/sentences").asInt());
-        dto.setNumberOfTokens(node.at("/tokens").asInt());
-
+        if (statistics != null) {
+            JsonNode node = JsonUtils.readTree(statistics);
+            dto.setNumberOfDoc(node.at("/documents").asInt());
+            dto.setNumberOfParagraphs(node.at("/paragraphs").asInt());
+            dto.setNumberOfSentences(node.at("/sentences").asInt());
+            dto.setNumberOfTokens(node.at("/tokens").asInt());
+        }
         return dto;
 
     }
diff --git a/full/src/main/java/de/ids_mannheim/korap/entity/QueryReference.java b/full/src/main/java/de/ids_mannheim/korap/entity/QueryReference.java
index 2a6ecff..1a9c843 100644
--- a/full/src/main/java/de/ids_mannheim/korap/entity/QueryReference.java
+++ b/full/src/main/java/de/ids_mannheim/korap/entity/QueryReference.java
@@ -14,7 +14,7 @@
 import javax.persistence.OneToMany;
 import javax.persistence.Table;
 
-import de.ids_mannheim.korap.constant.VirtualCorpusType;
+import de.ids_mannheim.korap.constant.ResourceType;
 import lombok.Getter;
 import lombok.Setter;
 
@@ -39,7 +39,7 @@
     private int id;
     private String name;
     @Enumerated(EnumType.STRING)
-    private VirtualCorpusType type; // TODO (nd): This should be named RessourceType
+    private ResourceType type;
     private String status;
     private String description;
     // @Enumerated(EnumType.STRING)
diff --git a/full/src/main/java/de/ids_mannheim/korap/entity/VirtualCorpus.java b/full/src/main/java/de/ids_mannheim/korap/entity/VirtualCorpus.java
index 24bdc6d..1f83756 100644
--- a/full/src/main/java/de/ids_mannheim/korap/entity/VirtualCorpus.java
+++ b/full/src/main/java/de/ids_mannheim/korap/entity/VirtualCorpus.java
@@ -14,7 +14,8 @@
 import javax.persistence.OneToMany;
 import javax.persistence.Table;
 
-import de.ids_mannheim.korap.constant.VirtualCorpusType;
+import de.ids_mannheim.korap.constant.QueryType;
+import de.ids_mannheim.korap.constant.ResourceType;
 import de.ids_mannheim.korap.user.User.CorpusAccess;
 import lombok.Getter;
 import lombok.Setter;
@@ -43,7 +44,10 @@
     private int id;
     private String name;
     @Enumerated(EnumType.STRING)
-    private VirtualCorpusType type;
+    private ResourceType type;
+    @Enumerated(EnumType.STRING)
+    @Column(name = "query_type")
+    private QueryType queryType;
     private String status;
     private String description;
     @Enumerated(EnumType.STRING)
diff --git a/full/src/main/java/de/ids_mannheim/korap/service/QueryReferenceService.java b/full/src/main/java/de/ids_mannheim/korap/service/QueryReferenceService.java
index 04d7b67..fe76821 100644
--- a/full/src/main/java/de/ids_mannheim/korap/service/QueryReferenceService.java
+++ b/full/src/main/java/de/ids_mannheim/korap/service/QueryReferenceService.java
@@ -17,7 +17,7 @@
 import de.ids_mannheim.korap.dao.AdminDao;
 import de.ids_mannheim.korap.dao.QueryReferenceDao;
 
-import de.ids_mannheim.korap.constant.VirtualCorpusType;
+import de.ids_mannheim.korap.constant.ResourceType;
 
 import de.ids_mannheim.korap.entity.QueryReference;
 
@@ -116,7 +116,7 @@
         try {
             qId = qDao.createQuery(
                 qName,
-                VirtualCorpusType.PRIVATE,
+                ResourceType.PRIVATE,
                 qJson,
                 "", // TODO: definition,
                 desc,
@@ -145,7 +145,75 @@
         //   based on its type.
     };
 
+    /*
+    public Status handlePutRequest (String username,
+                                    String qCreator,
+                                    String qName,
+                                    String qJson) throws KustvaktException {
+        
+        verifyUsername(username, qCreator);
+        String q = vcDao.retrieveQueryByName(qName, qCreator);
+        // ParameterChecker.checkObjectValue(qJson, "request entity");
+        ParameterChecker.checkStringValue(qJson, "q");
+        if (q == null) {
+            storeQuery(qJson, qName, username);
+            return Status.CREATED;
+        }
+        else {
+            editQuery(q, qJson, qName, username);
+            return Status.NO_CONTENT;
+        };
+    };
+    */
 
+    /*
+    public void editQuery (QueryRefrence existingQ,
+                           String newQJson,
+                           String qName,
+                           String username) throws KustvaktException {
+
+        if (!username.equals(existingQ.getCreatedBy())
+            && !adminDao.isAdmin(username)) {
+            throw new KustvaktException(
+                StatusCodes.AUTHORIZATION_FAILED,
+                "Unauthorized operation for user: " + username, username);
+        };
+
+        String corpusQuery = newVC.getCorpusQuery();
+
+        if (newQJson != null && !newQJson.isEmpty()) {
+            koralQuery = serializeCorpusQuery(corpusQuery);
+            requiredAccess = determineRequiredAccess(newVC.isCached(), vcName,
+                    koralQuery);
+        };
+
+        VirtualCorpusType type = newVC.getType();
+        if (type != null) {
+            if (existingVC.getType().equals(VirtualCorpusType.PUBLISHED)) {
+                // withdraw from publication
+                if (!type.equals(VirtualCorpusType.PUBLISHED)) {
+                    VirtualCorpusAccess hiddenAccess =
+                            accessDao.retrieveHiddenAccess(existingVC.getId());
+                    deleteVCAccess(hiddenAccess.getId(), "system");
+                    int groupId = hiddenAccess.getUserGroup().getId();
+                    userGroupService.deleteAutoHiddenGroup(groupId, "system");
+                    // EM: should the users within the hidden group receive 
+                    // notifications? 
+                }
+                // else remains the same
+            }
+            else if (type.equals(VirtualCorpusType.PUBLISHED)) {
+                publishVC(existingVC.getId());
+            }
+        }
+
+        vcDao.editVirtualCorpus(existingVC, vcName, type, requiredAccess,
+                koralQuery, newVC.getDefinition(), newVC.getDescription(),
+                newVC.getStatus(), newVC.isCached());
+    }
+    */
+
+    
     /**
      * Only admin and the owner of the virtual corpus are allowed to
      * delete a virtual corpus.
@@ -180,4 +248,53 @@
                 "Unauthorized operation for user: " + username, username);
         };
     };
+
+
+    /*
+    public void editVC (
+        VirtualCorpus existingVC,
+        VirtualCorpusJson newVC,
+        String vcName,
+        String username) throws KustvaktException {
+
+        if (!username.equals(existingVC.getCreatedBy())
+                && !adminDao.isAdmin(username)) {
+            throw new KustvaktException(StatusCodes.AUTHORIZATION_FAILED,
+                    "Unauthorized operation for user: " + username, username);
+        }
+
+        String koralQuery = null;
+        CorpusAccess requiredAccess = null;
+        String corpusQuery = newVC.getCorpusQuery();
+        if (corpusQuery != null && !corpusQuery.isEmpty()) {
+            koralQuery = serializeCorpusQuery(corpusQuery);
+            requiredAccess = determineRequiredAccess(newVC.isCached(), vcName,
+                    koralQuery);
+        }
+
+        VirtualCorpusType type = newVC.getType();
+        if (type != null) {
+            if (existingVC.getType().equals(VirtualCorpusType.PUBLISHED)) {
+                // withdraw from publication
+                if (!type.equals(VirtualCorpusType.PUBLISHED)) {
+                    VirtualCorpusAccess hiddenAccess =
+                            accessDao.retrieveHiddenAccess(existingVC.getId());
+                    deleteVCAccess(hiddenAccess.getId(), "system");
+                    int groupId = hiddenAccess.getUserGroup().getId();
+                    userGroupService.deleteAutoHiddenGroup(groupId, "system");
+                    // EM: should the users within the hidden group receive 
+                    // notifications? 
+                }
+                // else remains the same
+            }
+            else if (type.equals(VirtualCorpusType.PUBLISHED)) {
+                publishVC(existingVC.getId());
+            }
+        }
+
+        vcDao.editVirtualCorpus(existingVC, vcName, type, requiredAccess,
+                koralQuery, newVC.getDefinition(), newVC.getDescription(),
+                newVC.getStatus(), newVC.isCached());
+    }
+    */
 };
diff --git a/full/src/main/java/de/ids_mannheim/korap/service/VirtualCorpusService.java b/full/src/main/java/de/ids_mannheim/korap/service/VirtualCorpusService.java
index 1163573..9d5ea85 100644
--- a/full/src/main/java/de/ids_mannheim/korap/service/VirtualCorpusService.java
+++ b/full/src/main/java/de/ids_mannheim/korap/service/VirtualCorpusService.java
@@ -20,8 +20,9 @@
 import de.ids_mannheim.korap.KrillCollection;
 import de.ids_mannheim.korap.config.FullConfiguration;
 import de.ids_mannheim.korap.constant.GroupMemberStatus;
+import de.ids_mannheim.korap.constant.QueryType;
 import de.ids_mannheim.korap.constant.VirtualCorpusAccessStatus;
-import de.ids_mannheim.korap.constant.VirtualCorpusType;
+import de.ids_mannheim.korap.constant.ResourceType;
 import de.ids_mannheim.korap.dao.AdminDao;
 import de.ids_mannheim.korap.dao.VirtualCorpusAccessDao;
 import de.ids_mannheim.korap.dao.VirtualCorpusDao;
@@ -42,7 +43,7 @@
 import de.ids_mannheim.korap.utils.ParameterChecker;
 import de.ids_mannheim.korap.web.SearchKrill;
 import de.ids_mannheim.korap.web.controller.VirtualCorpusController;
-import de.ids_mannheim.korap.web.input.VirtualCorpusJson;
+import de.ids_mannheim.korap.web.input.QueryJson;
 
 /**
  * VirtualCorpusService handles the logic behind
@@ -119,7 +120,7 @@
     }
 
     public List<VirtualCorpusDto> listVCByType (String username,
-            String createdBy, VirtualCorpusType type) throws KustvaktException {
+            String createdBy, ResourceType type) throws KustvaktException {
 
         boolean isAdmin = adminDao.isAdmin(username);
 
@@ -168,7 +169,7 @@
 
         if (vc.getCreatedBy().equals(username) || adminDao.isAdmin(username)) {
 
-            if (vc.getType().equals(VirtualCorpusType.PUBLISHED)) {
+            if (vc.getType().equals(ResourceType.PUBLISHED)) {
                 VirtualCorpusAccess access =
                         accessDao.retrieveHiddenAccess(vcId);
                 accessDao.deleteAccess(access, "system");
@@ -209,7 +210,7 @@
         else if (vc.getCreatedBy().equals(username)
                 || adminDao.isAdmin(username)) {
 
-            if (vc.getType().equals(VirtualCorpusType.PUBLISHED)) {
+            if (vc.getType().equals(ResourceType.PUBLISHED)) {
                 VirtualCorpusAccess access =
                         accessDao.retrieveHiddenAccess(vc.getId());
                 accessDao.deleteAccess(access, "system");
@@ -236,7 +237,7 @@
 //    }
 
     public Status handlePutRequest (String username, String vcCreator,
-            String vcName, VirtualCorpusJson vcJson) throws KustvaktException {
+            String vcName, QueryJson vcJson) throws KustvaktException {
         
         verifyUsername(username, vcCreator);
         VirtualCorpus vc = vcDao.retrieveVCByName(vcName, vcCreator);
@@ -251,7 +252,7 @@
         }
     }
 
-    public void editVC (VirtualCorpus existingVC, VirtualCorpusJson newVC,
+    public void editVC (VirtualCorpus existingVC, QueryJson newVC,
             String vcName, String username) throws KustvaktException {
 
         if (!username.equals(existingVC.getCreatedBy())
@@ -269,11 +270,11 @@
                     koralQuery);
         }
 
-        VirtualCorpusType type = newVC.getType();
+        ResourceType type = newVC.getType();
         if (type != null) {
-            if (existingVC.getType().equals(VirtualCorpusType.PUBLISHED)) {
+            if (existingVC.getType().equals(ResourceType.PUBLISHED)) {
                 // withdraw from publication
-                if (!type.equals(VirtualCorpusType.PUBLISHED)) {
+                if (!type.equals(ResourceType.PUBLISHED)) {
                     VirtualCorpusAccess hiddenAccess =
                             accessDao.retrieveHiddenAccess(existingVC.getId());
                     deleteVCAccess(hiddenAccess.getId(), "system");
@@ -284,7 +285,7 @@
                 }
                 // else remains the same
             }
-            else if (type.equals(VirtualCorpusType.PUBLISHED)) {
+            else if (type.equals(ResourceType.PUBLISHED)) {
                 publishVC(existingVC.getId());
             }
         }
@@ -314,18 +315,27 @@
         }
     }
 
-    public void storeVC (VirtualCorpusJson vc, String vcName, String createdBy)
+    public void storeVC (QueryJson vc, String vcName, String createdBy)
             throws KustvaktException {
-        ParameterChecker.checkStringValue(vc.getCorpusQuery(), "corpusQuery");
-        String koralQuery = serializeCorpusQuery(vc.getCorpusQuery());
-
-        storeVC(vcName, vc.getType(), koralQuery, vc.getDefinition(),
+        String koralQuery = null;
+        if (vc.getQueryType().equals(QueryType.VIRTUAL_CORPUS)){
+            ParameterChecker.checkStringValue(vc.getCorpusQuery(), "corpusQuery");
+            koralQuery = serializeCorpusQuery(vc.getCorpusQuery());
+        }
+        else if (vc.getQueryType().equals(QueryType.QUERY)){
+            ParameterChecker.checkStringValue(vc.getQuery(), "query");
+            ParameterChecker.checkStringValue(vc.getQueryLanguage(), "queryLanguage");
+            koralQuery = serializeQuery(vc.getQuery(), vc.getQueryLanguage());
+        }
+        
+        storeVC(vcName, vc.getType(), vc.getQueryType(), koralQuery, vc.getDefinition(),
                 vc.getDescription(), vc.getStatus(), vc.isCached(), createdBy);
     }
 
-    public void storeVC (String vcName, VirtualCorpusType type, String koralQuery,
-            String definition, String description, String status,
-            boolean isCached, String username) throws KustvaktException {
+    public void storeVC (String vcName, ResourceType type,
+            QueryType queryType, String koralQuery, String definition,
+            String description, String status, boolean isCached,
+            String username) throws KustvaktException {
         ParameterChecker.checkNameValue(vcName, "vcName");
         ParameterChecker.checkObjectValue(type, "type");
 
@@ -336,7 +346,7 @@
                     vcName);
         }
 
-        if (type.equals(VirtualCorpusType.SYSTEM) && !username.equals("system")
+        if (type.equals(ResourceType.SYSTEM) && !username.equals("system")
                 && !adminDao.isAdmin(username)) {
             throw new KustvaktException(StatusCodes.AUTHORIZATION_FAILED,
                     "Unauthorized operation for user: " + username, username);
@@ -348,9 +358,9 @@
         if (DEBUG) jlog.debug("Storing VC " + vcName + "in the database ");
         int vcId = 0;
         try {
-            vcId = vcDao.createVirtualCorpus(vcName, type, requiredAccess,
-                    koralQuery, definition, description, status, isCached,
-                    username);
+            vcId = vcDao.createVirtualCorpus(vcName, type, queryType,
+                    requiredAccess, koralQuery, definition, description, status,
+                    isCached, username);
 
         }
         catch (Exception e) {
@@ -366,7 +376,7 @@
             throw new KustvaktException(StatusCodes.DB_INSERT_FAILED,
                     cause.getMessage());
         }
-        if (type.equals(VirtualCorpusType.PUBLISHED)) {
+        if (type.equals(ResourceType.PUBLISHED)) {
             publishVC(vcId);
         }
     }
@@ -388,6 +398,17 @@
         }
         return koralQuery;
     }
+    
+    private String serializeQuery (String query, String queryLanguage)
+            throws KustvaktException {
+        QuerySerializer serializer = new QuerySerializer();
+        String koralQuery;
+            koralQuery = serializer.setQuery(query, queryLanguage).toJSON();
+        if (DEBUG) {
+            jlog.debug(koralQuery);
+        }
+        return koralQuery;
+    }
 
     public CorpusAccess determineRequiredAccess (boolean isCached, String name,
             String koralQuery) throws KustvaktException {
@@ -474,7 +495,7 @@
                         cause.getMessage());
             }
             
-            vcDao.editVirtualCorpus(vc, null, VirtualCorpusType.PROJECT, null,
+            vcDao.editVirtualCorpus(vc, null, ResourceType.PROJECT, null,
                     null, null, null, null, vc.isCached());
         }
     }
@@ -618,7 +639,10 @@
             String createdBy) throws KustvaktException {
         VirtualCorpus vc = searchVCByName(username, vcName, createdBy);
         String json = vc.getKoralQuery();
-        String statistics = krill.getStatistics(json);
+        String statistics = null;
+        if (vc.getQueryType().equals(QueryType.VIRTUAL_CORPUS)){
+            statistics = krill.getStatistics(json);
+        }
         return converter.createVirtualCorpusDto(vc, statistics);
     }
 
@@ -634,19 +658,19 @@
 
     private void checkVCAccess (VirtualCorpus vc, String username)
             throws KustvaktException {
-        VirtualCorpusType type = vc.getType();
+        ResourceType type = vc.getType();
 
         if (!adminDao.isAdmin(username)
                 && !username.equals(vc.getCreatedBy())) {
-            if (type.equals(VirtualCorpusType.PRIVATE)
-                    || (type.equals(VirtualCorpusType.PROJECT)
+            if (type.equals(ResourceType.PRIVATE)
+                    || (type.equals(ResourceType.PROJECT)
                             && !hasAccess(username, vc.getId()))) {
                 throw new KustvaktException(StatusCodes.AUTHORIZATION_FAILED,
                         "Unauthorized operation for user: " + username,
                         username);
             }
 
-            else if (VirtualCorpusType.PUBLISHED.equals(type)
+            else if (ResourceType.PUBLISHED.equals(type)
                     && !username.equals("guest")) {
                 // add user in the VC's auto group
                 UserGroup userGroup = userGroupService
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/controller/QueryReferenceController.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/QueryReferenceController.java
new file mode 100644
index 0000000..ff8f35b
--- /dev/null
+++ b/full/src/main/java/de/ids_mannheim/korap/web/controller/QueryReferenceController.java
@@ -0,0 +1,165 @@
+package de.ids_mannheim.korap.web.controller;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.SecurityContext;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+
+import com.sun.jersey.spi.container.ResourceFilters;
+
+import de.ids_mannheim.korap.constant.OAuth2Scope;
+import de.ids_mannheim.korap.constant.QueryType;
+import de.ids_mannheim.korap.dto.VirtualCorpusDto;
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.oauth2.service.OAuth2ScopeService;
+import de.ids_mannheim.korap.security.context.TokenContext;
+import de.ids_mannheim.korap.service.VirtualCorpusService;
+import de.ids_mannheim.korap.web.KustvaktResponseHandler;
+import de.ids_mannheim.korap.web.filter.APIVersionFilter;
+import de.ids_mannheim.korap.web.filter.AuthenticationFilter;
+import de.ids_mannheim.korap.web.filter.BlockingFilter;
+import de.ids_mannheim.korap.web.filter.DemoUserFilter;
+import de.ids_mannheim.korap.web.filter.PiwikFilter;
+import de.ids_mannheim.korap.web.input.QueryJson;
+
+/**
+ * QueryReferenceController defines web APIs related to the
+ * management of query references.
+ *
+ * This controller is based on VirtualCorpusController.
+ *
+ * @author diewald, margaretha
+ *
+ */
+@Controller
+@Path("{version}/query")
+@ResourceFilters({ APIVersionFilter.class, AuthenticationFilter.class,
+        BlockingFilter.class, PiwikFilter.class })
+public class QueryReferenceController {
+
+    @Autowired
+    private KustvaktResponseHandler kustvaktResponseHandler;
+    @Autowired
+    private VirtualCorpusService service;
+    @Autowired
+    private OAuth2ScopeService scopeService;
+
+    /**
+     * Creates a query reference according to the given Json.
+     * The query reference creator must be the same as the
+     * authenticated username.
+     * 
+     * TODO: In the future, this may also update a query.
+     *
+     * @param securityContext
+     * @param qCreator
+     *            the username of the vc creator, must be the same
+     *            as the authenticated username
+     * @param qName
+     *           the vc name
+     * @param query a json object describing the query and its properties
+     * @return
+     * @throws KustvaktException
+     */
+    @PUT
+    @Path("/~{qCreator}/{qName}")
+    @Consumes(MediaType.APPLICATION_JSON + ";charset=utf-8")
+    public Response createQuery (
+        @Context SecurityContext securityContext,
+        @PathParam("qCreator") String qCreator,
+        @PathParam("qName") String qName,
+        QueryJson query) throws KustvaktException {
+
+        TokenContext context =
+            (TokenContext) securityContext.getUserPrincipal();
+
+        try {
+            scopeService.verifyScope(context, OAuth2Scope.EDIT_VC);
+            Status status = service.handlePutRequest(context.getUsername(),
+                    qCreator, qName, query);
+            return Response.status(status).build();
+        }
+        catch (KustvaktException e) {
+            throw kustvaktResponseHandler.throwit(e);
+        }
+        
+    }
+
+    /**
+     * Returns the query with the given name and creator.
+     * 
+     * @param securityContext
+     * @param createdBy
+     *            query creator
+     * @param qName
+     *            query name
+     * @return the query with the given name and creator.
+     */
+    @GET
+    @Path("~{createdBy}/{qName}")
+    @Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
+    @ResourceFilters({ APIVersionFilter.class, AuthenticationFilter.class,
+        DemoUserFilter.class, PiwikFilter.class })
+    public VirtualCorpusDto retrieveQueryByName (
+            @Context SecurityContext securityContext,
+            @PathParam("createdBy") String createdBy,
+            @PathParam("qName") String qName) {
+        TokenContext context =
+                (TokenContext) securityContext.getUserPrincipal();
+        try {
+            scopeService.verifyScope(context, OAuth2Scope.VC_INFO);
+            return service.retrieveVCByName(context.getUsername(), qName,
+                    createdBy);
+        }
+        catch (KustvaktException e) {
+            throw kustvaktResponseHandler.throwit(e);
+        }
+    }
+
+    /**
+     * Only the VC owner and system admins can delete VC. VCA admins
+     * can delete VC-accesses e.g. of project VC, but not the VC
+     * themselves.
+     * 
+     * @param securityContext
+     * @param createdBy
+     *            vc creator
+     * @param vcName
+     *            vc name
+     * @return HTTP status 200, if successful
+     */
+    /*
+    @DELETE
+    @Path("~{createdBy}/{vcName}")
+    public Response deleteVCByName (@Context SecurityContext securityContext,
+            @PathParam("createdBy") String createdBy,
+            @PathParam("vcName") String vcName) {
+        TokenContext context =
+                (TokenContext) securityContext.getUserPrincipal();
+        try {
+            scopeService.verifyScope(context, OAuth2Scope.DELETE_VC);
+            service.deleteVCByName(context.getUsername(), vcName, createdBy);
+        }
+        catch (KustvaktException e) {
+        throw kustvaktResponseHandler.throwit(e);
+        }
+        return Response.ok().build();
+    };
+    */
+
+    
+    // TODO: List all queries available to the logged in user
+    // TODO: List all queries of a sepcific user
+    // TODO: Some admin routes missing.
+    // TODO: Some sharing routes missing
+};
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/controller/VirtualCorpusController.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/VirtualCorpusController.java
index 3509d03..645329e 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/controller/VirtualCorpusController.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/controller/VirtualCorpusController.java
@@ -23,7 +23,7 @@
 import com.sun.jersey.spi.container.ResourceFilters;
 
 import de.ids_mannheim.korap.constant.OAuth2Scope;
-import de.ids_mannheim.korap.constant.VirtualCorpusType;
+import de.ids_mannheim.korap.constant.ResourceType;
 import de.ids_mannheim.korap.dto.VirtualCorpusAccessDto;
 import de.ids_mannheim.korap.dto.VirtualCorpusDto;
 import de.ids_mannheim.korap.exceptions.KustvaktException;
@@ -36,7 +36,7 @@
 import de.ids_mannheim.korap.web.filter.BlockingFilter;
 import de.ids_mannheim.korap.web.filter.DemoUserFilter;
 import de.ids_mannheim.korap.web.filter.PiwikFilter;
-import de.ids_mannheim.korap.web.input.VirtualCorpusJson;
+import de.ids_mannheim.korap.web.input.QueryJson;
 
 /**
  * VirtualCorpusController defines web APIs related to virtual corpus
@@ -93,7 +93,7 @@
     public Response createUpdateVC (@Context SecurityContext securityContext,
             @PathParam("vcCreator") String vcCreator,
             @PathParam("vcName") String vcName,
-            VirtualCorpusJson vc) throws KustvaktException {
+            QueryJson vc) throws KustvaktException {
         TokenContext context =
                 (TokenContext) securityContext.getUserPrincipal();
 
@@ -213,7 +213,7 @@
      * @param createdBy
      *            username of virtual corpus creator
      * @param type
-     *            {@link VirtualCorpusType}
+     *            {@link ResourceType}
      * @return a list of virtual corpora
      */
     @GET
@@ -222,7 +222,7 @@
     public List<VirtualCorpusDto> listVCByType (
             @Context SecurityContext securityContext,
             @QueryParam("createdBy") String createdBy,
-            @QueryParam("type") VirtualCorpusType type) {
+            @QueryParam("type") ResourceType type) {
         TokenContext context =
                 (TokenContext) securityContext.getUserPrincipal();
         try {
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/input/VirtualCorpusJson.java b/full/src/main/java/de/ids_mannheim/korap/web/input/QueryJson.java
similarity index 62%
rename from full/src/main/java/de/ids_mannheim/korap/web/input/VirtualCorpusJson.java
rename to full/src/main/java/de/ids_mannheim/korap/web/input/QueryJson.java
index 1f14f9c..0e312d7 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/input/VirtualCorpusJson.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/input/QueryJson.java
@@ -1,7 +1,8 @@
 package de.ids_mannheim.korap.web.input;
 
 
-import de.ids_mannheim.korap.constant.VirtualCorpusType;
+import de.ids_mannheim.korap.constant.QueryType;
+import de.ids_mannheim.korap.constant.ResourceType;
 import de.ids_mannheim.korap.service.VirtualCorpusService;
 import de.ids_mannheim.korap.web.controller.VirtualCorpusController;
 import lombok.Getter;
@@ -16,16 +17,22 @@
  */
 @Getter
 @Setter
-public class VirtualCorpusJson {
+public class QueryJson {
     // default false
     private boolean isCached;
     
-    // required in creating VCs
-    private VirtualCorpusType type;
+    // required
+    private ResourceType type;
+    private QueryType queryType;
+    // required for queryType="VIRTUAL_CORPUS"
     private String corpusQuery;
+    // required for queryType="QUERY"
+    private String query;
+    private String queryLanguage;
     
     // optional
     private String definition;
     private String description;
     private String status;
+    private String queryVersion;
 }
\ No newline at end of file
diff --git a/full/src/main/resources/db/sqlite/V1.1__create_virtual_corpus_tables.sql b/full/src/main/resources/db/sqlite/V1.1__create_virtual_corpus_tables.sql
index dbb9901..3245040 100644
--- a/full/src/main/resources/db/sqlite/V1.1__create_virtual_corpus_tables.sql
+++ b/full/src/main/resources/db/sqlite/V1.1__create_virtual_corpus_tables.sql
@@ -69,6 +69,7 @@
   id INTEGER PRIMARY KEY AUTOINCREMENT,
   name VARCHAR(255) NOT NULL,
   type VARCHAR(100) NOT NULL,
+  query_type VARCHAR(100) NOT NULL,
   required_access VARCHAR(100) NOT NULL,
   created_by VARCHAR(100) NOT NULL,
   description VARCHAR(255) DEFAULT NULL,
diff --git a/full/src/main/resources/db/test/V3.1__insert_virtual_corpus.sql b/full/src/main/resources/db/test/V3.1__insert_virtual_corpus.sql
index ea8f1f7..778fb4b 100644
--- a/full/src/main/resources/db/test/V3.1__insert_virtual_corpus.sql
+++ b/full/src/main/resources/db/test/V3.1__insert_virtual_corpus.sql
@@ -61,28 +61,28 @@
 
 		
 -- virtual corpora
-INSERT INTO virtual_corpus(name, type, required_access, created_by, description, status, corpus_query) 
-	VALUES ("dory-vc", "PRIVATE", "FREE", "dory", "test vc", "experimental",
+INSERT INTO virtual_corpus(name, type, query_type, required_access, created_by, description, status, corpus_query) 
+	VALUES ("dory-vc", "PRIVATE", "VIRTUAL_CORPUS", "FREE", "dory", "test vc", "experimental",
 	'{"collection": { "@type": "koral:docGroup", "operands": [ { "@type": "koral:doc", "key": "corpusSigle", "match": "match:eq", "value": "GOE" }, { "@type": "koral:doc", "key": "creationDate", "match": "match:geq", "type": "type:date", "value": "1820" } ], "operation": "operation:and" }}');
 	
-INSERT INTO virtual_corpus(name, type, required_access, created_by, description, status, corpus_query) 
-	VALUES ("group-vc", "PROJECT", "PUB", "dory", "test vc", "experimental",
+INSERT INTO virtual_corpus(name, type, query_type, required_access, created_by, description, status, corpus_query) 
+	VALUES ("group-vc", "PROJECT", "VIRTUAL_CORPUS", "PUB", "dory", "test vc", "experimental",
 	'{"collection": { "@type": "koral:docGroup", "operands": [ { "@type": "koral:doc", "key": "corpusSigle", "match": "match:eq", "value": "GOE" }, { "@type": "koral:doc", "key": "creationDate", "match": "match:leq", "type": "type:date", "value": "1810" } ], "operation": "operation:and" }}');
 
-INSERT INTO virtual_corpus(name, type, required_access, created_by, description, status, corpus_query) 
-	VALUES ("system-vc", "SYSTEM", "ALL", "system", "test vc", "experimental",
+INSERT INTO virtual_corpus(name, type, query_type, required_access, created_by, description, status, corpus_query) 
+	VALUES ("system-vc", "SYSTEM", "VIRTUAL_CORPUS", "ALL", "system", "test vc", "experimental",
 	'{"collection":{"@type":"koral:doc","value":"GOE","match":"match:eq","key":"corpusSigle"}}');
 
-INSERT INTO virtual_corpus(name, type, required_access, created_by, description, status, corpus_query) 
-	VALUES ("published-vc", "PUBLISHED", "ALL", "marlin", "test vc", "experimental",
+INSERT INTO virtual_corpus(name, type, query_type, required_access, created_by, description, status, corpus_query) 
+	VALUES ("published-vc", "PUBLISHED", "VIRTUAL_CORPUS", "ALL", "marlin", "test vc", "experimental",
 	'{"collection":{"@type":"koral:doc","value":"GOE","match":"match:eq","key":"corpusSigle"}}');
 
-INSERT INTO virtual_corpus(name, type, required_access, created_by, description, status, corpus_query) 
-	VALUES ("marlin-vc", "PRIVATE", "FREE", "marlin", "marlin test share vc", "experimental",
+INSERT INTO virtual_corpus(name, type, query_type, required_access, created_by, description, status, corpus_query) 
+	VALUES ("marlin-vc", "PRIVATE", "VIRTUAL_CORPUS", "FREE", "marlin", "marlin test share vc", "experimental",
 	'{"collection": { "@type": "koral:docGroup", "operands": [ { "@type": "koral:doc", "key": "corpusSigle", "match": "match:eq", "value": "GOE" }, { "@type": "koral:doc", "key": "creationDate", "match": "match:geq", "type": "type:date", "value": "1820" } ], "operation": "operation:and" }}');
 
-INSERT INTO virtual_corpus(name, type, required_access, created_by, description, status, corpus_query) 
-	VALUES ("nemo-vc", "PRIVATE", "ALL", "nemo", "nemo test vc", "experimental",
+INSERT INTO virtual_corpus(name, type, query_type, required_access, created_by, description, status, corpus_query) 
+	VALUES ("nemo-vc", "PRIVATE", "VIRTUAL_CORPUS", "ALL", "nemo", "nemo test vc", "experimental",
 	'{"collection":{"@type":"koral:doc","value":"GOE","match":"match:eq","key":"corpusSigle"}}');	
 	
 -- virtual corpus access
diff --git a/full/src/test/java/de/ids_mannheim/korap/dao/UserGroupDaoTest.java b/full/src/test/java/de/ids_mannheim/korap/dao/UserGroupDaoTest.java
index 1aa6ca2..4d26b71 100644
--- a/full/src/test/java/de/ids_mannheim/korap/dao/UserGroupDaoTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/dao/UserGroupDaoTest.java
@@ -18,9 +18,10 @@
 import de.ids_mannheim.korap.config.FullConfiguration;
 import de.ids_mannheim.korap.constant.GroupMemberStatus;
 import de.ids_mannheim.korap.constant.PredefinedRole;
+import de.ids_mannheim.korap.constant.QueryType;
 import de.ids_mannheim.korap.constant.UserGroupStatus;
 import de.ids_mannheim.korap.constant.VirtualCorpusAccessStatus;
-import de.ids_mannheim.korap.constant.VirtualCorpusType;
+import de.ids_mannheim.korap.constant.ResourceType;
 import de.ids_mannheim.korap.entity.Role;
 import de.ids_mannheim.korap.entity.UserGroup;
 import de.ids_mannheim.korap.entity.UserGroupMember;
@@ -134,8 +135,9 @@
         String createdBy = "dory";
         String name = "dory new vc";
         int id = virtualCorpusDao.createVirtualCorpus(name,
-                VirtualCorpusType.PROJECT, CorpusAccess.PUB,
-                "corpusSigle=WPD15", "", "", "", false, createdBy);
+                ResourceType.PROJECT, QueryType.VIRTUAL_CORPUS,
+                CorpusAccess.PUB, "corpusSigle=WPD15", "", "", "", false,
+                createdBy);
 
         VirtualCorpus virtualCorpus = virtualCorpusDao.retrieveVCById(id);
         userGroupDao.addVCToGroup(virtualCorpus, createdBy,
diff --git a/full/src/test/java/de/ids_mannheim/korap/dao/VirtualCorpusDaoTest.java b/full/src/test/java/de/ids_mannheim/korap/dao/VirtualCorpusDaoTest.java
index 525f64a..266a67f 100644
--- a/full/src/test/java/de/ids_mannheim/korap/dao/VirtualCorpusDaoTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/dao/VirtualCorpusDaoTest.java
@@ -13,7 +13,8 @@
 import org.springframework.beans.factory.annotation.Autowired;
 
 import de.ids_mannheim.korap.config.SpringJerseyTest;
-import de.ids_mannheim.korap.constant.VirtualCorpusType;
+import de.ids_mannheim.korap.constant.QueryType;
+import de.ids_mannheim.korap.constant.ResourceType;
 import de.ids_mannheim.korap.entity.VirtualCorpus;
 import de.ids_mannheim.korap.exceptions.KustvaktException;
 import de.ids_mannheim.korap.user.User;
@@ -29,7 +30,7 @@
     @Test
     public void testListVCByType () throws KustvaktException {
         List<VirtualCorpus> vcList =
-                dao.retrieveVCByType(VirtualCorpusType.PUBLISHED, null);
+                dao.retrieveVCByType(ResourceType.PUBLISHED, null);
         assertEquals(1, vcList.size());
 
         VirtualCorpus vc = vcList.get(0);
@@ -41,13 +42,14 @@
     @Test
     public void testSystemVC () throws KustvaktException {
         // insert vc
-        int id = dao.createVirtualCorpus("system-vc", VirtualCorpusType.SYSTEM,
-                User.CorpusAccess.FREE, "corpusSigle=GOE", "definition",
-                "description", "experimental", false, "test class");
+        int id = dao.createVirtualCorpus("system-vc", ResourceType.SYSTEM,
+                QueryType.VIRTUAL_CORPUS, User.CorpusAccess.FREE,
+                "corpusSigle=GOE", "definition", "description", "experimental",
+                false, "test class");
 
         // select vc
         List<VirtualCorpus> vcList =
-                dao.retrieveVCByType(VirtualCorpusType.SYSTEM, null);
+                dao.retrieveVCByType(ResourceType.SYSTEM, null);
         assertEquals(2, vcList.size());
 
         VirtualCorpus vc = dao.retrieveVCById(id);
@@ -64,15 +66,16 @@
         thrown.expect(PersistenceException.class);
         thrown.expectMessage("could not execute statement");
         
-        dao.createVirtualCorpus("system-vc", VirtualCorpusType.SYSTEM,
-                User.CorpusAccess.FREE, "corpusSigle=GOE", "definition",
-                "description", "experimental", false, "system");
+        dao.createVirtualCorpus("system-vc", ResourceType.SYSTEM,
+                QueryType.VIRTUAL_CORPUS, User.CorpusAccess.FREE,
+                "corpusSigle=GOE", "definition", "description", "experimental",
+                false, "system");
     }
 
     @Test
     public void retrieveSystemVC () throws KustvaktException {
         List<VirtualCorpus> vc =
-                dao.retrieveVCByType(VirtualCorpusType.SYSTEM, null);
+                dao.retrieveVCByType(ResourceType.SYSTEM, null);
         assertEquals(1, vc.size());
     }
 
diff --git a/full/src/test/java/de/ids_mannheim/korap/service/QueryReferenceServiceTest.java b/full/src/test/java/de/ids_mannheim/korap/service/QueryReferenceServiceTest.java
index 93d1133..cb3adbf 100644
--- a/full/src/test/java/de/ids_mannheim/korap/service/QueryReferenceServiceTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/service/QueryReferenceServiceTest.java
@@ -17,13 +17,13 @@
 import com.fasterxml.jackson.databind.JsonNode;
 
 import de.ids_mannheim.korap.constant.UserGroupStatus;
-import de.ids_mannheim.korap.constant.VirtualCorpusType;
+import de.ids_mannheim.korap.constant.ResourceType;
 import de.ids_mannheim.korap.dto.VirtualCorpusAccessDto;
 import de.ids_mannheim.korap.dto.VirtualCorpusDto;
 import de.ids_mannheim.korap.entity.UserGroup;
 import de.ids_mannheim.korap.entity.VirtualCorpus;
 import de.ids_mannheim.korap.exceptions.KustvaktException;
-import de.ids_mannheim.korap.web.input.VirtualCorpusJson;
+import de.ids_mannheim.korap.web.input.QueryJson;
 
 @RunWith(SpringJUnit4ClassRunner.class)
 @ContextConfiguration("classpath:test-config.xml")
diff --git a/full/src/test/java/de/ids_mannheim/korap/service/VirtualCorpusServiceTest.java b/full/src/test/java/de/ids_mannheim/korap/service/VirtualCorpusServiceTest.java
index fbd95aa..a422b1c 100644
--- a/full/src/test/java/de/ids_mannheim/korap/service/VirtualCorpusServiceTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/service/VirtualCorpusServiceTest.java
@@ -13,14 +13,15 @@
 import org.springframework.test.context.ContextConfiguration;
 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 
+import de.ids_mannheim.korap.constant.QueryType;
 import de.ids_mannheim.korap.constant.UserGroupStatus;
-import de.ids_mannheim.korap.constant.VirtualCorpusType;
+import de.ids_mannheim.korap.constant.ResourceType;
 import de.ids_mannheim.korap.dto.VirtualCorpusAccessDto;
 import de.ids_mannheim.korap.dto.VirtualCorpusDto;
 import de.ids_mannheim.korap.entity.UserGroup;
 import de.ids_mannheim.korap.entity.VirtualCorpus;
 import de.ids_mannheim.korap.exceptions.KustvaktException;
-import de.ids_mannheim.korap.web.input.VirtualCorpusJson;
+import de.ids_mannheim.korap.web.input.QueryJson;
 
 @RunWith(SpringJUnit4ClassRunner.class)
 @ContextConfiguration("classpath:test-config.xml")
@@ -43,9 +44,10 @@
         // + "(UNIQUE constraint failed: virtual_corpus.name, "
         // + "virtual_corpus.created_by)");
 
-        VirtualCorpusJson vc = new VirtualCorpusJson();
+        QueryJson vc = new QueryJson();
         vc.setCorpusQuery("corpusSigle=GOE");
-        vc.setType(VirtualCorpusType.PRIVATE);
+        vc.setType(ResourceType.PRIVATE);
+        vc.setQueryType(QueryType.VIRTUAL_CORPUS);
         vcService.storeVC(vc, "dory-vc", "dory");
     }
 
@@ -53,9 +55,10 @@
     public void createDeletePublishVC () throws KustvaktException {
         String vcName = "new-published-vc";
 
-        VirtualCorpusJson vc = new VirtualCorpusJson();
+        QueryJson vc = new QueryJson();
         vc.setCorpusQuery("corpusSigle=GOE");
-        vc.setType(VirtualCorpusType.PUBLISHED);
+        vc.setType(ResourceType.PUBLISHED);
+        vc.setQueryType(QueryType.VIRTUAL_CORPUS);
         String username = "VirtualCorpusServiceTest";
         vcService.storeVC(vc, vcName, username );
 
@@ -94,15 +97,15 @@
         String vcName = "group-vc";
         VirtualCorpus existingVC =
                 vcService.searchVCByName(username, vcName, username);
-        VirtualCorpusJson vcJson = new VirtualCorpusJson();
-        vcJson.setType(VirtualCorpusType.PUBLISHED);
+        QueryJson vcJson = new QueryJson();
+        vcJson.setType(ResourceType.PUBLISHED);
 
         vcService.editVC(existingVC, vcJson, vcName, username);
 
         // check VC
         VirtualCorpusDto vcDto = vcService.searchVCById("dory", vcId);
         assertEquals(vcName, vcDto.getName());
-        assertEquals(VirtualCorpusType.PUBLISHED.displayName(),
+        assertEquals(ResourceType.PUBLISHED.displayName(),
                 vcDto.getType());
 
         // check access
@@ -121,15 +124,15 @@
 
         // 2nd edit (withdraw from publication)
 
-        vcJson = new VirtualCorpusJson();
-        vcJson.setType(VirtualCorpusType.PROJECT);
+        vcJson = new QueryJson();
+        vcJson.setType(ResourceType.PROJECT);
 
         vcService.editVC(existingVC, vcJson, vcName, username);
 
         // check VC
         vcDto = vcService.searchVCById("dory", vcId);
         assertEquals("group-vc", vcDto.getName());
-        assertEquals(VirtualCorpusType.PROJECT.displayName(), vcDto.getType());
+        assertEquals(ResourceType.PROJECT.displayName(), vcDto.getType());
 
         // check access
         accesses = vcService.listVCAccessByUsername("admin");
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/QueryReferenceControllerTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/QueryReferenceControllerTest.java
new file mode 100644
index 0000000..57c0df5
--- /dev/null
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/QueryReferenceControllerTest.java
@@ -0,0 +1,63 @@
+package de.ids_mannheim.korap.web.controller;
+
+import static org.junit.Assert.assertEquals;
+
+import org.apache.http.entity.ContentType;
+import org.junit.Test;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.net.HttpHeaders;
+import com.sun.jersey.api.client.ClientHandlerException;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.ClientResponse.Status;
+import com.sun.jersey.api.client.UniformInterfaceException;
+
+import de.ids_mannheim.korap.authentication.http.HttpAuthorizationHandler;
+import de.ids_mannheim.korap.config.Attributes;
+import de.ids_mannheim.korap.config.SpringJerseyTest;
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.utils.JsonUtils;
+
+public class QueryReferenceControllerTest extends SpringJerseyTest{
+
+    private String testUser = "qRefControllerTest";
+    
+    @Test
+    public void testCreatePrivateQuery () throws KustvaktException {
+        String json = "{\"type\": \"PRIVATE\""
+                + ",\"queryType\": \"QUERY\""
+                + ",\"queryLanguage\": \"poliqarp\""
+                + ",\"query\": \"der\"}";
+        
+        String qName="new_query";
+        ClientResponse response = resource().path(API_VERSION).path("query")
+                .path("~"+testUser).path(qName)
+                .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
+                        .createBasicAuthorizationHeaderValue(testUser, "pass"))
+                .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
+                .header(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON)
+                .put(ClientResponse.class, json);
+
+        assertEquals(Status.CREATED.getStatusCode(), response.getStatus());
+
+        JsonNode node = testRetrieveQueryByName(testUser, testUser, qName);
+        System.out.println(node);
+    }
+    
+    
+    private JsonNode testRetrieveQueryByName (String username, String qCreator,
+            String qName) throws UniformInterfaceException,
+            ClientHandlerException, KustvaktException {
+        ClientResponse response = resource().path(API_VERSION).path("query")
+                .path("~" + qCreator).path(qName)
+                .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
+                        .createBasicAuthorizationHeaderValue(username, "pass"))
+                .get(ClientResponse.class);
+        String entity = response.getEntity(String.class);
+//         System.out.println(entity);
+        assertEquals(Status.OK.getStatusCode(), response.getStatus());
+
+        return JsonUtils.readTree(entity);
+    }
+    
+}
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/VirtualCorpusControllerAdminTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/VirtualCorpusControllerAdminTest.java
index a23ce28..590886e 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/VirtualCorpusControllerAdminTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/VirtualCorpusControllerAdminTest.java
@@ -16,7 +16,7 @@
 
 import de.ids_mannheim.korap.authentication.http.HttpAuthorizationHandler;
 import de.ids_mannheim.korap.config.Attributes;
-import de.ids_mannheim.korap.constant.VirtualCorpusType;
+import de.ids_mannheim.korap.constant.ResourceType;
 import de.ids_mannheim.korap.exceptions.KustvaktException;
 import de.ids_mannheim.korap.utils.JsonUtils;
 
@@ -64,7 +64,7 @@
 
         JsonNode node = JsonUtils.readTree(entity);
         assertEquals("group-vc", node.at("/name").asText());
-        assertEquals(VirtualCorpusType.PROJECT.displayName(),
+        assertEquals(ResourceType.PROJECT.displayName(),
                 node.at("/type").asText());
     }
 
@@ -103,8 +103,9 @@
 
     @Test
     public void testCreateSystemVC () throws KustvaktException {
-        String json = "{\"type\": \"SYSTEM\","
-                + "\"corpusQuery\": \"creationDate since 1820\"}";
+        String json = "{\"type\": \"SYSTEM\""
+                + ",\"queryType\": \"VIRTUAL_CORPUS\""
+                + ",\"corpusQuery\": \"creationDate since 1820\"}";
 
         ClientResponse response = resource().path(API_VERSION).path("vc")
                 .path("~"+admin).path("new-system-vc")
@@ -140,8 +141,9 @@
     @Test
     public void testPrivateVC () throws UniformInterfaceException,
             ClientHandlerException, KustvaktException {
-        String json = "{\"type\": \"PRIVATE\","
-                + "\"corpusQuery\": \"corpusSigle=GOE\"}";
+        String json = "{\"type\": \"PRIVATE\""
+                + ",\"queryType\": \"VIRTUAL_CORPUS\""
+                + ",\"corpusQuery\": \"corpusSigle=GOE\"}";
 
         String vcName = "new-vc";
         ClientResponse response = resource().path(API_VERSION).path("vc")
@@ -266,7 +268,7 @@
         String accessId = node.at("/accessId").asText();
         testDeleteVCAccess(accessId);
 
-        testEditVCType(admin, vcCreator, vcName, VirtualCorpusType.PRIVATE);
+        testEditVCType(admin, vcCreator, vcName, ResourceType.PRIVATE);
     }
 
     private void testCreateVCAccess (String vcCreator, String vcName,
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/VirtualCorpusControllerTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/VirtualCorpusControllerTest.java
index 6afb02d..66a2b42 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/VirtualCorpusControllerTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/VirtualCorpusControllerTest.java
@@ -26,7 +26,7 @@
 import de.ids_mannheim.korap.authentication.http.HttpAuthorizationHandler;
 import de.ids_mannheim.korap.config.Attributes;
 import de.ids_mannheim.korap.constant.AuthenticationScheme;
-import de.ids_mannheim.korap.constant.VirtualCorpusType;
+import de.ids_mannheim.korap.constant.ResourceType;
 import de.ids_mannheim.korap.exceptions.KustvaktException;
 import de.ids_mannheim.korap.exceptions.StatusCodes;
 import de.ids_mannheim.korap.utils.JsonUtils;
@@ -117,7 +117,7 @@
 
         JsonNode node = testSearchVC(testUser, "system", "system-vc");
         assertEquals("system-vc", node.at("/name").asText());
-        assertEquals(VirtualCorpusType.SYSTEM.displayName(),
+        assertEquals(ResourceType.SYSTEM.displayName(),
                 node.at("/type").asText());
     }
 
@@ -129,7 +129,7 @@
                 .path("~system").path("system-vc").get(ClientResponse.class);
         JsonNode node = JsonUtils.readTree(response.getEntity(String.class));
         assertEquals("system-vc", node.at("/name").asText());
-        assertEquals(VirtualCorpusType.SYSTEM.displayName(),
+        assertEquals(ResourceType.SYSTEM.displayName(),
                 node.at("/type").asText());
         assertEquals(11, node.at("/numberOfDoc").asInt());
         assertEquals(772, node.at("/numberOfParagraphs").asInt());
@@ -144,7 +144,7 @@
 
         JsonNode node = testSearchVC("dory", "dory", "dory-vc");
         assertEquals("dory-vc", node.at("/name").asText());
-        assertEquals(VirtualCorpusType.PRIVATE.displayName(),
+        assertEquals(ResourceType.PRIVATE.displayName(),
                 node.at("/type").asText());
     }
 
@@ -175,7 +175,7 @@
 
         JsonNode node = testSearchVC("nemo", "dory", "group-vc");
         assertEquals("group-vc", node.at("/name").asText());
-        assertEquals(VirtualCorpusType.PROJECT.displayName(),
+        assertEquals(ResourceType.PROJECT.displayName(),
                 node.at("/type").asText());
     }
 
@@ -207,7 +207,7 @@
 
         JsonNode node = testSearchVC("gill", "marlin", "published-vc");
         assertEquals("published-vc", node.at("/name").asText());
-        assertEquals(VirtualCorpusType.PUBLISHED.displayName(),
+        assertEquals(ResourceType.PUBLISHED.displayName(),
                 node.at("/type").asText());
 
         // check gill in the hidden group of the vc
@@ -292,8 +292,9 @@
 
     @Test
     public void testCreatePrivateVC () throws KustvaktException {
-        String json = "{\"type\": \"PRIVATE\","
-                + "\"corpusQuery\": \"corpusSigle=GOE\"}";
+        String json = "{\"type\": \"PRIVATE\""
+                + ",\"queryType\": \"VIRTUAL_CORPUS\""
+                + ",\"corpusQuery\": \"corpusSigle=GOE\"}";
 
         ClientResponse response = resource().path(API_VERSION).path("vc")
                 .path("~"+testUser).path("new_vc")
@@ -321,6 +322,7 @@
     @Test
     public void testCreatePublishedVC () throws KustvaktException {
         String json = "{\"type\": \"PUBLISHED\""
+                + ",\"queryType\": \"VIRTUAL_CORPUS\""
                 + ",\"corpusQuery\": \"corpusSigle=GOE\"}";
 
         String vcName = "new-published-vc";
@@ -448,8 +450,9 @@
 
     @Test
     public void testCreateSystemVC () throws KustvaktException {
-        String json = "{\"type\": \"SYSTEM\","
-                + "\"corpusQuery\": \"creationDate since 1820\"}";
+        String json = "{\"type\": \"SYSTEM\""
+                + ",\"queryType\": \"VIRTUAL_CORPUS\""
+                + ",\"corpusQuery\": \"creationDate since 1820\"}";
 
         ClientResponse response = resource().path(API_VERSION).path("vc")
                 .path("~"+testUser).path("new_vc")
@@ -472,8 +475,9 @@
 
     @Test
     public void testCreateVCInvalidName () throws KustvaktException {
-        String json = "{\"type\": \"PRIVATE\","
-                + "\"corpusQuery\": \"creationDate since 1820\"}";
+        String json = "{\"type\": \"PRIVATE\""
+                + ",\"queryType\": \"VIRTUAL_CORPUS\""
+                + ",\"corpusQuery\": \"creationDate since 1820\"}";
 
         ClientResponse response = resource().path(API_VERSION).path("vc")
                 .path("~"+testUser).path("new $vc")
@@ -492,8 +496,9 @@
     
     @Test
     public void testCreateVCNameTooShort () throws KustvaktException {
-        String json = "{\"type\": \"PRIVATE\","
-                + "\"corpusQuery\": \"creationDate since 1820\"}";
+        String json = "{\"type\": \"PRIVATE\""
+                + ",\"queryType\": \"VIRTUAL_CORPUS\""
+                + ",\"corpusQuery\": \"creationDate since 1820\"}";
 
         ClientResponse response = resource().path(API_VERSION).path("vc")
                 .path("~"+testUser).path("ne")
@@ -535,7 +540,9 @@
 
     @Test
     public void testCreateVCWithoutcorpusQuery () throws KustvaktException {
-        String json = "{\"type\": \"PRIVATE\"}";
+        String json = "{\"type\": \"PRIVATE\""
+                + ",\"queryType\": \"VIRTUAL_CORPUS\""
+                + "}";
 
         ClientResponse response = resource().path(API_VERSION).path("vc")
                 .path("~"+testUser).path("new_vc")
@@ -574,7 +581,9 @@
 
     @Test
     public void testCreateVCWithoutType () throws KustvaktException {
-        String json = "{\"corpusQuery\": " + "\"creationDate since 1820\"}";
+        String json = "{\"corpusQuery\": " + "\"creationDate since 1820\""
+                + ",\"queryType\": \"VIRTUAL_CORPUS\""
+                + "}";
 
         ClientResponse response = resource().path(API_VERSION).path("vc")
                 .path("~"+testUser).path("new_vc")
@@ -595,8 +604,9 @@
 
     @Test
     public void testCreateVCWithWrongType () throws KustvaktException {
-        String json = "{\"type\": \"PRIVAT\","
-                + "\"corpusQuery\": \"creationDate since 1820\"}";
+        String json = "{\"type\": \"PRIVAT\""
+                + ",\"queryType\": \"VIRTUAL_CORPUS\""
+                + ",\"corpusQuery\": \"creationDate since 1820\"}";
 
         ClientResponse response = resource().path(API_VERSION).path("vc")
                 .path("~"+testUser).path("new_vc")
@@ -613,7 +623,7 @@
                 node.at("/errors/0/0").asInt());
         assertTrue(node.at("/errors/0/1").asText().startsWith(
                 "Cannot deserialize value of type `de.ids_mannheim.korap.constant."
-                        + "VirtualCorpusType` from String \"PRIVAT\""));
+                        + "ResourceType` from String \"PRIVAT\""));
     }
 
     @Test
@@ -729,7 +739,7 @@
 
         // check the vc type
         JsonNode node = testSearchVC("dory", "dory", vcName);
-        assertEquals(VirtualCorpusType.PROJECT.displayName(),
+        assertEquals(ResourceType.PROJECT.displayName(),
                 node.get("type").asText());
 
         // edit vc
@@ -746,7 +756,7 @@
         // check VC
         node = testListOwnerVC("dory");
         JsonNode n = node.get(1);
-        assertEquals(VirtualCorpusType.PUBLISHED.displayName(),
+        assertEquals(ResourceType.PUBLISHED.displayName(),
                 n.get("type").asText());
 
         // check hidden VC access
@@ -771,7 +781,7 @@
         assertEquals(Status.NO_CONTENT.getStatusCode(), response.getStatus());
 
         node = testListOwnerVC("dory");
-        assertEquals(VirtualCorpusType.PROJECT.displayName(),
+        assertEquals(ResourceType.PROJECT.displayName(),
                 node.get(1).get("type").asText());
 
         // check VC access
@@ -871,7 +881,7 @@
         node = testlistAccessByGroup("dory", groupName);
         assertEquals(1, node.size());
 
-        testEditVCType("marlin", "marlin", vcName, VirtualCorpusType.PRIVATE);
+        testEditVCType("marlin", "marlin", vcName, ResourceType.PRIVATE);
     }
 
     private ClientResponse testShareVCByCreator (String vcCreator,
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/VirtualCorpusTestBase.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/VirtualCorpusTestBase.java
index c3493f3..f100941 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/VirtualCorpusTestBase.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/VirtualCorpusTestBase.java
@@ -14,7 +14,7 @@
 import de.ids_mannheim.korap.authentication.http.HttpAuthorizationHandler;
 import de.ids_mannheim.korap.config.Attributes;
 import de.ids_mannheim.korap.config.SpringJerseyTest;
-import de.ids_mannheim.korap.constant.VirtualCorpusType;
+import de.ids_mannheim.korap.constant.ResourceType;
 import de.ids_mannheim.korap.exceptions.KustvaktException;
 import de.ids_mannheim.korap.utils.JsonUtils;
 
@@ -37,7 +37,7 @@
     }
     
     protected void testEditVCType (String username, String vcCreator,
-            String vcName, VirtualCorpusType type)
+            String vcName, ResourceType type)
             throws KustvaktException {
         String json = "{\"type\": \"" + type + "\"}";