An error occurred while loading the file. Please try again.
-
Paul-Christian Volkmer authoredbbd4b091
Forked from
ARSnova / ARSnova Backend
2071 commits behind the upstream repository.
UserService.java 8.88 KiB
package de.thm.arsnova.services;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import org.scribe.up.profile.facebook.FacebookProfile;
import org.scribe.up.profile.google.Google2Profile;
import org.scribe.up.profile.twitter.TwitterProfile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.cas.authentication.CasAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import com.github.leleuj.ss.oauth.client.authentication.OAuthAuthenticationToken;
import de.thm.arsnova.dao.IDatabaseDao;
import de.thm.arsnova.entities.User;
import de.thm.arsnova.exceptions.UnauthorizedException;
import de.thm.arsnova.socket.ARSnovaSocketIOServer;
public class UserService implements IUserService, InitializingBean, DisposableBean {
private static final int DEFAULT_SCHEDULER_DELAY_MS = 60000;
private static final int MAX_USER_INACTIVE_SECONDS = 120;
public static final Logger LOGGER = LoggerFactory.getLogger(UserService.class);
private static final ConcurrentHashMap<UUID, User> socketid2user = new ConcurrentHashMap<UUID, User>();
/* used for Socket.IO online check solution (new) */
private static final ConcurrentHashMap<User, String> user2session = new ConcurrentHashMap<User, String>();
/* used for HTTP polling online check solution (legacy) */
private static final ConcurrentHashMap<User, String> user2sessionLegacy = new ConcurrentHashMap<User, String>();
@Autowired
private IDatabaseDao databaseDao;
@Autowired
private ARSnovaSocketIOServer socketIoServer;
@Scheduled(fixedDelay = DEFAULT_SCHEDULER_DELAY_MS)
public final void removeInactiveUsersFromLegacyMap() {
List<String> usernames = databaseDao.getActiveUsers(MAX_USER_INACTIVE_SECONDS);
Set<String> affectedSessions = new HashSet<String>();
for (Entry<User, String> e : user2sessionLegacy.entrySet()) {
User key = e.getKey();
if (usernames != null && !usernames.contains(key.getUsername())) {
if (null != e.getValue()) {
affectedSessions.add(e.getValue());
} else {
LOGGER.warn("Session for user {} is null", key);
}
user2sessionLegacy.remove(e.getKey());
}
}
for (String sessionKeyword : affectedSessions) {
socketIoServer.reportActiveUserCountForSession(sessionKeyword);
}
}
@Override
public User getCurrentUser() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || authentication.getPrincipal() == null) {
return null;
}
User user = null;
if (authentication instanceof OAuthAuthenticationToken) {
OAuthAuthenticationToken token = (OAuthAuthenticationToken) authentication;
if (token.getUserProfile() instanceof Google2Profile) {
Google2Profile profile = (Google2Profile) token.getUserProfile();
user = new User(profile);
} else if (token.getUserProfile() instanceof TwitterProfile) {
TwitterProfile profile = (TwitterProfile) token.getUserProfile();
user = new User(profile);
} else if (token.getUserProfile() instanceof FacebookProfile) {
FacebookProfile profile = (FacebookProfile) token.getUserProfile();
user = new User(profile);
}
} else if (authentication instanceof CasAuthenticationToken) {
CasAuthenticationToken token = (CasAuthenticationToken) authentication;
user = new User(token.getAssertion().getPrincipal());
} else if (authentication instanceof AnonymousAuthenticationToken) {
AnonymousAuthenticationToken token = (AnonymousAuthenticationToken) authentication;
user = new User(token);
} else if (authentication instanceof UsernamePasswordAuthenticationToken) {
UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) authentication;
user = new User(token);
}
if (user == null || user.getUsername().equals("anonymous")) {
throw new UnauthorizedException();
}
return user;
}
@Override
public User getUser2SocketId(UUID socketId) {
return socketid2user.get(socketId);
}
@Override
public void putUser2SocketId(UUID socketId, User user) {
socketid2user.put(socketId, user);
}
@Override
public Set<Map.Entry<UUID, User>> socketId2User() {
return socketid2user.entrySet();
}
@Override
public void removeUser2SocketId(UUID socketId) {
socketid2user.remove(socketId);
}
@Override
public boolean isUserInSession(User user, String keyword) {
if (keyword == null) {
return false;
}
String session = user2sessionLegacy.get(user);
if (session == null) {
return false;
}
return keyword.equals(session);
}
@Override
public Set<User> getUsersInSession(String keyword) {
Set<User> result = new HashSet<User>();
for (Entry<User, String> e : user2session.entrySet()) {
if (e.getValue().equals(keyword)) {
result.add(e.getKey());
}
}
for (Entry<User, String> e : user2sessionLegacy.entrySet()) {
if (e.getValue().equals(keyword)) {
result.add(e.getKey());
}
}
return result;
}
@Override
public int getUsersInSessionCount(String keyword) {
return getUsersInSession(keyword).size();
}
@Override
@Transactional(isolation = Isolation.READ_COMMITTED)
public void addCurrentUserToSessionMap(String keyword) {
User user = getCurrentUser();
if (user == null) {
throw new UnauthorizedException();
}
user2sessionLegacy.put(user, keyword);
}
@Override
@Transactional(isolation = Isolation.READ_COMMITTED)
public void addUserToSessionBySocketId(UUID socketId, String keyword) {
User user = socketid2user.get(socketId);
user2session.put(user, keyword);
}
@Override
@Transactional(isolation = Isolation.READ_COMMITTED)
public void removeUserFromSessionBySocketId(UUID socketId) {
User user = socketid2user.get(socketId);
if (null == user) {
LOGGER.warn("null == user for socket {}", socketId);
return;
}
user2session.remove(user);
}
@Override
public String getSessionForUser(String username) {
for (Entry<User, String> entry : user2session.entrySet()) {
if (entry.getKey().getUsername().equals(username)) {
return entry.getValue();
}
}
for (Entry<User, String> entry : user2sessionLegacy.entrySet()) {
if (entry.getKey().getUsername().equals(username)) {
return entry.getValue();
}
}
return null;
}
@Override
public void afterPropertiesSet() {
try {
File tmpDir = new File(System.getProperty("java.io.tmpdir"));
File store = new File(tmpDir, "arsnova.bin");
if (!store.exists()) {
return;
}
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(store));
Hashtable<String, Map<?, ?>> map = (Hashtable<String, Map<?, ?>>) ois.readObject();
ois.close();
Map<UUID, User> s2u = (Map<UUID, User>) map.get("socketid2user");
Map<User, String> u2s = (Map<User, String>) map.get("user2session");
LOGGER.info("load from store: {}", map);
socketid2user.putAll(s2u);
user2sessionLegacy.putAll(u2s);
} catch (IOException e) {
LOGGER.error("IOException during restoring UserService", e);
} catch (ClassNotFoundException e) {
LOGGER.error("ClassNotFoundException during restoring UserService", e);
}
}
@Override
public void destroy() {
Hashtable<String, Map<?, ?>> map = new Hashtable<String, Map<?, ?>>();
map.put("socketid2user", socketid2user);
map.put("user2session", user2sessionLegacy);
try {
File tmpDir = new File(System.getProperty("java.io.tmpdir"));
File store = new File(tmpDir, "arsnova.bin");
if (!store.exists()) {
if (! store.createNewFile()) {
LOGGER.info("Could not create store file");
}
}
OutputStream file = new FileOutputStream(store);
ObjectOutputStream objOut = new ObjectOutputStream(file);
objOut.writeObject(map);
objOut.close();
file.close();
LOGGER.info("saved to store: {}", map);
} catch (IOException e) {
LOGGER.error("IOException while saving UserService", e);
}
}
@Override
public void removeUserFromMaps(User user) {
if (user != null) {
user2session.remove(user);
user2sessionLegacy.remove(user);
}
}
@Override
public int loggedInUsers() {
return user2sessionLegacy.size();
}
}