package org.beangle.security.monitor.auth.session.service;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.beangle.commons.collection.ListUtil;
import org.beangle.commons.collection.MapUtil;
import org.beangle.security.User;
import org.beangle.security.UserCategory;
import org.beangle.security.monitor.Authentication;
import org.beangle.security.monitor.AuthenticationException;
import org.beangle.security.monitor.OnlineActivity;
import org.beangle.security.monitor.auth.session.CategoryProfile;
import org.beangle.security.monitor.auth.session.SessionIdentifierAware;
import org.beangle.security.monitor.auth.session.SessionProfile;
import org.beangle.security.monitor.auth.session.SessionProfileProvider;
import org.beangle.security.monitor.auth.session.SessionRegistry;
import org.beangle.security.monitor.auth.session.model.OnlineActivityBean;
import org.beangle.security.monitor.auth.ui.UserDetails;
import org.beangle.security.monitor.auth.web.WebUserDetails;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DefaultSessionController implements ProfileSessionController {
private final Logger logger = LoggerFactory.getLogger(DefaultSessionController.class);
protected SessionRegistry sessionRegistry;
/** 用户类型配置提供服务 */
protected SessionProfileProvider profileProvider;
/** 各类监测类型的监测数据 */
protected Map<UserCategory, OnlineProfile> profileMap = MapUtil.newHashMap();
/** 是否加载了用户配置 */
private boolean loaded = false;
private boolean exceptionIfMaximumExceeded = false;
/**
* allowableSessionsExceeded
*
* @param sessionId
* @param sessions
* @param allowableSessions
* @param registry
* @see checkAuthenticationAllowed
*/
protected boolean allowableSessionsExceeded(String sessionId, List<OnlineActivity> sessions,
int allowableSessions, SessionRegistry registry) {
if (exceptionIfMaximumExceeded || (sessions == null)) {
return false;
}
// Determine least recently used session, and mark it for invalidation
OnlineActivity leastRecentlyUsed = null;
for (int i = 0; i < sessions.size(); i++) {
if ((leastRecentlyUsed == null)
|| sessions.get(i).getLastAccessAt()
.before(leastRecentlyUsed.getLastAccessAt())) {
leastRecentlyUsed = (OnlineActivity) sessions.get(i);
}
}
leastRecentlyUsed.expireNow();
return true;
}
public boolean checkAuthenticationAllowed(Authentication request)
throws AuthenticationException {
Object principal = request.getPrincipal();
String sessionId = ((SessionIdentifierAware) request.getDetails()).getSessionId();
List<OnlineActivity> sessions = sessionRegistry.getOnlineActivities(principal, false);
int sessionCount = 0;
if (sessions != null) {
sessionCount = sessions.size();
}
int allowableSessions = getMaximumSessionsForThisUser(request);
if (sessionCount < allowableSessions) {
return true;
} else if (allowableSessions == -1) {
return true;
} else if (sessionCount == allowableSessions) {
for (int i = 0; i < sessionCount; i++) {
if ((sessions.get(i)).getSessionid().equals(sessionId)) {
return true;
}
}
}
return allowableSessionsExceeded(sessionId, sessions, allowableSessions, sessionRegistry);
}
public int getMax() {
int max = 0;
for (OnlineProfile element : profileMap.values()) {
max += element.getCategoryProfile().getCapacity();
}
return max;
}
public int getMax(UserCategory category) {
return profileMap.get(category).getCategoryProfile().getCapacity();
}
public int getInactiveInterval(UserCategory category) {
return profileMap.get(category).getCategoryProfile().getInactiveInterval();
}
public int getOnlineCount() {
int online = 0;
for (OnlineProfile element : profileMap.values()) {
online += element.getOnline();
}
return online;
}
public int getOnlineCount(UserCategory category) {
return ((OnlineProfile) profileMap.get(category)).getOnline();
}
public boolean isMaxArrived() {
return getOnlineCount() >= getMax();
}
public boolean isMaxArrived(UserCategory category) {
return getOnlineCount(category) >= getMax(category);
}
public List<OnlineProfile> getOnlineProfiles() {
return ListUtil.newArrayList(profileMap.values());
}
// FIXME 动态更新配置
// public void setCategoryProfile(UserCategory category, CategoryProfile
// profile) {
// ((OnlineProfile) profileMap.get(category)).setCategoryProfile(profile);
// }
public void changeCategory(String sessionId, UserCategory category) {
OnlineActivityBean record = (OnlineActivityBean) sessionRegistry
.getOnlineActivity(sessionId);
if (!record.getCategory().equals(category)) {
profileMap.get(record.getCategory()).left();
profileMap.get(category).reserve();
record.setCategory(category);
}
}
/**
* 注销会话
*/
public OnlineActivity removeAuthentication(String sessionId) {
OnlineActivity info = sessionRegistry.remove(sessionId);
if (null != info) {
UserCategory category = info.getCategory();
OnlineProfile profile = ((OnlineProfile) profileMap.get(category));
profile.left();
}
return info;
}
/**
* 根据用户身份确定单个用户的最大会话数<br>
* Method intended for use by subclasses to override the maximum number of
* sessions that are permitted for a particular authentication.
*
* @param authentication
* to determine the maximum sessions for
* @return either -1 meaning unlimited, or a positive integer to limit
* (never zero)
*/
protected int getMaximumSessionsForThisUser(Authentication auth) {
loadProfilesWhenNecessary();
UserDetails details = (UserDetails) auth.getDetails();
OnlineProfile profile = (OnlineProfile) profileMap.get(details.getCategory());
if (null == profile) {
logger.error("cannot find profile for {}", details.getCategory().getId());
throw new RuntimeException("cannot find profile:" + details.getCategory().getName());
}
return profile.getCategoryProfile().getUserMaxSessions();
}
/**
* 注册用户
*/
public void registerAuthentication(Authentication authentication) {
WebUserDetails details = (WebUserDetails) authentication.getDetails();
OnlineProfile profile = (OnlineProfile) profileMap.get(details.getCategory());
OnlineActivity existed = getOnlineActivity(details.getSessionId());
String sessionId = details.getSessionId();
Object principal = authentication.getPrincipal();
OnlineActivity newOne = OnlineActivityBuilder.build(principal, authentication.getDetails(),
sessionId, new Date());
// 原先没有的要占座
if (null == existed) {
if (!profile.reserve())
throw new AuthenticationException(Authentication.ERROR_OVERMAX);
}
// calculateOnline();
sessionRegistry.register(sessionId, principal, newOne);
// logger.debug("Register session {} for {}", sessionId, principal);
}
public void calculateOnline() {
int all = 0;
for (UserCategory category : profileMap.keySet()) {
OnlineProfile p = (OnlineProfile) profileMap.get(category);
all += p.getOnline();
}
if (all != sessionRegistry.count()) {
logger.info("start calculate...registry {} profile {}", new Integer(sessionRegistry
.count()), new Integer(all));
if (all > 0)
throw new RuntimeException("");
Map<UserCategory, OnlineProfile> newProfileMap = MapUtil.newHashMap();
for (final UserCategory category : profileMap.keySet()) {
OnlineProfile profile = (OnlineProfile) profileMap.get(category);
OnlineProfile newProfile = new OnlineProfile();
newProfile.setCategoryProfile(profile.getCategoryProfile());
newProfileMap.put(category, newProfile);
}
List<OnlineActivity> infos = sessionRegistry.getOnlineActivities();
for (final OnlineActivity info : infos) {
OnlineProfile profile = newProfileMap.get(info.getCategory());
profile.reserve();
}
profileMap.putAll(newProfileMap);
}
}
public Collection<OnlineActivity> getOnlineActivities(UserCategory category) {
List<OnlineActivity> activities = ListUtil.newArrayList();
for (OnlineActivity oa : sessionRegistry.getOnlineActivities()) {
if (oa.getCategory().equals(category)) {
activities.add(oa);
}
}
return activities;
}
public void loadProfilesWhenNecessary() {
if (!loaded) {
synchronized (this) {
if (loaded)
return;
loadProfiles();
}
}
}
public void loadProfiles() {
if (null == profileProvider) {
loaded = true;
logger.warn("Cannot load profile for profileProvider not found!");
return;
}
SessionProfile sessionProfile = profileProvider.getProfile();
if (null != sessionProfile) {
for (CategoryProfile cp : sessionProfile.getCategoryProfiles().values()) {
int initOnline=0;
OnlineProfile existed=profileMap.get(cp.getCategory());
if(null!=existed){
initOnline=existed.getOnline();
}
profileMap.put(cp.getCategory(), new OnlineProfile(cp,initOnline));
logger.info(cp.toString());
}
}
loaded = !(profileMap.isEmpty());
}
public Collection<OnlineActivity> getOnlineActivities(User user) {
return sessionRegistry.getOnlineActivities(user.getName(), true);
}
public SessionProfileProvider getProfileProvider() {
return profileProvider;
}
public void setProfileProvider(SessionProfileProvider profileProvider) {
this.profileProvider = profileProvider;
}
public void setExceptionIfMaximumExceeded(boolean exceptionIfMaximumExceeded) {
this.exceptionIfMaximumExceeded = exceptionIfMaximumExceeded;
}
public OnlineActivity getOnlineActivity(String sessionId) {
return sessionRegistry.getOnlineActivity(sessionId);
}
public List<OnlineActivity> getOnlineActivities() {
return sessionRegistry.getOnlineActivities();
}
public boolean isRegisted(Object principal) {
return sessionRegistry.isRegisted(principal);
}
public void setSessionRegistry(SessionRegistry sessionRegistry) {
this.sessionRegistry = sessionRegistry;
}
}