From f9f568a85b350c2b302212afa77d16524b40b32a Mon Sep 17 00:00:00 2001
From: Daniel Gerhardt <code@dgerhardt.net>
Date: Tue, 26 Sep 2017 12:53:05 +0200
Subject: [PATCH] Extract interface from EntityService

---
 .../thm/arsnova/services/CommentService.java  |  2 +-
 .../arsnova/services/CommentServiceImpl.java  |  2 +-
 .../thm/arsnova/services/ContentService.java  |  2 +-
 .../arsnova/services/ContentServiceImpl.java  |  2 +-
 .../services/DefaultEntityServiceImpl.java    | 80 +++++++++++++++++++
 .../thm/arsnova/services/EntityService.java   | 59 ++------------
 .../de/thm/arsnova/services/MotdService.java  |  2 +-
 .../thm/arsnova/services/MotdServiceImpl.java |  2 +-
 .../thm/arsnova/services/SessionService.java  |  2 +-
 .../arsnova/services/SessionServiceImpl.java  |  3 +-
 ...java => DefaultEntityServiceImplTest.java} |  6 +-
 11 files changed, 98 insertions(+), 64 deletions(-)
 create mode 100644 src/main/java/de/thm/arsnova/services/DefaultEntityServiceImpl.java
 rename src/test/java/de/thm/arsnova/services/{EntityServiceTest.java => DefaultEntityServiceImplTest.java} (93%)

diff --git a/src/main/java/de/thm/arsnova/services/CommentService.java b/src/main/java/de/thm/arsnova/services/CommentService.java
index 6ffc38c91..4713dfb8d 100644
--- a/src/main/java/de/thm/arsnova/services/CommentService.java
+++ b/src/main/java/de/thm/arsnova/services/CommentService.java
@@ -6,7 +6,7 @@ import de.thm.arsnova.entities.User;
 
 import java.util.List;
 
-public interface CommentService {
+public interface CommentService extends EntityService<Comment> {
 	boolean save(Comment comment);
 
 	int count(String sessionKey);
diff --git a/src/main/java/de/thm/arsnova/services/CommentServiceImpl.java b/src/main/java/de/thm/arsnova/services/CommentServiceImpl.java
index 82eaca02d..0066191a7 100644
--- a/src/main/java/de/thm/arsnova/services/CommentServiceImpl.java
+++ b/src/main/java/de/thm/arsnova/services/CommentServiceImpl.java
@@ -24,7 +24,7 @@ import java.util.List;
  * Performs all comment related operations.
  */
 @Service
-public class CommentServiceImpl extends EntityService<Comment> implements CommentService, ApplicationEventPublisherAware {
+public class CommentServiceImpl extends DefaultEntityServiceImpl<Comment> implements CommentService, ApplicationEventPublisherAware {
 	private UserService userService;
 
 	private CommentRepository commentRepository;
diff --git a/src/main/java/de/thm/arsnova/services/ContentService.java b/src/main/java/de/thm/arsnova/services/ContentService.java
index 6a66cc999..d7735b75c 100644
--- a/src/main/java/de/thm/arsnova/services/ContentService.java
+++ b/src/main/java/de/thm/arsnova/services/ContentService.java
@@ -27,7 +27,7 @@ import java.util.Map;
 /**
  * The functionality the question service should provide.
  */
-public interface ContentService {
+public interface ContentService extends EntityService<Content> {
 	Content save(Content content);
 
 	Content get(String id);
diff --git a/src/main/java/de/thm/arsnova/services/ContentServiceImpl.java b/src/main/java/de/thm/arsnova/services/ContentServiceImpl.java
index 167b31863..ad8874c84 100644
--- a/src/main/java/de/thm/arsnova/services/ContentServiceImpl.java
+++ b/src/main/java/de/thm/arsnova/services/ContentServiceImpl.java
@@ -63,7 +63,7 @@ import java.util.stream.Collectors;
  * Performs all content and answer related operations.
  */
 @Service
-public class ContentServiceImpl extends EntityService<Content> implements ContentService, ApplicationEventPublisherAware {
+public class ContentServiceImpl extends DefaultEntityServiceImpl<Content> implements ContentService, ApplicationEventPublisherAware {
 	private UserService userService;
 
 	private LogEntryRepository dbLogger;
diff --git a/src/main/java/de/thm/arsnova/services/DefaultEntityServiceImpl.java b/src/main/java/de/thm/arsnova/services/DefaultEntityServiceImpl.java
new file mode 100644
index 000000000..3ca52edf2
--- /dev/null
+++ b/src/main/java/de/thm/arsnova/services/DefaultEntityServiceImpl.java
@@ -0,0 +1,80 @@
+package de.thm.arsnova.services;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.ObjectReader;
+import de.thm.arsnova.entities.Entity;
+import de.thm.arsnova.entities.serialization.View;
+import org.springframework.data.repository.CrudRepository;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.security.access.prepost.PreFilter;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Map;
+
+public class DefaultEntityServiceImpl<T extends Entity> implements EntityService<T> {
+	protected Class<T> type;
+	protected CrudRepository<T, String> repository;
+	private ObjectMapper objectMapper;
+
+	public DefaultEntityServiceImpl(Class<T> type, CrudRepository<T, String> repository, ObjectMapper objectMapper) {
+		this.type = type;
+		this.repository = repository;
+		this.objectMapper = objectMapper;
+	}
+
+	@Override
+	@PreAuthorize("hasPermission(#id, #this.this.getTypeName(), 'read')")
+	public T get(final String id) {
+		return repository.findOne(id);
+	}
+
+	@Override
+	@PreAuthorize("hasPermission(#entity, 'create')")
+	public T create(final T entity) {
+		if (entity.getId() != null || entity.getRevision() != null) {
+			throw new IllegalArgumentException("Entity is not new.");
+		}
+		return repository.save(entity);
+	}
+
+	@Override
+	@PreAuthorize("hasPermission(#oldEntity, 'update')")
+	public T update(final T oldEntity, final T newEntity) {
+		newEntity.setId(oldEntity.getId());
+		return repository.save(newEntity);
+	}
+
+	@Override
+	@PreAuthorize("hasPermission(#entity, 'update')")
+	public T patch(final T entity, final Map<String, Object> changes) throws IOException {
+		ObjectReader reader = objectMapper.readerForUpdating(entity).withView(View.Public.class);
+		JsonNode tree = objectMapper.valueToTree(changes);
+		reader.readValue(tree);
+
+		return repository.save(entity);
+	}
+
+	@Override
+	@PreFilter(value = "hasPermission(filterObject, 'update')", filterTarget = "entities")
+	public Iterable<T> patch(final Collection<T> entities, final Map<String, Object> changes) throws IOException {
+		JsonNode tree = objectMapper.valueToTree(changes);
+		for (T entity : entities) {
+			ObjectReader reader = objectMapper.readerForUpdating(entity).withView(View.Public.class);
+			reader.readValue(tree);
+		}
+
+		return repository.save(entities);
+	}
+
+	@Override
+	@PreAuthorize("hasPermission(#entity, 'delete')")
+	public void delete(final T entity) {
+		repository.delete(entity);
+	}
+
+	public String getTypeName() {
+		return type.getSimpleName().toLowerCase();
+	}
+}
diff --git a/src/main/java/de/thm/arsnova/services/EntityService.java b/src/main/java/de/thm/arsnova/services/EntityService.java
index 28315ebcf..42f258765 100644
--- a/src/main/java/de/thm/arsnova/services/EntityService.java
+++ b/src/main/java/de/thm/arsnova/services/EntityService.java
@@ -1,11 +1,6 @@
 package de.thm.arsnova.services;
 
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.ObjectReader;
 import de.thm.arsnova.entities.Entity;
-import de.thm.arsnova.entities.serialization.View;
-import org.springframework.data.repository.CrudRepository;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.security.access.prepost.PreFilter;
 
@@ -13,62 +8,22 @@ import java.io.IOException;
 import java.util.Collection;
 import java.util.Map;
 
-public class EntityService<T extends Entity> {
-	protected Class<T> type;
-	protected CrudRepository<T, String> repository;
-	private ObjectMapper objectMapper;
-
-	public EntityService(Class<T> type, CrudRepository<T, String> repository, ObjectMapper objectMapper) {
-		this.type = type;
-		this.repository = repository;
-		this.objectMapper = objectMapper;
-	}
-
+public interface EntityService<T extends Entity> {
 	@PreAuthorize("hasPermission(#id, #this.this.getTypeName(), 'read')")
-	public T get(final String id) {
-		return repository.findOne(id);
-	}
+	T get(String id);
 
 	@PreAuthorize("hasPermission(#entity, 'create')")
-	public T create(final T entity) {
-		if (entity.getId() != null || entity.getRevision() != null) {
-			throw new IllegalArgumentException("Entity is not new.");
-		}
-		return repository.save(entity);
-	}
+	T create(T entity);
 
 	@PreAuthorize("hasPermission(#oldEntity, 'update')")
-	public T update(final T oldEntity, final T newEntity) {
-		newEntity.setId(oldEntity.getId());
-		return repository.save(newEntity);
-	}
+	T update(T oldEntity, T newEntity);
 
 	@PreAuthorize("hasPermission(#entity, 'update')")
-	public T patch(final T entity, final Map<String, Object> changes) throws IOException {
-		ObjectReader reader = objectMapper.readerForUpdating(entity).withView(View.Public.class);
-		JsonNode tree = objectMapper.valueToTree(changes);
-		reader.readValue(tree);
-
-		return repository.save(entity);
-	}
+	T patch(T entity, Map<String, Object> changes) throws IOException;
 
 	@PreFilter(value = "hasPermission(filterObject, 'update')", filterTarget = "entities")
-	public Iterable<T> patch(final Collection<T> entities, final Map<String, Object> changes) throws IOException {
-		JsonNode tree = objectMapper.valueToTree(changes);
-		for (T entity : entities) {
-			ObjectReader reader = objectMapper.readerForUpdating(entity).withView(View.Public.class);
-			reader.readValue(tree);
-		}
-
-		return repository.save(entities);
-	}
+	Iterable<T> patch(Collection<T> entities, Map<String, Object> changes) throws IOException;
 
 	@PreAuthorize("hasPermission(#entity, 'delete')")
-	public void delete(final T entity) {
-		repository.delete(entity);
-	}
-
-	public String getTypeName() {
-		return type.getSimpleName().toLowerCase();
-	}
+	void delete(T entity);
 }
diff --git a/src/main/java/de/thm/arsnova/services/MotdService.java b/src/main/java/de/thm/arsnova/services/MotdService.java
index 177e721d5..91303a43e 100644
--- a/src/main/java/de/thm/arsnova/services/MotdService.java
+++ b/src/main/java/de/thm/arsnova/services/MotdService.java
@@ -26,7 +26,7 @@ import java.util.List;
 /**
  * The functionality the motd service should provide.
  */
-public interface MotdService {
+public interface MotdService extends EntityService<Motd> {
 	Motd getByKey(String keyword);
 
 	List<Motd> getAdminMotds();  //all w/o the sessionmotds
diff --git a/src/main/java/de/thm/arsnova/services/MotdServiceImpl.java b/src/main/java/de/thm/arsnova/services/MotdServiceImpl.java
index 4c699c696..f2b6613f2 100644
--- a/src/main/java/de/thm/arsnova/services/MotdServiceImpl.java
+++ b/src/main/java/de/thm/arsnova/services/MotdServiceImpl.java
@@ -41,7 +41,7 @@ import java.util.StringTokenizer;
  * Performs all question, interposed question, and answer related operations.
  */
 @Service
-public class MotdServiceImpl extends EntityService<Motd> implements MotdService {
+public class MotdServiceImpl extends DefaultEntityServiceImpl<Motd> implements MotdService {
 	private UserService userService;
 
 	private SessionService sessionService;
diff --git a/src/main/java/de/thm/arsnova/services/SessionService.java b/src/main/java/de/thm/arsnova/services/SessionService.java
index 58f687791..d1ea50a71 100644
--- a/src/main/java/de/thm/arsnova/services/SessionService.java
+++ b/src/main/java/de/thm/arsnova/services/SessionService.java
@@ -31,7 +31,7 @@ import java.util.UUID;
 /**
  * The functionality the session service should provide.
  */
-public interface SessionService {
+public interface SessionService extends EntityService<Session> {
 	Session getByKey(String keyword);
 
 	Session getForAdmin(final String keyword);
diff --git a/src/main/java/de/thm/arsnova/services/SessionServiceImpl.java b/src/main/java/de/thm/arsnova/services/SessionServiceImpl.java
index 78dbf631e..c504763c5 100644
--- a/src/main/java/de/thm/arsnova/services/SessionServiceImpl.java
+++ b/src/main/java/de/thm/arsnova/services/SessionServiceImpl.java
@@ -43,7 +43,6 @@ import de.thm.arsnova.exceptions.BadRequestException;
 import de.thm.arsnova.exceptions.ForbiddenException;
 import de.thm.arsnova.exceptions.NotFoundException;
 import de.thm.arsnova.exceptions.PayloadTooLargeException;
-import de.thm.arsnova.exceptions.UnauthorizedException;
 import de.thm.arsnova.persistance.SessionRepository;
 import de.thm.arsnova.persistance.VisitedSessionRepository;
 import org.ektorp.UpdateConflictException;
@@ -71,7 +70,7 @@ import java.util.UUID;
  * Performs all session related operations.
  */
 @Service
-public class SessionServiceImpl extends EntityService<Session> implements SessionService, ApplicationEventPublisherAware {
+public class SessionServiceImpl extends DefaultEntityServiceImpl<Session> implements SessionService, ApplicationEventPublisherAware {
 	private static final long SESSION_INACTIVITY_CHECK_INTERVAL_MS = 30 * 60 * 1000L;
 
 	private static final Logger logger = LoggerFactory.getLogger(SessionServiceImpl.class);
diff --git a/src/test/java/de/thm/arsnova/services/EntityServiceTest.java b/src/test/java/de/thm/arsnova/services/DefaultEntityServiceImplTest.java
similarity index 93%
rename from src/test/java/de/thm/arsnova/services/EntityServiceTest.java
rename to src/test/java/de/thm/arsnova/services/DefaultEntityServiceImplTest.java
index e3d3a2b50..a7708c9ee 100644
--- a/src/test/java/de/thm/arsnova/services/EntityServiceTest.java
+++ b/src/test/java/de/thm/arsnova/services/DefaultEntityServiceImplTest.java
@@ -33,7 +33,7 @@ import static org.junit.Assert.*;
 @WebAppConfiguration
 @ContextConfiguration(classes = {AppConfig.class, TestAppConfig.class, TestPersistanceConfig.class, TestSecurityConfig.class})
 @ActiveProfiles("test")
-public class EntityServiceTest {
+public class DefaultEntityServiceImplTest {
 	@Autowired
 	@Qualifier("defaultJsonMessageConverter")
 	private MappingJackson2HttpMessageConverter jackson2HttpMessageConverter;
@@ -45,7 +45,7 @@ public class EntityServiceTest {
 	@WithMockUser(username="TestUser")
 	public void testPatch() throws IOException {
 		final ObjectMapper objectMapper = jackson2HttpMessageConverter.getObjectMapper();
-		final EntityService<Session> entityService = new EntityService<>(Session.class, sessionRepository, objectMapper);
+		final DefaultEntityServiceImpl<Session> entityService = new DefaultEntityServiceImpl<>(Session.class, sessionRepository, objectMapper);
 
 		when(sessionRepository.save(any(Session.class))).then(returnsFirstArg());
 
@@ -78,7 +78,7 @@ public class EntityServiceTest {
 	@WithMockUser(username="TestUser")
 	public void testPatchWithList() throws IOException {
 		final ObjectMapper objectMapper = jackson2HttpMessageConverter.getObjectMapper();
-		final EntityService<Session> entityService = new EntityService<>(Session.class, sessionRepository, objectMapper);
+		final DefaultEntityServiceImpl<Session> entityService = new DefaultEntityServiceImpl<>(Session.class, sessionRepository, objectMapper);
 
 		when(sessionRepository.save(any(Session.class))).then(returnsFirstArg());
 
-- 
GitLab