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