Divided codes into service/logic and controller layers.

Change-Id: I8f5f2fe11862bb23e011585561ea18a1b9e43cb6
diff --git a/full/pom.xml b/full/pom.xml
index ae87426..d4aca6e 100644
--- a/full/pom.xml
+++ b/full/pom.xml
@@ -70,9 +70,38 @@
 					<compilerVersion>${java.version}</compilerVersion>
 					<source>${java.version}</source>
 					<target>${java.version}</target>
+					<processors>
+						<processor>lombok.launch.AnnotationProcessorHider$AnnotationProcessor</processor>
+						<processor>org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor</processor>
+					</processors>
 				</configuration>
 			</plugin>
-
+	<!-- 		<plugin>
+				<groupId>org.bsc.maven</groupId>
+				<artifactId>maven-processor-plugin</artifactId>
+				<version>2.2.4</version>
+				<executions>
+					<execution>
+						<id>process</id>
+						<goals>
+							<goal>process</goal>
+						</goals>
+						<phase>generate-sources</phase>
+						<configuration>
+							<processors>
+								<processor>lombok.launch.AnnotationProcessorHider$AnnotationProcessor,org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor</processor>
+							</processors>
+						</configuration>
+					</execution>
+				</executions>
+				<dependencies>
+					<dependency>
+						<groupId>org.hibernate</groupId>
+						<artifactId>hibernate-jpamodelgen</artifactId>
+						<version>5.2.12.Final</version>
+					</dependency>
+				</dependencies>
+			</plugin> -->
 			<plugin>
 				<groupId>org.apache.maven.plugins</groupId>
 				<artifactId>maven-surefire-plugin</artifactId>
@@ -172,14 +201,20 @@
 			<artifactId>unboundid-ldapsdk</artifactId>
 			<version>3.2.1</version>
 		</dependency>
-		
+
 		<!-- Hibernate -->
 		<dependency>
 			<groupId>org.hibernate</groupId>
 			<artifactId>hibernate-entitymanager</artifactId>
 			<version>5.1.8.Final</version>
 		</dependency>
-		
+		<dependency>
+			<groupId>org.hibernate</groupId>
+			<artifactId>hibernate-jpamodelgen</artifactId>
+			<version>5.2.12.Final</version>
+			<scope>provided</scope>
+		</dependency>
+
 		<!-- MySql -->
 		<dependency>
 			<groupId>mysql</groupId>
@@ -212,7 +247,7 @@
 			<artifactId>spring-tx</artifactId>
 			<version>${spring-framework.version}</version>
 		</dependency>
-		
+
 		<!-- Flyway -->
 		<dependency>
 			<groupId>org.flywaydb</groupId>
diff --git a/full/src/main/java/de/ids_mannheim/korap/dao/AnnotationDao.java b/full/src/main/java/de/ids_mannheim/korap/dao/AnnotationDao.java
index b8cf357..afc360f 100644
--- a/full/src/main/java/de/ids_mannheim/korap/dao/AnnotationDao.java
+++ b/full/src/main/java/de/ids_mannheim/korap/dao/AnnotationDao.java
@@ -10,9 +10,11 @@
 import javax.persistence.criteria.Predicate;
 import javax.persistence.criteria.Root;
 
-import org.springframework.stereotype.Component;
+import org.springframework.stereotype.Repository;
 
 import de.ids_mannheim.korap.entity.AnnotationPair;
+import de.ids_mannheim.korap.entity.AnnotationPair_;
+import de.ids_mannheim.korap.entity.Annotation_;
 
 
 /**
@@ -22,7 +24,7 @@
  * @author margaretha
  *
  */
-@Component
+@Repository
 public class AnnotationDao {
 
     @PersistenceContext
@@ -39,8 +41,8 @@
         CriteriaQuery<AnnotationPair> query =
                 criteriaBuilder.createQuery(AnnotationPair.class);
         Root<AnnotationPair> annotationPair = query.from(AnnotationPair.class);
-        annotationPair.fetch("annotation1");
-        annotationPair.fetch("annotation2");
+        annotationPair.fetch(AnnotationPair_.annotation1);
+        annotationPair.fetch(AnnotationPair_.annotation2);
         query.select(annotationPair);
         Query q = entityManager.createQuery(query);
         return q.getResultList();
@@ -65,9 +67,9 @@
         CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
         CriteriaQuery<Object> query = criteriaBuilder.createQuery();
         Root<AnnotationPair> annotationPair = query.from(AnnotationPair.class);
-        annotationPair.fetch("annotation1");
-        annotationPair.fetch("annotation2");
-        annotationPair.fetch("values");
+        annotationPair.fetch(AnnotationPair_.annotation1);
+        annotationPair.fetch(AnnotationPair_.annotation2);
+        annotationPair.fetch(AnnotationPair_.values);
 
         // EM: Hibernate bug in join n:m (see AnnotationPair.values). 
         // There should not be any redundant AnnotationPair. 
@@ -77,14 +79,16 @@
         query = query.select(annotationPair);
 
         if (!foundry.isEmpty()) {
-            Predicate foundryPredicate = criteriaBuilder.equal(
-                    annotationPair.get("annotation1").get("code"), foundry);
+            Predicate foundryPredicate = criteriaBuilder.equal(annotationPair
+                    .get(AnnotationPair_.annotation1).get(Annotation_.code),
+                    foundry);
             if (layer.isEmpty() || layer.equals("*")) {
                 query.where(foundryPredicate);
             }
             else {
-                Predicate layerPredicate = criteriaBuilder.equal(
-                        annotationPair.get("annotation2").get("code"), layer);
+                Predicate layerPredicate = criteriaBuilder.equal(annotationPair
+                        .get(AnnotationPair_.annotation2).get(Annotation_.code),
+                        layer);
                 Predicate andPredicate =
                         criteriaBuilder.and(foundryPredicate, layerPredicate);
                 query.where(andPredicate);
diff --git a/full/src/main/java/de/ids_mannheim/korap/dao/ResourceDao.java b/full/src/main/java/de/ids_mannheim/korap/dao/ResourceDao.java
index 0a14a3c..16913bd 100644
--- a/full/src/main/java/de/ids_mannheim/korap/dao/ResourceDao.java
+++ b/full/src/main/java/de/ids_mannheim/korap/dao/ResourceDao.java
@@ -9,9 +9,10 @@
 import javax.persistence.criteria.CriteriaQuery;
 import javax.persistence.criteria.Root;
 
-import org.springframework.stereotype.Component;
+import org.springframework.stereotype.Repository;
 
 import de.ids_mannheim.korap.entity.Resource;
+import de.ids_mannheim.korap.entity.Resource_;
 
 /**
  * ResourceDao manages SQL queries regarding resource info and layers.
@@ -19,21 +20,22 @@
  * @author margaretha
  *
  */
-@Component
+@Repository
 public class ResourceDao {
 
     @PersistenceContext
     private EntityManager entityManager;
-    
+
     /** Select all from the resource table  
      *  
      * @return a list of resources
      */
     public List<Resource> getAllResources () {
         CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
-        CriteriaQuery<Resource> query = criteriaBuilder.createQuery(Resource.class);
+        CriteriaQuery<Resource> query =
+                criteriaBuilder.createQuery(Resource.class);
         Root<Resource> resource = query.from(Resource.class);
-        resource.fetch("layers");
+        resource.fetch(Resource_.layers);
         query.select(resource);
         Query q = entityManager.createQuery(query);
         return q.getResultList();
diff --git a/full/src/main/java/de/ids_mannheim/korap/dao/UserGroupDao.java b/full/src/main/java/de/ids_mannheim/korap/dao/UserGroupDao.java
index 900e062..324aeb8 100644
--- a/full/src/main/java/de/ids_mannheim/korap/dao/UserGroupDao.java
+++ b/full/src/main/java/de/ids_mannheim/korap/dao/UserGroupDao.java
@@ -1,6 +1,5 @@
 package de.ids_mannheim.korap.dao;
 
-import java.util.ArrayList;
 import java.util.List;
 
 import javax.persistence.EntityManager;
@@ -8,22 +7,29 @@
 import javax.persistence.Query;
 import javax.persistence.criteria.CriteriaBuilder;
 import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.ListJoin;
+import javax.persistence.criteria.Predicate;
 import javax.persistence.criteria.Root;
 
-import org.springframework.stereotype.Component;
+import org.springframework.stereotype.Repository;
 import org.springframework.transaction.annotation.Transactional;
 
+import de.ids_mannheim.korap.constants.GroupMemberStatus;
 import de.ids_mannheim.korap.constants.UserGroupStatus;
 import de.ids_mannheim.korap.constants.VirtualCorpusAccessStatus;
 import de.ids_mannheim.korap.entity.UserGroup;
 import de.ids_mannheim.korap.entity.UserGroupMember;
+import de.ids_mannheim.korap.entity.UserGroupMember_;
+import de.ids_mannheim.korap.entity.UserGroup_;
 import de.ids_mannheim.korap.entity.VirtualCorpus;
 import de.ids_mannheim.korap.entity.VirtualCorpusAccessGroup;
 
 @Transactional
-@Component
+@Repository
 public class UserGroupDao {
 
+    public static final String USER_GROUP_ALL = "all";
+
     @PersistenceContext
     private EntityManager entityManager;
 
@@ -57,23 +63,57 @@
 
         Root<UserGroup> root = query.from(UserGroup.class);
         query.select(root);
-        query.where(criteriaBuilder.equal(root.get("id"), groupId));
+        query.where(criteriaBuilder.equal(root.get(UserGroup_.id), groupId));
         Query q = entityManager.createQuery(query);
         return (UserGroup) q.getSingleResult();
     }
 
+    public List<UserGroup> retrieveGroupByUserId (String userId) {
+        CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
+        CriteriaQuery<UserGroup> query =
+                criteriaBuilder.createQuery(UserGroup.class);
+
+        Root<UserGroup> root = query.from(UserGroup.class);
+
+        Predicate allUserGroup = criteriaBuilder.and(
+                criteriaBuilder.equal(root.get(UserGroup_.name),
+                        USER_GROUP_ALL),
+                criteriaBuilder.notEqual(root.get(UserGroup_.status),
+                        UserGroupStatus.DELETED));
+
+
+        ListJoin<UserGroup, UserGroupMember> members =
+                root.join(UserGroup_.members);
+        Predicate memberships = criteriaBuilder.and(
+                criteriaBuilder.equal(members.get(UserGroupMember_.userId),
+                        userId),
+                criteriaBuilder.equal(members.get(UserGroupMember_.status),
+                        GroupMemberStatus.ACTIVE));
+
+
+        query.select(root);
+        query.where(criteriaBuilder.and(allUserGroup, memberships));
+        Query q = entityManager.createQuery(query);
+        return q.getResultList();
+    }
+
+    public void addVCToGroup (VirtualCorpus virtualCorpus, String createdBy,
+            VirtualCorpusAccessStatus status, UserGroup group) {
+        VirtualCorpusAccessGroup accessGroup = new VirtualCorpusAccessGroup();
+        accessGroup.setCreatedBy(createdBy);
+        accessGroup.setStatus(status);
+        accessGroup.setUserGroup(group);
+        accessGroup.setVirtualCorpus(virtualCorpus);
+        entityManager.persist(accessGroup);
+    }
+
     public void addVCToGroup (List<VirtualCorpus> virtualCorpora,
-            String createdBy, UserGroup group) {
-        // check role
-        
-        VirtualCorpusAccessGroup accessGroup;
+            String createdBy, UserGroup group,
+            VirtualCorpusAccessStatus status) {
+
         for (VirtualCorpus vc : virtualCorpora) {
-            accessGroup = new VirtualCorpusAccessGroup();
-            accessGroup.setCreatedBy(createdBy);
-            accessGroup.setStatus(VirtualCorpusAccessStatus.ACTIVE);
-            accessGroup.setUserGroup(group);
-            accessGroup.setVirtualCorpus(vc);
-            entityManager.persist(accessGroup);
+            addVCToGroup(vc, createdBy, status, group);
         }
     }
+
 }
diff --git a/full/src/main/java/de/ids_mannheim/korap/dao/UserGroupMemberDao.java b/full/src/main/java/de/ids_mannheim/korap/dao/UserGroupMemberDao.java
index 5404c02..301de3b 100644
--- a/full/src/main/java/de/ids_mannheim/korap/dao/UserGroupMemberDao.java
+++ b/full/src/main/java/de/ids_mannheim/korap/dao/UserGroupMemberDao.java
@@ -7,43 +7,40 @@
 import javax.persistence.Query;
 import javax.persistence.criteria.CriteriaBuilder;
 import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Join;
 import javax.persistence.criteria.Predicate;
 import javax.persistence.criteria.Root;
 
-import org.springframework.stereotype.Component;
+import org.springframework.stereotype.Repository;
 import org.springframework.transaction.annotation.Transactional;
 
 import de.ids_mannheim.korap.constants.GroupMemberStatus;
-import de.ids_mannheim.korap.entity.UserGroup;
+import de.ids_mannheim.korap.entity.Role;
 import de.ids_mannheim.korap.entity.UserGroupMember;
+import de.ids_mannheim.korap.entity.UserGroupMember_;
 import de.ids_mannheim.korap.exceptions.KustvaktException;
 import de.ids_mannheim.korap.utils.ParameterChecker;
 
 @Transactional
-@Component
-public class UserGroupMemberDao {
+@Repository
+public class UserGroupMemberDao<X> {
 
     @PersistenceContext
     private EntityManager entityManager;
 
-    public void addMember (UserGroupMember member, UserGroup userGroup)
+    public void addMember (UserGroupMember member)
             throws KustvaktException {
         ParameterChecker.checkObjectValue(member, "userGroupMember");
-        ParameterChecker.checkObjectValue(userGroup, "userGroup");
-
-        List<UserGroupMember> members = userGroup.getMembers();
-        members.add(member);
-        entityManager.persist(userGroup);
+        entityManager.persist(member);
     }
     
-    public void addMembers (List<UserGroupMember> newMembers, UserGroup userGroup)
+    public void addMembers (List<UserGroupMember> members)
             throws KustvaktException {
-        ParameterChecker.checkObjectValue(newMembers, "List<UserGroupMember>");
-        ParameterChecker.checkObjectValue(userGroup, "userGroup");
+        ParameterChecker.checkObjectValue(members, "List<UserGroupMember>");
 
-        List<UserGroupMember> members = userGroup.getMembers();
-        members.addAll(newMembers);
-        entityManager.persist(userGroup);
+        for (UserGroupMember member: members){
+            addMember(member);
+        }
     }
     
     public void approveMember (String userId, int groupId)
@@ -83,8 +80,8 @@
         Root<UserGroupMember> root = query.from(UserGroupMember.class);
 
         Predicate predicate = criteriaBuilder.and(
-                criteriaBuilder.equal(root.get("groupId"), groupId),
-                criteriaBuilder.equal(root.get("userId"), userId));
+                criteriaBuilder.equal(root.get(UserGroupMember_.group), groupId),
+                criteriaBuilder.equal(root.get(UserGroupMember_.userId), userId));
 
         query.select(root);
         query.where(predicate);
@@ -92,4 +89,21 @@
         return (UserGroupMember) q.getSingleResult();
     }
 
+    public List<UserGroupMember> retrieveMemberByRole (int groupId, int roleId) {
+        CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
+        CriteriaQuery<UserGroupMember> query =
+                criteriaBuilder.createQuery(UserGroupMember.class);
+
+        Root<UserGroupMember> root = query.from(UserGroupMember.class);
+        Join<UserGroupMember, Role> memberRole = root.join("roles");
+        
+        Predicate predicate = criteriaBuilder.and(
+                criteriaBuilder.equal(root.get(UserGroupMember_.group), groupId),
+                criteriaBuilder.equal(memberRole.get("role_id"), roleId));
+
+        query.select(root);
+        query.where(predicate);
+        Query q = entityManager.createQuery(query);
+        return q.getResultList();
+    }
 }
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 22042a7..6085309 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
@@ -14,7 +14,7 @@
 import javax.persistence.criteria.Predicate;
 import javax.persistence.criteria.Root;
 
-import org.springframework.stereotype.Component;
+import org.springframework.stereotype.Repository;
 import org.springframework.transaction.annotation.Transactional;
 
 import de.ids_mannheim.korap.constants.GroupMemberStatus;
@@ -34,7 +34,7 @@
  *
  */
 @Transactional
-@Component
+@Repository
 public class VirtualCorpusDao {
 
     @PersistenceContext
diff --git a/full/src/main/java/de/ids_mannheim/korap/dto/converter/AnnotationConverter.java b/full/src/main/java/de/ids_mannheim/korap/dto/converter/AnnotationConverter.java
index c049c2a..0e6cf13 100644
--- a/full/src/main/java/de/ids_mannheim/korap/dto/converter/AnnotationConverter.java
+++ b/full/src/main/java/de/ids_mannheim/korap/dto/converter/AnnotationConverter.java
@@ -5,7 +5,7 @@
 import java.util.List;
 import java.util.Map;
 
-import org.springframework.stereotype.Component;
+import org.springframework.stereotype.Service;
 
 import de.ids_mannheim.korap.dto.FoundryDto;
 import de.ids_mannheim.korap.dto.FoundryDto.Layer;
@@ -21,7 +21,7 @@
  * @author margaretha
  *
  */
-@Component
+@Service
 public class AnnotationConverter {
 
     /**
diff --git a/full/src/main/java/de/ids_mannheim/korap/dto/converter/ResourceConverter.java b/full/src/main/java/de/ids_mannheim/korap/dto/converter/ResourceConverter.java
index 03f00b3..8e22249 100644
--- a/full/src/main/java/de/ids_mannheim/korap/dto/converter/ResourceConverter.java
+++ b/full/src/main/java/de/ids_mannheim/korap/dto/converter/ResourceConverter.java
@@ -5,13 +5,13 @@
 import java.util.List;
 import java.util.Map;
 
-import org.springframework.stereotype.Component;
+import org.springframework.stereotype.Service;
 
 import de.ids_mannheim.korap.dto.ResourceDto;
 import de.ids_mannheim.korap.entity.AnnotationPair;
 import de.ids_mannheim.korap.entity.Resource;
 
-@Component
+@Service
 public class ResourceConverter {
 
     public List<ResourceDto> convertToResourcesDto (List<Resource> resources) {
diff --git a/full/src/main/java/de/ids_mannheim/korap/service/AnnotationService.java b/full/src/main/java/de/ids_mannheim/korap/service/AnnotationService.java
new file mode 100644
index 0000000..164887b
--- /dev/null
+++ b/full/src/main/java/de/ids_mannheim/korap/service/AnnotationService.java
@@ -0,0 +1,84 @@
+package de.ids_mannheim.korap.service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import de.ids_mannheim.korap.dao.AnnotationDao;
+import de.ids_mannheim.korap.dto.FoundryDto;
+import de.ids_mannheim.korap.dto.LayerDto;
+import de.ids_mannheim.korap.dto.converter.AnnotationConverter;
+import de.ids_mannheim.korap.entity.AnnotationPair;
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.exceptions.StatusCodes;
+import de.ids_mannheim.korap.web.utils.KustvaktResponseHandler;
+
+@Service
+public class AnnotationService {
+
+    private static Logger jlog =
+            LoggerFactory.getLogger(AnnotationService.class);
+
+    @Autowired
+    private AnnotationDao annotationDao;
+
+    @Autowired
+    private AnnotationConverter annotationConverter;
+
+    public List<LayerDto> getLayerDtos () {
+        List<AnnotationPair> layers = annotationDao.getAllFoundryLayerPairs();
+        jlog.debug("/layers " + layers.toString());
+        List<LayerDto> layerDto = annotationConverter.convertToLayerDto(layers);
+        return layerDto;
+    }
+
+    public List<FoundryDto> getFoundryDtos (List<String> codes, String language)
+            throws KustvaktException {
+        List<AnnotationPair> annotationPairs = null;
+        String foundry = "", layer = "";
+        if (codes.contains("*")) {
+            annotationPairs =
+                    annotationDao.getAnnotationDescriptions(foundry, layer);
+        }
+        else {
+            String[] annotationCode;
+            annotationPairs = new ArrayList<AnnotationPair>();
+            for (String code : codes) {
+                jlog.debug("code " + code);
+                annotationCode = code.split("/");
+                if (annotationCode.length == 1) {
+                    foundry = annotationCode[0];
+                }
+                else if (annotationCode.length == 2) {
+                    foundry = annotationCode[0];
+                    layer = annotationCode[1];
+                }
+                else {
+                    jlog.error("Annotation code is wrong: " + annotationCode);
+                    throw KustvaktResponseHandler.throwit(
+                            new KustvaktException(StatusCodes.INVALID_ATTRIBUTE,
+                                    "Bad attribute:", code));
+                }
+
+                annotationPairs.addAll(annotationDao
+                        .getAnnotationDescriptions(foundry, layer));
+            }
+        }
+
+        if (annotationPairs != null && !annotationPairs.isEmpty()) {
+            List<FoundryDto> foundryDtos = annotationConverter
+                    .convertToFoundryDto(annotationPairs, language);
+            jlog.debug("/description " + annotationPairs.toString());
+            return foundryDtos;
+        }
+        else {
+            throw new KustvaktException(StatusCodes.NO_RESULT_FOUND,
+                    "No result found.", "");
+        }
+
+    }
+}
diff --git a/full/src/main/java/de/ids_mannheim/korap/service/ResourceService.java b/full/src/main/java/de/ids_mannheim/korap/service/ResourceService.java
new file mode 100644
index 0000000..937f337
--- /dev/null
+++ b/full/src/main/java/de/ids_mannheim/korap/service/ResourceService.java
@@ -0,0 +1,33 @@
+package de.ids_mannheim.korap.service;
+
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import de.ids_mannheim.korap.dao.ResourceDao;
+import de.ids_mannheim.korap.dto.ResourceDto;
+import de.ids_mannheim.korap.dto.converter.ResourceConverter;
+import de.ids_mannheim.korap.entity.Resource;
+
+@Service
+public class ResourceService {
+
+    private static Logger jlog = LoggerFactory.getLogger(ResourceService.class);
+
+    @Autowired
+    private ResourceDao resourceDao;
+    @Autowired
+    private ResourceConverter resourceConverter;
+
+    public List<ResourceDto> getResourceDtos () {
+        List<Resource> resources = resourceDao.getAllResources();
+        List<ResourceDto> resourceDtos =
+                resourceConverter.convertToResourcesDto(resources);
+        jlog.debug("/info " + resourceDtos.toString());
+        return resourceDtos;
+    }
+
+}
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/controller/AdminController.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/AdminController.java
index 67be146..c9e8a4b 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/controller/AdminController.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/controller/AdminController.java
@@ -1,4 +1,4 @@
-package de.ids_mannheim.korap.web.service.full;
+package de.ids_mannheim.korap.web.controller;
 
 import java.util.List;
 import java.util.Locale;
@@ -48,15 +48,15 @@
 @Path(KustvaktServer.API_VERSION + "/admin")
 @ResourceFilters({ AdminFilter.class, PiwikFilter.class })
 @Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
-public class AdminService {
+public class AdminController {
 
-    private static Logger jlog = LoggerFactory.getLogger(AdminService.class);
+    private static Logger jlog = LoggerFactory.getLogger(AdminController.class);
 
     private AuditingIface auditingController;
     private DocumentDao documentDao;
 
 
-    public AdminService () {
+    public AdminController () {
         this.auditingController = BeansFactory.getKustvaktContext()
                 .getAuditingProvider();
         this.documentDao = new DocumentDao(
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/controller/AnnotationController.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/AnnotationController.java
index 101bba1..331ed6f 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/controller/AnnotationController.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/controller/AnnotationController.java
@@ -1,7 +1,6 @@
-package de.ids_mannheim.korap.web.service.full;
+package de.ids_mannheim.korap.web.controller;
 
 import java.io.IOException;
-import java.util.ArrayList;
 import java.util.List;
 
 import javax.ws.rs.Consumes;
@@ -20,14 +19,10 @@
 import com.fasterxml.jackson.databind.JsonNode;
 import com.sun.jersey.spi.container.ResourceFilters;
 
-import de.ids_mannheim.korap.dao.AnnotationDao;
-import de.ids_mannheim.korap.dto.FoundryDto;
-import de.ids_mannheim.korap.dto.LayerDto;
-import de.ids_mannheim.korap.dto.converter.AnnotationConverter;
-import de.ids_mannheim.korap.entity.AnnotationPair;
 import de.ids_mannheim.korap.exceptions.KustvaktException;
 import de.ids_mannheim.korap.exceptions.StatusCodes;
 import de.ids_mannheim.korap.filter.AuthFilter;
+import de.ids_mannheim.korap.service.AnnotationService;
 import de.ids_mannheim.korap.utils.JsonUtils;
 import de.ids_mannheim.korap.web.filter.DemoUserFilter;
 import de.ids_mannheim.korap.web.filter.PiwikFilter;
@@ -43,17 +38,13 @@
 @Path("annotation/")
 @ResourceFilters({ AuthFilter.class, DemoUserFilter.class, PiwikFilter.class })
 @Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
-public class AnnotationService {
+public class AnnotationController {
 
     private static Logger jlog =
-            LoggerFactory.getLogger(AnnotationService.class);
+            LoggerFactory.getLogger(AnnotationController.class);
 
     @Autowired
-    private AnnotationDao annotationDao;
-
-    @Autowired
-    private AnnotationConverter annotationConverter;
-
+    private AnnotationService annotationService;
 
     /**
      * Returns information about all supported layers
@@ -63,10 +54,7 @@
     @GET
     @Path("layers")
     public Response getLayers () {
-        List<AnnotationPair> layers = annotationDao.getAllFoundryLayerPairs();
-        jlog.debug("/layers " + layers.toString());
-        List<LayerDto> layerDto = annotationConverter.convertToLayerDto(layers);
-        String result = JsonUtils.toJSON(layerDto);
+        String result = JsonUtils.toJSON(annotationService.getLayerDtos());
         return Response.ok(result).build();
     }
 
@@ -80,14 +68,16 @@
      *            2-letter language code (description language)
      * @return a list of foundry, layer, value information in json
      */
+    @SuppressWarnings("unchecked")
     @POST
     @Path("description")
     @Consumes(MediaType.APPLICATION_JSON)
     public Response getFoundryDescriptions (String json) {
         JsonNode node = JsonUtils.readTree(json);
         if (node == null) {
-            throw KustvaktResponseHandler.throwit(new KustvaktException(
-                    StatusCodes.MISSING_ARGUMENT, "Missing a json string.", ""));
+            throw KustvaktResponseHandler
+                    .throwit(new KustvaktException(StatusCodes.MISSING_ARGUMENT,
+                            "Missing a json string.", ""));
         }
 
         String language;
@@ -120,52 +110,20 @@
                             "Missing attribute:", "codes"));
         }
         else if (codes.isEmpty()) {
-            throw KustvaktResponseHandler.throwit(new KustvaktException(
-                    StatusCodes.NO_RESULT_FOUND, "No result found.","codes:[]"));
-        }
-        
-        List<AnnotationPair> annotationPairs = null;
-        String foundry = "", layer = "";
-        if (codes.contains("*")) {
-            annotationPairs =
-                    annotationDao.getAnnotationDescriptions(foundry, layer);
-        }
-        else {
-            String[] annotationCode;
-            annotationPairs = new ArrayList<AnnotationPair>();
-            for (String code : codes) {
-                jlog.debug("code " + code);
-                annotationCode = code.split("/");
-                if (annotationCode.length == 1) {
-                    foundry = annotationCode[0];
-                }
-                else if (annotationCode.length == 2) {
-                    foundry = annotationCode[0];
-                    layer = annotationCode[1];
-                }
-                else {
-                    jlog.error("Annotation code is wrong: " + annotationCode);
-                    throw KustvaktResponseHandler.throwit(
-                            new KustvaktException(StatusCodes.INVALID_ATTRIBUTE,
-                                    "Bad attribute:", code));
-                }
-
-                annotationPairs.addAll(annotationDao
-                        .getAnnotationDescriptions(foundry, layer));
-            }
+            throw KustvaktResponseHandler
+                    .throwit(new KustvaktException(StatusCodes.NO_RESULT_FOUND,
+                            "No result found.", "codes:[]"));
         }
 
-        if (annotationPairs != null && !annotationPairs.isEmpty()) {
-            List<FoundryDto> dtos = annotationConverter
-                    .convertToFoundryDto(annotationPairs, language);
-            jlog.debug("/description " + annotationPairs.toString());
-            String result = JsonUtils.toJSON(dtos);
-            return Response.ok(result).build();
+        String result;
+        try {
+            result = JsonUtils
+                    .toJSON(annotationService.getFoundryDtos(codes, language));
         }
-        else {
-            throw KustvaktResponseHandler.throwit(new KustvaktException(
-                    StatusCodes.NO_RESULT_FOUND, "No result found.",""));
+        catch (KustvaktException e) {
+            throw KustvaktResponseHandler.throwit(e);
         }
+        return Response.ok(result).build();
     }
 
 }
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/controller/AuthenticationController.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/AuthenticationController.java
index 96f345c..b475c9c 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/controller/AuthenticationController.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/controller/AuthenticationController.java
@@ -1,4 +1,4 @@
-package de.ids_mannheim.korap.web.service.full;
+package de.ids_mannheim.korap.web.controller;
 
 import com.sun.jersey.spi.container.ContainerRequest;
 import com.sun.jersey.spi.container.ResourceFilters;
@@ -45,20 +45,20 @@
 @Path("/auth")
 @ResourceFilters({ PiwikFilter.class })
 @Produces(MediaType.TEXT_HTML + ";charset=utf-8")
-public class AuthService {
+public class AuthenticationController {
 
     private static Boolean DEBUG_LOG = true;
 
     //todo: bootstrap function to transmit certain default configuration settings and examples (example user queries,
     // default usersettings, etc.)
-    private static Logger jlog = KustvaktLogger.getLogger(AuthService.class);
+    private static Logger jlog = KustvaktLogger.getLogger(AuthenticationController.class);
 
     private AuthenticationManagerIface controller;
 
 
     //    private SendMail mail;
 
-    public AuthService () {
+    public AuthenticationController () {
         this.controller =
                 BeansFactory.getKustvaktContext().getAuthenticationManager();
         //todo: replace with real property values
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/controller/DocumentController.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/DocumentController.java
index df23da8..c23db52 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/controller/DocumentController.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/controller/DocumentController.java
@@ -1,4 +1,4 @@
-package de.ids_mannheim.korap.web.service.full;
+package de.ids_mannheim.korap.web.controller;
 
 import com.sun.jersey.spi.container.ResourceFilters;
 import de.ids_mannheim.korap.config.BeansFactory;
@@ -19,22 +19,25 @@
 import java.util.List;
 
 /**
+ * EM: To Do: restructure codes regarding service and controller layers
+ * 
  * @author hanl
  * @date 19/11/2014
  */
 @Path(KustvaktServer.API_VERSION + "/doc")
 @ResourceFilters({ AdminFilter.class })
 @Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
-public class DocumentService {
+public class DocumentController {
 
-    private static Logger jlog = LoggerFactory.getLogger(DocumentService.class);
+    private static Logger jlog =
+            LoggerFactory.getLogger(DocumentController.class);
     private DocumentDao documentDao;
 
 
     // todo: error handling
-    public DocumentService () {
-        this.documentDao = new DocumentDao(BeansFactory.getKustvaktContext()
-                .getPersistenceClient());
+    public DocumentController () {
+        this.documentDao = new DocumentDao(
+                BeansFactory.getKustvaktContext().getPersistenceClient());
     }
 
 
@@ -61,10 +64,8 @@
     public Response get (@PathParam("corpus") String corpus,
             @QueryParam("index") Integer index,
             @QueryParam("offset") Integer length) {
-        if (index == null)
-            index = 1;
-        if (length == null)
-            length = 25;
+        if (index == null) index = 1;
+        if (length == null) length = 25;
         try {
             List docs = this.documentDao.findbyCorpus(corpus, length, index);
             //todo: serialize to document json
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/controller/KustvaktController.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/KustvaktController.java
index 7c7b647..f581f37 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/controller/KustvaktController.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/controller/KustvaktController.java
@@ -1,4 +1,4 @@
-package de.ids_mannheim.korap.web.service.full;
+package de.ids_mannheim.korap.web.controller;
 
 import de.ids_mannheim.korap.server.KustvaktServer;
 import de.ids_mannheim.korap.utils.JsonUtils;
@@ -19,9 +19,9 @@
  */
 @Path("kustvakt")
 @Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
-public class KustvaktService {
+public class KustvaktController {
 
-    private static Logger jlog = LoggerFactory.getLogger(UserService.class);
+    private static Logger jlog = LoggerFactory.getLogger(UserController.class);
 
 
     @Path("info")
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuthController.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuthController.java
index 778ac27..7192e3e 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuthController.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuthController.java
@@ -1,4 +1,4 @@
-package de.ids_mannheim.korap.web.service.full;
+package de.ids_mannheim.korap.web.controller;
 
 import com.sun.jersey.spi.container.ContainerRequest;
 import com.sun.jersey.spi.container.ResourceFilters;
@@ -52,7 +52,7 @@
 //todo: only allow oauth2 access_token requests GET methods?
 //todo: allow refresh tokens
 @Path(KustvaktServer.API_VERSION + "/oauth2")
-public class OAuthService {
+public class OAuthController {
 
     private OAuth2Handler handler;
     private AuthenticationManagerIface controller;
@@ -60,7 +60,7 @@
     private KustvaktConfiguration config;
 
 
-    public OAuthService () {
+    public OAuthController () {
         this.handler = new OAuth2Handler(BeansFactory.getKustvaktContext()
                 .getPersistenceClient());
         this.controller = BeansFactory.getKustvaktContext()
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/controller/ResourceController.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/ResourceController.java
index 5319c51..103072e 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/controller/ResourceController.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/controller/ResourceController.java
@@ -1,6 +1,4 @@
-package de.ids_mannheim.korap.web.service.full;
-
-import java.util.List;
+package de.ids_mannheim.korap.web.controller;
 
 import javax.ws.rs.GET;
 import javax.ws.rs.Path;
@@ -8,17 +6,12 @@
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
 
 import com.sun.jersey.spi.container.ResourceFilters;
 
-import de.ids_mannheim.korap.dao.ResourceDao;
-import de.ids_mannheim.korap.dto.ResourceDto;
-import de.ids_mannheim.korap.dto.converter.ResourceConverter;
-import de.ids_mannheim.korap.entity.Resource;
+import de.ids_mannheim.korap.service.ResourceService;
 import de.ids_mannheim.korap.utils.JsonUtils;
 import de.ids_mannheim.korap.web.filter.PiwikFilter;
 
@@ -30,16 +23,12 @@
  */
 @Controller
 @Path("resource/")
-@ResourceFilters({PiwikFilter.class})
+@ResourceFilters({ PiwikFilter.class })
 @Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
-public class ResourceService {
-
-    private static Logger jlog = LoggerFactory.getLogger(ResourceService.class);
+public class ResourceController {
 
     @Autowired
-    private ResourceDao resourceDao;
-    @Autowired
-    private ResourceConverter resourceConverter;
+    private ResourceService resourceService;
 
 
     /** Returns descriptions of all free resources stored in 
@@ -51,11 +40,7 @@
     @GET
     @Path("info")
     public Response getAllResourceInfo () {
-        List<Resource> resources = resourceDao.getAllResources();
-        List<ResourceDto> resourceDtos = resourceConverter
-                .convertToResourcesDto(resources);
-        String result = JsonUtils.toJSON(resourceDtos);
-        jlog.debug("/info " + resourceDtos.toString());
+        String result = JsonUtils.toJSON(resourceService.getResourceDtos());
         return Response.ok(result).build();
     }
 }
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/controller/SearchController.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/SearchController.java
index b6e23e3..363477a 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/controller/SearchController.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/controller/SearchController.java
@@ -1,4 +1,5 @@
-package de.ids_mannheim.korap.web.service.full;//package de.ids_mannheim.korap.ext.web;
+package de.ids_mannheim.korap.web.controller;// package
+                                             // de.ids_mannheim.korap.ext.web;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -65,18 +66,20 @@
 import de.ids_mannheim.korap.web.utils.KustvaktResponseHandler;
 
 /**
+ * EM: To Do: restructure codes regarding service and controller layers
  * @author hanl, margaretha
  * @date 29/01/2014
  * @lastUpdate 06/2017
  */
 @Controller
 @Path("/")
-@RequestMapping ( "/" )
+@RequestMapping("/")
 @ResourceFilters({ AuthFilter.class, DemoUserFilter.class, PiwikFilter.class })
 @Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
-public class SearchService {
+public class SearchController {
 
-    private static Logger jlog = LoggerFactory.getLogger(SearchService.class);
+    private static Logger jlog =
+            LoggerFactory.getLogger(SearchController.class);
 
     @Autowired
     private SearchKrill searchKrill;
@@ -90,12 +93,12 @@
     private RewriteHandler processor;
 
 
-    public SearchService () {
+    public SearchController () {
         this.resourceHandler = new ResourceHandler();
         UriBuilder builder = UriBuilder.fromUri("http://10.0.10.13").port(9997);
         this.graphDBhandler = new ClientsHandler(builder.build());
     }
-    
+
     @PostConstruct
     private void doPostConstruct () {
         this.processor.defaultRewriteConstraints();
@@ -123,10 +126,9 @@
 
         try {
             Class cl_type = ResourceFactory.getResourceClass(type);
-            if (cl_type == null)
-                throw KustvaktResponseHandler.throwit(
-                        StatusCodes.MISSING_ARGUMENT,
-                        "Resource type not available!", "");
+            if (cl_type == null) throw KustvaktResponseHandler.throwit(
+                    StatusCodes.MISSING_ARGUMENT,
+                    "Resource type not available!", "");
 
             User user = controller.getUser(ctx.getUsername());
 
@@ -349,23 +351,19 @@
             @QueryParam("cq") String cq) {
         TokenContext ctx = (TokenContext) securityContext.getUserPrincipal();
         QuerySerializer ss = new QuerySerializer().setQuery(q, ql, v);
-        if (cq != null)
-            ss.setCollection(cq);
+        if (cq != null) ss.setCollection(cq);
 
         MetaQueryBuilder meta = new MetaQueryBuilder();
-        if (pageIndex != null)
-            meta.addEntry("startIndex", pageIndex);
+        if (pageIndex != null) meta.addEntry("startIndex", pageIndex);
         if (pageIndex == null && startPage != null)
             meta.addEntry("startPage", startPage);
-        if (pageLength != null)
-            meta.addEntry("count", pageLength);
-        if (context != null)
-            meta.setSpanContext(context);
+        if (pageLength != null) meta.addEntry("count", pageLength);
+        if (context != null) meta.setSpanContext(context);
         meta.addEntry("cutOff", cutoff);
 
         ss.setMeta(meta.raw());
         String result = ss.toJSON();
-        jlog.debug("Query: "+result);
+        jlog.debug("Query: " + result);
         return Response.ok(result).build();
     }
 
@@ -386,8 +384,8 @@
 
     // todo: does cq have any sensible worth here? --> would say no! --> is
     // useful in non type/id scenarios
-    
-    /* EM: potentially an unused service! */    
+
+    /* EM: potentially an unused service! */
     // EM: build query using the given virtual collection id
     // EM: change the HTTP method to from TRACE to GET
     // EM: change path from search to query
@@ -410,16 +408,12 @@
         QuerySerializer ss = new QuerySerializer().setQuery(q, ql, v);
 
         MetaQueryBuilder meta = new MetaQueryBuilder();
-        if (pageIndex != null)
-            meta.addEntry("startIndex", pageIndex);
+        if (pageIndex != null) meta.addEntry("startIndex", pageIndex);
         if (pageIndex == null && startPage != null)
             meta.addEntry("startPage", startPage);
-        if (pageLength != null)
-            meta.addEntry("count", pageLength);
-        if (context != null)
-            meta.setSpanContext(context);
-        if (cutoff != null)
-            meta.addEntry("cutOff", cutoff);
+        if (pageLength != null) meta.addEntry("count", pageLength);
+        if (context != null) meta.setSpanContext(context);
+        if (cutoff != null) meta.addEntry("cutOff", cutoff);
 
         ss.setMeta(meta.raw());
 
@@ -429,7 +423,7 @@
         String query = "";
         // EM: is this necessary at all?
         KustvaktResource resource = isCollectionIdValid(ctx.getName(), id);
-        if (resource!=null){
+        if (resource != null) {
             if (resource instanceof VirtualCollection) {
                 JsonNode node = cquery.and().mergeWith(resource.getData());
                 query = JsonUtils.toJSON(node);
@@ -441,42 +435,43 @@
             }
         }
 
-        jlog.debug("Query: "+query);
+        jlog.debug("Query: " + query);
         return Response.ok(query).build();
     }
 
     // EM: prototype
-    private KustvaktResource isCollectionIdValid (String username, String collectionId) {
-        
-//        try {
-//            if (ctx.isDemo()) {
-//                // EM: FIX ME: Is there public VCs? set default username 
-                  // for nonlogin user, change demo? 
-//                Set set = ResourceFinder.searchPublicFiltered(
-//                        ResourceFactory.getResourceClass(type), id);
-//                resource = (KustvaktResource) set.toArray()[0];
-//            }
-//            else {
-//                // EM: FIX ME: search in user VC
-//                User user = controller.getUser(ctx.getUsername());
-//                if (StringUtils.isInteger(id))
-//                    resource = this.resourceHandler
-//                            .findbyIntId(Integer.valueOf(id), user);
-//                else
-//                    resource = this.resourceHandler.findbyStrId(id, user,
-//                            ResourceFactory.getResourceClass(type));
-//            }
-//        }
-//        // todo: instead of throwing exception, build notification and rewrites
-//        // into result query
-//        catch (KustvaktException e) {
-//            jlog.error("Exception encountered: {}", e.string());
-//            throw KustvaktResponseHandler.throwit(e);
-//        }
-        
+    private KustvaktResource isCollectionIdValid (String username,
+            String collectionId) {
+
+        //        try {
+        //            if (ctx.isDemo()) {
+        //                // EM: FIX ME: Is there public VCs? set default username 
+        // for nonlogin user, change demo? 
+        //                Set set = ResourceFinder.searchPublicFiltered(
+        //                        ResourceFactory.getResourceClass(type), id);
+        //                resource = (KustvaktResource) set.toArray()[0];
+        //            }
+        //            else {
+        //                // EM: FIX ME: search in user VC
+        //                User user = controller.getUser(ctx.getUsername());
+        //                if (StringUtils.isInteger(id))
+        //                    resource = this.resourceHandler
+        //                            .findbyIntId(Integer.valueOf(id), user);
+        //                else
+        //                    resource = this.resourceHandler.findbyStrId(id, user,
+        //                            ResourceFactory.getResourceClass(type));
+        //            }
+        //        }
+        //        // todo: instead of throwing exception, build notification and rewrites
+        //        // into result query
+        //        catch (KustvaktException e) {
+        //            jlog.error("Exception encountered: {}", e.string());
+        //            throw KustvaktResponseHandler.throwit(e);
+        //        }
+
         return null;
     }
-    
+
 
     @POST
     @Path("search")
@@ -505,27 +500,25 @@
 
     @GET
     @Path("search")
-    public Response search (
-    		@Context SecurityContext securityContext,
-    		@Context HttpHeaders headers,
-    		@Context Locale locale, @QueryParam("q") String q,
-            @QueryParam("ql") String ql, @QueryParam("v") String v,
-            @QueryParam("context") String ctx,
+    public Response search (@Context SecurityContext securityContext,
+            @Context HttpHeaders headers, @Context Locale locale,
+            @QueryParam("q") String q, @QueryParam("ql") String ql,
+            @QueryParam("v") String v, @QueryParam("context") String ctx,
             @QueryParam("cutoff") Boolean cutoff,
             @QueryParam("count") Integer pageLength,
             @QueryParam("offset") Integer pageIndex,
             @QueryParam("page") Integer pageInteger,
             @QueryParam("cq") String cq, @QueryParam("engine") String engine) {
 
-    	TokenContext context = (TokenContext) securityContext
-                .getUserPrincipal();
+        TokenContext context =
+                (TokenContext) securityContext.getUserPrincipal();
         KustvaktConfiguration.BACKENDS eng = this.config.chooseBackend(engine);
         User user;
         try {
             user = controller.getUser(context.getUsername());
             controller.setAccessAndLocation(user, headers);
-//            System.out.printf("Debug: /search/: location=%s, access='%s'.\n", user.locationtoString(), user.accesstoString());
-        	}
+            //            System.out.printf("Debug: /search/: location=%s, access='%s'.\n", user.locationtoString(), user.accesstoString());
+        }
         catch (KustvaktException e) {
             jlog.error("Failed retrieving user in the search service: {}",
                     e.string());
@@ -534,8 +527,7 @@
 
         QuerySerializer serializer = new QuerySerializer();
         serializer.setQuery(q, ql, v);
-        if (cq != null)
-            serializer.setCollection(cq);
+        if (cq != null) serializer.setCollection(cq);
 
         MetaQueryBuilder meta = createMetaQuery(pageIndex, pageInteger, ctx,
                 pageLength, cutoff);
@@ -551,7 +543,7 @@
         }
 
         String result = doSearch(eng, query, pageLength, meta);
-        jlog.debug("Query result: "+result);
+        jlog.debug("Query result: " + result);
         return Response.ok(result).build();
     }
 
@@ -823,32 +815,33 @@
                 // todo: throw exception response for no resource to save!
                 return null;
 
-            KoralCollectionQueryBuilder cquery = new KoralCollectionQueryBuilder();
+            KoralCollectionQueryBuilder cquery =
+                    new KoralCollectionQueryBuilder();
             cquery.setBaseQuery(base);
 
             try {
                 cachetmp = ResourceFactory.getCachedCollection(cquery.toJSON());
 
                 // see if collection was cached!
-                VirtualCollection tmp = resourceHandler.getCache(cachetmp.getId(),
-                        VirtualCollection.class);
+                VirtualCollection tmp = resourceHandler
+                        .getCache(cachetmp.getId(), VirtualCollection.class);
                 // if not cached, fill with stats values
                 if (tmp == null) {
                     String stats = searchKrill.getStatistics(cquery.toJSON());
                     cachetmp.setStats(JsonUtils.readSimple(stats, Map.class));
                 }
-            
+
                 if (!cache) {
-                    collection = ResourceFactory.getPermanentCollection(cachetmp,
-                            name, description);
+                    collection = ResourceFactory.getPermanentCollection(
+                            cachetmp, name, description);
                     vals = collection.toMap();
-                        resourceHandler.storeResources(user, collection);
+                    resourceHandler.storeResources(user, collection);
                 }
                 else {
                     resourceHandler.cache(cachetmp);
                     vals = cachetmp.toMap();
                 }
-            
+
             }
             catch (KustvaktException e) {
                 throw KustvaktResponseHandler.throwit(e);
@@ -902,7 +895,8 @@
         if (VirtualCollection.class.equals(ctype)) {
             VirtualCollection cachetmp, collection;
 
-            KoralCollectionQueryBuilder cquery = new KoralCollectionQueryBuilder();
+            KoralCollectionQueryBuilder cquery =
+                    new KoralCollectionQueryBuilder();
             if (reference != null && !reference.equals("null")) {
                 try {
                     cquery.setBaseQuery(resourceHandler.findbyStrId(reference,
@@ -913,8 +907,7 @@
                     throw KustvaktResponseHandler.throwit(e);
                 }
             }
-            if (query != null && !query.isEmpty())
-                cquery.with(query);
+            if (query != null && !query.isEmpty()) cquery.with(query);
 
             cachetmp = ResourceFactory.getCachedCollection(cquery.toJSON());
 
@@ -992,10 +985,8 @@
 
     @GET
     @Path("/corpus/{corpusId}/{docId}/{textId}/{matchId}/matchInfo")
-    public Response getMatchInfo (
-    		@Context SecurityContext ctx,
-    		@Context HttpHeaders headers,
-            @Context Locale locale, 
+    public Response getMatchInfo (@Context SecurityContext ctx,
+            @Context HttpHeaders headers, @Context Locale locale,
             @PathParam("corpusId") String corpusId,
             @PathParam("docId") String docId,
             @PathParam("textId") String textId,
@@ -1007,9 +998,9 @@
         TokenContext tokenContext = (TokenContext) ctx.getUserPrincipal();
         spans = spans != null ? spans : false;
 
-        String matchid = searchKrill.getMatchId(corpusId, docId, textId, matchId);
-        if (layers == null || layers.isEmpty())
-            layers = new HashSet<>();
+        String matchid =
+                searchKrill.getMatchId(corpusId, docId, textId, matchId);
+        if (layers == null || layers.isEmpty()) layers = new HashSet<>();
 
         boolean match_only = foundries == null || foundries.isEmpty();
 
@@ -1017,50 +1008,51 @@
         try {
             user = controller.getUser(tokenContext.getUsername());
             controller.setAccessAndLocation(user, headers);
-            System.out.printf("Debug: /getMatchInfo/: location=%s, access='%s'.\n", user.locationtoString(), user.accesstoString());
-            }
+            System.out.printf(
+                    "Debug: /getMatchInfo/: location=%s, access='%s'.\n",
+                    user.locationtoString(), user.accesstoString());
+        }
         catch (KustvaktException e) {
             jlog.error("Failed getting user in the matchInfo service: {}",
                     e.string());
             throw KustvaktResponseHandler.throwit(e);
         }
-        
+
         CorpusAccess corpusAccess = user.getCorpusAccess();
         Pattern p;
         switch (corpusAccess) {
-		case PUB:
-			p = config.getPublicLicensePattern();
-			break;
-		case ALL:
-			p = config.getAllLicensePattern();
-			break;
-		default: // FREE
-			p = config.getFreeLicensePattern();
-			break;
-		}
-        
+            case PUB:
+                p = config.getPublicLicensePattern();
+                break;
+            case ALL:
+                p = config.getAllLicensePattern();
+                break;
+            default: // FREE
+                p = config.getFreeLicensePattern();
+                break;
+        }
+
         String results;
         try {
-            if (!match_only){
-            	
-            	ArrayList<String> foundryList = new ArrayList<String>();
+            if (!match_only) {
+
+                ArrayList<String> foundryList = new ArrayList<String>();
                 ArrayList<String> layerList = new ArrayList<String>();
-                
+
                 // EM: now without user, just list all foundries and layers
                 if (foundries.contains("*")) {
-                	foundryList = config.getFoundries();
-                	layerList = config.getLayers();
+                    foundryList = config.getFoundries();
+                    layerList = config.getLayers();
                 }
-                else{
-                	foundryList.addAll(foundries);
-                	layerList.addAll(layers);
+                else {
+                    foundryList.addAll(foundries);
+                    layerList.addAll(layers);
                 }
-                
-                results = searchKrill.getMatch(matchid,
-                        foundryList, layerList,
+
+                results = searchKrill.getMatch(matchid, foundryList, layerList,
                         spans, false, true, p);
             }
-            else{
+            else {
                 results = searchKrill.getMatch(matchid, p);
             }
         }
@@ -1069,7 +1061,7 @@
             throw KustvaktResponseHandler.throwit(StatusCodes.ILLEGAL_ARGUMENT,
                     e.getMessage(), "");
         }
-        jlog.debug("MatchInfo results: "+results);
+        jlog.debug("MatchInfo results: " + results);
         return Response.ok(results).build();
     }
 
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/controller/StatisticController.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/StatisticController.java
index ee30523..d9d0cd2 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/controller/StatisticController.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/controller/StatisticController.java
@@ -1,4 +1,4 @@
-package de.ids_mannheim.korap.web.service.full;
+package de.ids_mannheim.korap.web.controller;
 
 import java.util.Locale;
 
@@ -26,7 +26,7 @@
 import de.ids_mannheim.korap.web.utils.KustvaktResponseHandler;
 
 /**
- * Services related to statistics
+ * Web services related to statistics
  * 
  * @author hanl
  * @author margaretha
@@ -38,11 +38,11 @@
 @Path("statistics/")
 @ResourceFilters({ PiwikFilter.class })
 @Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
-public class StatisticService {
+public class StatisticController {
 
 
     private static Logger jlog =
-            LoggerFactory.getLogger(StatisticService.class);
+            LoggerFactory.getLogger(StatisticController.class);
 
     @Autowired
     private SearchKrill searchKrill;
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/controller/UserController.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/UserController.java
index f18d72f..1399c5c 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/controller/UserController.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/controller/UserController.java
@@ -1,4 +1,4 @@
-package de.ids_mannheim.korap.web.service.full;
+package de.ids_mannheim.korap.web.controller;
 
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
@@ -35,15 +35,15 @@
 @Path("/user")
 @Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
 @ResourceFilters({ PiwikFilter.class })
-public class UserService {
+public class UserController {
 
-    private static Logger jlog = LoggerFactory.getLogger(UserService.class);
+    private static Logger jlog = LoggerFactory.getLogger(UserController.class);
     private AuthenticationManagerIface controller;
 
     private @Context UriInfo info;
 
 
-    public UserService () {
+    public UserController () {
         this.controller = BeansFactory.getKustvaktContext()
                 .getAuthenticationManager();
     }
diff --git a/full/src/main/resources/META-INF/persistence.xml b/full/src/main/resources/META-INF/persistence.xml
index ae76d18..35b8d66 100644
--- a/full/src/main/resources/META-INF/persistence.xml
+++ b/full/src/main/resources/META-INF/persistence.xml
@@ -1,5 +1,10 @@
-<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
-    <persistence-unit name="entityManagerUnit" transaction-type="RESOURCE_LOCAL">
-        <exclude-unlisted-classes/>
-    </persistence-unit>
+<persistence xmlns="http://java.sun.com/xml/ns/persistence"
+	version="1.0">
+	<persistence-unit name="entityManagerUnit"
+		transaction-type="RESOURCE_LOCAL">
+		<exclude-unlisted-classes />
+	</persistence-unit>
+	<persistence-unit-metadata>
+		<xml-mapping-metadata-complete />
+	</persistence-unit-metadata>
 </persistence>
\ No newline at end of file
diff --git a/full/src/main/resources/db/new-mysql/V1.1__create_virtual_corpus_tables.sql b/full/src/main/resources/db/new-mysql/V1.1__create_virtual_corpus_tables.sql
index a69ef64..3a0b5e8 100644
--- a/full/src/main/resources/db/new-mysql/V1.1__create_virtual_corpus_tables.sql
+++ b/full/src/main/resources/db/new-mysql/V1.1__create_virtual_corpus_tables.sql
@@ -1,3 +1,17 @@
+CREATE TABLE IF NOT EXISTS privilege (
+  id varchar(20) PRIMARY KEY NOT NULL
+);
+
+CREATE TABLE IF NOT EXISTS role (
+  id INTEGER PRIMARY KEY AUTO_INCREMENT,
+  name varchar(100) NOT NULL,
+  privilege varchar(20) NOT NULL,
+  UNIQUE INDEX unique_index (name,privilege),
+  FOREIGN KEY (privilege) 
+  	REFERENCES privilege (id)
+  	ON DELETE CASCADE
+);
+
 CREATE TABLE IF NOT EXISTS user_group (
   id INTEGER PRIMARY KEY AUTO_INCREMENT,
   name varchar(100) NOT NULL,
@@ -21,24 +35,10 @@
   	ON DELETE CASCADE
 ); 
 
-CREATE TABLE IF NOT EXISTS role (
-  id INTEGER PRIMARY KEY AUTO_INCREMENT,
-  name varchar(100) NOT NULL,
-  privilege varchar(20) NOT NULL,
-  UNIQUE INDEX unique_index (name,privilege),
-  FOREIGN KEY (privilege) 
-  	REFERENCES privilege (id)
-  	ON DELETE CASCADE
-);
-
-CREATE TABLE IF NOT EXISTS privilege (
-  id varchar(20) PRIMARY KEY NOT NULL
-);
-
 CREATE TABLE IF NOT EXISTS group_member_role (
   id INTEGER PRIMARY KEY AUTO_INCREMENT,
   group_member_id int(11) NOT NULL,
-  role_id varchar(100) NOT NULL,
+  role_id int NOT NULL,
   UNIQUE INDEX unique_index (group_member_id,role_id),
   FOREIGN KEY (group_member_id)
   	REFERENCES user_group_member (id)