Skip to content
Snippets Groups Projects
Commit 6ebdb3d5 authored by Daniel Gerhardt's avatar Daniel Gerhardt
Browse files

Add caching for CRUD operations of DefaultEntityServiceImpl

See #2.
parent 7407aa8d
Branches
No related merge requests found
...@@ -24,6 +24,7 @@ import de.thm.arsnova.event.AfterCreationEvent; ...@@ -24,6 +24,7 @@ import de.thm.arsnova.event.AfterCreationEvent;
import de.thm.arsnova.event.AfterDeletionEvent; import de.thm.arsnova.event.AfterDeletionEvent;
import de.thm.arsnova.event.AfterFullUpdateEvent; import de.thm.arsnova.event.AfterFullUpdateEvent;
import de.thm.arsnova.event.AfterPatchEvent; import de.thm.arsnova.event.AfterPatchEvent;
import de.thm.arsnova.event.AfterUpdateEvent;
import de.thm.arsnova.event.BeforeCreationEvent; import de.thm.arsnova.event.BeforeCreationEvent;
import de.thm.arsnova.event.BeforeDeletionEvent; import de.thm.arsnova.event.BeforeDeletionEvent;
import de.thm.arsnova.event.BeforeFullUpdateEvent; import de.thm.arsnova.event.BeforeFullUpdateEvent;
...@@ -31,10 +32,16 @@ import de.thm.arsnova.event.BeforePatchEvent; ...@@ -31,10 +32,16 @@ import de.thm.arsnova.event.BeforePatchEvent;
import de.thm.arsnova.model.Entity; import de.thm.arsnova.model.Entity;
import de.thm.arsnova.model.serialization.View; import de.thm.arsnova.model.serialization.View;
import de.thm.arsnova.persistence.CrudRepository; import de.thm.arsnova.persistence.CrudRepository;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware; import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.event.EventListener;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.access.prepost.PreFilter; import org.springframework.security.access.prepost.PreFilter;
import org.springframework.stereotype.Component;
import java.io.IOException; import java.io.IOException;
import java.util.Date; import java.util.Date;
...@@ -63,17 +70,16 @@ public class DefaultEntityServiceImpl<T extends Entity> implements EntityService ...@@ -63,17 +70,16 @@ public class DefaultEntityServiceImpl<T extends Entity> implements EntityService
@Override @Override
@PreAuthorize("hasPermission(#id, #this.this.getTypeName(), 'read')") @PreAuthorize("hasPermission(#id, #this.this.getTypeName(), 'read')")
public T get(final String id) { public T get(final String id) {
return repository.findOne(id); return get(id, false);
} }
@Override @Override
@Cacheable(cacheNames = "entity", key = "#root.target.getTypeName() + '-' + #id", condition = "#internal == false")
public T get(final String id, final boolean internal) { public T get(final String id, final boolean internal) {
T entity; T entity;
entity = repository.findOne(id);
if (internal) { if (internal) {
entity = repository.findOne(id);
entity.setInternal(true); entity.setInternal(true);
} else {
entity = get(id);
} }
modifyRetrieved(entity); modifyRetrieved(entity);
...@@ -260,4 +266,25 @@ public class DefaultEntityServiceImpl<T extends Entity> implements EntityService ...@@ -260,4 +266,25 @@ public class DefaultEntityServiceImpl<T extends Entity> implements EntityService
public void setApplicationEventPublisher(final ApplicationEventPublisher applicationEventPublisher) { public void setApplicationEventPublisher(final ApplicationEventPublisher applicationEventPublisher) {
this.eventPublisher = applicationEventPublisher; this.eventPublisher = applicationEventPublisher;
} }
@Component
public static class EntityCacheHandler {
@CachePut(cacheNames = "entity", key = "#event.entity.class.simpleName.toLowerCase() + '-' + #event.entity.id")
@EventListener
public Entity handleCreate(AfterCreationEvent event) {
return event.getEntity();
}
@CachePut(cacheNames = "entity", key = "#event.entity.class.simpleName.toLowerCase() + '-' + #event.entity.id")
@EventListener
public Entity handleUpdate(AfterUpdateEvent event) {
return event.getEntity();
}
@CacheEvict(cacheNames = "entity", key = "#event.entity.class.simpleName.toLowerCase() + '-' + #event.entity.id")
@EventListener
public void handleDelete(AfterDeletionEvent event) {
}
}
} }
...@@ -12,6 +12,7 @@ import org.junit.Test; ...@@ -12,6 +12,7 @@ import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cache.CacheManager;
import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisher;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ActiveProfiles;
...@@ -24,8 +25,9 @@ import java.util.ArrayList; ...@@ -24,8 +25,9 @@ import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.*;
import static org.mockito.AdditionalAnswers.returnsFirstArg; import static org.mockito.AdditionalAnswers.returnsFirstArg;
import static org.mockito.Matchers.anyListOf; import static org.mockito.Matchers.anyListOf;
import static org.mockito.Mockito.any; import static org.mockito.Mockito.any;
...@@ -44,6 +46,9 @@ public class DefaultEntityServiceImplTest { ...@@ -44,6 +46,9 @@ public class DefaultEntityServiceImplTest {
@Autowired @Autowired
private ApplicationEventPublisher eventPublisher; private ApplicationEventPublisher eventPublisher;
@Autowired
private CacheManager cacheManager;
@Autowired @Autowired
private RoomRepository roomRepository; private RoomRepository roomRepository;
...@@ -130,4 +135,40 @@ public class DefaultEntityServiceImplTest { ...@@ -130,4 +135,40 @@ public class DefaultEntityServiceImplTest {
assertEquals(patchedClosed, room2.isClosed()); assertEquals(patchedClosed, room2.isClosed());
assertEquals(originalOwnerId2, room2.getOwnerId()); assertEquals(originalOwnerId2, room2.getOwnerId());
} }
@Test
@WithMockUser("TestUser")
public void testCaching() {
final ObjectMapper objectMapper = jackson2HttpMessageConverter.getObjectMapper();
final DefaultEntityServiceImpl<Room> entityService = new DefaultEntityServiceImpl<>(Room.class, roomRepository, objectMapper);
entityService.setApplicationEventPublisher(eventPublisher);
final Room room1 = new Room();
room1.setId("a34876427c634a9b9cb56789d73607f0");
room1.setOwnerId("TestUser");
final Room room2 = new Room();
room2.setId("4638748d89884ff7936d7fe994a4090c");
room2.setOwnerId("TestUser");
final Room room3 = new Room();
room3.setId("c9651db0a67b49789a354e90e0401032");
room3.setOwnerId("TestUser");
final Room room4 = new Room();
room4.setId("66c1673056b2410b87335b9f317da5aa");
room4.setOwnerId("TestUser");
when(roomRepository.findById(any(String.class))).thenReturn(Optional.of(room1));
when(roomRepository.findOne(any(String.class))).thenReturn(room1);
assertSame(room1, entityService.get(room1.getId()));
/* room1 should now be cached for room1.id */
assertSame(room1, cacheManager.getCache("entity").get("room-" + room1.getId()).get());
when(roomRepository.findById(any(String.class))).thenReturn(Optional.of(room2));
when(roomRepository.findOne(any(String.class))).thenReturn(room2);
assertSame(room1, entityService.get(room1.getId()));
assertSame("Cache should not be used if internal == true.", room2, entityService.get(room1.getId(), true));
entityService.delete(room1);
/* room1 should no longer be cached for room1.id */
assertSame("Entity should not be cached.", null, cacheManager.getCache("entity").get("room-" + room1.getId()));
assertSame(room2, entityService.get(room1.getId()));
}
} }
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment