From 902c1723174088400f41f07e9043772a88885e03 Mon Sep 17 00:00:00 2001 From: Paul-Christian Volkmer <paul-christian.volkmer@mni.thm.de> Date: Tue, 11 Jun 2013 17:28:24 +0200 Subject: [PATCH] Store feedback in memory using FeedbackStorage With this patch all feedbacks will be stored in memory without any interaction with CouchDB. Due to in memory storage, all feedbacks will be removed if server gets restartet. Depending on new requests, feedbacks will be deleted after some time. --- .../java/de/thm/arsnova/FeedbackStorage.java | 128 ++++++++++++++++++ .../thm/arsnova/services/FeedbackService.java | 111 +++------------ .../services/UserSessionServiceImpl.java | 2 +- .../controller/FeedbackControllerTest.java | 6 +- .../controller/StatisticsControllerTest.java | 4 +- .../de/thm/arsnova/dao/StubDatabaseDao.java | 9 ++ .../arsnova/services/FeedbackServiceTest.java | 61 +++++++++ .../services/StatisticsServiceTest.java | 2 +- 8 files changed, 223 insertions(+), 100 deletions(-) create mode 100644 src/main/java/de/thm/arsnova/FeedbackStorage.java diff --git a/src/main/java/de/thm/arsnova/FeedbackStorage.java b/src/main/java/de/thm/arsnova/FeedbackStorage.java new file mode 100644 index 000000000..3ac11f553 --- /dev/null +++ b/src/main/java/de/thm/arsnova/FeedbackStorage.java @@ -0,0 +1,128 @@ +package de.thm.arsnova; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import de.thm.arsnova.dao.IDatabaseDao; +import de.thm.arsnova.entities.Feedback; +import de.thm.arsnova.entities.User; +import de.thm.arsnova.exceptions.NotFoundException; + +public class FeedbackStorage { + private static class FeedbackStorageObject { + private int value; + private Date timestamp; + private User user; + + public FeedbackStorageObject(int initValue, User u) { + this.value = initValue; + this.timestamp = new Date(); + this.user = u; + } + + public int getValue() { + return value; + } + public Date getTimestamp() { + return timestamp; + } + public boolean fromUser(User u) { + return u.getUsername().equals(user.getUsername()); + } + } + + private Map<String, Map<String, FeedbackStorageObject>> data; + + private IDatabaseDao dao; + + public FeedbackStorage(IDatabaseDao newDao) { + this.data = new HashMap<String, Map<String,FeedbackStorageObject>>(); + this.dao = newDao; + } + + public Feedback getFeedback(String keyword) { + int a = 0; + int b = 0; + int c = 0; + int d = 0; + + if (dao.getSession(keyword) == null) { + throw new NotFoundException(); + } + + if (data.get(keyword) == null) { + return new Feedback(0, 0, 0, 0); + } + + for (FeedbackStorageObject fso : data.get(keyword).values()) { + switch (fso.getValue()) { + case Feedback.FEEDBACK_FASTER: + a++; + break; + case Feedback.FEEDBACK_OK: + b++; + break; + case Feedback.FEEDBACK_SLOWER: + c++; + break; + case Feedback.FEEDBACK_AWAY: + d++; + break; + default: + break; + } + } + return new Feedback(a, b, c, d); + } + + public Integer getMyFeedback(String keyword, User u) { + if (data.get(keyword) == null) { + return null; + } + + for (FeedbackStorageObject fso : data.get(keyword).values()) { + if (fso.fromUser(u)) { + return fso.getValue(); + } + } + + return null; + } + + public boolean saveFeedback(String keyword, int value, User user) { + if (dao.getSession(keyword) == null) { + throw new NotFoundException(); + } + + if (data.get(keyword) == null) { + data.put(keyword, new HashMap<String, FeedbackStorageObject>()); + } + + System.out.println(user.getUsername()); + + data.get(keyword).put(user.getUsername(), new FeedbackStorageObject(value, user)); + return true; + } + + public void cleanFeedbackVotes(int cleanupFeedbackDelay) { + for (String keyword : data.keySet()) { + this.cleanSessionFeedbackVotes(keyword, cleanupFeedbackDelay); + } + } + + private void cleanSessionFeedbackVotes(String keyword, int cleanupFeedbackDelay) { + final long timelimitInMillis = 60000 * (long) cleanupFeedbackDelay; + final long maxAllowedTimeInMillis = System.currentTimeMillis() - timelimitInMillis; + + Map<String, FeedbackStorageObject> sessionFeedbacks = data.get(keyword); + + for (Map.Entry<String, FeedbackStorageObject> entry : sessionFeedbacks.entrySet()) { + if ( + entry.getValue().getTimestamp().getTime() < maxAllowedTimeInMillis + ) { + sessionFeedbacks.remove(entry.getKey()); + } + } + } +} diff --git a/src/main/java/de/thm/arsnova/services/FeedbackService.java b/src/main/java/de/thm/arsnova/services/FeedbackService.java index 0a808082e..db7bff304 100644 --- a/src/main/java/de/thm/arsnova/services/FeedbackService.java +++ b/src/main/java/de/thm/arsnova/services/FeedbackService.java @@ -19,22 +19,21 @@ package de.thm.arsnova.services; -import java.util.Date; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; +import javax.annotation.PostConstruct; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; +import de.thm.arsnova.FeedbackStorage; import de.thm.arsnova.dao.IDatabaseDao; import de.thm.arsnova.entities.Feedback; import de.thm.arsnova.entities.User; -import de.thm.arsnova.events.ARSnovaEvent; -import de.thm.arsnova.events.Publisher; import de.thm.arsnova.exceptions.NoContentException; import de.thm.arsnova.socket.ARSnovaSocketIOServer; @@ -57,25 +56,32 @@ public class FeedbackService implements IFeedbackService { @Autowired private IUserService userService; + + private FeedbackStorage feedbackStorage; public final void setDatabaseDao(final IDatabaseDao newDatabaseDao) { this.databaseDao = newDatabaseDao; } + @PostConstruct + public void init() { + this.feedbackStorage = new FeedbackStorage(databaseDao); + } + @Override @Scheduled(fixedDelay = DEFAULT_SCHEDULER_DELAY) public final void cleanFeedbackVotes() { - databaseDao.cleanFeedbackVotes(cleanupFeedbackDelay); + feedbackStorage.cleanFeedbackVotes(cleanupFeedbackDelay); } @Override public final Feedback getFeedback(final String keyword) { - return databaseDao.getFeedback(keyword); + return feedbackStorage.getFeedback(keyword); } @Override public final int getFeedbackCount(final String keyword) { - Feedback feedback = databaseDao.getFeedback(keyword); + Feedback feedback = feedbackStorage.getFeedback(keyword); List<Integer> values = feedback.getValues(); return values.get(Feedback.FEEDBACK_FASTER) + values.get(Feedback.FEEDBACK_OK) + values.get(Feedback.FEEDBACK_SLOWER) + values.get(Feedback.FEEDBACK_AWAY); @@ -83,7 +89,7 @@ public class FeedbackService implements IFeedbackService { @Override public final double getAverageFeedback(final String sessionkey) { - Feedback feedback = databaseDao.getFeedback(sessionkey); + Feedback feedback = feedbackStorage.getFeedback(sessionkey); List<Integer> values = feedback.getValues(); double count = values.get(Feedback.FEEDBACK_FASTER) + values.get(Feedback.FEEDBACK_OK) + values.get(Feedback.FEEDBACK_SLOWER) + values.get(Feedback.FEEDBACK_AWAY); @@ -103,7 +109,7 @@ public class FeedbackService implements IFeedbackService { @Override public final boolean saveFeedback(final String keyword, final int value, final User user) { - boolean result = databaseDao.saveFeedback(keyword, value, user); + boolean result = feedbackStorage.saveFeedback(keyword, value, user); if (result) { this.server.reportUpdatedFeedbackForSession(keyword); } @@ -138,91 +144,6 @@ public class FeedbackService implements IFeedbackService { @Override public final Integer getMyFeedback(final String keyword, final User user) { - return this.databaseDao.getMyFeedback(keyword, user); - } - - private static class FeedbackStorageObject { - private int value; - private Date timestamp; - - public FeedbackStorageObject(int initValue) { - this.value = initValue; - this.timestamp = new Date(); - } - - public int getValue() { - return value; - } - public Date getTimestamp() { - return timestamp; - } - } - - private static class FeedbackStorage { - private Map<String, Map<String, FeedbackStorageObject>> data; - - public FeedbackStorage() { - this.data = new HashMap<String, Map<String,FeedbackStorageObject>>(); - } - - public Feedback getFeedback(String keyword) { - int a = 0; - int b = 0; - int c = 0; - int d = 0; - - if (data.get(keyword) == null) { - return new Feedback(0, 0, 0, 0); - } - - for (FeedbackStorageObject fso : data.get(keyword).values()) { - switch (fso.getValue()) { - case Feedback.FEEDBACK_FASTER: - a++; - break; - case Feedback.FEEDBACK_OK: - b++; - break; - case Feedback.FEEDBACK_SLOWER: - c++; - break; - case Feedback.FEEDBACK_AWAY: - d++; - break; - default: - break; - } - } - return new Feedback(a, b, c, d); - } - - public boolean saveFeedback(String keyword, int value, User user) { - if (data.get(keyword) == null) { - data.put(keyword, new HashMap<String, FeedbackStorageObject>()); - } - data.get(keyword).put(user.getUsername(), new FeedbackStorageObject(value)); - return true; - } - - public void cleanFeedbackVotes(int cleanupFeedbackDelay) { - for (String keyword : data.keySet()) { - this.cleanSessionFeedbackVotes(keyword, cleanupFeedbackDelay); - } - } - - private void cleanSessionFeedbackVotes(String keyword, int cleanupFeedbackDelay) { - final long timelimitInMillis = 60000 * (long) cleanupFeedbackDelay; - final long maxAllowedTimeInMillis = System.currentTimeMillis() - timelimitInMillis; - - Map<String, FeedbackStorageObject> sessionFeedbacks = data.get(keyword); - - for (Map.Entry<String, FeedbackStorageObject> entry : sessionFeedbacks.entrySet()) { - if ( - entry.getValue().getTimestamp().getTime() < maxAllowedTimeInMillis - ) { - sessionFeedbacks.remove(entry.getKey()); - } - } - } + return this.feedbackStorage.getMyFeedback(keyword, user); } } diff --git a/src/main/java/de/thm/arsnova/services/UserSessionServiceImpl.java b/src/main/java/de/thm/arsnova/services/UserSessionServiceImpl.java index c0635767d..57340a41f 100644 --- a/src/main/java/de/thm/arsnova/services/UserSessionServiceImpl.java +++ b/src/main/java/de/thm/arsnova/services/UserSessionServiceImpl.java @@ -88,7 +88,7 @@ public class UserSessionServiceImpl implements UserSessionService, Serializable return result; } - return null; + return new LoggedIn(); } private boolean hasConnectedWebSocket() { diff --git a/src/test/java/de/thm/arsnova/controller/FeedbackControllerTest.java b/src/test/java/de/thm/arsnova/controller/FeedbackControllerTest.java index d0b8997bc..662f1f823 100644 --- a/src/test/java/de/thm/arsnova/controller/FeedbackControllerTest.java +++ b/src/test/java/de/thm/arsnova/controller/FeedbackControllerTest.java @@ -20,6 +20,7 @@ import org.springframework.web.servlet.HandlerAdapter; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter; +import de.thm.arsnova.FeedbackStorage; import de.thm.arsnova.dao.StubDatabaseDao; import de.thm.arsnova.exceptions.NoContentException; import de.thm.arsnova.exceptions.NotFoundException; @@ -47,6 +48,8 @@ public class FeedbackControllerTest { @Autowired private StubDatabaseDao databaseDao; + + private FeedbackStorage feedbackStorage; @After public final void cleanup() { @@ -58,6 +61,7 @@ public class FeedbackControllerTest { this.request = new MockHttpServletRequest(); this.response = new MockHttpServletResponse(); handlerAdapter = applicationContext.getBean(AnnotationMethodHandlerAdapter.class); + this.feedbackStorage = new FeedbackStorage(databaseDao); } @Test(expected = NotFoundException.class) @@ -105,6 +109,6 @@ public class FeedbackControllerTest { handlerAdapter.handle(request, response, feedbackController); assertTrue(response.getStatus() == 200); - assertEquals("{\"values\":[2,3,5,7]}", response.getContentAsString()); + assertEquals("{\"values\":[0,0,0,0]}", response.getContentAsString()); } } diff --git a/src/test/java/de/thm/arsnova/controller/StatisticsControllerTest.java b/src/test/java/de/thm/arsnova/controller/StatisticsControllerTest.java index 2882e4b3c..63fcbcd0b 100644 --- a/src/test/java/de/thm/arsnova/controller/StatisticsControllerTest.java +++ b/src/test/java/de/thm/arsnova/controller/StatisticsControllerTest.java @@ -55,7 +55,7 @@ public class StatisticsControllerTest { request.setRequestURI("/statistics/sessioncount"); handlerAdapter.handle(request, response, statisticsController); - assertEquals("2", response.getContentAsString()); + assertEquals("3", response.getContentAsString()); } @Test @@ -64,7 +64,7 @@ public class StatisticsControllerTest { request.setRequestURI("/statistics/"); handlerAdapter.handle(request, response, statisticsController); - String expected = "{\"answers\":0,\"questions\":0,\"openSessions\":2,\"closedSessions\":0,\"activeUsers\":0}"; + String expected = "{\"answers\":0,\"questions\":0,\"openSessions\":3,\"closedSessions\":0,\"activeUsers\":0}"; assertEquals(expected, response.getContentAsString()); } } diff --git a/src/test/java/de/thm/arsnova/dao/StubDatabaseDao.java b/src/test/java/de/thm/arsnova/dao/StubDatabaseDao.java index 37750ff80..b1d6447fb 100644 --- a/src/test/java/de/thm/arsnova/dao/StubDatabaseDao.java +++ b/src/test/java/de/thm/arsnova/dao/StubDatabaseDao.java @@ -87,6 +87,15 @@ public class StubDatabaseDao implements IDatabaseDao { session.setShortName("TS2"); stubSessions.put("87654321", session); + + session = new Session(); + session.setActive(true); + session.setCreator("ptsr00"); + session.setKeyword("18273645"); + session.setName("TestSession2"); + session.setShortName("TS3"); + + stubSessions.put("18273645", session); } private void fillWithDummyFeedbacks() { diff --git a/src/test/java/de/thm/arsnova/services/FeedbackServiceTest.java b/src/test/java/de/thm/arsnova/services/FeedbackServiceTest.java index 2ea24a36d..e96de49ee 100644 --- a/src/test/java/de/thm/arsnova/services/FeedbackServiceTest.java +++ b/src/test/java/de/thm/arsnova/services/FeedbackServiceTest.java @@ -22,13 +22,16 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import org.junit.After; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import de.thm.arsnova.dao.StubDatabaseDao; +import de.thm.arsnova.entities.User; import de.thm.arsnova.exceptions.NoContentException; import de.thm.arsnova.exceptions.NotFoundException; @@ -49,6 +52,53 @@ public class FeedbackServiceTest { @Autowired private StubDatabaseDao databaseDao; + @Before + public final void setup() { + userService.setUserAuthenticated(false); + + feedbackService.saveFeedback("87654321", 0, new TestUser("testuser01")); + feedbackService.saveFeedback("87654321", 0, new TestUser("testuser02")); + feedbackService.saveFeedback("87654321", 1, new TestUser("testuser11")); + feedbackService.saveFeedback("87654321", 1, new TestUser("testuser12")); + feedbackService.saveFeedback("87654321", 1, new TestUser("testuser13")); + feedbackService.saveFeedback("87654321", 2, new TestUser("testuser21")); + feedbackService.saveFeedback("87654321", 2, new TestUser("testuser22")); + feedbackService.saveFeedback("87654321", 2, new TestUser("testuser23")); + feedbackService.saveFeedback("87654321", 2, new TestUser("testuser24")); + feedbackService.saveFeedback("87654321", 2, new TestUser("testuser25")); + feedbackService.saveFeedback("87654321", 3, new TestUser("testuser31")); + feedbackService.saveFeedback("87654321", 3, new TestUser("testuser32")); + feedbackService.saveFeedback("87654321", 3, new TestUser("testuser33")); + feedbackService.saveFeedback("87654321", 3, new TestUser("testuser34")); + feedbackService.saveFeedback("87654321", 3, new TestUser("testuser35")); + feedbackService.saveFeedback("87654321", 3, new TestUser("testuser36")); + feedbackService.saveFeedback("87654321", 3, new TestUser("testuser37")); + + + feedbackService.saveFeedback("18273645", 0, new TestUser("testuser01")); + feedbackService.saveFeedback("18273645", 0, new TestUser("testuser02")); + feedbackService.saveFeedback("18273645", 1, new TestUser("testuser11")); + feedbackService.saveFeedback("18273645", 1, new TestUser("testuser12")); + feedbackService.saveFeedback("18273645", 1, new TestUser("testuser13")); + feedbackService.saveFeedback("18273645", 2, new TestUser("testuser21")); + feedbackService.saveFeedback("18273645", 2, new TestUser("testuser22")); + feedbackService.saveFeedback("18273645", 2, new TestUser("testuser23")); + feedbackService.saveFeedback("18273645", 2, new TestUser("testuser24")); + feedbackService.saveFeedback("18273645", 2, new TestUser("testuser25")); + feedbackService.saveFeedback("18273645", 3, new TestUser("testuser31")); + feedbackService.saveFeedback("18273645", 3, new TestUser("testuser32")); + feedbackService.saveFeedback("18273645", 3, new TestUser("testuser33")); + feedbackService.saveFeedback("18273645", 3, new TestUser("testuser34")); + feedbackService.saveFeedback("18273645", 3, new TestUser("testuser35")); + feedbackService.saveFeedback("18273645", 3, new TestUser("testuser36")); + feedbackService.saveFeedback("18273645", 3, new TestUser("testuser37")); + feedbackService.saveFeedback("18273645", 3, new TestUser("testuser38")); + feedbackService.saveFeedback("18273645", 3, new TestUser("testuser39")); + feedbackService.saveFeedback("18273645", 3, new TestUser("testuser310")); + feedbackService.saveFeedback("18273645", 3, new TestUser("testuser311")); + + } + @After public final void cleanup() { databaseDao.cleanupTestData(); @@ -112,4 +162,15 @@ public class FeedbackServiceTest { userService.setUserAuthenticated(true); assertEquals(2.1904, feedbackService.getAverageFeedback("18273645"), 0.001); } + + public static class TestUser extends User { + private static final long serialVersionUID = 1L; + + private String username; + private String type; + + public TestUser(String username) { + super( new UsernamePasswordAuthenticationToken(username, "secret") ); + } + } } \ No newline at end of file diff --git a/src/test/java/de/thm/arsnova/services/StatisticsServiceTest.java b/src/test/java/de/thm/arsnova/services/StatisticsServiceTest.java index a0e846e68..ec348f3b6 100644 --- a/src/test/java/de/thm/arsnova/services/StatisticsServiceTest.java +++ b/src/test/java/de/thm/arsnova/services/StatisticsServiceTest.java @@ -67,7 +67,7 @@ public class StatisticsServiceTest { @Test public final void testShouldReturnStatistics() { Statistics actual = statisticsService.getStatistics(); - assertEquals(2, actual.getOpenSessions()); + assertEquals(3, actual.getOpenSessions()); assertEquals(1, actual.getClosedSessions()); } } -- GitLab