From 1ca1aa74cc3797638e990c0abe127bec0661ec9c Mon Sep 17 00:00:00 2001
From: srosse <none@none>
Date: Fri, 16 Nov 2012 10:59:20 +0100
Subject: [PATCH] OO-271: refactor the user session management, move the the
 logic in its own manager, persist the time out values, make the admin GUI a
 bit better

---
 .../bps/course/nodes/vc/_spring/vcContext.xml |   7 +-
 .../java/org/olat/NewControllerFactory.java   |   6 +-
 src/main/java/org/olat/admin/AdminModule.java |  16 +-
 .../org/olat/admin/AdminModuleDispatcher.java |   7 +-
 .../admin/_i18n/LocalStrings_de.properties    |   4 +
 .../datasources/ThreadAndControllerInfo.java  |   5 +-
 .../admin/sysinfo/MRTGStatsDispatcher.java    |  10 +-
 .../olat/admin/sysinfo/SessionAdminForm.java  |  92 ---
 .../SessionAdminOldestSessionForm.java        |  78 ---
 .../SessionAdministrationController.java      | 216 ------
 .../olat/admin/sysinfo/SysinfoController.java |  16 -
 .../sysinfo/UserSessionAdminController.java   | 110 +++
 .../UserSessionConfigAdminController.java     | 192 +++++
 .../admin/sysinfo/UserSessionController.java  |  82 ++-
 .../sysinfo/UserSessionDetailsController.java | 114 +++
 .../UserSessionInformationsController.java    | 106 +++
 .../admin/sysinfo/UserSessionTableModel.java  |  15 +-
 .../sysinfo/_content/usersession_admin.html   |   7 +
 .../sysinfo/_content/usersession_infos.html   |   2 +
 .../sysinfo/_i18n/LocalStrings_de.properties  |   3 +
 .../org/olat/basesecurity/AuthHelper.java     |  17 +-
 .../_spring/baseSecurityContext.xml           |   6 +-
 .../commons/servlets/WebDAVManagerImpl.java   |  18 +-
 .../servlets/_spring/webdavManagerContext.xml |   1 +
 .../ContextHelpFilePathHandler.java           |  19 +-
 .../org/olat/core/_spring/mainCorecontext.xml |   1 -
 .../_spring/contextHelpCorecontext.xml        |   7 +-
 .../fullWebApp/DefaultFooterController.java   |   5 +-
 .../fullWebApp/DefaultTopNavController.java   |   4 +-
 .../util/_spring/StickyMessageCorecontext.xml |   6 +-
 .../glossary/_spring/glossaryCorecontext.xml  |   7 +-
 .../services/_spring/servicesCorecontext.xml  |   1 -
 .../_spring/taskExecutorCorecontext.xml       |   7 +-
 .../java/org/olat/core/gui/UserRequest.java   |   4 +-
 .../org/olat/core/gui/components/Window.java  |   2 -
 .../components/util/UserLoggedInCounter.java  |   7 +-
 .../core/gui/control/DefaultController.java   |   5 +-
 .../generic/layout/GenericMainController.java |  16 +
 .../org/olat/core/gui/media/ServletUtil.java  |   7 +-
 .../java/org/olat/core/logging/Tracing.java   |   6 +-
 .../activity/UserActivityLoggerImpl.java      |   4 +-
 .../org/olat/core/util/SignOnOffEvent.java    |   2 +
 .../java/org/olat/core/util/UserSession.java  | 660 ++----------------
 .../core/util/_spring/utilCorecontext.xml     |  25 +
 .../org/olat/core/util/i18n/I18nManager.java  |   4 +-
 .../util/i18n/_spring/i18nCorecontext.xml     |   6 +-
 .../core/util/session/UserSessionManager.java | 605 ++++++++++++++++
 .../core/util/session/UserSessionModule.java  |  85 +++
 .../version/_spring/versioningCorecontext.xml |   7 +-
 .../assessment/_spring/assessmentContext.xml  |   3 +-
 .../nodes/_spring/buildingblockContext.xml    |   1 -
 .../dispatcher/AuthenticatedDispatcher.java   |   4 +-
 .../org/olat/dispatcher/DMZDispatcher.java    |   6 +-
 .../org/olat/dispatcher/RESTDispatcher.java   |   3 +-
 .../RedirectToAutoGuestLoginDispatcher.java   |  11 +-
 .../group/_spring/businessGroupContext.xml    |   1 -
 .../org/olat/ims/qti/QTIStaticsHandler.java   |   5 +-
 .../_spring/instantMessagingContext.xml       |   1 -
 .../rosterandchat/ChangePresenceJob.java      |  12 +-
 .../ui/ConnectedUsersLocal.java               |  10 +-
 .../olat/modules/_spring/modulesContext.xml   |   1 -
 .../_spring/openmeetingsContext.xml           |   1 -
 .../modules/vitero/_spring/viteroContext.xml  |   1 -
 .../accesscontrol/_spring/acContext.xml       |   1 -
 .../provider/paypal/ui/PaypalMapper.java      |   4 +-
 .../restapi/security/RestApiLoginFilter.java  |  11 +-
 .../system/OpenOLATStatisticsWebService.java  |   7 +-
 .../ShibbolethRegistrationController.java     |   8 +-
 .../olat/upgrade/_spring/upgradeContext.xml   |   1 -
 .../org/olat/user/ChangePrefsController.java  |  15 +-
 .../resources/serviceconfig/olat.properties   |   4 +
 .../org/olat/_spring/extensionContext.xml     |  41 +-
 .../dispatcher/mapper/MapperServiceTest.java  |   5 +-
 src/test/java/org/olat/test/OlatTestCase.java |   1 +
 74 files changed, 1608 insertions(+), 1182 deletions(-)
 delete mode 100644 src/main/java/org/olat/admin/sysinfo/SessionAdminForm.java
 delete mode 100644 src/main/java/org/olat/admin/sysinfo/SessionAdminOldestSessionForm.java
 delete mode 100644 src/main/java/org/olat/admin/sysinfo/SessionAdministrationController.java
 create mode 100644 src/main/java/org/olat/admin/sysinfo/UserSessionAdminController.java
 create mode 100644 src/main/java/org/olat/admin/sysinfo/UserSessionConfigAdminController.java
 create mode 100644 src/main/java/org/olat/admin/sysinfo/UserSessionDetailsController.java
 create mode 100644 src/main/java/org/olat/admin/sysinfo/UserSessionInformationsController.java
 create mode 100644 src/main/java/org/olat/admin/sysinfo/_content/usersession_admin.html
 create mode 100644 src/main/java/org/olat/admin/sysinfo/_content/usersession_infos.html
 create mode 100644 src/main/java/org/olat/core/util/session/UserSessionManager.java
 create mode 100644 src/main/java/org/olat/core/util/session/UserSessionModule.java

diff --git a/src/main/java/de/bps/course/nodes/vc/_spring/vcContext.xml b/src/main/java/de/bps/course/nodes/vc/_spring/vcContext.xml
index d21ccb56525..55cccb7c9f3 100644
--- a/src/main/java/de/bps/course/nodes/vc/_spring/vcContext.xml
+++ b/src/main/java/de/bps/course/nodes/vc/_spring/vcContext.xml
@@ -1,14 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <beans xmlns="http://www.springframework.org/schema/beans"
 	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-	xmlns:context="http://www.springframework.org/schema/context" 
 	xsi:schemaLocation="
   http://www.springframework.org/schema/beans 
-  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
-  http://www.springframework.org/schema/context 
-  http://www.springframework.org/schema/context/spring-context-3.0.xsd">
-
-<context:annotation-config />
+  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
 
 <!-- ####################################### -->
 <!-- # VIRTUAL CLASSROOM SERVICE PROVIDERS # -->
diff --git a/src/main/java/org/olat/NewControllerFactory.java b/src/main/java/org/olat/NewControllerFactory.java
index a248af842a8..04ad67dfbc7 100644
--- a/src/main/java/org/olat/NewControllerFactory.java
+++ b/src/main/java/org/olat/NewControllerFactory.java
@@ -48,6 +48,7 @@ import org.olat.core.id.context.ContextEntryControllerCreator;
 import org.olat.core.id.context.TabContext;
 import org.olat.core.logging.AssertException;
 import org.olat.core.logging.LogDelegator;
+import org.olat.core.util.UserSession;
 import org.olat.core.util.resource.OresHelper;
 import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryManager;
@@ -163,7 +164,8 @@ public class NewControllerFactory extends LogDelegator {
 		}
 
 		// was brasato:: DTabs dts = wControl.getDTabs();
-		Window window = Windows.getWindows(ureq.getUserSession()).getWindow(ureq);
+		UserSession usess = ureq.getUserSession();
+		Window window = Windows.getWindows(usess).getWindow(ureq);
 
 		if (window == null) {
 			logDebug("Found no window for jumpin => take WindowBackOffice", null);
@@ -230,7 +232,7 @@ public class NewControllerFactory extends LogDelegator {
 				return false;
 			} else {
 				WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(bc, dt.getWindowControl());
-				ureq.getUserSession().addToHistory(ureq, bc);
+				usess.addToHistory(ureq, bc);
 				Controller launchC = typeHandler.createController(mainCe, ureq, bwControl);
 				if (launchC == null) {
 					throw new AssertException("ControllerFactory could not create a controller to be launched. Please validate businesspath " 
diff --git a/src/main/java/org/olat/admin/AdminModule.java b/src/main/java/org/olat/admin/AdminModule.java
index 4ee6f59e2a0..2f8e0a11f34 100644
--- a/src/main/java/org/olat/admin/AdminModule.java
+++ b/src/main/java/org/olat/admin/AdminModule.java
@@ -33,6 +33,7 @@ import org.olat.NewControllerFactory;
 import org.olat.admin.site.AdminSite;
 import org.olat.admin.user.UserAdminContextEntryControllerCreator;
 import org.olat.basesecurity.AuthHelper;
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.fullWebApp.util.GlobalStickyMessage;
 import org.olat.core.commons.persistence.DBFactory;
 import org.olat.core.configuration.AbstractOLATModule;
@@ -40,7 +41,7 @@ import org.olat.core.configuration.PersistedProperties;
 import org.olat.core.id.User;
 import org.olat.core.id.context.SiteContextEntryControllerCreator;
 import org.olat.core.logging.Tracing;
-import org.olat.core.util.UserSession;
+import org.olat.core.util.session.UserSessionManager;
 import org.olat.instantMessaging.rosterandchat.ChangePresenceJob;
 import org.olat.properties.Property;
 import org.olat.properties.PropertyManager;
@@ -172,9 +173,9 @@ public class AdminModule extends AbstractOLATModule {
 	 * Invalidated all session except administrator-sessions. 
 	 * @return  Number of invalidated sessions
 	 */
-	public static int invalidateAllSessions() {
+	public static int invalidateAllSessionsDepr() {
 		Tracing.logAudit("Session administration: Invalidate all sessions.", AdminModule.class);
-		return UserSession.invalidateAllSessions();
+		return CoreSpringFactory.getImpl(UserSessionManager.class).invalidateAllSessions();
 	}
 
 	/**
@@ -182,19 +183,20 @@ public class AdminModule extends AbstractOLATModule {
 	 * @param nbrSessions
 	 * @return  Number of invalidated sessions
 	 */
-	public static int invalidateOldestSessions(int nbrSessions) {
+	public static int invalidateOldestSessionsDepr(int nbrSessions) {
 		Tracing.logAudit("Session administration: Invalidate oldest sessions Nbr-Sessions=" + nbrSessions, AdminModule.class);
-		return UserSession.invalidateOldestSessions(nbrSessions);
+		return  CoreSpringFactory.getImpl(UserSessionManager.class).invalidateOldestSessions(nbrSessions);
 	}
 
 	/**
 	 * Set global session timeout in msec.
 	 * @param sessionTimeout
 	 */
-	public static void setSessionTimeout(int sessionTimeout) {
+	public static void setSessionTimeoutDepr(int sessionTimeout) {
 		Tracing.logAudit("Session administration: Set session-timeout=" + sessionTimeout, AdminModule.class);
 		//in seconds
-		UserSession.setGlobalSessionTimeout(sessionTimeout);
+
+		CoreSpringFactory.getImpl(UserSessionManager.class).setGlobalSessionTimeout(sessionTimeout);
 		//in milliseconds for presence job
 		ChangePresenceJob.setAutoLogOutCutTimeValue(sessionTimeout*1000);
 	}
diff --git a/src/main/java/org/olat/admin/AdminModuleDispatcher.java b/src/main/java/org/olat/admin/AdminModuleDispatcher.java
index b2ba812bc97..d4e226e1e1e 100644
--- a/src/main/java/org/olat/admin/AdminModuleDispatcher.java
+++ b/src/main/java/org/olat/admin/AdminModuleDispatcher.java
@@ -33,6 +33,7 @@ import org.olat.core.CoreSpringFactory;
 import org.olat.core.dispatcher.Dispatcher;
 import org.olat.core.dispatcher.DispatcherAction;
 import org.olat.core.gui.media.ServletUtil;
+import org.olat.core.util.session.UserSessionManager;
 
 /**
  * 
@@ -92,7 +93,7 @@ public class AdminModuleDispatcher implements Dispatcher {
 		}else if (cmd.equalsIgnoreCase(CMD_SET_MAX_SESSIONS)) {
 			handleSetMaxSessions(request, response);
 		}else if (cmd.equalsIgnoreCase(CMD_INVALIDATE_ALL_SESSIONS)) {
-			AdminModule.invalidateAllSessions();
+			CoreSpringFactory.getImpl(UserSessionManager.class).invalidateAllSessions();
 			ServletUtil.serveStringResource(request, response, "Ok, Invalidated all sessions");
 		}else if (cmd.equalsIgnoreCase(CMD_INVALIDATE_OLDEST_SESSIONS)) {
 			handleInvidateOldestSessions(request, response);
@@ -130,7 +131,7 @@ public class AdminModuleDispatcher implements Dispatcher {
 		} else {
 			try {
 				int sessionTimeout = Integer.parseInt(paramStr);
-				AdminModule.setSessionTimeout(sessionTimeout);
+				CoreSpringFactory.getImpl(UserSessionManager.class).setGlobalSessionTimeout(sessionTimeout);
 				ServletUtil.serveStringResource(request, response, "Ok, sessiontimeout=" + sessionTimeout);
 			} catch (NumberFormatException nbrException) {
 				ServletUtil.serveStringResource(request, response, "NOT_OK, parameter " + PARAMETER_SESSIONTIMEOUT + " must be a number");
@@ -151,7 +152,7 @@ public class AdminModuleDispatcher implements Dispatcher {
 		} else {
 			try {
 				int nbrSessions = Integer.parseInt(nbrSessionsString);
-				AdminModule.invalidateOldestSessions(nbrSessions);
+				CoreSpringFactory.getImpl(UserSessionManager.class).invalidateOldestSessions(nbrSessions);
 				ServletUtil.serveStringResource(request, response, "Ok, Invalidated oldest sessions, nbrSessions=" + nbrSessions);
 			} catch (NumberFormatException nbrException) {
 				ServletUtil.serveStringResource(request, response, "NOT_OK, parameter " + PARAMETER_NBR_SESSIONS + " must be a number");
diff --git a/src/main/java/org/olat/admin/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/admin/_i18n/LocalStrings_de.properties
index 7426cb15518..c204660df94 100644
--- a/src/main/java/org/olat/admin/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/admin/_i18n/LocalStrings_de.properties
@@ -72,6 +72,10 @@ menu.statistics=Statistiken
 menu.statistics.alt=Logfile Statistiken
 menu.sysinfo=System Informationen
 menu.sysinfo.alt=System Informationen
+menu.system=System
+menu.system.alt=System
+menu.session=Benutzersessions
+menu.session.alt=Benutzersessions
 menu.ucreate=Benutzer erstellen
 menu.ucreate.alt=Benutzer erstellen
 menu.umgmt=Benutzerverwaltung
diff --git a/src/main/java/org/olat/admin/jmx/datasources/ThreadAndControllerInfo.java b/src/main/java/org/olat/admin/jmx/datasources/ThreadAndControllerInfo.java
index 9a1b9f5c5a5..1d9f6e12bcc 100644
--- a/src/main/java/org/olat/admin/jmx/datasources/ThreadAndControllerInfo.java
+++ b/src/main/java/org/olat/admin/jmx/datasources/ThreadAndControllerInfo.java
@@ -27,9 +27,10 @@ package org.olat.admin.jmx.datasources;
 import java.lang.management.ManagementFactory;
 import java.lang.management.MemoryMXBean;
 
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.dispatcher.DispatcherAction;
 import org.olat.core.gui.control.DefaultController;
-import org.olat.core.util.UserSession;
+import org.olat.core.util.session.UserSessionManager;
 
 /**
  * Description:<br>
@@ -51,7 +52,7 @@ public class ThreadAndControllerInfo {
 	}
 		
 	public int getAuthenticatedNodeUsersCount() {
-		return UserSession.getAuthenticatedUserSessions().size();
+		return CoreSpringFactory.getImpl(UserSessionManager.class).getNumberOfAuthenticatedUserSessions();
 	}
 		
 	public long getMemoryHeapUsageKB() {
diff --git a/src/main/java/org/olat/admin/sysinfo/MRTGStatsDispatcher.java b/src/main/java/org/olat/admin/sysinfo/MRTGStatsDispatcher.java
index b9068897ab2..446dd67bf4d 100644
--- a/src/main/java/org/olat/admin/sysinfo/MRTGStatsDispatcher.java
+++ b/src/main/java/org/olat/admin/sysinfo/MRTGStatsDispatcher.java
@@ -35,8 +35,8 @@ import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.Set;
 import java.util.Map.Entry;
+import java.util.Set;
 import java.util.logging.Level;
 
 import javax.servlet.http.HttpServletRequest;
@@ -48,6 +48,7 @@ import org.olat.basesecurity.Constants;
 import org.olat.basesecurity.SecurityGroup;
 import org.olat.commons.coordinate.cluster.jms.ClusterEventBus;
 import org.olat.commons.coordinate.cluster.jms.SimpleProbe;
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.persistence.DBQueryImpl;
 import org.olat.core.dispatcher.Dispatcher;
 import org.olat.core.dispatcher.DispatcherAction;
@@ -58,6 +59,7 @@ import org.olat.core.logging.Tracing;
 import org.olat.core.util.SessionInfo;
 import org.olat.core.util.UserSession;
 import org.olat.core.util.coordinate.CoordinatorManager;
+import org.olat.core.util.session.UserSessionManager;
 import org.olat.course.CourseModule;
 import org.olat.instantMessaging.InstantMessagingModule;
 import org.olat.repository.RepositoryEntry;
@@ -169,7 +171,8 @@ public class MRTGStatsDispatcher implements Dispatcher {
 		int httpsCount = 0;
 		int activeSessionCnt = 0;
 		if (command.equals("users")) { // get user stats of (authenticated) usersessions
-			Set<UserSession> userSessions = UserSession.getAuthenticatedUserSessions();
+			UserSessionManager sessionManager = CoreSpringFactory.getImpl(UserSessionManager.class);
+			Set<UserSession> userSessions = sessionManager.getAuthenticatedUserSessions();
 			for (Iterator<UserSession> it_usess = userSessions.iterator(); it_usess.hasNext();) {
 				UserSession usess = (UserSession) it_usess.next();
 				activeSessionCnt++;
@@ -182,7 +185,8 @@ public class MRTGStatsDispatcher implements Dispatcher {
 			result.append("\n0\n");
 			result.append(instanceId);
 		} else if (command.equals("webdav")) { // get webdav stats of (authenticated) usersessions
-			Set<UserSession> userSessions = UserSession.getAuthenticatedUserSessions();
+			UserSessionManager sessionManager = CoreSpringFactory.getImpl(UserSessionManager.class);
+			Set<UserSession> userSessions = sessionManager.getAuthenticatedUserSessions();
 			int webdavcount = 0;
 			int securewebdavcount = 0;
 			for (Iterator<UserSession> it_usess = userSessions.iterator(); it_usess.hasNext();) {
diff --git a/src/main/java/org/olat/admin/sysinfo/SessionAdminForm.java b/src/main/java/org/olat/admin/sysinfo/SessionAdminForm.java
deleted file mode 100644
index 903530526e6..00000000000
--- a/src/main/java/org/olat/admin/sysinfo/SessionAdminForm.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/**
-* OLAT - Online Learning and Training<br>
-* http://www.olat.org
-* <p>
-* Licensed under the Apache License, Version 2.0 (the "License"); <br>
-* you may not use this file except in compliance with the License.<br>
-* You may obtain a copy of the License at
-* <p>
-* http://www.apache.org/licenses/LICENSE-2.0
-* <p>
-* Unless required by applicable law or agreed to in writing,<br>
-* software distributed under the License is distributed on an "AS IS" BASIS, <br>
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
-* See the License for the specific language governing permissions and <br>
-* limitations under the License.
-* <p>
-* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br>
-* University of Zurich, Switzerland.
-* <hr>
-* <a href="http://www.openolat.org">
-* OpenOLAT - Online Learning and Training</a><br>
-* This file has been modified by the OpenOLAT community. Changes are licensed
-* under the Apache 2.0 license as the original file.
-*/
-
-package org.olat.admin.sysinfo;
-
-import org.olat.core.gui.UserRequest;
-import org.olat.core.gui.components.form.flexible.FormItemContainer;
-import org.olat.core.gui.components.form.flexible.elements.IntegerElement;
-import org.olat.core.gui.components.form.flexible.elements.Submit;
-import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
-import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
-import org.olat.core.gui.components.form.flexible.impl.elements.FormSubmit;
-import org.olat.core.gui.control.Controller;
-import org.olat.core.gui.control.Event;
-import org.olat.core.gui.control.WindowControl;
-import org.olat.core.gui.translator.Translator;
-
-public class SessionAdminForm extends FormBasicController {
-	private IntegerElement sessionTimeout;
-	private IntegerElement maxSessions;
-	private int initialSessionTimeoutInSec;
-	private int initialMaxSessions;
-	
-	public SessionAdminForm(UserRequest ureq, WindowControl wControl, Translator translator, int initialSessionTimeoutInSec, int initialMaxSessions) {
-		super(ureq, wControl);
-		setTranslator(translator);
-		this.initialSessionTimeoutInSec = initialSessionTimeoutInSec;
-		this.initialMaxSessions = initialMaxSessions;
-		initForm(ureq);		
-	}
-	
-	@Override
-	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
-		FormLayoutContainer verticalL = FormLayoutContainer.createVerticalFormLayout("verticalL", getTranslator());
-		formLayout.add(verticalL);
-		sessionTimeout = uifactory.addIntegerElement("session.timeout", "session.timeout.label", initialSessionTimeoutInSec, verticalL);
-		maxSessions = uifactory.addIntegerElement("max.sessions", "max.sessions.label", initialMaxSessions, verticalL);
-		Submit saveButton = new FormSubmit("save","save");
-		formLayout.add(saveButton);	
-	}	
-	
-	@Override
-	protected void doDispose() {
-		//empty		
-	}
-
-	@Override
-	protected void formOK(UserRequest ureq) {
-		fireEvent(ureq, Event.DONE_EVENT);  
-	}
-	
-	@Override
-	protected void formResetted(UserRequest ureq) {
-		fireEvent(ureq, Event.CANCELLED_EVENT);      
-	}	
-
-	/**
-	 * sessiontimout in seconds
-	 * @return
-	 */
-	public int getSessionTimeout() {
-		return sessionTimeout.getIntValue();
-	}
-
-	public int getMaxSessions() {
-		return maxSessions.getIntValue();
-	}
-	
-}
-	
diff --git a/src/main/java/org/olat/admin/sysinfo/SessionAdminOldestSessionForm.java b/src/main/java/org/olat/admin/sysinfo/SessionAdminOldestSessionForm.java
deleted file mode 100644
index 147b3c87be8..00000000000
--- a/src/main/java/org/olat/admin/sysinfo/SessionAdminOldestSessionForm.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/**
-* OLAT - Online Learning and Training<br>
-* http://www.olat.org
-* <p>
-* Licensed under the Apache License, Version 2.0 (the "License"); <br>
-* you may not use this file except in compliance with the License.<br>
-* You may obtain a copy of the License at
-* <p>
-* http://www.apache.org/licenses/LICENSE-2.0
-* <p>
-* Unless required by applicable law or agreed to in writing,<br>
-* software distributed under the License is distributed on an "AS IS" BASIS, <br>
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
-* See the License for the specific language governing permissions and <br>
-* limitations under the License.
-* <p>
-* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br>
-* University of Zurich, Switzerland.
-* <hr>
-* <a href="http://www.openolat.org">
-* OpenOLAT - Online Learning and Training</a><br>
-* This file has been modified by the OpenOLAT community. Changes are licensed
-* under the Apache 2.0 license as the original file.
-*/
-
-package org.olat.admin.sysinfo;
-
-import org.olat.core.gui.UserRequest;
-import org.olat.core.gui.components.form.flexible.FormItemContainer;
-import org.olat.core.gui.components.form.flexible.elements.IntegerElement;
-import org.olat.core.gui.components.form.flexible.elements.Submit;
-import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
-import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
-import org.olat.core.gui.components.form.flexible.impl.elements.FormSubmit;
-import org.olat.core.gui.control.Controller;
-import org.olat.core.gui.control.Event;
-import org.olat.core.gui.control.WindowControl;
-import org.olat.core.gui.translator.Translator;
-
-public class SessionAdminOldestSessionForm extends FormBasicController {
-	private IntegerElement nbrSessions;
-	
-	public SessionAdminOldestSessionForm(UserRequest ureq, WindowControl wControl, Translator translator) {
-		super(ureq, wControl);
-		setTranslator(translator);
-		initForm(ureq);		
-	}
-	
-	@Override
-	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
-		FormLayoutContainer verticalL = FormLayoutContainer.createVerticalFormLayout("verticalL", getTranslator());
-		formLayout.add(verticalL);
-		nbrSessions = uifactory.addIntegerElement("nbr.session", "nbr.session.label", 0, verticalL);
-		Submit oldestSessionButton = new FormSubmit("save","oldest.session.button");
-		formLayout.add(oldestSessionButton);	
-	}	
-	
-	@Override
-	protected void doDispose() {
-		//empty		
-	}
-
-	@Override
-	protected void formOK(UserRequest ureq) {
-		fireEvent(ureq, Event.DONE_EVENT);  
-	}
-	
-	@Override
-	protected void formResetted(UserRequest ureq) {
-		fireEvent(ureq, Event.CANCELLED_EVENT);      
-	}	
-
-	public int getNbrSessions() {
-		return nbrSessions.getIntValue();
-	}
-
-}
-	
diff --git a/src/main/java/org/olat/admin/sysinfo/SessionAdministrationController.java b/src/main/java/org/olat/admin/sysinfo/SessionAdministrationController.java
deleted file mode 100644
index 216637a2c11..00000000000
--- a/src/main/java/org/olat/admin/sysinfo/SessionAdministrationController.java
+++ /dev/null
@@ -1,216 +0,0 @@
-/**
-* OLAT - Online Learning and Training<br>
-* http://www.olat.org
-* <p>
-* Licensed under the Apache License, Version 2.0 (the "License"); <br>
-* you may not use this file except in compliance with the License.<br>
-* You may obtain a copy of the License at
-* <p>
-* http://www.apache.org/licenses/LICENSE-2.0
-* <p>
-* Unless required by applicable law or agreed to in writing,<br>
-* software distributed under the License is distributed on an "AS IS" BASIS, <br>
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
-* See the License for the specific language governing permissions and <br>
-* limitations under the License.
-* <p>
-* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br>
-* University of Zurich, Switzerland.
-* <hr>
-* <a href="http://www.openolat.org">
-* OpenOLAT - Online Learning and Training</a><br>
-* This file has been modified by the OpenOLAT community. Changes are licensed
-* under the Apache 2.0 license as the original file.
-*/
-
-package org.olat.admin.sysinfo;
-
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
-import java.util.Iterator;
-import java.util.Set;
-
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.olat.admin.AdminModule;
-import org.olat.basesecurity.AuthHelper;
-import org.olat.core.gui.UserRequest;
-import org.olat.core.gui.Windows;
-import org.olat.core.gui.components.Component;
-import org.olat.core.gui.components.Window;
-import org.olat.core.gui.components.link.Link;
-import org.olat.core.gui.components.link.LinkFactory;
-import org.olat.core.gui.components.text.TextFactory;
-import org.olat.core.gui.components.velocity.VelocityContainer;
-import org.olat.core.gui.control.Controller;
-import org.olat.core.gui.control.DefaultController;
-import org.olat.core.gui.control.Event;
-import org.olat.core.gui.control.WindowControl;
-import org.olat.core.gui.control.controller.BasicController;
-import org.olat.core.gui.control.generic.modal.DialogBoxController;
-import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory;
-import org.olat.core.id.Identity;
-import org.olat.core.logging.OLog;
-import org.olat.core.logging.Tracing;
-import org.olat.core.util.Formatter;
-import org.olat.core.util.UserSession;
-import org.olat.core.util.Util;
-import org.olat.core.util.WebappHelper;
-import org.olat.core.util.coordinate.CoordinatorManager;
-import org.olat.properties.Property;
-import org.olat.properties.PropertyManager;
-
-/**
- *  @author Christian Guretzki
- */
-
-public class SessionAdministrationController extends BasicController {
-	
-	OLog log = Tracing.createLoggerFor(this.getClass());
-	private static final String VELOCITY_ROOT = Util.getPackageVelocityRoot(SysinfoController.class);
-
-	private VelocityContainer myContent;
-	private Link invalidateAllSsssionLink;
-	private DialogBoxController invalidateAllConfirmController;
-	private Link blockLoginLink;
-	private Link allowLoginLink;
-	private DialogBoxController blockLoginConfirmController;
-	private Link rejectDMZReuqestsLink;
-	private Link allowDMZRequestsLink;
-	private DialogBoxController rejectDMZRequestsConfirmController;
-  private SessionAdminForm sessionAdminForm;
-  private SessionAdminOldestSessionForm sessionAdminOldestSessionForm;
-  
-	/**
-	 * Controlls user session in admin view.
-	 * 
-	 * @param ureq
-	 * @param wControl
-	 */
-	public SessionAdministrationController(UserRequest ureq, WindowControl wControl) { 
-		super(ureq, wControl);
-		
-		myContent = createVelocityContainer("sessionadministration");
-		
-		invalidateAllSsssionLink = LinkFactory.createButton("session.admin.invalidate.all.link", myContent, this);
-		myContent.contextPut("loginBlocked", AdminModule.isLoginBlocked());
-		blockLoginLink = LinkFactory.createButton("session.admin.block.login.link", myContent, this);
-		
-		boolean showRejectLink = CoordinatorManager.getInstance().getCoordinator().isClusterMode();
-		myContent.contextPut("showRejectDMZRequestsLink", showRejectLink);
-		if (showRejectLink) {
-			myContent.contextPut("rejectingDMZRequests", AuthHelper.isRejectDMZRequests());
-			
-			TextFactory.createTextComponentFromI18nKey("session.admin.reject.dmz.requests.intro", "session.admin.reject.dmz.requests.intro", 
-					getTranslator(), null, true, myContent);
-			TextFactory.createTextComponentFromI18nKey("session.admin.allow.dmz.requests.intro", "session.admin.allow.dmz.requests.intro", 
-					getTranslator(), null, true, myContent);
-			rejectDMZReuqestsLink = LinkFactory.createButton("session.admin.reject.dmz.requests.link", myContent, this);
-			allowDMZRequestsLink = LinkFactory.createButton("session.admin.allow.dmz.requests.link", myContent, this);
-		}
-		PropertyManager pm = PropertyManager.getInstance();
-		Property p = pm.findProperty(null, null, null, AdminModule.SYSTEM_PROPERTY_CATEGORY, AdminModule.PROPERTY_SESSION_ADMINISTRATION);
-		String sessionToken = (p == null ? "" : p.getStringValue());
-		myContent.contextPut("sessionToken", sessionToken);
-		allowLoginLink = LinkFactory.createButton("session.admin.allow.login.link", myContent, this);
-		sessionAdminOldestSessionForm  = new SessionAdminOldestSessionForm(ureq, wControl, getTranslator());
-		listenTo(sessionAdminOldestSessionForm);
-		myContent.put("session.admin.oldest.session.form", sessionAdminOldestSessionForm.getInitialComponent());
-		sessionAdminForm = new SessionAdminForm(ureq, wControl, getTranslator(), AdminModule.getSessionTimeout(), AdminModule.getMaxSessions() );
-		listenTo(sessionAdminForm);
-		myContent.put("session.admin.form", sessionAdminForm.getInitialComponent());
-		myContent.contextPut("usersessions", getUsersSessionAsString(ureq));
-		putInitialPanel(myContent);
-	}
-
-
-	/**
-	 * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest,
-	 *      org.olat.core.gui.components.Component, org.olat.core.gui.control.Event)
-	 */
-	public void event(UserRequest ureq, Component source, Event event) {
-		if (source == invalidateAllSsssionLink){
-			invalidateAllConfirmController = activateYesNoDialog(ureq, null, translate("invalidate.all.sure"), invalidateAllConfirmController);
-			return;
-		} else if(source == blockLoginLink) {
-			blockLoginConfirmController = activateYesNoDialog(ureq, null, translate("block.login.sure"), invalidateAllConfirmController);			
-		} else if(source == rejectDMZReuqestsLink) {
-			rejectDMZRequestsConfirmController = activateYesNoDialog(ureq, null, translate("reject.dmz.requests.sure"), rejectDMZRequestsConfirmController);
-		} else if(source == allowDMZRequestsLink) {
-			AdminModule.setRejectDMZRequests(false);
-			myContent.contextPut("rejectingDMZRequests", AdminModule.isRejectDMZRequests());
-			showInfo("allow.dmz.requests.done");
-		} else if(source == allowLoginLink) {
-			AdminModule.setLoginBlocked(false);
-			myContent.contextPut("loginBlocked", Boolean.FALSE);
-			showInfo("allow.login.done");
-		}
-	}
-
-	/**
-	 * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest,
-	 *      org.olat.core.gui.control.Controller, org.olat.core.gui.control.Event)
-	 */
-	public void event(UserRequest ureq, Controller source, Event event) {
-		if (source == invalidateAllConfirmController) {
-			if (DialogBoxUIFactory.isYesEvent(event)) { 
-				int nbrOfInvalidatedSessions = AdminModule.invalidateAllSessions();	
-				showInfo("invalidate.session.done", Integer.toString(nbrOfInvalidatedSessions));
-			}
-		} else if (source == blockLoginConfirmController) {
-			if (DialogBoxUIFactory.isYesEvent(event)) { 
-				AdminModule.setLoginBlocked(true);
-				myContent.contextPut("loginBlocked", Boolean.TRUE);
-				showInfo("block.login.done");
-			}
-		} else if (source == rejectDMZRequestsConfirmController) {
-			if (DialogBoxUIFactory.isYesEvent(event)) { 
-				AdminModule.setRejectDMZRequests(true);
-				myContent.contextPut("rejectingDMZRequests", AuthHelper.isRejectDMZRequests());
-				showInfo("reject.dmz.requests.done");
-			}
-		} else if (source == sessionAdminOldestSessionForm) {
-			int nbrOfInvalidatedSessions = AdminModule.invalidateOldestSessions(sessionAdminOldestSessionForm.getNbrSessions());
-			showInfo("invalidate.session.done", Integer.toString(nbrOfInvalidatedSessions));
-		} else if (source == sessionAdminForm && event == event.DONE_EVENT) {
-			AdminModule.setSessionTimeout(sessionAdminForm.getSessionTimeout());
-			AdminModule.setMaxSessions(sessionAdminForm.getMaxSessions());
-		}
-
-	}
-
-	protected void doDispose() {
-		// DialogBoxController and TableController get disposed by BasicController
-	}
-	
-	private String getUsersSessionAsString(UserRequest ureq) {
-		StringBuilder sb = new StringBuilder();
-		int ucCnt = UserSession.getUserSessionsCnt();
-		Set usesss = UserSession.getAuthenticatedUserSessions();
-		int contcnt = DefaultController.getControllerCount();
-		sb.append("total usersessions (auth and non auth): "+ucCnt+"<br />auth usersessions: "+usesss.size()+"<br />Total Controllers (active, not disposed) of all users:"+contcnt+"<br /><br />");
-		Formatter f = Formatter.getInstance(ureq.getLocale());
-		for (Iterator iter = usesss.iterator(); iter.hasNext();) {
-			UserSession usess = (UserSession) iter.next();
-			Identity iden = usess.getIdentity();
-			sb.append("authusersession (").append(usess.hashCode()).append(") of ");
-			if (iden != null) {
-				sb.append(iden.getName()).append(" ").append(iden.getKey());
-			}
-			else {
-				sb.append(" - ");
-			}
-			sb.append("<br />");
-			Windows ws = Windows.getWindows(usess);
-			for (Iterator iterator = ws.getWindowIterator(); iterator.hasNext(); ) {
-				Window window = (Window) iterator.next();
-				sb.append("- window ").append(window.getDispatchID()).append(" ").append(window.getLatestDispatchComponentInfo()).append("<br />");
-			}
-			sb.append("<br />");
-		}
-		return sb.toString();
-	}
-	
-}
\ No newline at end of file
diff --git a/src/main/java/org/olat/admin/sysinfo/SysinfoController.java b/src/main/java/org/olat/admin/sysinfo/SysinfoController.java
index 60f6118afa8..8025cddb6ac 100644
--- a/src/main/java/org/olat/admin/sysinfo/SysinfoController.java
+++ b/src/main/java/org/olat/admin/sysinfo/SysinfoController.java
@@ -50,7 +50,6 @@ import org.olat.admin.cache.AllCachesController;
 import org.olat.basesecurity.BaseSecurity;
 import org.olat.basesecurity.BaseSecurityManager;
 import org.olat.basesecurity.Constants;
-import org.olat.basesecurity.SecurityGroup;
 import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.chiefcontrollers.BaseChiefController;
 import org.olat.core.commons.persistence.DBFactory;
@@ -107,9 +106,7 @@ public class SysinfoController extends BasicController implements Activateable2
 
 	private VelocityContainer mySessions, mySnoop, myErrors, myLoglevels, mySysinfo, myMultiUserEvents,myHibernateInfo;
 	private Panel cachePanel;
-	private UserSessionController usessC;
 	private LockController lockController;
-	private SessionAdministrationController sessionAdministrationController;
 	private TabbedPane tabbedPane;
 	
 	private RequestLoglevelController requestLoglevelController;
@@ -146,7 +143,6 @@ public class SysinfoController extends BasicController implements Activateable2
 				OresHelper.lookupType(this.getClass())))
 			throw new OLATSecurityException("Insufficient permissions to access SysinfoController");
 
-		usessC = new UserSessionController(ureq, getWindowControl());
 		lockController = new LockController(ureq, getWindowControl());
 		myErrors = createVelocityContainer("errors");
 		myLoglevels = createVelocityContainer("loglevels");
@@ -165,7 +161,6 @@ public class SysinfoController extends BasicController implements Activateable2
 		disableHibernateStatisticsButton = LinkFactory.createButton("disable.hibernate.statistics", myHibernateInfo, this);
 		clearHibernateStatisticsButton = LinkFactory.createButton("clear.hibernate.statistics", myHibernateInfo, this);
 		
-		sessionAdministrationController = new SessionAdministrationController(ureq, getWindowControl() );
 		requestLoglevelController = new RequestLoglevelController(ureq, getWindowControl());
 		myMultiUserEvents = createVelocityContainer("multiuserevents");
 		
@@ -174,7 +169,6 @@ public class SysinfoController extends BasicController implements Activateable2
 		infoMsgCtrl = InfoMgr.getInfoMessageController(ureq, getWindowControl());
 			
 		tabbedPane = new TabbedPane("tp", ureq.getLocale());
-		tabbedPane.addTab(ACTION_SESSIONS, usessC.getInitialComponent());
 		tabbedPane.addTab(ACTION_INFOMSG,infoMsgCtrl.getInitialComponent());
 		tabbedPane.addTab(ACTION_ERRORS, myErrors);
 		//fxdiff: FXOLAT-79 check fxadmin-rights
@@ -182,7 +176,6 @@ public class SysinfoController extends BasicController implements Activateable2
 		tabbedPane.addTab(ACTION_SYSINFO, mySysinfo);
 		tabbedPane.addTab(ACTION_SNOOP, mySnoop);
 		tabbedPane.addTab("requestloglevel", requestLoglevelController.getInitialComponent());
-		tabbedPane.addTab("usersessions", sessionAdministrationController.getInitialComponent());
 		tabbedPane.addTab(ACTION_LOCKS, lockController.getInitialComponent());
 		// fxdiff: not usable:	tabbedPane.addTab(getTranslator().translate("sess.multiuserevents"), myMultiUserEvents);
 		tabbedPane.addTab(ACTION_HIBERNATEINFO, myHibernateInfo);
@@ -344,9 +337,6 @@ public class SysinfoController extends BasicController implements Activateable2
 				mySysinfo.contextPut("threads",getThreadsInfo());
 				mySysinfo.contextPut("javaenv", getJavaenv());
 				
-			} 
-			else if (newComponent == usessC.getInitialComponent()) {
-				usessC.reset();
 			}
 			else if (newComponent == lockController.getInitialComponent()) {
 				lockController.resetTableModel();
@@ -379,8 +369,6 @@ public class SysinfoController extends BasicController implements Activateable2
 				*/
 				sb.append(" <a href=\"http://bugs.olat.org/jira/browse/OLAT-3681\">OLAT-3681</a> ");
 				myMultiUserEvents.contextPut("info", sb.toString());
-			} 
-			else  if (newComponent == sessionAdministrationController.getInitialComponent()) {
 			}
 			else if (newComponent == myHibernateInfo) {
 				myHibernateInfo.contextPut("isStatisticsEnabled", DBFactory.getInstance(false).getStatistics().isStatisticsEnabled());
@@ -631,10 +619,6 @@ public class SysinfoController extends BasicController implements Activateable2
 	 * @see org.olat.core.gui.control.DefaultController#doDispose(boolean)
 	 */
 	protected void doDispose() {
-		if (usessC != null) {
-			usessC.dispose();
-			usessC = null;
-		}
 		if (cacheController != null) {
 			cacheController.dispose();
 			cacheController = null;
diff --git a/src/main/java/org/olat/admin/sysinfo/UserSessionAdminController.java b/src/main/java/org/olat/admin/sysinfo/UserSessionAdminController.java
new file mode 100644
index 00000000000..5089de3298b
--- /dev/null
+++ b/src/main/java/org/olat/admin/sysinfo/UserSessionAdminController.java
@@ -0,0 +1,110 @@
+package org.olat.admin.sysinfo;
+
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.Component;
+import org.olat.core.gui.components.link.Link;
+import org.olat.core.gui.components.link.LinkFactory;
+import org.olat.core.gui.components.segmentedview.SegmentViewComponent;
+import org.olat.core.gui.components.segmentedview.SegmentViewEvent;
+import org.olat.core.gui.components.segmentedview.SegmentViewFactory;
+import org.olat.core.gui.components.stack.StackedController;
+import org.olat.core.gui.components.stack.StackedControllerAware;
+import org.olat.core.gui.components.velocity.VelocityContainer;
+import org.olat.core.gui.control.Event;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.gui.control.controller.BasicController;
+
+/**
+ * 
+ * Initial date: 15.11.2012<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class UserSessionAdminController extends BasicController implements StackedControllerAware {
+
+	private final Link sessionsLink, configLink, infosLink;
+	private final SegmentViewComponent segmentView;
+	
+	private final VelocityContainer mainVC;
+	
+	private UserSessionController sessionListCtrl;
+	private UserSessionConfigAdminController configCtrl;
+	private UserSessionInformationsController infoCtrl;
+	private StackedController stackedController;
+	
+	public UserSessionAdminController(UserRequest ureq, WindowControl wControl) {
+		super(ureq, wControl);
+		
+		mainVC = createVelocityContainer("usersession_admin");
+		
+		segmentView = SegmentViewFactory.createSegmentView("segments", mainVC, this);
+		sessionsLink = LinkFactory.createLink("session.list", mainVC, this);
+		segmentView.addSegment(sessionsLink, true);
+		
+		configLink = LinkFactory.createLink("session.configuration", mainVC, this);
+		segmentView.addSegment(configLink, false);
+
+		infosLink = LinkFactory.createLink("sess.details", mainVC, this);
+		segmentView.addSegment(infosLink, false);
+		
+		mainVC.put("segments", segmentView);
+		doOpenSessionList(ureq);
+		putInitialPanel(mainVC);
+	}
+
+	@Override
+	public void setStackedController(StackedController stackPanel) {
+		this.stackedController = stackPanel;
+		if(sessionListCtrl != null) {
+			sessionListCtrl.setStackedController(stackedController);
+		}
+	}
+
+	@Override
+	protected void doDispose() {
+		this.stackedController = null;
+	}
+
+	@Override
+	protected void event(UserRequest ureq, Component source, Event event) {
+		if(source == segmentView) {
+			if(event instanceof SegmentViewEvent) {
+				SegmentViewEvent sve = (SegmentViewEvent)event;
+				String segmentCName = sve.getComponentName();
+				Component clickedLink = mainVC.getComponent(segmentCName);
+				if (clickedLink == sessionsLink) {
+					doOpenSessionList(ureq);
+				} else if (clickedLink == configLink) {
+					doOpenConfiguration(ureq);
+				} else if (clickedLink == infosLink) {
+					doOpenInformations(ureq);
+				}
+			}
+		}
+	}
+
+	private void doOpenSessionList(UserRequest ureq) {
+		if(sessionListCtrl == null) {
+			sessionListCtrl = new UserSessionController(ureq, getWindowControl());
+			sessionListCtrl.setStackedController(stackedController);
+			listenTo(sessionListCtrl);
+		}
+		mainVC.put("segmentCmp", sessionListCtrl.getInitialComponent());
+	}
+
+	private void doOpenConfiguration(UserRequest ureq) {
+		if(configCtrl == null) {
+			configCtrl = new UserSessionConfigAdminController(ureq, getWindowControl());
+			listenTo(configCtrl);
+		}
+		mainVC.put("segmentCmp", configCtrl.getInitialComponent());
+	}
+	
+	private void doOpenInformations(UserRequest ureq) {
+		if(infoCtrl == null) {
+			infoCtrl = new UserSessionInformationsController(ureq, getWindowControl());
+			listenTo(infoCtrl);
+		}
+		mainVC.put("segmentCmp", infoCtrl.getInitialComponent());
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/admin/sysinfo/UserSessionConfigAdminController.java b/src/main/java/org/olat/admin/sysinfo/UserSessionConfigAdminController.java
new file mode 100644
index 00000000000..a3a090a1ede
--- /dev/null
+++ b/src/main/java/org/olat/admin/sysinfo/UserSessionConfigAdminController.java
@@ -0,0 +1,192 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br>
+* University of Zurich, Switzerland.
+* <hr>
+* <a href="http://www.openolat.org">
+* OpenOLAT - Online Learning and Training</a><br>
+* This file has been modified by the OpenOLAT community. Changes are licensed
+* under the Apache 2.0 license as the original file.
+*/
+
+package org.olat.admin.sysinfo;
+
+import org.olat.admin.AdminModule;
+import org.olat.basesecurity.AuthHelper;
+import org.olat.core.CoreSpringFactory;
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.FormItem;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.elements.FormLink;
+import org.olat.core.gui.components.form.flexible.elements.IntegerElement;
+import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
+import org.olat.core.gui.components.form.flexible.impl.FormEvent;
+import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
+import org.olat.core.gui.components.link.Link;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.Event;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.gui.control.generic.modal.DialogBoxController;
+import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory;
+import org.olat.core.util.coordinate.CoordinatorManager;
+import org.olat.core.util.session.UserSessionManager;
+import org.olat.core.util.session.UserSessionModule;
+
+/**
+ * 
+ * Initial date: 15.11.2012<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class UserSessionConfigAdminController extends FormBasicController {
+	private IntegerElement sessionTimeoutEl;
+	private IntegerElement sessionTimeoutAuthEl;
+	private IntegerElement maxSessionsEl;
+	private IntegerElement nbrSessionsEl;
+	
+	private DialogBoxController invalidateAllConfirmController;
+	private DialogBoxController blockLoginConfirmController;
+	private DialogBoxController rejectDMZRequestsConfirmController;
+	
+	private FormLink saveLink, invalidateOldSessionLink, invalidateAllSessionLink;
+	private FormLink allowLoginLink, blockLoginLink;
+	private FormLink rejectDMZRequestsLink, allowDMZRequestsLink;
+	
+	private final UserSessionModule sessionModule;
+	private final UserSessionManager sessionManager;
+	
+	public UserSessionConfigAdminController(UserRequest ureq, WindowControl wControl) {
+		super(ureq, wControl);
+		
+		sessionModule = CoreSpringFactory.getImpl(UserSessionModule.class);
+		sessionManager = CoreSpringFactory.getImpl(UserSessionManager.class);
+		
+		initForm(ureq);		
+	}
+	
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		int sessionTimeout = sessionModule.getSessionTimeout();
+		sessionTimeoutEl = uifactory.addIntegerElement("session.timeout", "session.timeout.label", sessionTimeout, formLayout);
+		int initialSessionAuth = sessionModule.getSessionTimeoutAuthenticated();
+		sessionTimeoutAuthEl = uifactory.addIntegerElement("session.timeout.auth", "session.timeout.auth.label", initialSessionAuth, formLayout);
+		int maxSessions = AdminModule.getMaxSessions();
+		maxSessionsEl = uifactory.addIntegerElement("max.sessions", "max.sessions.label", maxSessions, formLayout);
+		
+		FormLayoutContainer buttonsLayout = FormLayoutContainer.createButtonLayout("buttons", getTranslator());
+		formLayout.add(buttonsLayout);
+		saveLink = uifactory.addFormLink("save", "save", null, buttonsLayout, Link.BUTTON);
+
+		uifactory.addSpacerElement("spacer-1", formLayout, false);
+		
+		nbrSessionsEl = uifactory.addIntegerElement("nbr.session", "nbr.session.label", 0, formLayout);
+		FormLayoutContainer buttonsLayout2 = FormLayoutContainer.createButtonLayout("buttons2", getTranslator());
+		formLayout.add(buttonsLayout2);
+		invalidateOldSessionLink = uifactory.addFormLink("kill.old", "oldest.session.button", null, buttonsLayout2, Link.BUTTON);
+		invalidateAllSessionLink = uifactory.addFormLink("kill.all", "session.admin.invalidate.all.link", null, buttonsLayout2, Link.BUTTON);
+
+		uifactory.addSpacerElement("spacer-2", formLayout, false);
+		
+		FormLayoutContainer buttonsLayout3 = FormLayoutContainer.createButtonLayout("buttons3", getTranslator());
+		formLayout.add(buttonsLayout3);
+		blockLoginLink = uifactory.addFormLink("block.login.all", "session.admin.block.login.link", null, buttonsLayout3, Link.BUTTON);
+		allowLoginLink = uifactory.addFormLink("allow.login.all", "session.admin.allow.login.link", null, buttonsLayout3, Link.BUTTON);
+		updateLoginBlock();
+		
+		@SuppressWarnings("deprecation")
+		boolean clusterMode = CoordinatorManager.getInstance().getCoordinator().isClusterMode();
+		if (clusterMode) {
+			rejectDMZRequestsLink = uifactory.addFormLink("block.dmz.node", "session.admin.reject.dmz.requests.link", null, buttonsLayout3, Link.BUTTON);
+			allowDMZRequestsLink = uifactory.addFormLink("allow.dmz.node", "session.admin.allow.dmz.requests.link", null, buttonsLayout3, Link.BUTTON);
+			updateDmzBlock();
+		}
+	}
+	
+	private void updateDmzBlock() {
+		rejectDMZRequestsLink.setVisible(!AuthHelper.isRejectDMZRequests());
+		allowDMZRequestsLink.setVisible(AuthHelper.isRejectDMZRequests());
+	}
+	
+	private void updateLoginBlock() {
+		blockLoginLink.setVisible(!AdminModule.isLoginBlocked());
+		allowLoginLink.setVisible(AdminModule.isLoginBlocked());
+	}
+	
+	@Override
+	protected void doDispose() {
+		//empty		
+	}
+	
+	@Override
+	protected void formOK(UserRequest ureq) {
+		//
+	}
+
+	@Override
+	protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
+		if(source == saveLink) {
+			int sessionTimeout = sessionTimeoutEl.getIntValue();
+			sessionModule.setSessionTimeout(sessionTimeout);
+			int sessionTimeoutAuth = sessionTimeoutAuthEl.getIntValue();
+			sessionModule.setSessionTimeoutAuthenticated(sessionTimeoutAuth);
+			int maxSessions = maxSessionsEl.getIntValue();
+			AdminModule.setMaxSessions(maxSessions);
+			sessionManager.setGlobalSessionTimeout(sessionTimeoutAuth);
+		} else if(source == invalidateOldSessionLink) {
+			int nbrSessions = nbrSessionsEl.getIntValue();
+			int nbrOfInvalidatedSessions = sessionManager.invalidateOldestSessions(nbrSessions);
+			showInfo("invalidate.session.done", Integer.toString(nbrOfInvalidatedSessions));
+		} else if(source == invalidateAllSessionLink) {
+			invalidateAllConfirmController = activateYesNoDialog(ureq, null, translate("invalidate.all.sure"), invalidateAllConfirmController);
+		} else if(source == blockLoginLink) {	
+			blockLoginConfirmController = activateYesNoDialog(ureq, null, translate("block.login.sure"), blockLoginConfirmController);
+		} else if(source == allowLoginLink) {
+			AdminModule.setLoginBlocked(false);
+			updateLoginBlock();
+		} else if(source == rejectDMZRequestsLink) {
+			rejectDMZRequestsConfirmController = activateYesNoDialog(ureq, null, translate("reject.dmz.requests.sure"), rejectDMZRequestsConfirmController);
+		} else if(source == allowDMZRequestsLink) {
+			AdminModule.setRejectDMZRequests(false);
+			updateDmzBlock();
+			showInfo("allow.dmz.requests.done");
+		} else {
+			super.formInnerEvent(ureq, source, event);
+		}
+	}
+	
+	@Override
+	public void event(UserRequest ureq, Controller source, Event event) {
+		if (source == invalidateAllConfirmController) {
+			if (DialogBoxUIFactory.isYesEvent(event)) { 
+				int nbrOfInvalidatedSessions = sessionManager.invalidateAllSessions();	
+				showInfo("invalidate.session.done", Integer.toString(nbrOfInvalidatedSessions));
+			}
+		} else if (source == blockLoginConfirmController) {
+			if (DialogBoxUIFactory.isYesEvent(event)) { 
+				AdminModule.setLoginBlocked(true);
+				showInfo("block.login.done");
+			}
+			updateLoginBlock();
+		} else if (source == rejectDMZRequestsConfirmController) {
+			if (DialogBoxUIFactory.isYesEvent(event)) { 
+				AdminModule.setRejectDMZRequests(true);
+				showInfo("reject.dmz.requests.done");
+			}
+			updateDmzBlock();
+		}
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/admin/sysinfo/UserSessionController.java b/src/main/java/org/olat/admin/sysinfo/UserSessionController.java
index a7f3be29e92..631c44e53c3 100644
--- a/src/main/java/org/olat/admin/sysinfo/UserSessionController.java
+++ b/src/main/java/org/olat/admin/sysinfo/UserSessionController.java
@@ -26,19 +26,16 @@
 package org.olat.admin.sysinfo;
 
 import java.util.ArrayList;
-import java.util.Date;
-import java.util.Iterator;
 import java.util.List;
 
-import javax.servlet.http.HttpSession;
-
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.gui.UserRequest;
-import org.olat.core.gui.Windows;
 import org.olat.core.gui.components.Component;
-import org.olat.core.gui.components.Window;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.components.link.LinkFactory;
 import org.olat.core.gui.components.panel.Panel;
+import org.olat.core.gui.components.stack.StackedController;
+import org.olat.core.gui.components.stack.StackedControllerAware;
 import org.olat.core.gui.components.table.DefaultColumnDescriptor;
 import org.olat.core.gui.components.table.StaticColumnDescriptor;
 import org.olat.core.gui.components.table.Table;
@@ -52,29 +49,29 @@ import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.controller.BasicController;
 import org.olat.core.gui.control.generic.modal.DialogBoxController;
 import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory;
-import org.olat.core.util.Formatter;
-import org.olat.core.util.SessionInfo;
 import org.olat.core.util.UserSession;
-import org.olat.core.util.coordinate.CoordinatorManager;
-import org.olat.core.util.coordinate.LockEntry;
+import org.olat.core.util.session.UserSessionManager;
+import org.olat.user.UserManager;
 
 /**
  *  Initial Date:  01.09.2004
  *  @author Mike Stock
  */
 
-public class UserSessionController extends BasicController {
+public class UserSessionController extends BasicController implements StackedControllerAware {
 	
 	private VelocityContainer myContent;
 	private TableController tableCtr;
-	private Formatter f;
+	//private Formatter f;
 	private UserSessionTableModel usessTableModel;
 	private DialogBoxController dialogController;
-	private int selRow;
-	private Link backLink;
-	private Link sessKillButton;
+	//private int selRow;
+	private Link backLink, sessKillButton;
 
 	private Panel myPanel;
+	private final UserSessionManager sessionManager;
+	private StackedController stackController;
+	
 	/**
 	 * Timeframe in minutes is needed to calculate the last klicks from users in OLAT. 
 	 */
@@ -88,8 +85,10 @@ public class UserSessionController extends BasicController {
 	 */
 	public UserSessionController(UserRequest ureq, WindowControl wControl) { 
 		super(ureq, wControl);
+
+		sessionManager = CoreSpringFactory.getImpl(UserSessionManager.class);
 		
-		f = Formatter.getInstance(ureq.getLocale());
+		//f = Formatter.getInstance(ureq.getLocale());
 
 		myContent = createVelocityContainer("sessions");
 		
@@ -113,19 +112,23 @@ public class UserSessionController extends BasicController {
 		myPanel = putInitialPanel(myContent);
 	}
 
+	@Override
+	public void setStackedController(StackedController stackPanel) {
+		this.stackController = stackPanel;
+	}
+
 	/**
 	 * Re-initialize this controller. Fetches sessions again.
 	 */
 	public void reset() {
-		List<UserSession> authUserSessions = new ArrayList<UserSession>(UserSession.getAuthenticatedUserSessions());
-		usessTableModel = new UserSessionTableModel(authUserSessions, getTranslator());
+		List<UserSession> authUserSessions = new ArrayList<UserSession>(sessionManager.getAuthenticatedUserSessions());
+		usessTableModel = new UserSessionTableModel(authUserSessions);
 		tableCtr.setTableDataModel(usessTableModel);
 		// view number of user - lastKlick <= LAST_KLICK_TIMEFRAME min
 		long now = System.currentTimeMillis();
 		int counter = 0;
 		for (UserSession usess : authUserSessions) {
-			
-			long lastklick = usess.getSessionInfo().getLastClickTime();
+			long lastklick = usess.getSessionInfo() == null ? -1 : usess.getSessionInfo().getLastClickTime();
 			if ((now - lastklick) <= DIFF) {
 				counter++;
 			}
@@ -142,10 +145,8 @@ public class UserSessionController extends BasicController {
 		if (source == backLink){
 			myPanel.popContent();
 			reset();
-		}
-		else if (source == sessKillButton){
+		} else if (source == sessKillButton){
 			dialogController = activateYesNoDialog(ureq, null, translate("sess.kill.sure"), dialogController);
-			return;
 		}
 	}
 
@@ -156,7 +157,7 @@ public class UserSessionController extends BasicController {
 	public void event(UserRequest ureq, Controller source, Event event) {
 		if (source == dialogController) {
 			if (DialogBoxUIFactory.isYesEvent(event)) { 
-				UserSession usess = (UserSession) usessTableModel.getObject(selRow);
+				/*UserSession usess = (UserSession) usessTableModel.getObject(selRow);
 				SessionInfo sessInfo = usess.getSessionInfo();
 				if (usess.isAuthenticated()) {
 					HttpSession session = sessInfo.getSession();
@@ -168,19 +169,35 @@ public class UserSessionController extends BasicController {
 						}
 					}
 					showInfo("sess.kill.done", sessInfo.getLogin() );
-				}
+				}*/
 				reset();
 			}
 		}
 		else if (source == tableCtr) {
 			if (event.getCommand().equals(Table.COMMANDLINK_ROWACTION_CLICKED)) {
-				TableEvent te = (TableEvent) event;
-				selRow = te.getRowId();
+				TableEvent te = (TableEvent)event;
+				int selRow = te.getRowId();
 				// session info (we only have authenticated sessions here
-				UserSession usess = (UserSession) usessTableModel.getObject(selRow);
+				UserSession usess = (UserSession) tableCtr.getTableDataModel().getObject(selRow);
+				UserSessionDetailsController detailsCtrl = new UserSessionDetailsController(ureq, getWindowControl(), usess);
+				listenTo(detailsCtrl);
+				
+				String username = usess.getIdentity() == null ? "-"
+						: UserManager.getInstance().getUserDisplayName(usess.getIdentity().getUser());
+				stackController.pushController(username, detailsCtrl);
+				
+				
 				//if (!usess.isAuthenticated()) throw new AssertException("usersession was not authenticated!?");
 				
-				VelocityContainer sesDetails = createVelocityContainer("sessionDetails");
+				
+				
+				
+				
+				
+				
+				
+				
+				/*VelocityContainer sesDetails = createVelocityContainer("sessionDetails");
 				sesDetails.contextPut("us", usess);
 				SessionInfo sessInfo = usess.getSessionInfo();
 				sesDetails.contextPut("si", sessInfo);
@@ -213,7 +230,7 @@ public class UserSessionController extends BasicController {
 				if (success) {
 					// lock information
 					String username = sessInfo.getLogin();
-					ArrayList lockList = new ArrayList();
+					List<String> lockList = new ArrayList<String>();
 					List<LockEntry> locks = CoordinatorManager.getInstance().getCoordinator().getLocker().adminOnlyGetLockEntries();
 					Formatter f = Formatter.getInstance(ureq.getLocale());
 					for (LockEntry entry : locks) {
@@ -229,8 +246,8 @@ public class UserSessionController extends BasicController {
 					// GUI statistics
 					Windows ws = Windows.getWindows(usess);
 					StringBuilder sb = new StringBuilder();
-					for (Iterator iterator = ws.getWindowIterator(); iterator.hasNext();) {
-						Window window = (Window) iterator.next();
+					for (Iterator<Window> iterator = ws.getWindowIterator(); iterator.hasNext();) {
+						Window window = iterator.next();
 						sb.append("- Window ").append(window.getDispatchID()).append(" dispatch info: ").append(window.getLatestDispatchComponentInfo()).append("<br />");
 					}
 					sb.append("<br />");
@@ -240,6 +257,7 @@ public class UserSessionController extends BasicController {
 				sesDetails.put("sess.kill", sessKillButton);
 				
 				myPanel.pushContent(sesDetails);
+				*/
 			}
 		}
 	}
diff --git a/src/main/java/org/olat/admin/sysinfo/UserSessionDetailsController.java b/src/main/java/org/olat/admin/sysinfo/UserSessionDetailsController.java
new file mode 100644
index 00000000000..90f45aab901
--- /dev/null
+++ b/src/main/java/org/olat/admin/sysinfo/UserSessionDetailsController.java
@@ -0,0 +1,114 @@
+package org.olat.admin.sysinfo;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.servlet.http.HttpSession;
+
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.Windows;
+import org.olat.core.gui.components.Component;
+import org.olat.core.gui.components.Window;
+import org.olat.core.gui.components.velocity.VelocityContainer;
+import org.olat.core.gui.control.Event;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.gui.control.controller.BasicController;
+import org.olat.core.util.Formatter;
+import org.olat.core.util.SessionInfo;
+import org.olat.core.util.UserSession;
+import org.olat.core.util.coordinate.CoordinatorManager;
+import org.olat.core.util.coordinate.LockEntry;
+
+/**
+ * 
+ * Initial date: 15.11.2012<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class UserSessionDetailsController extends BasicController {
+	
+	private final VelocityContainer sesDetails;
+	
+	public UserSessionDetailsController(UserRequest ureq, WindowControl wControl, UserSession usess) {
+		super(ureq, wControl);
+		
+		sesDetails = createVelocityContainer("sessionDetails");
+		sesDetails.contextPut("us", usess);
+		SessionInfo sessInfo = usess.getSessionInfo();
+		sesDetails.contextPut("si", sessInfo);
+		boolean isAuth = usess.isAuthenticated();
+		sesDetails.contextPut("isauth", isAuth? "yes" : "-- NOT AUTHENTICATED!");
+
+		long creatTime = -1;
+		long lastAccessTime = -1; 
+		
+		boolean success = false;
+		if (isAuth) {
+			try {
+				HttpSession se = sessInfo.getSession();
+				creatTime = se.getCreationTime();
+				lastAccessTime = se.getLastAccessedTime();
+				success = true;
+			} catch (Exception ise) {
+				// nothing to do
+			}
+		}
+		
+		if (success) {
+			Formatter f = Formatter.getInstance(ureq.getLocale());
+			sesDetails.contextPut("created", f.formatDateAndTime(new Date(creatTime)));
+			sesDetails.contextPut("lastaccess", f.formatDateAndTime(new Date(lastAccessTime)));
+		} else {
+			sesDetails.contextPut("created", " -- this session has been invalidated --");
+			sesDetails.contextPut("lastaccess", " -- this session has been invalidated --");
+		}
+		
+		if (success) {
+			// lock information
+			String username = sessInfo.getLogin();
+			List<String> lockList = new ArrayList<String>();
+			List<LockEntry> locks = CoordinatorManager.getInstance().getCoordinator().getLocker().adminOnlyGetLockEntries();
+			Formatter f = Formatter.getInstance(ureq.getLocale());
+			for (LockEntry entry : locks) {
+				if (entry.getOwner().getName().equals(username)) {
+					lockList.add(entry.getKey()+" "+f.formatDateAndTime(new Date(entry.getLockAquiredTime())));
+				}
+			}					
+			sesDetails.contextPut("locklist", lockList);
+
+			// user environment
+			sesDetails.contextPut("env", usess.getIdentityEnvironment());
+
+			// GUI statistics
+			Windows ws = Windows.getWindows(usess);
+			StringBuilder sb = new StringBuilder();
+			for (Iterator<Window> iterator = ws.getWindowIterator(); iterator.hasNext();) {
+				Window window = iterator.next();
+				sb.append("- Window ").append(window.getDispatchID()).append(" dispatch info: ").append(window.getLatestDispatchComponentInfo()).append("<br />");
+			}
+			sb.append("<br />");
+			sesDetails.contextPut("guistats", sb.toString());
+		}
+		//TODO sesDetails.put("sess.kill", sessKillButton);
+		
+		
+	}
+	
+	@Override
+	protected void doDispose() {
+		//
+	}
+
+	@Override
+	protected void event(UserRequest ureq, Component source, Event event) {
+		//
+	}
+
+
+	
+	
+
+
+}
diff --git a/src/main/java/org/olat/admin/sysinfo/UserSessionInformationsController.java b/src/main/java/org/olat/admin/sysinfo/UserSessionInformationsController.java
new file mode 100644
index 00000000000..d3fccdbb44d
--- /dev/null
+++ b/src/main/java/org/olat/admin/sysinfo/UserSessionInformationsController.java
@@ -0,0 +1,106 @@
+/**
+* OLAT - Online Learning and Training<br>
+* http://www.olat.org
+* <p>
+* Licensed under the Apache License, Version 2.0 (the "License"); <br>
+* you may not use this file except in compliance with the License.<br>
+* You may obtain a copy of the License at
+* <p>
+* http://www.apache.org/licenses/LICENSE-2.0
+* <p>
+* Unless required by applicable law or agreed to in writing,<br>
+* software distributed under the License is distributed on an "AS IS" BASIS, <br>
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+* See the License for the specific language governing permissions and <br>
+* limitations under the License.
+* <p>
+* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br>
+* University of Zurich, Switzerland.
+* <hr>
+* <a href="http://www.openolat.org">
+* OpenOLAT - Online Learning and Training</a><br>
+* This file has been modified by the OpenOLAT community. Changes are licensed
+* under the Apache 2.0 license as the original file.
+*/
+
+package org.olat.admin.sysinfo;
+
+import java.util.Iterator;
+import java.util.Set;
+
+import org.olat.core.CoreSpringFactory;
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.Windows;
+import org.olat.core.gui.components.Component;
+import org.olat.core.gui.components.Window;
+import org.olat.core.gui.components.velocity.VelocityContainer;
+import org.olat.core.gui.control.DefaultController;
+import org.olat.core.gui.control.Event;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.gui.control.controller.BasicController;
+import org.olat.core.id.Identity;
+import org.olat.core.util.UserSession;
+import org.olat.core.util.session.UserSessionManager;
+
+/**
+ * 
+ * Initial date: 15.11.2012<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class UserSessionInformationsController extends BasicController {
+
+	private final VelocityContainer myContent;
+  private final UserSessionManager sessionManager;
+  
+	/**
+	 * Controlls user session in admin view.
+	 * 
+	 * @param ureq
+	 * @param wControl
+	 */
+	public UserSessionInformationsController(UserRequest ureq, WindowControl wControl) { 
+		super(ureq, wControl);
+		sessionManager = CoreSpringFactory.getImpl(UserSessionManager.class);
+		
+		myContent = createVelocityContainer("usersession_infos");
+		myContent.contextPut("usersessions", getUsersSessionAsString(ureq));
+		putInitialPanel(myContent);
+	}
+
+	public void event(UserRequest ureq, Component source, Event event) {
+		//
+	}
+
+
+	protected void doDispose() {
+		//
+	}
+	
+	private String getUsersSessionAsString(UserRequest ureq) {
+		StringBuilder sb = new StringBuilder();
+		int ucCnt = sessionManager.getUserSessionsCnt();
+		Set<UserSession> usesss = sessionManager.getAuthenticatedUserSessions();
+		int contcnt = DefaultController.getControllerCount();
+		sb.append("total usersessions (auth and non auth): "+ucCnt+"<br />auth usersessions: "+usesss.size()+"<br />Total Controllers (active, not disposed) of all users:"+contcnt+"<br /><br />");
+
+		for (Iterator<UserSession> iter = usesss.iterator(); iter.hasNext();) {
+			UserSession usess = iter.next();
+			Identity iden = usess.getIdentity();
+			sb.append("authusersession (").append(usess.hashCode()).append(") of ");
+			if (iden != null) {
+				sb.append(iden.getName()).append(" ").append(iden.getKey());
+			} else {
+				sb.append(" - ");
+			}
+			sb.append("<br />");
+			Windows ws = Windows.getWindows(usess);
+			for (Iterator<Window> iterator = ws.getWindowIterator(); iterator.hasNext(); ) {
+				Window window = iterator.next();
+				sb.append("- window ").append(window.getDispatchID()).append(" ").append(window.getLatestDispatchComponentInfo()).append("<br />");
+			}
+			sb.append("<br />");
+		}
+		return sb.toString();
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/admin/sysinfo/UserSessionTableModel.java b/src/main/java/org/olat/admin/sysinfo/UserSessionTableModel.java
index 73585f173fe..3558bdcc56c 100644
--- a/src/main/java/org/olat/admin/sysinfo/UserSessionTableModel.java
+++ b/src/main/java/org/olat/admin/sysinfo/UserSessionTableModel.java
@@ -29,7 +29,6 @@ import java.util.Date;
 import java.util.List;
 
 import org.olat.core.gui.components.table.DefaultTableDataModel;
-import org.olat.core.gui.translator.Translator;
 import org.olat.core.util.SessionInfo;
 import org.olat.core.util.UserSession;
 
@@ -39,14 +38,13 @@ import org.olat.core.util.UserSession;
  * @author Mike Stock
  */
 
-public class UserSessionTableModel extends DefaultTableDataModel {
-	private Translator trans;
+public class UserSessionTableModel extends DefaultTableDataModel<UserSession> {
+
 	/**
 	 * @param userSessions
 	 */
-	public UserSessionTableModel(List userSessions, Translator trans) {
+	public UserSessionTableModel(List<UserSession> userSessions) {
 		super(userSessions);
-		this.trans = trans;
 	}
 	
 	/**
@@ -91,16 +89,13 @@ public class UserSessionTableModel extends DefaultTableDataModel {
 					}
 				default: return "Error";
 			}
-		}
-		else { // not signed on
+		} else { // not signed on
 			switch (col) {
 				case 5: return null;
 				case 6: return null;
 				case 7: return null;
 				default: return "-";
 			}
-		}
-																					
+		}																			
 	}
-
 }
diff --git a/src/main/java/org/olat/admin/sysinfo/_content/usersession_admin.html b/src/main/java/org/olat/admin/sysinfo/_content/usersession_admin.html
new file mode 100644
index 00000000000..3d776f93825
--- /dev/null
+++ b/src/main/java/org/olat/admin/sysinfo/_content/usersession_admin.html
@@ -0,0 +1,7 @@
+<div class="b_clearfix">
+	$r.render("segments") <br/>	
+		
+	#if($r.available("segmentCmp"))
+		$r.render("segmentCmp")
+	#end
+</div>
\ No newline at end of file
diff --git a/src/main/java/org/olat/admin/sysinfo/_content/usersession_infos.html b/src/main/java/org/olat/admin/sysinfo/_content/usersession_infos.html
new file mode 100644
index 00000000000..587532300e2
--- /dev/null
+++ b/src/main/java/org/olat/admin/sysinfo/_content/usersession_infos.html
@@ -0,0 +1,2 @@
+<h4>$r.translate("usersession.title")</h4>
+$usersessions
diff --git a/src/main/java/org/olat/admin/sysinfo/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/admin/sysinfo/_i18n/LocalStrings_de.properties
index 631cdebe800..e7f875bf9bf 100644
--- a/src/main/java/org/olat/admin/sysinfo/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/admin/sysinfo/_i18n/LocalStrings_de.properties
@@ -68,6 +68,8 @@ sess.roles=Rollen
 sess.secure=Verschl\u00FCsseltes Einloggen
 sess.title=Aktive Benutzer-Sessions
 sess.webMode=Web Modus
+session.list=Benutzersessions
+session.configuration=Konfiguration
 session.admin.allow.login.link=Loginsperrung aufheben
 session.admin.block.login.link=Neue Logins sperren
 session.admin.reject.dmz.requests.intro=Alle Requests auf DMZ auf andere in mod_jk verfügbare Nodes umleiten - ausgenommen Admin Benutzer via Cluster-tab 'Wechseln zu Node'
@@ -79,6 +81,7 @@ reject.dmz.requests.done=Alle Requests auf DMZ werden ab jetzt auf andere Nodes
 allow.dmz.requests.done=Alle Requests auf DMZ werden ab jetzt wieder zugelassen
 session.admin.invalidate.all.link=Alle Sessions invalidieren
 session.timeout.label=Session timeout in sec
+session.timeout.auth.label=Authenticated session timeout in sec
 sessionadministration.title=Session Administration
 sessions=Sessions
 snoop=Snoop
diff --git a/src/main/java/org/olat/basesecurity/AuthHelper.java b/src/main/java/org/olat/basesecurity/AuthHelper.java
index 205ae0adb3d..83cf66bcd7f 100644
--- a/src/main/java/org/olat/basesecurity/AuthHelper.java
+++ b/src/main/java/org/olat/basesecurity/AuthHelper.java
@@ -38,6 +38,7 @@ import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpSession;
 
 import org.olat.commons.rss.RSSUtil;
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.chiefcontrollers.BaseChiefControllerCreator;
 import org.olat.core.commons.fullWebApp.BaseFullWebappController;
 import org.olat.core.commons.fullWebApp.BaseFullWebappControllerParts;
@@ -71,6 +72,7 @@ import org.olat.core.util.WebappHelper;
 import org.olat.core.util.i18n.I18nManager;
 import org.olat.core.util.i18n.I18nModule;
 import org.olat.core.util.prefs.Preferences;
+import org.olat.core.util.session.UserSessionManager;
 import org.olat.login.AuthBFWCParts;
 import org.olat.login.GuestBFWCParts;
 import org.olat.user.UserManager;
@@ -306,22 +308,23 @@ public class AuthHelper {
 			log.audit("was denied login");
 			return LOGIN_DENIED;			
 		}
+		UserSessionManager sessionManager = CoreSpringFactory.getImpl(UserSessionManager.class);
 		// if the user sending the cookie did not log out and we are logging in
 		// again, then we need to make sure everything is cleaned up. we cleanup in all cases.
 		UserSession usess = ureq.getUserSession();
 		// prepare for a new user: clear all the instance vars of the userSession
 		// note: does not invalidate the session, since it is reused
-		usess.signOffAndClear();
+		sessionManager.signOffAndClear(usess);
 		// init the UserSession for the new User
 		// we can set the identity and finish the log in process
 		usess.setIdentity(identity);
 		setRolesFor(identity, usess);
-		
+
 		// check if loginDenied or maxSession (only for non-admin)
 		if ( (loginBlocked && !usess.getRoles().isOLATAdmin())
-				|| ( ((maxSessions != MAX_SESSION_NO_LIMIT) && (UserSession.getUserSessionsCnt() >= maxSessions)) && !usess.getRoles().isOLATAdmin() ) ) {
-			log.audit("Login was blocked for username=" + usess.getIdentity().getName() + ", loginBlocked=" + loginBlocked + " NbrOfSessions=" + UserSession.getUserSessionsCnt());
-			usess.signOffAndClear();
+				|| ( ((maxSessions != MAX_SESSION_NO_LIMIT) && (sessionManager.getUserSessionsCnt() >= maxSessions)) && !usess.getRoles().isOLATAdmin() ) ) {
+			log.audit("Login was blocked for username=" + usess.getIdentity().getName() + ", loginBlocked=" + loginBlocked + " NbrOfSessions=" + sessionManager.getUserSessionsCnt());
+			sessionManager.signOffAndClear(usess);
 			return LOGIN_NOTAVAILABLE;
 		}
 		
@@ -337,11 +340,11 @@ public class AuthHelper {
 		// calculate session info and attach it to the user session
 		setSessionInfoFor(identity, authProvider, ureq, rest);
 		//confirm signedOn
-		usess.signOn();
+		sessionManager.signOn(usess);
 		// set users web delivery mode
 		setAjaxModeFor(ureq);
 		// update web delivery mode in session info
-		ureq.getUserSession().getSessionInfo().setWebModeFromUreq(ureq);
+		usess.getSessionInfo().setWebModeFromUreq(ureq);
 		return LOGIN_OK;
 	}
 
diff --git a/src/main/java/org/olat/basesecurity/_spring/baseSecurityContext.xml b/src/main/java/org/olat/basesecurity/_spring/baseSecurityContext.xml
index 2f4a9dd6cd1..29f9354774e 100644
--- a/src/main/java/org/olat/basesecurity/_spring/baseSecurityContext.xml
+++ b/src/main/java/org/olat/basesecurity/_spring/baseSecurityContext.xml
@@ -1,14 +1,10 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <beans xmlns="http://www.springframework.org/schema/beans"
 	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-	xmlns:context="http://www.springframework.org/schema/context" 
 	xsi:schemaLocation="
   http://www.springframework.org/schema/beans 
-  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
-  http://www.springframework.org/schema/context 
-  http://www.springframework.org/schema/context/spring-context-3.0.xsd">
+  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
 
-<context:annotation-config />
 
 <!-- manager -->
 <bean id="baseSecurityManager" class="org.olat.basesecurity.BaseSecurityManager" init-method="init" 
diff --git a/src/main/java/org/olat/commons/servlets/WebDAVManagerImpl.java b/src/main/java/org/olat/commons/servlets/WebDAVManagerImpl.java
index 330bdaecf48..b209d96d635 100644
--- a/src/main/java/org/olat/commons/servlets/WebDAVManagerImpl.java
+++ b/src/main/java/org/olat/commons/servlets/WebDAVManagerImpl.java
@@ -35,6 +35,7 @@ import javax.servlet.http.HttpServletResponse;
 import org.olat.admin.user.delete.service.UserDeletionManager;
 import org.olat.basesecurity.BaseSecurityManager;
 import org.olat.basesecurity.BaseSecurityModule;
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.id.Identity;
 import org.olat.core.id.Roles;
 import org.olat.core.id.User;
@@ -45,6 +46,7 @@ import org.olat.core.util.SessionInfo;
 import org.olat.core.util.UserSession;
 import org.olat.core.util.cache.n.CacheWrapper;
 import org.olat.core.util.coordinate.CoordinatorManager;
+import org.olat.core.util.session.UserSessionManager;
 import org.olat.login.auth.WebDAVAuthManager;
 
 import com.oreilly.servlet.Base64Decoder;
@@ -65,6 +67,7 @@ public class WebDAVManagerImpl extends WebDAVManager {
 	private CoordinatorManager coordinatorManager;
 
 	private CacheWrapper timedSessionCache;
+	private UserSessionManager sessionManager;
 
 	/**
 	 * [spring]
@@ -74,6 +77,14 @@ public class WebDAVManagerImpl extends WebDAVManager {
 		INSTANCE = this;
 	}
 
+	/**
+	 * [used by Spring]
+	 * @param sessionManager
+	 */
+	public void setSessionManager(UserSessionManager sessionManager) {
+		this.sessionManager = sessionManager;
+	}
+
 	/**
 	 * @see org.olat.commons.servlets.WebDAVManager#handleAuthentication(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
 	 */
@@ -163,14 +174,14 @@ public class WebDAVManagerImpl extends WebDAVManager {
 			// that neither field is blank
 			Identity identity = WebDAVAuthManager.authenticate(userID, password);
 			if (identity != null) {
-				UserSession usess = UserSession.getUserSession(request);
+				UserSession usess = sessionManager.getUserSession(request);
 				synchronized(usess) {
 					//double check to prevent severals concurrent login
 					if(usess.isAuthenticated()) {
 						return usess;
 					}
 				
-					usess.signOffAndClear();
+					sessionManager.signOffAndClear(usess);
 					usess.setIdentity(identity);
 					UserDeletionManager.getInstance().setIdentityAsActiv(identity);
 					// set the roles (admin, author, guest)
@@ -200,7 +211,7 @@ public class WebDAVManagerImpl extends WebDAVManager {
 					// set session info for this session
 					usess.setSessionInfo(sinfo);
 					//
-					usess.signOn();
+					sessionManager.signOn(usess);
 					return usess;
 				}
 			}
@@ -208,7 +219,6 @@ public class WebDAVManagerImpl extends WebDAVManager {
 		return null;
 	}
 	
-	
 	/**
 	 * @see org.olat.core.servlets.WebDAVManager#isEnabled()
 	 */
diff --git a/src/main/java/org/olat/commons/servlets/_spring/webdavManagerContext.xml b/src/main/java/org/olat/commons/servlets/_spring/webdavManagerContext.xml
index 89b80108b2b..b804d742ea9 100644
--- a/src/main/java/org/olat/commons/servlets/_spring/webdavManagerContext.xml
+++ b/src/main/java/org/olat/commons/servlets/_spring/webdavManagerContext.xml
@@ -9,6 +9,7 @@
 	<constructor-arg ref="coordinatorManager"/>
 	<!-- set to false to disable the WebDAV support and remove the WebDAV Link from the GUI -->
 	<property name="enabled" value="${webdav.links.enabled}" />
+	<property name="sessionManager" ref="userSessionManager" />
 </bean>  
                        
 </beans>
diff --git a/src/main/java/org/olat/commons/servlets/pathhandlers/ContextHelpFilePathHandler.java b/src/main/java/org/olat/commons/servlets/pathhandlers/ContextHelpFilePathHandler.java
index 53cbcfc0b9b..c6f122f854b 100644
--- a/src/main/java/org/olat/commons/servlets/pathhandlers/ContextHelpFilePathHandler.java
+++ b/src/main/java/org/olat/commons/servlets/pathhandlers/ContextHelpFilePathHandler.java
@@ -29,13 +29,10 @@ import java.io.BufferedInputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.InputStream;
-import java.util.Locale;
 
 import javax.servlet.http.HttpServletRequest;
 
 import org.olat.commons.servlets.util.ResourceDescriptor;
-import org.olat.core.logging.StartupException;
-import org.olat.core.util.UserSession;
 import org.olat.core.util.WebappHelper;
 
 
@@ -64,15 +61,16 @@ public class ContextHelpFilePathHandler implements PathHandler {
 	 * @see org.olat.commons.servlets.pathhandlers.PathHandler#init(com.anthonyeden.lib.config.Configuration)
 	 */
 	public void init(String path) {
-		if (path == null) return;
-		if (path != null) {
+		if (path == null) {
+			return;
+		} else {
 			File f = new File(path);
 			if (f.isAbsolute()) {
 				setRoot(path);
 			} else {
 				setRoot(WebappHelper.getContextRoot() + "/" + path);
 			}
-		} else throw new StartupException("ContextHelpFilePathHandler did not find mandatory <root> element:" + path);
+		}
 	}
 
 	/**
@@ -96,14 +94,7 @@ public class ContextHelpFilePathHandler implements PathHandler {
 		try {
 			File f = new File(root + relPath);
 			if (f.isDirectory()) return null;
-			
-			if (!f.exists()) { // file not found ->
-				int i = 1;
-				i ++;
-			}
-			//FIXME:fj: handle appropriately
-			Locale loc = UserSession.getUserSession(request).getLocale();
-			
+
 			ResourceDescriptor rd = new ResourceDescriptor(relPath);
 			rd.setLastModified(f.lastModified());
 			rd.setSize(f.length());
diff --git a/src/main/java/org/olat/core/_spring/mainCorecontext.xml b/src/main/java/org/olat/core/_spring/mainCorecontext.xml
index da2a1724b4f..207a089ead8 100644
--- a/src/main/java/org/olat/core/_spring/mainCorecontext.xml
+++ b/src/main/java/org/olat/core/_spring/mainCorecontext.xml
@@ -11,7 +11,6 @@
   http://www.springframework.org/schema/tx
   http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
   
-	<context:annotation-config />
 	<context:component-scan base-package="org.olat.core.dispatcher.mapper" />
 	<tx:annotation-driven transaction-manager="txManager"/>
 
diff --git a/src/main/java/org/olat/core/commons/contextHelp/_spring/contextHelpCorecontext.xml b/src/main/java/org/olat/core/commons/contextHelp/_spring/contextHelpCorecontext.xml
index a659ee6ae48..af50e3e4e79 100644
--- a/src/main/java/org/olat/core/commons/contextHelp/_spring/contextHelpCorecontext.xml
+++ b/src/main/java/org/olat/core/commons/contextHelp/_spring/contextHelpCorecontext.xml
@@ -1,14 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <beans xmlns="http://www.springframework.org/schema/beans"
 	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-	xmlns:context="http://www.springframework.org/schema/context" 
 	xsi:schemaLocation="
   http://www.springframework.org/schema/beans 
-  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
-  http://www.springframework.org/schema/context 
-  http://www.springframework.org/schema/context/spring-context-3.0.xsd">
-  
-<context:annotation-config />
+  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
 
 <bean id="contextHelpManager" class="org.olat.core.commons.contextHelp.ContextHelpManager" >
 	<constructor-arg ref="coordinatorManager" />
diff --git a/src/main/java/org/olat/core/commons/fullWebApp/DefaultFooterController.java b/src/main/java/org/olat/core/commons/fullWebApp/DefaultFooterController.java
index d6949c27c48..a0aa9977069 100644
--- a/src/main/java/org/olat/core/commons/fullWebApp/DefaultFooterController.java
+++ b/src/main/java/org/olat/core/commons/fullWebApp/DefaultFooterController.java
@@ -19,6 +19,7 @@
  */
 package org.olat.core.commons.fullWebApp;
 
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.defaults.dispatcher.ClassPathStaticDispatcher;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.Windows;
@@ -28,7 +29,7 @@ import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.controller.BasicController;
 import org.olat.core.helpers.Settings;
-import org.olat.core.util.UserSession;
+import org.olat.core.util.session.UserSessionManager;
 
 /**
  * <h3>Description:</h3>
@@ -70,7 +71,7 @@ public class DefaultFooterController extends BasicController {
 
 		// Push information about logged in users
 		footerVC
-				.contextPut("userSessionsCnt", UserSession.getUserSessionsCnt());
+				.contextPut("userSessionsCnt", CoreSpringFactory.getImpl(UserSessionManager.class).getUserSessionsCnt());
 
 		// Push information about user
 		if (ureq.getUserSession().isAuthenticated()) {
diff --git a/src/main/java/org/olat/core/commons/fullWebApp/DefaultTopNavController.java b/src/main/java/org/olat/core/commons/fullWebApp/DefaultTopNavController.java
index 3a4afc379e2..ef1d359f09e 100644
--- a/src/main/java/org/olat/core/commons/fullWebApp/DefaultTopNavController.java
+++ b/src/main/java/org/olat/core/commons/fullWebApp/DefaultTopNavController.java
@@ -19,6 +19,7 @@
  */
 package org.olat.core.commons.fullWebApp;
 
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.dispatcher.DispatcherAction;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
@@ -26,6 +27,7 @@ import org.olat.core.gui.components.velocity.VelocityContainer;
 import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.controller.BasicController;
+import org.olat.core.util.session.UserSessionManager;
 
 /**
  * <h3>Description:</h3>
@@ -62,7 +64,7 @@ public class DefaultTopNavController extends BasicController {
 		String command = event.getCommand();
 		if (source == topNavVC) {
 			if (command.equals("logout")) {
-				ureq.getUserSession().signOffAndClear();
+				CoreSpringFactory.getImpl(UserSessionManager.class).signOffAndClear(ureq.getUserSession());
 			} else if (command.equals("login")) {
 				DispatcherAction
 						.redirectToDefaultDispatcher(ureq.getHttpResp());
diff --git a/src/main/java/org/olat/core/commons/fullWebApp/util/_spring/StickyMessageCorecontext.xml b/src/main/java/org/olat/core/commons/fullWebApp/util/_spring/StickyMessageCorecontext.xml
index 7d91c2c103a..0be6085b0de 100644
--- a/src/main/java/org/olat/core/commons/fullWebApp/util/_spring/StickyMessageCorecontext.xml
+++ b/src/main/java/org/olat/core/commons/fullWebApp/util/_spring/StickyMessageCorecontext.xml
@@ -1,14 +1,10 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <beans xmlns="http://www.springframework.org/schema/beans"
 	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-	xmlns:context="http://www.springframework.org/schema/context" 
 	xsi:schemaLocation="
   http://www.springframework.org/schema/beans 
-  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
-  http://www.springframework.org/schema/context 
-  http://www.springframework.org/schema/context/spring-context-3.0.xsd">
+  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
 
-<context:annotation-config />
 
 <!-- manager -->
 <bean id="globalStickyMessage" class="org.olat.core.commons.fullWebApp.util.GlobalStickyMessage" init-method="init" >
diff --git a/src/main/java/org/olat/core/commons/modules/glossary/_spring/glossaryCorecontext.xml b/src/main/java/org/olat/core/commons/modules/glossary/_spring/glossaryCorecontext.xml
index f07b680ba85..04942299059 100644
--- a/src/main/java/org/olat/core/commons/modules/glossary/_spring/glossaryCorecontext.xml
+++ b/src/main/java/org/olat/core/commons/modules/glossary/_spring/glossaryCorecontext.xml
@@ -1,14 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <beans xmlns="http://www.springframework.org/schema/beans"
 	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-	xmlns:context="http://www.springframework.org/schema/context" 
 	xsi:schemaLocation="
   http://www.springframework.org/schema/beans 
-  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
-  http://www.springframework.org/schema/context 
-  http://www.springframework.org/schema/context/spring-context-3.0.xsd">
-
-<context:annotation-config />
+  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
 
 	<!--
 		*****************************************
diff --git a/src/main/java/org/olat/core/commons/services/_spring/servicesCorecontext.xml b/src/main/java/org/olat/core/commons/services/_spring/servicesCorecontext.xml
index fd7c39ecf35..90b29f9721e 100644
--- a/src/main/java/org/olat/core/commons/services/_spring/servicesCorecontext.xml
+++ b/src/main/java/org/olat/core/commons/services/_spring/servicesCorecontext.xml
@@ -8,7 +8,6 @@
   http://www.springframework.org/schema/context 
   http://www.springframework.org/schema/context/spring-context-3.0.xsd">
   
-<context:annotation-config />
 <context:component-scan base-package="org.olat.core.commons.services" />
 
 </beans>
\ No newline at end of file
diff --git a/src/main/java/org/olat/core/commons/taskExecutor/_spring/taskExecutorCorecontext.xml b/src/main/java/org/olat/core/commons/taskExecutor/_spring/taskExecutorCorecontext.xml
index 6e76b2d6a95..8f2f6173410 100644
--- a/src/main/java/org/olat/core/commons/taskExecutor/_spring/taskExecutorCorecontext.xml
+++ b/src/main/java/org/olat/core/commons/taskExecutor/_spring/taskExecutorCorecontext.xml
@@ -1,14 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <beans xmlns="http://www.springframework.org/schema/beans"
 	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-	xmlns:context="http://www.springframework.org/schema/context" 
 	xsi:schemaLocation="
   http://www.springframework.org/schema/beans 
-  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
-  http://www.springframework.org/schema/context 
-  http://www.springframework.org/schema/context/spring-context-3.0.xsd">
-
-<context:annotation-config />
+  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
 
 <bean id="taskExecutorManager" class="org.olat.core.commons.taskExecutor.TaskExecutorManager" destroy-method="destroy">
 	<constructor-arg index="0">
diff --git a/src/main/java/org/olat/core/gui/UserRequest.java b/src/main/java/org/olat/core/gui/UserRequest.java
index be352794b4b..26a9671bbc4 100644
--- a/src/main/java/org/olat/core/gui/UserRequest.java
+++ b/src/main/java/org/olat/core/gui/UserRequest.java
@@ -40,11 +40,13 @@ import java.util.StringTokenizer;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.gui.control.DispatchResult;
 import org.olat.core.id.Identity;
 import org.olat.core.logging.AssertException;
 import org.olat.core.logging.Tracing;
 import org.olat.core.util.UserSession;
+import org.olat.core.util.session.UserSessionManager;
 
 /**
  * is the "thing" generated by one user-click. It contains mainly the servlet
@@ -137,7 +139,7 @@ public class UserRequest {
 	 */
 	public UserSession getUserSession() {
 		//FIXME:fj:b cache usersession here
-		UserSession result = UserSession.getUserSession(getHttpReq());
+		UserSession result = CoreSpringFactory.getImpl(UserSessionManager.class).getUserSession(getHttpReq());
 		if (result==null) {
 			Tracing.logWarn("getUserSession: null, this="+this, new RuntimeException("getUserSession"), UserSession.class);
 		}
diff --git a/src/main/java/org/olat/core/gui/components/Window.java b/src/main/java/org/olat/core/gui/components/Window.java
index b5c2f56acd1..77aba129760 100644
--- a/src/main/java/org/olat/core/gui/components/Window.java
+++ b/src/main/java/org/olat/core/gui/components/Window.java
@@ -27,7 +27,6 @@
 package org.olat.core.gui.components;
 
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -41,7 +40,6 @@ import org.json.JSONException;
 import org.json.JSONObject;
 import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.persistence.DBFactory;
-import org.olat.core.dispatcher.mapper.MapperDispatcher;
 import org.olat.core.dispatcher.mapper.MapperService;
 import org.olat.core.gui.GUIInterna;
 import org.olat.core.gui.GlobalSettings;
diff --git a/src/main/java/org/olat/core/gui/components/util/UserLoggedInCounter.java b/src/main/java/org/olat/core/gui/components/util/UserLoggedInCounter.java
index 5ffb79b7799..930419dcc3c 100644
--- a/src/main/java/org/olat/core/gui/components/util/UserLoggedInCounter.java
+++ b/src/main/java/org/olat/core/gui/components/util/UserLoggedInCounter.java
@@ -21,10 +21,11 @@
 
 package org.olat.core.gui.components.util;
 
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
 import org.olat.core.gui.components.ComponentRenderer;
-import org.olat.core.util.UserSession;
+import org.olat.core.util.session.UserSessionManager;
 
 /**
  * <h3>Description:</h3>
@@ -45,7 +46,7 @@ public class UserLoggedInCounter extends Component {
 	 */
 	public UserLoggedInCounter() {
 		super("UserCounter");
-		this.currentCount = UserSession.getUserSessionWebCounter();
+		this.currentCount = CoreSpringFactory.getImpl(UserSessionManager.class).getUserSessionWebCounter();
 		this.setSpanAsDomReplaceable(true);
 	}
 	
@@ -55,7 +56,7 @@ public class UserLoggedInCounter extends Component {
 	@Override
 	public boolean isDirty() {
 		int lastCount = currentCount;
-		currentCount = UserSession.getUserSessionWebCounter();
+		currentCount = CoreSpringFactory.getImpl(UserSessionManager.class).getUserSessionWebCounter();
 		return (currentCount != lastCount);
 	}
 
diff --git a/src/main/java/org/olat/core/gui/control/DefaultController.java b/src/main/java/org/olat/core/gui/control/DefaultController.java
index 4e1d4f82310..165aa55208e 100644
--- a/src/main/java/org/olat/core/gui/control/DefaultController.java
+++ b/src/main/java/org/olat/core/gui/control/DefaultController.java
@@ -32,6 +32,7 @@ import java.util.List;
 import java.util.Locale;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
 import org.olat.core.gui.components.panel.Panel;
@@ -48,9 +49,9 @@ import org.olat.core.logging.activity.IUserActivityLogger;
 import org.olat.core.logging.activity.ThreadLocalUserActivityLoggerInstaller;
 import org.olat.core.logging.activity.UserActivityLoggerImpl;
 import org.olat.core.util.RunnableWithException;
-import org.olat.core.util.UserSession;
 import org.olat.core.util.Util;
 import org.olat.core.util.i18n.I18nModule;
+import org.olat.core.util.session.UserSessionManager;
 
 /**
  * Description: <br>
@@ -327,7 +328,7 @@ public abstract class DefaultController implements Controller, ControllerEventLi
 			// throw this in the unlikely odd still
 			throw new IllegalStateException("no logger set");
 		}
-		logger.frameworkSetSession(UserSession.getUserSessionIfAlreadySet(req.getHttpReq()));
+		logger.frameworkSetSession(CoreSpringFactory.getImpl(UserSessionManager.class).getUserSessionIfAlreadySet(req.getHttpReq()));
 	}
 	
 	/**
diff --git a/src/main/java/org/olat/core/gui/control/generic/layout/GenericMainController.java b/src/main/java/org/olat/core/gui/control/generic/layout/GenericMainController.java
index 9a4b1b1278f..031ddf790b7 100644
--- a/src/main/java/org/olat/core/gui/control/generic/layout/GenericMainController.java
+++ b/src/main/java/org/olat/core/gui/control/generic/layout/GenericMainController.java
@@ -77,6 +77,8 @@ public abstract class GenericMainController extends MainLayoutBasicController im
 
 	private static final String GMCMT = "GMCMenuTree";
 
+
+	private Link backLink;
 	private MenuTree olatMenuTree;
 	private Panel content;
 	private VelocityContainer stackVC;
@@ -125,6 +127,13 @@ public abstract class GenericMainController extends MainLayoutBasicController im
 		String stackPage = Util.getPackageVelocityRoot(StackedController.class) + "/stack.html";
 		stackVC = new VelocityContainer(null, "vc_stack", stackPage, getTranslator(), this);
 		stackVC.put("content", columnLayoutCtr.getInitialComponent());
+		//back link
+		backLink = LinkFactory.createCustomLink("back", "back", null, Link.NONTRANSLATED + Link.LINK_CUSTOM_CSS, stackVC, this);
+		backLink.setCustomEnabledLinkCSS("b_breadcumb_back");
+		backLink.setCustomDisplayText("\u25C4"); // unicode back arrow (black left pointer symbol)
+		backLink.setTitle(translate("back"));
+		backLink.setAccessKey("b"); // allow navigation using keyboard
+		stackVC.put("back", backLink);
 		//add the root
 		Link link = LinkFactory.createLink("gcrumb_root", stackVC, this);
 		link.setCustomDisplayText(firstNode.getTitle());
@@ -318,6 +327,13 @@ public abstract class GenericMainController extends MainLayoutBasicController im
 
 	@Override
 	protected void event(UserRequest ureq, Component source, Event event) {
+		if (source.equals(backLink)) {
+			if (stack.size() > 1) {
+				// back means to one level down, change source to the stack item one below current
+				source = stack.get(stack.size()-2);
+				// now continue as if user manually pressed a stack item in the list
+			}
+		}
 		if(stack.contains(source)) {
 			int index = stack.indexOf(source);
 			if(index < (stack.size() - 1)) {
diff --git a/src/main/java/org/olat/core/gui/media/ServletUtil.java b/src/main/java/org/olat/core/gui/media/ServletUtil.java
index 9a0ce76b562..f0e0ba0c36e 100644
--- a/src/main/java/org/olat/core/gui/media/ServletUtil.java
+++ b/src/main/java/org/olat/core/gui/media/ServletUtil.java
@@ -40,6 +40,7 @@ import java.util.StringTokenizer;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.gui.Windows;
 import org.olat.core.gui.util.bandwidth.SlowBandWidthSimulator;
 import org.olat.core.helpers.Settings;
@@ -47,7 +48,7 @@ import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
 import org.olat.core.util.FileUtils;
 import org.olat.core.util.StringHelper;
-import org.olat.core.util.UserSession;
+import org.olat.core.util.session.UserSessionManager;
 
 /**
  * @author Felix Jost
@@ -144,7 +145,7 @@ public class ServletUtil {
 				}
 				
 				if (Settings.isDebuging()) {
-					SlowBandWidthSimulator sbs = Windows.getWindows(UserSession.getUserSession(httpReq)).getSlowBandWidthSimulator();
+					SlowBandWidthSimulator sbs = Windows.getWindows(CoreSpringFactory.getImpl(UserSessionManager.class).getUserSession(httpReq)).getSlowBandWidthSimulator();
 					out = sbs.wrapOutputStream(httpResp.getOutputStream());
 				} else {
 					out = httpResp.getOutputStream();
@@ -446,7 +447,7 @@ public class ServletUtil {
 			
 			OutputStream os;
 			if (Settings.isDebuging()) {
-				SlowBandWidthSimulator sbs = Windows.getWindows(UserSession.getUserSession(httpReq)).getSlowBandWidthSimulator();
+				SlowBandWidthSimulator sbs = Windows.getWindows(CoreSpringFactory.getImpl(UserSessionManager.class).getUserSession(httpReq)).getSlowBandWidthSimulator();
 				os = sbs.wrapOutputStream(response.getOutputStream());	
 			} else {
 				os = response.getOutputStream();
diff --git a/src/main/java/org/olat/core/logging/Tracing.java b/src/main/java/org/olat/core/logging/Tracing.java
index 1ef345ac6eb..6962bea0e97 100644
--- a/src/main/java/org/olat/core/logging/Tracing.java
+++ b/src/main/java/org/olat/core/logging/Tracing.java
@@ -38,10 +38,12 @@ import javax.servlet.http.HttpServletRequest;
 import org.apache.log4j.Level;
 import org.apache.log4j.LogManager;
 import org.apache.log4j.Logger;
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.helpers.Settings;
 import org.olat.core.id.Identity;
 import org.olat.core.util.UserSession;
 import org.olat.core.util.WebappHelper;
+import org.olat.core.util.session.UserSessionManager;
 
 /**
  * This is the central place where all log information should pass.
@@ -356,7 +358,7 @@ public class Tracing {
 		String userAgent = null;
 		String referer = null;
 		if (ureq != null) {
-			usess = UserSession.getUserSessionIfAlreadySet(ureq);
+			usess = CoreSpringFactory.getImpl(UserSessionManager.class).getUserSessionIfAlreadySet(ureq);
 			if (usess != null) {
 				identity = usess.getIdentity();
 				remoteIp = ureq.getRemoteAddr();
@@ -415,7 +417,7 @@ public class Tracing {
 		String userAgent = null;
 		String referer = null;
 		if (ureq != null) {
-			usess = UserSession.getUserSession(ureq);
+			usess = CoreSpringFactory.getImpl(UserSessionManager.class).getUserSession(ureq);
 			identity = usess.getIdentity();
 			remoteIp = ureq.getRemoteAddr();
 			userAgent = ureq.getHeader("User-Agent");
diff --git a/src/main/java/org/olat/core/logging/activity/UserActivityLoggerImpl.java b/src/main/java/org/olat/core/logging/activity/UserActivityLoggerImpl.java
index 234dee71003..8f9eff9191c 100644
--- a/src/main/java/org/olat/core/logging/activity/UserActivityLoggerImpl.java
+++ b/src/main/java/org/olat/core/logging/activity/UserActivityLoggerImpl.java
@@ -40,6 +40,7 @@ import java.util.Set;
 
 import javax.servlet.http.HttpServletRequest;
 
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.persistence.DB;
 import org.olat.core.commons.persistence.DBFactory;
 import org.olat.core.gui.control.Controller;
@@ -51,6 +52,7 @@ import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
 import org.olat.core.util.UserSession;
 import org.olat.core.util.i18n.I18nManager;
+import org.olat.core.util.session.UserSessionManager;
 
 /**
  * Default implementation of the IUserActivityLogger which logs into
@@ -195,7 +197,7 @@ public class UserActivityLoggerImpl implements IUserActivityLogger {
 			throw new IllegalArgumentException("hReq must not be null");
 		}
 
-		session_ = UserSession.getUserSessionIfAlreadySet(hReq);
+		session_ = CoreSpringFactory.getImpl(UserSessionManager.class).getUserSessionIfAlreadySet(hReq);
 		if (session_!=null) {
 			identity_ = session_.getIdentity();
 		}
diff --git a/src/main/java/org/olat/core/util/SignOnOffEvent.java b/src/main/java/org/olat/core/util/SignOnOffEvent.java
index d2f2aeeacfb..1ba58ea1164 100644
--- a/src/main/java/org/olat/core/util/SignOnOffEvent.java
+++ b/src/main/java/org/olat/core/util/SignOnOffEvent.java
@@ -35,6 +35,8 @@ import org.olat.core.util.event.MultiUserEvent;
  */
 public class SignOnOffEvent extends MultiUserEvent {
 
+	private static final long serialVersionUID = 5721212429245547948L;
+	
 	private String identityName;
 	private boolean signOn;
 	/**
diff --git a/src/main/java/org/olat/core/util/UserSession.java b/src/main/java/org/olat/core/util/UserSession.java
index c0cb376ae25..1ababad2d81 100644
--- a/src/main/java/org/olat/core/util/UserSession.java
+++ b/src/main/java/org/olat/core/util/UserSession.java
@@ -27,27 +27,19 @@
 package org.olat.core.util;
 
 import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Comparator;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
-import java.util.Set;
 import java.util.Stack;
-import java.util.TreeSet;
-import java.util.concurrent.atomic.AtomicInteger;
 
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpSession;
 import javax.servlet.http.HttpSessionBindingEvent;
 import javax.servlet.http.HttpSessionBindingListener;
 
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.persistence.DBFactory;
 import org.olat.core.gui.UserRequest;
-import org.olat.core.gui.control.Disposable;
 import org.olat.core.gui.control.Event;
 import org.olat.core.id.Identity;
 import org.olat.core.id.IdentityEnvironment;
@@ -55,22 +47,18 @@ import org.olat.core.id.OLATResourceable;
 import org.olat.core.id.Roles;
 import org.olat.core.id.context.BusinessControl;
 import org.olat.core.id.context.ContextEntry;
-import org.olat.core.id.context.HistoryManager;
 import org.olat.core.id.context.HistoryPoint;
 import org.olat.core.id.context.HistoryPointImpl;
-import org.olat.core.logging.AssertException;
+import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
-import org.olat.core.logging.activity.CoreLoggingResourceable;
-import org.olat.core.logging.activity.OlatLoggingAction;
-import org.olat.core.logging.activity.ThreadLocalUserActivityLogger;
 import org.olat.core.logging.activity.ThreadLocalUserActivityLoggerInstaller;
-import org.olat.core.logging.activity.UserActivityLoggerImpl;
 import org.olat.core.util.coordinate.CoordinatorManager;
 import org.olat.core.util.event.EventBus;
 import org.olat.core.util.event.GenericEventListener;
 import org.olat.core.util.prefs.Preferences;
 import org.olat.core.util.prefs.PreferencesFactory;
 import org.olat.core.util.resource.OresHelper;
+import org.olat.core.util.session.UserSessionManager;
 
 /**
  * Description: <BR/>the httpsession contains an instance of this class. the
@@ -81,50 +69,27 @@ import org.olat.core.util.resource.OresHelper;
  */
 public class UserSession implements HttpSessionBindingListener, GenericEventListener, Serializable  {
 	
+	private static final OLog log = Tracing.createLoggerFor(UserSession.class);	
 	private static final long serialVersionUID = 1975177605776990868L;
-	
-	private static final String USERSESSIONKEY = UserSession.class.getName();
-	public static final OLATResourceable ORES_USERSESSION = OresHelper.createOLATResourceableType(UserSession.class);
-	public static final String STORE_KEY_KILLED_EXISTING_SESSION = "killedExistingSession";
-
-  //clusterNOK cache ??
-	private static final Set<UserSession> authUserSessions = new HashSet<UserSession>(101);
-	private static final Set<String> userNameToIdentity = new HashSet<String>(101);
-	private static int sessionTimeoutInSec = 300;
-	private static int sessionTimeoutAuthInSec = 7200;
-	private static final Set<String> authUsersNamesOtherNodes = new HashSet<String>(101);
-
-	// things to put into that should not be clear when signing on (e.g. remember
-	// url for a direct jump)
-	private Map<String,Object> nonClearedStore = new HashMap<String,Object>();
 
 	// the environment (identity, locale, ..) of the identity
 	private IdentityEnvironment identityEnvironment;
 	private SessionInfo sessionInfo;
 	private Map<String,Object> store;
+	/**
+	 * things to put into that should not be clear when signing on (e.g. remember url for a direct jump)
+	 */
+	private Map<String,Object> nonClearedStore = new HashMap<String,Object>();
 	private boolean authenticated = false;
-	private boolean registeredWithBus = false;
 	private Preferences guiPreferences;
 	private EventBus singleUserSystemBus;
-	//fxdiff BAKS-7 Resume function
 	private Stack<HistoryPoint> history = new Stack<HistoryPoint>();
 
-	// counters to count numbers of sessions
-	private static final AtomicInteger sessionCountWeb = new AtomicInteger();
-	private static final AtomicInteger sessionCountRest = new AtomicInteger();
-	private static final AtomicInteger sessionCountDav = new AtomicInteger();
-	
-	private UserSession() {
+	public UserSession() {
 		init();
-		//usersession is listening for SignOnOffEvents from other clusternodes
-		CoordinatorManager.getInstance().getCoordinator().getEventBus().registerFor(this, null, ORES_USERSESSION);
-		registeredWithBus = true;
 	}
 
-	/**
-	 * 
-	 */
-	private void init() {
+	public void init() {
 		store = new HashMap<String,Object>(4);
 		identityEnvironment = new IdentityEnvironment();
 		singleUserSystemBus = CoordinatorManager.getInstance().getCoordinator().createSingleUserInstance();
@@ -133,65 +98,18 @@ public class UserSession implements HttpSessionBindingListener, GenericEventList
 	}
 
 	/**
-	 * @param session
-	 * @return associated user session
-	 */
-	public static UserSession getUserSession(HttpSession session) {
-		UserSession us;
-		synchronized (session) {//o_clusterOK by:fj
-			us = (UserSession) session.getAttribute(USERSESSIONKEY);
-			if (us == null) {
-				us = new UserSession();
-				session.setAttribute(USERSESSIONKEY, us); // triggers the
-				// valueBoundEvent -> nothing
-				// more to do here
-			}
-		}
-		//set a possible changed session timeout interval
-		if(us.isAuthenticated()) {
-			session.setMaxInactiveInterval(UserSession.sessionTimeoutAuthInSec);
-		} else {
-			session.setMaxInactiveInterval(UserSession.sessionTimeoutInSec);
-		}
-		return us;
-	}
-
-	/**
-	 * @param hreq
-	 * @return associated user session
+	 * @return true if is authenticated
 	 */
-	public static UserSession getUserSession(HttpServletRequest hreq) {
-		// get existing or create new session
-		return getUserSession(hreq.getSession(true));
+	public boolean isAuthenticated() {
+		return authenticated;
 	}
 	
-	/**
-	 * Return the UserSession of the given request if it is already set or null otherwise
-	 * @param hreq
-	 * @return
-	 */
-	public static UserSession getUserSessionIfAlreadySet(HttpServletRequest hreq) {
-		HttpSession session = hreq.getSession(false);
-		if (session==null) {
-			return null;
-		}
-
-		synchronized (session) {//o_clusterOK by:se
-			UserSession us = (UserSession) session.getAttribute(USERSESSIONKEY);
-			if(us != null && us.isAuthenticated()) {
-				session.setMaxInactiveInterval(UserSession.sessionTimeoutAuthInSec);
-			} else {
-				session.setMaxInactiveInterval(UserSession.sessionTimeoutInSec);
-			}
-			return us;
-		}
+	public void setAuthenticated(boolean authenticated) {
+		this.authenticated = authenticated;
 	}
 
-	/**
-	 * @return true if is authenticated
-	 */
-	public boolean isAuthenticated() {
-		return authenticated;
+	public Map<String,Object> getStore() {
+		return store;
 	}
 
 	/**
@@ -246,8 +164,7 @@ public class UserSession implements HttpSessionBindingListener, GenericEventList
 	 * @return Locale
 	 */
 	public Locale getLocale() {
-		Locale locale = identityEnvironment.getLocale();
-		return locale;
+		return identityEnvironment.getLocale();
 	}
 
 	/**
@@ -286,8 +203,8 @@ public class UserSession implements HttpSessionBindingListener, GenericEventList
 	 */
 	public Roles getRoles() {
 		Roles result = identityEnvironment.getRoles();
-		if (result==null) {
-			Tracing.logWarn("getRoles: null, this="+this, new RuntimeException("getRoles"), UserSession.class);
+		if (result == null) {
+			log.warn("getRoles: null, this="+this, new RuntimeException("getRoles"));
 		}
 		return result;
 	}
@@ -300,8 +217,52 @@ public class UserSession implements HttpSessionBindingListener, GenericEventList
 	public void setRoles(Roles roles) {
 		identityEnvironment.setRoles(roles);
 	}
+	
+	/**
+	 * @return identity environment
+	 */
+	public IdentityEnvironment getIdentityEnvironment() {
+		return identityEnvironment;
+	}
+
+	/**
+	 * may be null
+	 * <p>
+	 * @return session info object
+	 */
+	public SessionInfo getSessionInfo() {
+		return sessionInfo;
+	}
+
+	/**
+	 * @param sessionInfo
+	 */
+	public void setSessionInfo(SessionInfo sessionInfo) {
+		this.sessionInfo = sessionInfo;
+	}
+
+	/**
+	 * @return Returns the guiPreferences.
+	 */
+	public Preferences getGuiPreferences() {
+	    return guiPreferences;
+	}
+	
+	public void reloadPreferences() {
+		Identity identity = identityEnvironment.getIdentity();
+		guiPreferences = PreferencesFactory.getInstance().getPreferencesFor(identity, identityEnvironment.getRoles().isGuestOnly());
+	}
+
+	/**
+	 * This is the olatsystembus to broadcast event amongst controllers of a single user only
+	 * (the one whom this usersession belongs to)
+	 * 
+	 * @return the olatsystembus for the local user
+	 */
+	public EventBus getSingleUserEventCenter() {
+		return singleUserSystemBus;
+	}
 
-	//fxdiff BAKS-7 Resume function
 	public List<HistoryPoint> getHistoryStack() {
 		return history;
 	}
@@ -313,7 +274,6 @@ public class UserSession implements HttpSessionBindingListener, GenericEventList
 		return history.lastElement();
 	}
 	
-	//fxdiff BAKS-7 Resume function
 	public HistoryPoint popLastHistoryEntry() {
 		if(history.isEmpty()) return null;
 		history.pop();//current point
@@ -321,14 +281,12 @@ public class UserSession implements HttpSessionBindingListener, GenericEventList
 		return history.pop();//remove last point from history
 	}
 	
-	//fxdiff BAKS-7 Resume function
 	public void addToHistory(UserRequest ureq, HistoryPoint point) {
 		if(point == null) return;
 		//System.out.println(ureq.getUuid() + " Add point to history: " + point.getBusinessPath());
 		history.add(new HistoryPointImpl(ureq.getUuid(), point.getBusinessPath(), point.getEntries()));
 	}
 	
-	//fxdiff BAKS-7 Resume function
 	public void addToHistory(UserRequest ureq, BusinessControl businessControl) {
 		List<ContextEntry> entries = businessControl.getEntries();
 		String businessPath = businessControl.getAsString();
@@ -365,8 +323,8 @@ public class UserSession implements HttpSessionBindingListener, GenericEventList
 	 * @see javax.servlet.http.HttpSessionBindingListener#valueBound(javax.servlet.http.HttpSessionBindingEvent)
 	 */
 	public void valueBound(HttpSessionBindingEvent be) {
-		if (Tracing.isDebugEnabled(UserSession.class)) {
-			Tracing.logDebug("Opened UserSession:" + this.toString(), UserSession.class);
+		if (log.isDebug()) {
+			log.debug("Opened UserSession:" + toString());
 		}
 	}
 
@@ -380,9 +338,9 @@ public class UserSession implements HttpSessionBindingListener, GenericEventList
 			// the identity can be null if an loginscreen only session gets invalidated
 			// (no user was authenticated yet but a tomcat session was created)
 			Identity ident = identityEnvironment.getIdentity();
-			signOffAndClear();
-			if (Tracing.isDebugEnabled(UserSession.class)) {
-				Tracing.logDebug("Closed UserSession: identity = " + (ident == null ? "n/a":ident.getName()), UserSession.class);
+			CoreSpringFactory.getImpl(UserSessionManager.class).signOffAndClear(this);
+			if (log.isDebug()) {
+				log.debug("Closed UserSession: identity = " + (ident == null ? "n/a":ident.getName()));
 			}
 			//we do not have a request in the null case (app. server triggered) and user not yet logged in
 			//-> in this case we use the special empty activity logger
@@ -390,9 +348,7 @@ public class UserSession implements HttpSessionBindingListener, GenericEventList
 				ThreadLocalUserActivityLoggerInstaller.initEmptyUserActivityLogger();
 			}
 		} catch (Exception e) {
-			// safely retrieve
-			Identity ident = identityEnvironment.getIdentity();
-			Tracing.logError("exception while session was unbound!", e, UserSession.class);
+			log.error("exception while session was unbound!", e);
 		}
 		// called by tomcat's timer thread -> we need to close!! since the next unbound will be called from the same tomcat-thread
 		finally {
@@ -402,482 +358,20 @@ public class UserSession implements HttpSessionBindingListener, GenericEventList
 	}
 
 	/**
-	 * called from signOffAndClear()
-	 * called from event -> MUEvent
-	 * the real work to do during sign off but without sending the multiuserevent
-	 * this is used in case the user logs in to node1 and was logged in on node2 => 
-	 * node2 catches the sign on event and invalidates the user on node2 "silently", e.g.
-	 * without firing an event.
-	 */
-	private void signOffAndClearWithout(){
-		Tracing.logDebug("signOffAndClearWithout() START", getClass());
-		final Identity ident = identityEnvironment.getIdentity();
-		//System.out.println("signOffAndClearWithout, ident="+ident+", hash="+this.hashCode()+", identityenv "+identityEnvironment.hashCode());
-		// handle safely
-		boolean isDebug = Tracing.isDebugEnabled(UserSession.class); 
-		if (isDebug) {
-			Tracing.logDebug("UserSession:::logging off: " + sessionInfo, this.getClass());
-		}
-		//fxdiff BAKS-7 Resume function
-		if(isAuthenticated() && getLastHistoryPoint() != null && !getRoles().isGuestOnly()) {
-			HistoryManager.getInstance().persistHistoryPoint(ident, getLastHistoryPoint());
-		}
-
-		/**
-		 * use not RunnableWithException, as exceptionHandlng is inside the run
-		 */
-		Runnable run = new Runnable() {
-			public void run() {
-				Object obj = null;
-				try {
-					
-					// do logging
-					if (ident != null) {
-						ThreadLocalUserActivityLogger.log(OlatLoggingAction.OLAT_LOGOUT, UserSession.class, CoreLoggingResourceable.wrap(ident));
-					} else {
-						//System.out.println("identity is null!!!!!!!!!!!!!!!!!!!!!");
-					}
-					// notify all variables in the store (the values) about the disposal
-					// if
-					// Disposable
-
-					for (Iterator<Object> it_storevals = new ArrayList<Object>(store.values()).iterator(); it_storevals.hasNext();) {
-						obj = it_storevals.next();
-						if (obj instanceof Disposable) {
-							// synchronous, since triggered by tomcat session timeout or user
-							// click and
-							// asynchronous, if kicked out by administrator.
-							// we assume synchronous
-							// !!!!
-							// As a reminder, this .dispose() calls dispose on
-							// DefaultController which is synchronized.
-							// (Windows/WindowManagerImpl/WindowBackOfficeImpl/BaseChiefController/../
-							// dispose()
-							// !!!! was important for bug OLAT-3390
-
-							((Disposable) obj).dispose();
-						}
-					}
-				} catch (Exception e) {
-
-					String objtostr = "n/a";
-					try {
-						objtostr = obj.toString();
-					} catch (Exception ee) {
-						// ignore
-					}
-					Tracing.logError("exception in signOffAndClear: while disposing object:" + objtostr, e, UserSession.class);
-				}
-			}
-		};
-
-		ThreadLocalUserActivityLoggerInstaller.runWithUserActivityLogger(run, UserActivityLoggerImpl.newLoggerForValueUnbound(this));
-
-		synchronized (authUserSessions) {  //o_clusterOK by:fj
-			if(authUserSessions.remove(this)){
-				//remove only from identityEnvironment if found in sessions.
-				//see also SIDEEFFECT!! line in signOn(..)
-				Identity previousSignedOn = identityEnvironment.getIdentity();
-				if (previousSignedOn != null) {
-					Tracing.logDebug("signOffAndClearWithout() removing from userNameToIdentity: "+previousSignedOn.getName().toLowerCase(), getClass());
-					userNameToIdentity.remove(previousSignedOn.getName().toLowerCase());
-				}
-			}else{
-				if (isDebug) {
-					Tracing.logInfo("UserSession already removed! for ["+ident+"]", UserSession.class);
-				}			
-			}
-		}
-		// update logged in users counters
-		if (sessionInfo != null) {
-			if (sessionInfo.isREST()) {
-				sessionCountRest.decrementAndGet();
-			} else if (sessionInfo.isWebDAV()) {
-				sessionCountDav.decrementAndGet();
-			} else {
-				sessionCountWeb.decrementAndGet();
-			}
-		}
-		
-		Tracing.logDebug("signOffAndClearWithout() END", getClass());
-	}
-	
-	
-	/**
-	 * called to make sure the current authenticated user (if there is one at all)
-	 * is cleared and signed off. This method is firing the SignOnOffEvent Multiuserevent.
-	 */
-	public synchronized void signOffAndClear() {  //o_clusterOK by:fj
-		Tracing.logDebug("signOffAndClear() START", getClass());
-		//
-		signOffAndClearWithout();
-		// handle safely
-		try {
-			if (isAuthenticated()) {
-				Identity identity = identityEnvironment.getIdentity();
-				Tracing.logAudit("Logged off: " + sessionInfo, this.getClass());
-				CoordinatorManager.getInstance().getCoordinator().getEventBus().fireEventToListenersOf(new SignOnOffEvent(identity, false), ORES_USERSESSION);
-				Tracing.logDebug("signOffAndClear() deregistering usersession from eventbus, id="+sessionInfo, getClass());
-				CoordinatorManager.getInstance().getCoordinator().getEventBus().deregisterFor(this, ORES_USERSESSION);
-				//fxdiff FXOLAT-231: event on GUI Preferences extern changes
-				OLATResourceable ores = OresHelper.createOLATResourceableInstance(Preferences.class, identity.getKey());
-				CoordinatorManager.getInstance().getCoordinator().getEventBus().deregisterFor(this, ores);
-				registeredWithBus = false;
-			}
-		} catch (Exception e) {
-			Tracing.logError("exception in signOffAndClear: while sending signonoffevent!", e, UserSession.class);
-		}
-		// clear all instance variables, set authenticated to false
-		init();
-		Tracing.logDebug("signOffAndClear() END", getClass());
-	}
-
-	/**
-	 * prior to calling this method, all instance vars must be set.
-	 */
-	public synchronized void signOn() {
-		//   ^^^^^^^^^^^^ Added synchronized to be symmetric with sign off and to
-		//                fix a possible dead-lock see also OLAT-3390
-		Tracing.logDebug("signOn() START", getClass());
-		if (isAuthenticated()) throw new AssertException("sign on: already signed on!");
-		Identity identity = identityEnvironment.getIdentity();
-		if (identity == null) throw new AssertException("identity is null in identityEnvironment!");
-		if (sessionInfo == null) throw new AssertException("sessionInfo was null for identity " + identity);
-		//String login = identity.getName();
-		authenticated = true;
-
-		if (sessionInfo.isWebDAV()) {
-			// load user prefs
-			guiPreferences = PreferencesFactory.getInstance().getPreferencesFor(identity, identityEnvironment.getRoles().isGuestOnly());
-
-			synchronized (authUserSessions) {  //o_clusterOK by:se
-				// we're only adding this webdav session to the authUserSessions - not to the userNameToIdentity.
-				// userNameToIdentity is only needed for IM which can't do anything with a webdav session
-				authUserSessions.add(this);
-			}
-			Tracing.logAudit("Logged on [via webdav]: " + sessionInfo.toString(), this.getClass());
-			return;
-		}
-		
-		Tracing.logDebug("signOn() authUsersNamesOtherNodes.contains "+identity.getName()+": "+authUsersNamesOtherNodes.contains(identity.getName()), getClass());
-		
-		UserSession invalidatedSession = null;
-		synchronized (authUserSessions) {  //o_clusterOK by:fj
-		    // check if already a session exist for this user
-		    if ( (userNameToIdentity.contains(identity.getName().toLowerCase()) || authUsersNamesOtherNodes.contains(identity.getName()) ) 
-		         && !sessionInfo.isWebDAV() && !sessionInfo.isREST() && !getRoles().isGuestOnly()) {
-		        Tracing.logInfo("Loggin-process II: User has already a session => signOffAndClear existing session", this.getClass());
-		        
-		        invalidatedSession = getUserSessionFor(identity.getName().toLowerCase());
-		        //remove session to be invalidated
-		        //SIDEEFFECT!! to signOffAndClear
-		        //if invalidatedSession is removed from authUserSessions
-		        //signOffAndClear does not remove the identity.getName().toLowerCase() from the userNameToIdentity
-		        //
-		        authUserSessions.remove(invalidatedSession);
-		    }
-		    authUserSessions.add(this);
-			// user can choose upercase letters in identity name, but this has no effect on the
-			// database queries, the login form or the IM account. IM works only with lowercase
-			// characters -> map stores values as such
-			Tracing.logDebug("signOn() adding to userNameToIdentity: "+identity.getName().toLowerCase(), getClass());
-			userNameToIdentity.add(identity.getName().toLowerCase());
-		}
-		// load user prefs
-		guiPreferences = PreferencesFactory.getInstance().getPreferencesFor(identity, identityEnvironment.getRoles().isGuestOnly());
-
-		if (!registeredWithBus) {
-			// OLAT-3706
-			CoordinatorManager.getInstance().getCoordinator().getEventBus().registerFor(this, null, ORES_USERSESSION);
-		}
-
-		Tracing.logAudit("Logged on: " + sessionInfo.toString(), this.getClass());
-		CoordinatorManager.getInstance().getCoordinator().getEventBus().fireEventToListenersOf(new SignOnOffEvent(identity, true), ORES_USERSESSION);
-		
-		
-		// THE FOLLOWING CHECK MUST BE PLACED HERE NOT TO PRODUCE A DEAD-LOCK WITH SIGNOFFANDCLEAR
-		// check if a session from any browser was invalidated (IE has a cookie set per Browserinstance!!)
-		if (invalidatedSession != null || authUsersNamesOtherNodes.contains(identity.getName())) {
-			// put flag killed-existing-session into session-store to show info-message 'only one session for each user' on user-home screen
-			this.putEntry(STORE_KEY_KILLED_EXISTING_SESSION, Boolean.TRUE);
-			Tracing.logDebug("signOn() removing from authUsersNamesOtherNodes: "+identity.getName(), getClass());
-			authUsersNamesOtherNodes.remove(identity.getName());
-			//OLAT-3381 & OLAT-3382
-			if(invalidatedSession != null) invalidatedSession.signOffAndClear();
-		}
-		
-		// update logged in users counters
-		if (sessionInfo.isREST()) {
-			sessionCountRest.incrementAndGet();
-		} else if (sessionInfo.isWebDAV()) {
-			sessionCountDav.incrementAndGet();
-		} else {
-			sessionCountWeb.incrementAndGet();
-		}
-		
-		Tracing.logDebug("signOn() END", getClass());
-	}
-
-
-	/**
-	 * Lookup non-webdav, non-REST UserSession for username.
-	 * @param userName
-	 * @return user-session or null when no session was founded. 
-	 */
-	private UserSession getUserSessionFor(String userName) {
-		//do not call from somewhere else then signOffAndClear!!
-		Set<UserSession> authUserSessionsCopy = new HashSet<UserSession>(authUserSessions);
-		for (Iterator<UserSession> iterator = authUserSessionsCopy.iterator(); iterator.hasNext();) {
-			UserSession userSession = (UserSession) iterator.next();			
-			if (userName.equalsIgnoreCase(userSession.getIdentity().getName()) && userSession.getSessionInfo()!=null
-					&& !userSession.getSessionInfo().isWebDAV() && !userSession.getSessionInfo().isREST() ) {
-				return userSession;
-			}
-		}
-		return null;
-	}
-
-
-
-    /**
-	 * @param userName
-	 * @return the identity or null if no user with userName is currently logged
-	 *         on
-	 */
-	public static boolean isSignedOnIdentity(String userName) {
-		synchronized (authUserSessions) {  //o_clusterOK by:fj
-			return userNameToIdentity.contains(userName.toLowerCase());
-		}
-	}
-	
-	/**
-	 * @return set of authenticated active user sessions
-	 */
-	public static Set<UserSession> getAuthenticatedUserSessions() {
-		Set<UserSession> copy;
-		synchronized (authUserSessions) {  //o_clusterOK by:fj
-			copy = new HashSet<UserSession>(authUserSessions);
-		}
-		return copy;
-	}
-
-	/**
-	 * @see java.lang.Object#toString()
-	 */
-	public String toString() {
-		return "Session of " + identityEnvironment + ", " + super.toString();
-	}
-
-	/**
-	 * @return identity environment
-	 */
-	public IdentityEnvironment getIdentityEnvironment() {
-		return identityEnvironment;
-	}
-
-	/**
-	 * may be null
-	 * <p>
-	 * @return session info object
-	 */
-	public SessionInfo getSessionInfo() {
-		return sessionInfo;
-	}
-
-	/**
-	 * @param sessionInfo
-	 */
-	public void setSessionInfo(SessionInfo sessionInfo) {
-		this.sessionInfo = sessionInfo;
-	}
-
-	/**
-	 * @return Returns the userSessionsCnt (Web, WebDAV, REST) from this VM
-	 */
-	public static int getUserSessionsCnt() {
-	  //clusterNOK ?? return only number of locale sessions ?
-		return authUserSessions.size();
-	}
-
-	/**
-	 * @return The number of users currently logged in using the web interface
-	 *         (guests and authenticated users). Note that currently this only
-	 *         returns the users from this VM as the synchronization of user
-	 *         between cluster node is not correctly. In the long run we return
-	 *         all users here.
-	 */
-	public static int getUserSessionWebCounter() {
-		// clusterNOK ?? return only number of locale sessions ?
-		return sessionCountWeb.get();
-	}
-
-	/**
-	 * @return The number of users currently logged in using a WebDAV client.
-	 *         Note that currently this only returns the users from this VM as
-	 *         the synchronization of user between cluster node is not
-	 *         correctly. In the long run we return all users here.
-	 */
-	public static int getUserSessionDavCounter() {
-		// clusterNOK ?? return only number of locale sessions ?
-		return sessionCountDav.get();
-	}
-
-	/**
-	 * @return The number of users currently logged in using the REST API. Note
-	 *         that currently this only returns the users from this VM as the
-	 *         synchronization of user between cluster node is not correctly. In
-	 *         the long run we return all users here.
-	 */
-	public static int getUserSessionRestCounter() {
-		// clusterNOK ?? return only number of locale sessions ?
-		return sessionCountRest.get();
-	}	
-
-	/**
-	 * @return Returns the guiPreferences.
-	 */
-	public Preferences getGuiPreferences() {
-	    return guiPreferences;
-	}
-
-	/**
-	 * This is the olatsystembus to broadcast event amongst controllers of a single user only
-	 * (the one whom this usersession belongs to)
-	 * 
-	 * @return the olatsystembus for the local user
-	 */
-	public EventBus getSingleUserEventCenter() {
-		return singleUserSystemBus;
-	}
-
-
-	/**
-	 * only for SignOffEvents
-	 * - Usersession keeps book about usernames
-	 * - WindowManager responsible to dispose controller chain
-	 * @see org.olat.core.util.event.GenericEventListener#event(org.olat.core.gui.control.Event)
+	 * only for preference changed event
 	 */
 	public void event(Event event) {
 		//fxdiff FXOLAT-231: event on GUI Preferences extern changes
 		if("preferences.changed".equals(event.getCommand())) {
-			Identity identity = identityEnvironment.getIdentity();
-			guiPreferences = PreferencesFactory.getInstance().getPreferencesFor(identity, identityEnvironment.getRoles().isGuestOnly());
-			return;
-		}
-
-		Tracing.logDebug("event() START", getClass());
-		SignOnOffEvent se = (SignOnOffEvent) event;
-		Tracing.logDebug("event() is SignOnOffEvent. isSignOn="+se.isSignOn(), getClass());
-		if (!se.isEventOnThisNode()) {
-			// - signOnOff from other node
-			// - Single OLAT Instance is never passing by here.
-			if (se.isSignOn()) {
-				// it is a logged on event
-				// -> remember other nodes logged usernames
-				Tracing.logDebug("event() adding to authUsersNamesOtherNodes: "+se.getIdentityName(), getClass());
-				authUsersNamesOtherNodes.add(se.getIdentityName());
-				if (sessionInfo != null && se.getIdentityName().equals(sessionInfo.getLogin()) && !sessionInfo.isWebDAV()
-						&& !this.getRoles().isGuestOnly()) {
-					// if this listening UserSession instance is from the same user
-					// and it is not a WebDAV Session, and it is not GuestSession
-					// => log user off on this node
-					this.signOffAndClearWithout();
-					Tracing.logDebug("event() deregistering usersession from eventbus, id="+se.getIdentityName(), getClass());
-					CoordinatorManager.getInstance().getCoordinator().getEventBus().deregisterFor(this, ORES_USERSESSION);
-					registeredWithBus = false;
-					init();
-				}
-			} else {
-				// it is logged off event
-				// -> remove from other nodes logged on list.
-				Tracing.logDebug("event() removing from authUsersNamesOtherNodes: "+se.getIdentityName(), getClass());
-				authUsersNamesOtherNodes.remove(se.getIdentityName());
-			}
+			reloadPreferences();
 		}
-		Tracing.logDebug("event() END", getClass());
-	}
-	
-	/**
-	 * Invalidate all sessions except admin-sessions.
-	 * @return  Number of invalidated sessions.
-	 */
-	public static int invalidateAllSessions() {
-		Tracing.logDebug("invalidateAllSessions() START", UserSession.class);
-		int invalidateCounter = 0;
-		Tracing.logAudit("All sessions were invalidated by an administrator", UserSession.class);
-		//clusterNOK ?? invalidate only locale sessions ?
-		Set<UserSession> iterCopy = new HashSet<UserSession>(authUserSessions);
-		for (Iterator<UserSession> iterator = iterCopy.iterator(); iterator.hasNext();) {
-			UserSession userSession = (UserSession) iterator.next();
-			Roles userRoles = userSession != null ? userSession.getRoles() : null; 
-			if (userRoles != null && !userRoles.isOLATAdmin()) {
-				//do not logout administrators
-				try {
-					userSession.signOffAndClear();
-					if(userSession.getSessionInfo() != null && userSession.getSessionInfo().getSession() != null) {
-						userSession.getSessionInfo().getSession().invalidate();
-					}
-					invalidateCounter++;
-				} catch(Exception ex) {
-					// Session already signed off => do nothing and continues
-				}
-			}
-		}
-		Tracing.logDebug("invalidateAllSessions() END", UserSession.class);
-		return invalidateCounter;
-	}
-	
-	/**
-	 * Invalidate a given number of oldest (last-click-time) sessions except admin-sessions.
-	 * @param nbrSessions  number of sessions whisch will be invalidated
-	 * @return  Number of invalidated sessions. 
-	 */
-	public static int invalidateOldestSessions(int nbrSessions) {
-		int invalidateCounter = 0;
-		// 1. Copy authUserSessions in sorted TreeMap
-		// This is the Comparator that will be used to sort the TreeSet:
-		Comparator<UserSession> sessionComparator = new Comparator<UserSession>() {
-			public int compare(UserSession o1, UserSession o2) {
-				Long long1 = new Long((o1).getSessionInfo().getLastClickTime());
-				Long long2 = new Long((o2).getSessionInfo().getLastClickTime());
-				return long1.compareTo(long2);
-			}
-		};
-		// clusterNOK ?? invalidate only locale sessions ?
-		TreeSet<UserSession> sortedSet = new TreeSet<UserSession>(sessionComparator);
-		sortedSet.addAll(authUserSessions);
-		int i = 0;	
-		for (Iterator<UserSession> iterator = sortedSet.iterator(); iterator.hasNext() && i++<nbrSessions;) {
-			try {
-				UserSession userSession = (UserSession) iterator.next();
-				if (!userSession.getRoles().isOLATAdmin() && !userSession.getSessionInfo().isWebDAV()) {
-					userSession.signOffAndClear();
-					invalidateCounter++;
-				}
-			} catch (Throwable th) {
-				Tracing.logWarn("Error signOffAndClear ", th, UserSession.class);
-			}
-		}
-		return invalidateCounter;		
 	}
 
 	/**
-	 * set session timeout on http session - 
-	 * @param sessionTimeoutInSec
+	 * @see java.lang.Object#toString()
 	 */
-	public static void setGlobalSessionTimeout(int sessionTimeoutInSec) {
-		UserSession.sessionTimeoutAuthInSec = sessionTimeoutInSec;
-		Set<UserSession> sessionSnapShot = new HashSet<UserSession>(authUserSessions);
-		for (UserSession session : sessionSnapShot) {
-			try{
-				SessionInfo sessionInfo2 = session.getSessionInfo();
-				if(sessionInfo2 != null){
-					sessionInfo2.getSession().setMaxInactiveInterval(sessionTimeoutInSec);
-				}
-			}catch(Throwable th){
-				Tracing.logError("error setting sesssionTimeout", th, UserSession.class);
-			}
-		}
+	@Override
+	public String toString() {
+		return "Session of " + identityEnvironment + ", " + super.toString();
 	}
-	
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/core/util/_spring/utilCorecontext.xml b/src/main/java/org/olat/core/util/_spring/utilCorecontext.xml
index 2d3765a5705..65fa87b0279 100644
--- a/src/main/java/org/olat/core/util/_spring/utilCorecontext.xml
+++ b/src/main/java/org/olat/core/util/_spring/utilCorecontext.xml
@@ -7,6 +7,8 @@
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
   http://www.springframework.org/schema/context 
   http://www.springframework.org/schema/context/spring-context-3.0.xsd">
+  
+	<context:component-scan base-package="org.olat.core.util.session" />
 
 	<bean id="codeHelper" class="org.olat.core.util.CodeHelper" >
 		<constructor-arg value="${node.id}" />
@@ -21,4 +23,27 @@
 	<bean id="imageHelperServiceProvider_java" class="org.olat.core.util.image.spi.ImageHelperImpl" />
 	
 	<bean id="imageHelperServiceProvider_magick" class="org.olat.core.util.image.spi.ImageMagickHelper" />
+	
+		<!-- Definition of the providers -->
+	<bean id="userSessionModule" class="org.olat.core.util.session.UserSessionModule">
+		<property name="persistedProperties">
+	  	<bean class="org.olat.core.configuration.PersistedProperties" scope="prototype" init-method="init" destroy-method="destroy" 
+	  		depends-on="coordinatorManager,org.olat.core.util.WebappHelper">
+	    	<constructor-arg index="0" ref="coordinatorManager"/>
+	    	<constructor-arg index="1" ref="userSessionModule" />
+	  	</bean>
+		</property>
+	</bean>
+
+	<bean  class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
+		<property name="targetObject" ref="userSessionModule" />
+		<property name="targetMethod" value="init" />
+		<property name="arguments">
+			<value>
+				session.timeout=${session.timeout}
+			</value>
+		</property>
+	</bean>
+	
+	
 </beans>
diff --git a/src/main/java/org/olat/core/util/i18n/I18nManager.java b/src/main/java/org/olat/core/util/i18n/I18nManager.java
index 31a1b3b0344..8dc2ee4ae76 100644
--- a/src/main/java/org/olat/core/util/i18n/I18nManager.java
+++ b/src/main/java/org/olat/core/util/i18n/I18nManager.java
@@ -59,6 +59,7 @@ import java.util.regex.Pattern;
 
 import javax.servlet.http.HttpServletRequest;
 
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.helpers.Settings;
 import org.olat.core.logging.AssertException;
 import org.olat.core.logging.OLATRuntimeException;
@@ -74,6 +75,7 @@ import org.olat.core.util.SortedProperties;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.UserSession;
 import org.olat.core.util.WebappHelper;
+import org.olat.core.util.session.UserSessionManager;
 import org.springframework.core.io.ClassPathResource;
 import org.springframework.core.io.Resource;
 
@@ -1273,7 +1275,7 @@ public class I18nManager extends BasicManager {
 	 * @param hreq The http servlet request
 	 */
 	public static void attachI18nInfoToThread(HttpServletRequest hreq) {
-		UserSession usess = UserSession.getUserSession(hreq);
+		UserSession usess = CoreSpringFactory.getImpl(UserSessionManager.class).getUserSession(hreq);
 		if (threadLocalLocale == null) {
 			I18nManager.getInstance().logError("can't attach i18n info to thread: threadLocalLocale is null", null);
 		} else {
diff --git a/src/main/java/org/olat/core/util/i18n/_spring/i18nCorecontext.xml b/src/main/java/org/olat/core/util/i18n/_spring/i18nCorecontext.xml
index 78ee4463fe8..0a8c43c01b3 100644
--- a/src/main/java/org/olat/core/util/i18n/_spring/i18nCorecontext.xml
+++ b/src/main/java/org/olat/core/util/i18n/_spring/i18nCorecontext.xml
@@ -4,11 +4,7 @@
 	xmlns:context="http://www.springframework.org/schema/context" 
 	xsi:schemaLocation="
   http://www.springframework.org/schema/beans 
-  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
-  http://www.springframework.org/schema/context 
-  http://www.springframework.org/schema/context/spring-context-3.0.xsd">
-
-<context:annotation-config />
+  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
 
 <bean id="I18nManager" class="org.olat.core.util.i18n.I18nManager" />
 
diff --git a/src/main/java/org/olat/core/util/session/UserSessionManager.java b/src/main/java/org/olat/core/util/session/UserSessionManager.java
new file mode 100644
index 00000000000..d2eb5b12ffc
--- /dev/null
+++ b/src/main/java/org/olat/core/util/session/UserSessionManager.java
@@ -0,0 +1,605 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.core.util.session;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.annotation.PostConstruct;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+import org.olat.core.gui.control.Disposable;
+import org.olat.core.gui.control.Event;
+import org.olat.core.id.Identity;
+import org.olat.core.id.IdentityEnvironment;
+import org.olat.core.id.OLATResourceable;
+import org.olat.core.id.Roles;
+import org.olat.core.id.context.HistoryManager;
+import org.olat.core.logging.AssertException;
+import org.olat.core.logging.OLog;
+import org.olat.core.logging.Tracing;
+import org.olat.core.logging.activity.CoreLoggingResourceable;
+import org.olat.core.logging.activity.OlatLoggingAction;
+import org.olat.core.logging.activity.ThreadLocalUserActivityLogger;
+import org.olat.core.logging.activity.ThreadLocalUserActivityLoggerInstaller;
+import org.olat.core.logging.activity.UserActivityLoggerImpl;
+import org.olat.core.util.SessionInfo;
+import org.olat.core.util.SignOnOffEvent;
+import org.olat.core.util.StringHelper;
+import org.olat.core.util.UserSession;
+import org.olat.core.util.coordinate.CoordinatorManager;
+import org.olat.core.util.event.GenericEventListener;
+import org.olat.core.util.prefs.Preferences;
+import org.olat.core.util.resource.OresHelper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * 
+ * Initial date: 15.11.2012<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+@Service
+public class UserSessionManager implements GenericEventListener {
+	
+	private static final OLog log = Tracing.createLoggerFor(UserSessionManager.class);
+	private static final String USERSESSIONKEY = UserSession.class.getName();
+	
+	public static final OLATResourceable ORES_USERSESSION = OresHelper.createOLATResourceableType(UserSession.class);
+	public static final String STORE_KEY_KILLED_EXISTING_SESSION = "killedExistingSession";
+
+  //clusterNOK cache ??
+	private static final Set<UserSession> authUserSessions = new HashSet<UserSession>(101);
+	private static final Set<String> userNameToIdentity = new HashSet<String>(101);
+	private static final Set<String> authUsersNamesOtherNodes = new HashSet<String>(101);
+
+	private static final AtomicInteger sessionCountWeb = new AtomicInteger();
+	private static final AtomicInteger sessionCountRest = new AtomicInteger();
+	private static final AtomicInteger sessionCountDav = new AtomicInteger();
+	
+	@Autowired
+	private UserSessionModule sessionModule;
+	@Autowired
+	private CoordinatorManager coordinator;
+	@Autowired
+	private HistoryManager historyManager;
+	
+	@PostConstruct
+	public void initBean() {
+		coordinator.getCoordinator().getEventBus().registerFor(this, null, ORES_USERSESSION);
+	}
+
+	/**
+	 * @param session
+	 * @return associated user session
+	 */
+	public UserSession getUserSession(HttpSession session) {
+		UserSession us;
+		synchronized (session) {//o_clusterOK by:fj
+			us = (UserSession) session.getAttribute(USERSESSIONKEY);
+			if (us == null) {
+				us = new UserSession();
+				session.setAttribute(USERSESSIONKEY, us); // triggers the
+				// valueBoundEvent -> nothing
+				// more to do here
+			}
+		}
+		//set a possible changed session timeout interval
+		if(us.isAuthenticated()) {
+			session.setMaxInactiveInterval(sessionModule.getSessionTimeoutAuthenticated());
+		} else {
+			session.setMaxInactiveInterval(sessionModule.getSessionTimeout());
+		}
+		return us;
+	}
+
+	/**
+	 * @param hreq
+	 * @return associated user session
+	 */
+	public UserSession getUserSession(HttpServletRequest hreq) {
+		// get existing or create new session
+		HttpSession httpSession = hreq.getSession(true);
+		UserSession usess = getUserSession(httpSession);
+		return usess;
+	}
+	
+	/**
+	 * Return the UserSession of the given request if it is already set or null otherwise
+	 * @param hreq
+	 * @return
+	 */
+	public UserSession getUserSessionIfAlreadySet(HttpServletRequest hreq) {
+		HttpSession session = hreq.getSession(false);
+		if (session==null) {
+			return null;
+		}
+
+		synchronized (session) {//o_clusterOK by:se
+			UserSession us = (UserSession) session.getAttribute(USERSESSIONKEY);
+			if(us != null && us.isAuthenticated()) {
+				session.setMaxInactiveInterval(sessionModule.getSessionTimeoutAuthenticated());
+			} else {
+				session.setMaxInactiveInterval(sessionModule.getSessionTimeout());
+			}
+			return us;
+		}
+	}
+
+  /**
+ * @param userName
+ * @return the identity or null if no user with userName is currently logged
+ *         on
+ */
+	public boolean isSignedOnIdentity(String userName) {
+		synchronized (authUserSessions) {  //o_clusterOK by:fj
+			return userNameToIdentity.contains(userName.toLowerCase());
+		}
+	}
+	
+	/**
+	 * @return set of authenticated active user sessions
+	 */
+	public Set<UserSession> getAuthenticatedUserSessions() {
+		Set<UserSession> copy;
+		synchronized (authUserSessions) {  //o_clusterOK by:fj
+			copy = new HashSet<UserSession>(authUserSessions);
+		}
+		return copy;
+	}
+	
+	public int getNumberOfAuthenticatedUserSessions() {
+		synchronized(authUserSessions) {
+			return authUserSessions.size();
+		}
+	}
+	
+	/**
+	 * @return Returns the userSessionsCnt (Web, WebDAV, REST) from this VM
+	 */
+	public int getUserSessionsCnt() {
+	  //clusterNOK ?? return only number of locale sessions ?
+		synchronized(authUserSessions) {
+			return authUserSessions.size();
+		}
+	}
+	
+	/**
+	 * @return The number of users currently logged in using the web interface
+	 *         (guests and authenticated users). Note that currently this only
+	 *         returns the users from this VM as the synchronization of user
+	 *         between cluster node is not correctly. In the long run we return
+	 *         all users here.
+	 */
+	public int getUserSessionWebCounter() {
+		// clusterNOK ?? return only number of locale sessions ?
+		return sessionCountWeb.get();
+	}
+	
+	/**
+	 * @return The number of users currently logged in using a WebDAV client.
+	 *         Note that currently this only returns the users from this VM as
+	 *         the synchronization of user between cluster node is not
+	 *         correctly. In the long run we return all users here.
+	 */
+	public int getUserSessionDavCounter() {
+		// clusterNOK ?? return only number of locale sessions ?
+		return sessionCountDav.get();
+	}
+	
+	/**
+	 * @return The number of users currently logged in using the REST API. Note
+	 *         that currently this only returns the users from this VM as the
+	 *         synchronization of user between cluster node is not correctly. In
+	 *         the long run we return all users here.
+	 */
+	public int getUserSessionRestCounter() {
+		// clusterNOK ?? return only number of locale sessions ?
+		return sessionCountRest.get();
+	}
+
+
+
+	/**
+	 * prior to calling this method, all instance vars must be set.
+	 */
+	public synchronized void signOn(UserSession usess) {
+		//   ^^^^^^^^^^^^ Added synchronized to be symmetric with sign off and to
+		//                fix a possible dead-lock see also OLAT-3390
+		
+		boolean isDebug = log.isDebug();
+		if(isDebug) log.debug("signOn() START");
+		if (usess.isAuthenticated()) {
+			throw new AssertException("sign on: already signed on!");
+		}
+		
+		IdentityEnvironment identityEnvironment = usess.getIdentityEnvironment();
+		Identity identity = identityEnvironment.getIdentity();
+		if (identity == null) {
+			throw new AssertException("identity is null in identityEnvironment!");
+		}
+		SessionInfo sessionInfo = usess.getSessionInfo();
+		if (sessionInfo == null) {
+			throw new AssertException("sessionInfo was null for identity " + identity);
+		}
+		//String login = identity.getName();
+		usess.setAuthenticated(true);
+
+		if (sessionInfo.isWebDAV()) {
+			// load user prefs
+			usess.reloadPreferences();
+			synchronized (authUserSessions) {  //o_clusterOK by:se
+				// we're only adding this webdav session to the authUserSessions - not to the userNameToIdentity.
+				// userNameToIdentity is only needed for IM which can't do anything with a webdav session
+				authUserSessions.add(usess);
+			}
+			log.audit("Logged on [via webdav]: " + sessionInfo.toString());
+		} else {
+		
+			if(isDebug) log.debug("signOn() authUsersNamesOtherNodes.contains "+identity.getName()+": "+authUsersNamesOtherNodes.contains(identity.getName()));
+		
+			UserSession invalidatedSession = null;
+			synchronized (authUserSessions) {  //o_clusterOK by:fj
+		    // check if already a session exist for this user
+		    if ( (userNameToIdentity.contains(identity.getName().toLowerCase()) || authUsersNamesOtherNodes.contains(identity.getName()) ) 
+		         && !sessionInfo.isWebDAV() && !sessionInfo.isREST() && !usess.getRoles().isGuestOnly()) {
+		        log.info("Loggin-process II: User has already a session => signOffAndClear existing session");
+		        
+		        invalidatedSession = getUserSessionForGui(identity.getName().toLowerCase());
+		        //remove session to be invalidated
+		        //SIDEEFFECT!! to signOffAndClear
+		        //if invalidatedSession is removed from authUserSessions
+		        //signOffAndClear does not remove the identity.getName().toLowerCase() from the userNameToIdentity
+		        //
+		        authUserSessions.remove(invalidatedSession);
+		    }
+		    authUserSessions.add(usess);
+				// user can choose upercase letters in identity name, but this has no effect on the
+				// database queries, the login form or the IM account. IM works only with lowercase
+				// characters -> map stores values as such
+				if(isDebug) log.debug("signOn() adding to userNameToIdentity: "+identity.getName().toLowerCase());
+				userNameToIdentity.add(identity.getName().toLowerCase());
+			}
+		
+			//reload user prefs
+			usess.reloadPreferences();
+
+			log.audit("Logged on: " + sessionInfo.toString());
+			CoordinatorManager.getInstance().getCoordinator().getEventBus().fireEventToListenersOf(new SignOnOffEvent(identity, true), ORES_USERSESSION);
+
+			// THE FOLLOWING CHECK MUST BE PLACED HERE NOT TO PRODUCE A DEAD-LOCK WITH SIGNOFFANDCLEAR
+			// check if a session from any browser was invalidated (IE has a cookie set per Browserinstance!!)
+			if (invalidatedSession != null || authUsersNamesOtherNodes.contains(identity.getName())) {
+				// put flag killed-existing-session into session-store to show info-message 'only one session for each user' on user-home screen
+				usess.putEntry(STORE_KEY_KILLED_EXISTING_SESSION, Boolean.TRUE);
+				if(isDebug) log.debug("signOn() removing from authUsersNamesOtherNodes: "+identity.getName());
+				authUsersNamesOtherNodes.remove(identity.getName());
+				//OLAT-3381 & OLAT-3382
+				if(invalidatedSession != null) {
+					signOffAndClear(invalidatedSession);
+				}
+			}
+
+			if(isDebug) log.debug("signOn() END");
+		}
+		
+		// update logged in users counters
+		if (sessionInfo.isREST()) {
+			sessionCountRest.incrementAndGet();
+		} else if (sessionInfo.isWebDAV()) {
+			sessionCountDav.incrementAndGet();
+		} else {
+			sessionCountWeb.incrementAndGet();
+		}
+	}
+	
+	/**
+	 * called to make sure the current authenticated user (if there is one at all)
+	 * is cleared and signed off. This method is firing the SignOnOffEvent Multiuserevent.
+	 */
+	public synchronized void signOffAndClear(UserSession usess) {  //o_clusterOK by:fj
+		boolean isDebug = log.isDebug();
+		if(isDebug) log.debug("signOffAndClear() START");
+		//
+		
+		signOffAndClearWithout(usess);
+		// handle safely
+		try {
+			if (usess.isAuthenticated()) {
+				SessionInfo sessionInfo = usess.getSessionInfo();
+				IdentityEnvironment identityEnvironment = usess.getIdentityEnvironment();
+				Identity identity = identityEnvironment.getIdentity();
+				log.audit("Logged off: " + sessionInfo);
+				CoordinatorManager.getInstance().getCoordinator().getEventBus().fireEventToListenersOf(new SignOnOffEvent(identity, false), ORES_USERSESSION);
+				if(isDebug) log.debug("signOffAndClear() deregistering usersession from eventbus, id="+sessionInfo);
+				//fxdiff FXOLAT-231: event on GUI Preferences extern changes
+				OLATResourceable ores = OresHelper.createOLATResourceableInstance(Preferences.class, identity.getKey());
+				CoordinatorManager.getInstance().getCoordinator().getEventBus().deregisterFor(usess, ores);
+			}
+		} catch (Exception e) {
+			log.error("exception in signOffAndClear: while sending signonoffevent!", e);
+		}
+		// clear all instance variables, set authenticated to false
+		usess.init();
+		if(isDebug) log.debug("signOffAndClear() END");
+	}
+
+
+	/**
+	 * called from signOffAndClear()
+	 * called from event -> MUEvent
+	 * the real work to do during sign off but without sending the multiuserevent
+	 * this is used in case the user logs in to node1 and was logged in on node2 => 
+	 * node2 catches the sign on event and invalidates the user on node2 "silently", e.g.
+	 * without firing an event.
+	 */
+	public void signOffAndClearWithout(final UserSession usess) {
+		boolean isDebug = log.isDebug();
+		if(isDebug) log.debug("signOffAndClearWithout() START");
+		
+		final IdentityEnvironment identityEnvironment = usess.getIdentityEnvironment();
+		final SessionInfo sessionInfo = usess.getSessionInfo();
+		final Identity ident = identityEnvironment.getIdentity();
+		if (isDebug) log.debug("UserSession:::logging off: " + sessionInfo);
+
+		//fxdiff BAKS-7 Resume function
+		if(usess.isAuthenticated() && usess.getLastHistoryPoint() != null && !usess.getRoles().isGuestOnly()) {
+			historyManager.persistHistoryPoint(ident, usess.getLastHistoryPoint());
+		}
+
+		/**
+		 * use not RunnableWithException, as exceptionHandlng is inside the run
+		 */
+		Runnable run = new Runnable() {
+			public void run() {
+				Object obj = null;
+				try {
+					// do logging
+					if (ident != null) {
+						ThreadLocalUserActivityLogger.log(OlatLoggingAction.OLAT_LOGOUT, UserSession.class, CoreLoggingResourceable.wrap(ident));
+					} else {
+						//System.out.println("identity is null!!!!!!!!!!!!!!!!!!!!!");
+					}
+					// notify all variables in the store (the values) about the disposal
+					// if
+					// Disposable
+					List<Object> storeList = new ArrayList<Object>(usess.getStore().values());
+
+					for (Iterator<Object> it_storevals = storeList.iterator(); it_storevals.hasNext();) {
+						obj = it_storevals.next();
+						if (obj instanceof Disposable) {
+							// synchronous, since triggered by tomcat session timeout or user
+							// click and
+							// asynchronous, if kicked out by administrator.
+							// we assume synchronous
+							// !!!!
+							// As a reminder, this .dispose() calls dispose on
+							// DefaultController which is synchronized.
+							// (Windows/WindowManagerImpl/WindowBackOfficeImpl/BaseChiefController/../
+							// dispose()
+							// !!!! was important for bug OLAT-3390
+
+							((Disposable) obj).dispose();
+						}
+					}
+				} catch (Exception e) {
+
+					String objtostr = "n/a";
+					try {
+						objtostr = obj.toString();
+					} catch (Exception ee) {
+						// ignore
+					}
+					log.error("exception in signOffAndClear: while disposing object:" + objtostr, e);
+				}
+			}
+		};
+
+		ThreadLocalUserActivityLoggerInstaller.runWithUserActivityLogger(run, UserActivityLoggerImpl.newLoggerForValueUnbound(usess));
+
+		synchronized (authUserSessions) {  //o_clusterOK by:fj
+			if(authUserSessions.remove(usess)){
+				//remove only from identityEnvironment if found in sessions.
+				//see also SIDEEFFECT!! line in signOn(..)
+				Identity previousSignedOn = identityEnvironment.getIdentity();
+				if (previousSignedOn != null) {
+					if(isDebug) log.debug("signOffAndClearWithout() removing from userNameToIdentity: "+previousSignedOn.getName().toLowerCase());
+					userNameToIdentity.remove(previousSignedOn.getName().toLowerCase());
+				}
+			} else if (isDebug) {
+				log.info("UserSession already removed! for ["+ident+"]");			
+			}
+		}
+		// update logged in users counters
+		if (sessionInfo != null) {
+			if (sessionInfo.isREST()) {
+				sessionCountRest.decrementAndGet();
+			} else if (sessionInfo.isWebDAV()) {
+				sessionCountDav.decrementAndGet();
+			} else {
+				sessionCountWeb.decrementAndGet();
+			}
+		}
+		
+		if (isDebug) log.debug("signOffAndClearWithout() END");
+	}
+
+	/**
+	 * only for SignOffEvents
+	 * - Usersession keeps book about usernames
+	 * - WindowManager responsible to dispose controller chain
+	 * @see org.olat.core.util.event.GenericEventListener#event(org.olat.core.gui.control.Event)
+	 */
+	public void event(Event event) {
+		if(event instanceof SignOnOffEvent) {
+			SignOnOffEvent se = (SignOnOffEvent) event;
+			processSignOnOffEvent(se);
+		}
+	}
+	
+	private void processSignOnOffEvent(SignOnOffEvent se) {
+		try {
+			boolean debug = log.isDebug();
+			if(debug) log.debug("event() START");
+			if(debug) log.debug("event() is SignOnOffEvent. isSignOn="+se.isSignOn());
+			if (!se.isEventOnThisNode()) {
+				// - signOnOff from other node
+				// - Single OLAT Instance is never passing by here.
+				if (se.isSignOn()) {
+					// it is a logged on event
+					// -> remember other nodes logged usernames
+					if(debug) log.debug("event() adding to authUsersNamesOtherNodes: "+se.getIdentityName());
+					authUsersNamesOtherNodes.add(se.getIdentityName());
+					UserSession usess = getUserSessionForGui(se.getIdentityName());
+					if (usess.getSessionInfo() != null && se.getIdentityName().equals(usess.getSessionInfo().getLogin())
+							&& !usess.getSessionInfo().isWebDAV() && !usess.getRoles().isGuestOnly()) {
+						
+						// if this listening UserSession instance is from the same user
+						// and it is not a WebDAV Session, and it is not GuestSession
+						// => log user off on this node
+						signOffAndClearWithout(usess);
+						usess.init();
+					}
+				} else {
+					// it is logged off event
+					// -> remove from other nodes logged on list.
+					if(debug) log.debug("event() removing from authUsersNamesOtherNodes: "+se.getIdentityName());
+					authUsersNamesOtherNodes.remove(se.getIdentityName());
+				}
+			}
+			if(debug) log.debug("event() END");
+		} catch (Exception e) {
+			log.error("", e);
+		}
+	}
+	
+	/**
+	 * Invalidate all sessions except admin-sessions.
+	 * @return  Number of invalidated sessions.
+	 */
+	public int invalidateAllSessions() {
+		log.debug("invalidateAllSessions() START");
+		int invalidateCounter = 0;
+		log.audit("All sessions were invalidated by an administrator");
+		//clusterNOK ?? invalidate only locale sessions ?
+		Set<UserSession> iterCopy = getAuthenticatedUserSessions();
+		for (Iterator<UserSession> iterator = iterCopy.iterator(); iterator.hasNext();) {
+			UserSession userSession = iterator.next();
+			Roles userRoles = userSession != null ? userSession.getRoles() : null; 
+			if (userRoles != null && !userRoles.isOLATAdmin()) {
+				//do not logout administrators
+				try {
+					signOffAndClear(userSession);
+					if(userSession.getSessionInfo() != null && userSession.getSessionInfo().getSession() != null) {
+						userSession.getSessionInfo().getSession().invalidate();
+					}
+					invalidateCounter++;
+				} catch(Exception ex) {
+					// Session already signed off => do nothing and continues
+				}
+			}
+		}
+		log.debug("invalidateAllSessions() END");
+		return invalidateCounter;
+	}
+	
+	/**
+	 * Invalidate a given number of oldest (last-click-time) sessions except admin-sessions.
+	 * @param nbrSessions  number of sessions whisch will be invalidated
+	 * @return  Number of invalidated sessions. 
+	 */
+	public int invalidateOldestSessions(int nbrSessions) {
+		int invalidateCounter = 0;
+		// 1. Copy authUserSessions in sorted TreeMap
+		// This is the Comparator that will be used to sort the TreeSet:
+		Comparator<UserSession> sessionComparator = new Comparator<UserSession>() {
+			public int compare(UserSession o1, UserSession o2) {
+				Long long1 = new Long((o1).getSessionInfo().getLastClickTime());
+				Long long2 = new Long((o2).getSessionInfo().getLastClickTime());
+				return long1.compareTo(long2);
+			}
+		};
+		// clusterNOK ?? invalidate only locale sessions ?
+		TreeSet<UserSession> sortedSet = new TreeSet<UserSession>(sessionComparator);
+		sortedSet.addAll(authUserSessions);
+		int i = 0;	
+		for (Iterator<UserSession> iterator = sortedSet.iterator(); iterator.hasNext() && i++<nbrSessions;) {
+			try {
+				UserSession userSession = (UserSession) iterator.next();
+				if (!userSession.getRoles().isOLATAdmin() && !userSession.getSessionInfo().isWebDAV()) {
+					signOffAndClear(userSession);
+					invalidateCounter++;
+				}
+			} catch (Throwable th) {
+				log.warn("Error signOffAndClear ", th);
+			}
+		}
+		return invalidateCounter;		
+	}
+
+	/**
+	 * set session timeout on http session - 
+	 * @param sessionTimeoutInSec
+	 */
+	public void setGlobalSessionTimeout(int sessionTimeoutInSec) {
+		Collection<UserSession> sessionSnapShot = getAuthenticatedUserSessions();
+		for (UserSession session : sessionSnapShot) {
+			try{
+				SessionInfo sessionInfo = session.getSessionInfo();
+				if(sessionInfo != null && sessionInfo.getSession() != null) {
+					sessionInfo.getSession().setMaxInactiveInterval(sessionTimeoutInSec);
+				}
+			} catch(Throwable th){
+				log.error("error setting sesssionTimeout", th);
+			}
+		}
+	}
+	
+	/**
+	 * Lookup non-webdav, non-REST UserSession for username.
+	 * @param userName
+	 * @return user-session or null when no session was founded. 
+	 */
+	private UserSession getUserSessionForGui(String userName) {
+		if(StringHelper.containsNonWhitespace(userName)) {
+			//do not call from somewhere else then signOffAndClear!!
+			Collection<UserSession> authUserSessionsCopy = getAuthenticatedUserSessions();
+			for (UserSession userSession : authUserSessionsCopy) {		
+				Identity identity = userSession.getIdentity();
+				if (identity != null && userName.equalsIgnoreCase(identity.getName())
+						&& userSession.getSessionInfo() != null
+						&& !userSession.getSessionInfo().isWebDAV()
+						&& !userSession.getSessionInfo().isREST()) {
+					return userSession;
+				}
+			}
+		}
+		return null;
+	}
+}
diff --git a/src/main/java/org/olat/core/util/session/UserSessionModule.java b/src/main/java/org/olat/core/util/session/UserSessionModule.java
new file mode 100644
index 00000000000..6294d0e6c60
--- /dev/null
+++ b/src/main/java/org/olat/core/util/session/UserSessionModule.java
@@ -0,0 +1,85 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.core.util.session;
+
+import org.olat.core.configuration.AbstractOLATModule;
+import org.olat.core.configuration.PersistedProperties;
+import org.olat.core.util.StringHelper;
+
+/**
+ * 
+ * Initial date: 15.11.2012<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class UserSessionModule extends AbstractOLATModule {
+	
+
+	private static final String SESSION_TIMEOUT = "session.timeout";
+	private static final String SESSION_TIMEOUT_AUTH = "session.timeout.authenticated";
+	
+	private int sessionTimeout;
+	private int sessionTimeoutAuthenticated;
+
+	@Override
+	public void init() {
+		String timeoutObj = getStringPropertyValue(SESSION_TIMEOUT, true);
+		if(StringHelper.isLong(timeoutObj)) {
+			sessionTimeout = Integer.parseInt(timeoutObj);
+		}
+		
+		String timeoutAuthObj = getStringPropertyValue(SESSION_TIMEOUT_AUTH, true);
+		if(StringHelper.isLong(timeoutAuthObj)) {
+			sessionTimeoutAuthenticated = Integer.parseInt(timeoutAuthObj);
+		}
+	}
+	
+	@Override
+	protected void initDefaultProperties() {
+		sessionTimeout = getIntConfigParameter(SESSION_TIMEOUT, 7200);
+		sessionTimeoutAuthenticated = getIntConfigParameter(SESSION_TIMEOUT_AUTH, 300);
+	}
+
+	@Override
+	protected void initFromChangedProperties() {
+		init();
+	}
+
+	@Override
+	public void setPersistedProperties(PersistedProperties persistedProperties) {
+		this.moduleConfigProperties = persistedProperties;
+	}
+
+	public int getSessionTimeout() {
+		return sessionTimeout;
+	}
+
+	public void setSessionTimeout(int timeout) {
+		setStringProperty(SESSION_TIMEOUT, Integer.toString(timeout), true);
+	}
+
+	public int getSessionTimeoutAuthenticated() {
+		return sessionTimeoutAuthenticated;
+	}
+
+	public void setSessionTimeoutAuthenticated(int timeout) {
+		setStringProperty(SESSION_TIMEOUT_AUTH, Integer.toString(timeout), true);
+	}
+}
diff --git a/src/main/java/org/olat/core/util/vfs/version/_spring/versioningCorecontext.xml b/src/main/java/org/olat/core/util/vfs/version/_spring/versioningCorecontext.xml
index c432fde1c62..8a98892bab6 100644
--- a/src/main/java/org/olat/core/util/vfs/version/_spring/versioningCorecontext.xml
+++ b/src/main/java/org/olat/core/util/vfs/version/_spring/versioningCorecontext.xml
@@ -1,14 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <beans xmlns="http://www.springframework.org/schema/beans"
 	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-	xmlns:context="http://www.springframework.org/schema/context" 
 	xsi:schemaLocation="
   http://www.springframework.org/schema/beans 
-  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
-  http://www.springframework.org/schema/context 
-  http://www.springframework.org/schema/context/spring-context-3.0.xsd">
-
-<context:annotation-config />
+  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
 
 <bean id="versionsManager" class="org.olat.core.util.vfs.version.VersionsFileManager" init-method="init"/>
 
diff --git a/src/main/java/org/olat/course/assessment/_spring/assessmentContext.xml b/src/main/java/org/olat/course/assessment/_spring/assessmentContext.xml
index 4ae1eaae9fc..dd912adf960 100644
--- a/src/main/java/org/olat/course/assessment/_spring/assessmentContext.xml
+++ b/src/main/java/org/olat/course/assessment/_spring/assessmentContext.xml
@@ -7,8 +7,7 @@
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
   http://www.springframework.org/schema/context 
   http://www.springframework.org/schema/context/spring-context-3.0.xsd">
-  
-  <context:annotation-config />
+
 	<context:component-scan base-package="org.olat.course.assessment.manager" />
 
 <bean id="assessmentModule" class="org.olat.course.assessment.AssessmentModule" init-method="init" destroy-method="destroy" >
diff --git a/src/main/java/org/olat/course/nodes/_spring/buildingblockContext.xml b/src/main/java/org/olat/course/nodes/_spring/buildingblockContext.xml
index 9f3b10fd03d..e6f97e846bc 100644
--- a/src/main/java/org/olat/course/nodes/_spring/buildingblockContext.xml
+++ b/src/main/java/org/olat/course/nodes/_spring/buildingblockContext.xml
@@ -8,7 +8,6 @@
   http://www.springframework.org/schema/context 
   http://www.springframework.org/schema/context/spring-context-3.0.xsd">
 
-	<context:annotation-config />
 	<context:component-scan base-package="org.olat.course.nodes.en" />
 	  
 	<!-- Course node spring config: Course Nodes are searched on the whole classpath, just place your CourceNodeConfiguration somewhere
diff --git a/src/main/java/org/olat/dispatcher/AuthenticatedDispatcher.java b/src/main/java/org/olat/dispatcher/AuthenticatedDispatcher.java
index 4a6774b159e..9261ee87523 100644
--- a/src/main/java/org/olat/dispatcher/AuthenticatedDispatcher.java
+++ b/src/main/java/org/olat/dispatcher/AuthenticatedDispatcher.java
@@ -33,6 +33,7 @@ import javax.servlet.http.HttpSession;
 
 import org.olat.NewControllerFactory;
 import org.olat.basesecurity.AuthHelper;
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.dispatcher.Dispatcher;
 import org.olat.core.dispatcher.DispatcherAction;
 import org.olat.core.gui.UserRequest;
@@ -50,6 +51,7 @@ import org.olat.core.util.URIHelper;
 import org.olat.core.util.UserSession;
 import org.olat.core.util.i18n.I18nManager;
 import org.olat.core.util.i18n.I18nModule;
+import org.olat.core.util.session.UserSessionManager;
 import org.olat.core.util.threadlog.UserBasedLogLevelManager;
 import org.olat.login.LoginModule;
 
@@ -89,7 +91,7 @@ public class AuthenticatedDispatcher implements Dispatcher {
 		if ( log.isDebug() ) {
 			startExecute = System.currentTimeMillis();
 		}
-		UserSession usess = UserSession.getUserSession(request);
+		UserSession usess = CoreSpringFactory.getImpl(UserSessionManager.class).getUserSession(request);
 		UserRequest ureq = null;
 		try{
 			//upon creation URL is checked for 
diff --git a/src/main/java/org/olat/dispatcher/DMZDispatcher.java b/src/main/java/org/olat/dispatcher/DMZDispatcher.java
index 38c7888f07e..7244e8cfe8c 100644
--- a/src/main/java/org/olat/dispatcher/DMZDispatcher.java
+++ b/src/main/java/org/olat/dispatcher/DMZDispatcher.java
@@ -33,6 +33,7 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 import org.olat.basesecurity.AuthHelper;
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.dispatcher.Dispatcher;
 import org.olat.core.dispatcher.DispatcherAction;
 import org.olat.core.gui.UserRequest;
@@ -48,6 +49,7 @@ import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
 import org.olat.core.util.UserSession;
 import org.olat.core.util.i18n.I18nManager;
+import org.olat.core.util.session.UserSessionManager;
 
 /**
  * Initial Date: 28.11.2003
@@ -268,7 +270,7 @@ public class DMZDispatcher implements Dispatcher {
 					// the log-in link in the -same- browser window ->
 					// -> there is no window -> create a new one
 					window = null;
-					usess.signOffAndClear();
+					CoreSpringFactory.getImpl(UserSessionManager.class).signOffAndClear(usess);
 					usess.setLocale(LocaleNegotiator.getPreferedLocale(ureq));
 					I18nManager.updateLocaleInfoToThread(usess);//update locale infos
 					
@@ -280,7 +282,7 @@ public class DMZDispatcher implements Dispatcher {
 					} else {
 						// e.g. /dmz/ -> start screen, clear previous session data
 						window = null; 
-						usess.signOffAndClear();
+						CoreSpringFactory.getImpl(UserSessionManager.class).signOffAndClear(usess);
 						usess.setLocale(LocaleNegotiator.getPreferedLocale(ureq));
 						I18nManager.updateLocaleInfoToThread(usess);//update locale infos
 						// request new windows since it is a new usersession, the old one was purged
diff --git a/src/main/java/org/olat/dispatcher/RESTDispatcher.java b/src/main/java/org/olat/dispatcher/RESTDispatcher.java
index 1afa78dda67..954b2efe309 100644
--- a/src/main/java/org/olat/dispatcher/RESTDispatcher.java
+++ b/src/main/java/org/olat/dispatcher/RESTDispatcher.java
@@ -52,6 +52,7 @@ import org.olat.core.util.UserSession;
 import org.olat.core.util.WebappHelper;
 import org.olat.core.util.i18n.I18nManager;
 import org.olat.core.util.i18n.I18nModule;
+import org.olat.core.util.session.UserSessionManager;
 import org.olat.login.LoginModule;
 import org.olat.restapi.security.RestSecurityBean;
 import org.olat.restapi.security.RestSecurityHelper;
@@ -133,7 +134,7 @@ public class RESTDispatcher implements Dispatcher {
 		//
 		// create the olat ureq and get an associated main window to spawn the "tab"
 		//
-		UserSession usess = UserSession.getUserSession(request);
+		UserSession usess = CoreSpringFactory.getImpl(UserSessionManager.class).getUserSession(request);
 		UserRequest ureq = null;
 		try {
 			//upon creation URL is checked for 
diff --git a/src/main/java/org/olat/dispatcher/RedirectToAutoGuestLoginDispatcher.java b/src/main/java/org/olat/dispatcher/RedirectToAutoGuestLoginDispatcher.java
index 85813fa24c4..ae2f006fdae 100644
--- a/src/main/java/org/olat/dispatcher/RedirectToAutoGuestLoginDispatcher.java
+++ b/src/main/java/org/olat/dispatcher/RedirectToAutoGuestLoginDispatcher.java
@@ -28,6 +28,7 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 import org.olat.basesecurity.AuthHelper;
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.dispatcher.Dispatcher;
 import org.olat.core.dispatcher.DispatcherAction;
 import org.olat.core.gui.UserRequest;
@@ -35,9 +36,11 @@ import org.olat.core.gui.Windows;
 import org.olat.core.gui.components.Window;
 import org.olat.core.gui.control.ChiefController;
 import org.olat.core.logging.AssertException;
+import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
 import org.olat.core.util.UserSession;
 import org.olat.core.util.i18n.I18nManager;
+import org.olat.core.util.session.UserSessionManager;
 
 /**
  * Description:<br>
@@ -53,12 +56,14 @@ import org.olat.core.util.i18n.I18nManager;
  * @author Lars Eberle (<a href="http://www.bps-system.de/">BPS Bildungsportal Sachsen GmbH</a>)
  */
 public class RedirectToAutoGuestLoginDispatcher implements Dispatcher {
+	
+	private static final OLog log = Tracing.createLoggerFor(RedirectToAutoGuestLoginDispatcher.class);
 		
 	/**
 	 * @see org.olat.core.dispatcher.Dispatcher#execute(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.String)
 	 */
 	public void execute(HttpServletRequest request, HttpServletResponse response, String uriPrefix) {
-		UserSession usess = UserSession.getUserSession(request);
+		UserSession usess = CoreSpringFactory.getImpl(UserSessionManager.class).getUserSession(request);
 		UserRequest ureq = null;
 		try{
 			//upon creation URL is checked for 
@@ -70,8 +75,8 @@ public class RedirectToAutoGuestLoginDispatcher implements Dispatcher {
 			//or authors copy-pasted links to the content.
 			//showing redscreens for non valid URL is wrong instead
 			//a 404 message must be shown -> e.g. robots correct their links.
-			if(Tracing.isDebugEnabled(RedirectToAutoGuestLoginDispatcher.class)){
-				Tracing.logDebug("Bad Request "+request.getPathInfo(), this.getClass());
+			if(log.isDebug()){
+				log.debug("Bad Request "+request.getPathInfo());
 			}
 			DispatcherAction.sendBadRequest(request.getPathInfo(), response);
 			return;
diff --git a/src/main/java/org/olat/group/_spring/businessGroupContext.xml b/src/main/java/org/olat/group/_spring/businessGroupContext.xml
index 8d904c4e4f1..ff939db14e6 100644
--- a/src/main/java/org/olat/group/_spring/businessGroupContext.xml
+++ b/src/main/java/org/olat/group/_spring/businessGroupContext.xml
@@ -11,7 +11,6 @@
   http://www.springframework.org/schema/tx
   http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
 
-	<context:annotation-config />
 	<context:component-scan base-package="org.olat.group.manager,org.olat.group.area,org.olat.group.right" />
 	<tx:annotation-driven transaction-manager="txManager"/>
 
diff --git a/src/main/java/org/olat/ims/qti/QTIStaticsHandler.java b/src/main/java/org/olat/ims/qti/QTIStaticsHandler.java
index f7043ead309..7ab53f153d9 100644
--- a/src/main/java/org/olat/ims/qti/QTIStaticsHandler.java
+++ b/src/main/java/org/olat/ims/qti/QTIStaticsHandler.java
@@ -31,8 +31,9 @@ import javax.servlet.http.HttpServletRequest;
 
 import org.olat.commons.servlets.pathhandlers.FilePathHandler;
 import org.olat.commons.servlets.util.ResourceDescriptor;
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.modules.bc.FolderConfig;
-import org.olat.core.util.UserSession;
+import org.olat.core.util.session.UserSessionManager;
 
 /**
  * Initial Date:  16.06.2003
@@ -61,7 +62,7 @@ public class QTIStaticsHandler extends FilePathHandler {
 	}
 
 	public ResourceDescriptor getResourceDescriptor(HttpServletRequest request, String relPath) {
-		if (UserSession.getUserSession(request).isAuthenticated()) {
+		if (CoreSpringFactory.getImpl(UserSessionManager.class).getUserSession(request).isAuthenticated()) {
 			if (relPath.endsWith("qti.xml")) return null;
 			return super.getResourceDescriptor(request, relPath);
 		}	else
diff --git a/src/main/java/org/olat/instantMessaging/_spring/instantMessagingContext.xml b/src/main/java/org/olat/instantMessaging/_spring/instantMessagingContext.xml
index 35929316a69..035d5b30fb0 100644
--- a/src/main/java/org/olat/instantMessaging/_spring/instantMessagingContext.xml
+++ b/src/main/java/org/olat/instantMessaging/_spring/instantMessagingContext.xml
@@ -8,7 +8,6 @@
   http://www.springframework.org/schema/context 
   http://www.springframework.org/schema/context/spring-context-3.0.xsd">
 
-<context:annotation-config />
 <context:component-scan base-package="org.olat.instantMessaging" />
 	
 	<bean id="instantMessagingModule" class="org.olat.instantMessaging.InstantMessagingModule" 
diff --git a/src/main/java/org/olat/instantMessaging/rosterandchat/ChangePresenceJob.java b/src/main/java/org/olat/instantMessaging/rosterandchat/ChangePresenceJob.java
index a522d161fe4..3d1b478ee37 100644
--- a/src/main/java/org/olat/instantMessaging/rosterandchat/ChangePresenceJob.java
+++ b/src/main/java/org/olat/instantMessaging/rosterandchat/ChangePresenceJob.java
@@ -25,16 +25,17 @@
 */
 package org.olat.instantMessaging.rosterandchat;
 
-import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Iterator;
-import java.util.List;
 
 import javax.servlet.http.HttpSession;
 
 import org.jivesoftware.smack.packet.Presence;
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.scheduler.JobWithDB;
 import org.olat.core.util.SessionInfo;
 import org.olat.core.util.UserSession;
+import org.olat.core.util.session.UserSessionManager;
 import org.olat.instantMessaging.ClientManager;
 import org.olat.instantMessaging.InstantMessagingClient;
 import org.olat.instantMessaging.InstantMessagingModule;
@@ -65,8 +66,8 @@ public class ChangePresenceJob extends JobWithDB  {
 	   	try{	
 		Long timeNow = System.currentTimeMillis();
 
-		List<UserSession> authUserSessions = new ArrayList<UserSession>(UserSession.getAuthenticatedUserSessions());
-
+		UserSessionManager sessionManager = CoreSpringFactory.getImpl(UserSessionManager.class);
+		Collection<UserSession> authUserSessions = sessionManager.getAuthenticatedUserSessions();
 		for (Iterator<UserSession> iter = authUserSessions.iterator(); iter.hasNext();) {
 			UserSession session = iter.next();
 			long lastAccessTime = 0;
@@ -184,9 +185,6 @@ public class ChangePresenceJob extends JobWithDB  {
 		// Initialize static value only once because setInitialAutoLogOutCutTime is called at each ChangePresenceJob-run
 		if (!initializedAutoLogOutCutTime) {
 			autoLogOutCutTime = initialAutoLogOutCutTime;
-			// init GlobalSessionTimeout used by tomcat for session-timeout
-			int sessionTimeoutSeconds = Math.round((ChangePresenceJob.getAutoLogOutCutTimeValue() / 1000));
-			UserSession.setGlobalSessionTimeout(sessionTimeoutSeconds);
 			initializedAutoLogOutCutTime = true;
 		}
 	}
diff --git a/src/main/java/org/olat/instantMessaging/ui/ConnectedUsersLocal.java b/src/main/java/org/olat/instantMessaging/ui/ConnectedUsersLocal.java
index b554d915492..09efdcd31f4 100644
--- a/src/main/java/org/olat/instantMessaging/ui/ConnectedUsersLocal.java
+++ b/src/main/java/org/olat/instantMessaging/ui/ConnectedUsersLocal.java
@@ -32,6 +32,7 @@ import java.util.Map;
 import java.util.Set;
 
 import org.olat.basesecurity.BaseSecurityManager;
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.id.Identity;
 import org.olat.core.id.UserConstants;
 import org.olat.core.logging.AssertException;
@@ -40,6 +41,7 @@ import org.olat.core.logging.Tracing;
 import org.olat.core.util.UserSession;
 import org.olat.core.util.cache.n.CacheWrapper;
 import org.olat.core.util.coordinate.CoordinatorManager;
+import org.olat.core.util.session.UserSessionManager;
 import org.olat.instantMessaging.ClientHelper;
 import org.olat.instantMessaging.ImPreferences;
 import org.olat.instantMessaging.ImPrefsManager;
@@ -56,7 +58,7 @@ import org.olat.instantMessaging.syncservice.InstantMessagingSessionItems;
  */
 public class ConnectedUsersLocal implements InstantMessagingSessionItems {
 	
-	OLog log = Tracing.createLoggerFor(this.getClass());
+	private static final OLog log = Tracing.createLoggerFor(ConnectedUsersLocal.class);
 	private CacheWrapper sessionItemsCache;
 	private ImPrefsManager imPrefsManager;
 	
@@ -85,10 +87,12 @@ public class ConnectedUsersLocal implements InstantMessagingSessionItems {
 			}
 		}
 		
+		UserSessionManager sessionManager = CoreSpringFactory.getImpl(UserSessionManager.class);
+		
 		List<ConnectedUsersListEntry> entries = new ArrayList<ConnectedUsersListEntry>();
 		Map<String, Long> lastActivity = new HashMap<String, Long>();
 		Set<String> usernames = InstantMessagingModule.getAdapter().getUsernamesFromConnectedUsers();
-		Set<UserSession> authSessions = UserSession.getAuthenticatedUserSessions();
+		Set<UserSession> authSessions = sessionManager.getAuthenticatedUserSessions();
 		for (Iterator<UserSession> iter = authSessions.iterator(); iter.hasNext();) {
 			UserSession userSession = iter.next();
 			long lastAccTime = 0;
@@ -113,7 +117,7 @@ public class ConnectedUsersLocal implements InstantMessagingSessionItems {
 			
 			} else {
 				//item not in cache
-				if (UserSession.isSignedOnIdentity(olatusername)) {
+				if (sessionManager.isSignedOnIdentity(olatusername)) {
 					Identity identity = (Identity)BaseSecurityManager.getInstance().findIdentityByName(olatusername);
 					try {
 						ImPreferences imPrefs = imPrefsManager.loadOrCreatePropertiesFor(identity);
diff --git a/src/main/java/org/olat/modules/_spring/modulesContext.xml b/src/main/java/org/olat/modules/_spring/modulesContext.xml
index 692bd7b7a0e..f692e52196c 100644
--- a/src/main/java/org/olat/modules/_spring/modulesContext.xml
+++ b/src/main/java/org/olat/modules/_spring/modulesContext.xml
@@ -8,7 +8,6 @@
   http://www.springframework.org/schema/context 
   http://www.springframework.org/schema/context/spring-context-3.0.xsd">
   
-<context:annotation-config />
 <context:component-scan base-package="org.olat.modules" />
 
 </beans>
\ No newline at end of file
diff --git a/src/main/java/org/olat/modules/openmeetings/_spring/openmeetingsContext.xml b/src/main/java/org/olat/modules/openmeetings/_spring/openmeetingsContext.xml
index 03a68d2c1a4..12b6d4b6e31 100644
--- a/src/main/java/org/olat/modules/openmeetings/_spring/openmeetingsContext.xml
+++ b/src/main/java/org/olat/modules/openmeetings/_spring/openmeetingsContext.xml
@@ -8,7 +8,6 @@
   http://www.springframework.org/schema/context 
   http://www.springframework.org/schema/context/spring-context-3.0.xsd">
   
-	<context:annotation-config />
 	<context:component-scan base-package="org.olat.modules.openmeetings" />
 
 	<!-- Definition of the providers -->
diff --git a/src/main/java/org/olat/modules/vitero/_spring/viteroContext.xml b/src/main/java/org/olat/modules/vitero/_spring/viteroContext.xml
index 030d85e263b..ba56bf2cd65 100644
--- a/src/main/java/org/olat/modules/vitero/_spring/viteroContext.xml
+++ b/src/main/java/org/olat/modules/vitero/_spring/viteroContext.xml
@@ -8,7 +8,6 @@
   http://www.springframework.org/schema/context 
   http://www.springframework.org/schema/context/spring-context-3.0.xsd">
   
-	<context:annotation-config />
 	<context:component-scan base-package="org.olat.modules.vitero" />
 
 	<!-- Definition of the providers -->
diff --git a/src/main/java/org/olat/resource/accesscontrol/_spring/acContext.xml b/src/main/java/org/olat/resource/accesscontrol/_spring/acContext.xml
index 09aa3ba915f..4c4303e5219 100644
--- a/src/main/java/org/olat/resource/accesscontrol/_spring/acContext.xml
+++ b/src/main/java/org/olat/resource/accesscontrol/_spring/acContext.xml
@@ -10,7 +10,6 @@
                         http://www.springframework.org/schema/tx
                         http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
 
-	<context:annotation-config />
 	<context:component-scan base-package="org.olat.resource.accesscontrol" />
 	
 	<bean id="acModule" class="org.olat.resource.accesscontrol.AccessControlModule" depends-on="org.olat.core.util.WebappHelper">
diff --git a/src/main/java/org/olat/resource/accesscontrol/provider/paypal/ui/PaypalMapper.java b/src/main/java/org/olat/resource/accesscontrol/provider/paypal/ui/PaypalMapper.java
index 6395759377a..96909b02fd2 100644
--- a/src/main/java/org/olat/resource/accesscontrol/provider/paypal/ui/PaypalMapper.java
+++ b/src/main/java/org/olat/resource/accesscontrol/provider/paypal/ui/PaypalMapper.java
@@ -24,6 +24,7 @@ import java.util.List;
 
 import javax.servlet.http.HttpServletRequest;
 
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.dispatcher.mapper.Mapper;
 import org.olat.core.gui.media.MediaResource;
 import org.olat.core.gui.media.RedirectMediaResource;
@@ -33,6 +34,7 @@ import org.olat.core.id.context.ContextEntry;
 import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
 import org.olat.core.util.UserSession;
+import org.olat.core.util.session.UserSessionManager;
 import org.olat.resource.accesscontrol.provider.paypal.manager.PaypalManager;
 
 /**
@@ -59,7 +61,7 @@ public class PaypalMapper implements Mapper {
 	@Override
 	public MediaResource handle(String relPath, HttpServletRequest request) {
 		List<ContextEntry> entries = null;
-		UserSession usess = UserSession.getUserSession(request);
+		UserSession usess = CoreSpringFactory.getImpl(UserSessionManager.class).getUserSession(request);
 		try {
 			entries = BusinessControlFactory.getInstance().createCEListFromString(businessPath);
 			if(relPath.indexOf(';') > 0) {
diff --git a/src/main/java/org/olat/restapi/security/RestApiLoginFilter.java b/src/main/java/org/olat/restapi/security/RestApiLoginFilter.java
index 50bbd9f5870..a273947d1b3 100644
--- a/src/main/java/org/olat/restapi/security/RestApiLoginFilter.java
+++ b/src/main/java/org/olat/restapi/security/RestApiLoginFilter.java
@@ -49,6 +49,7 @@ import org.olat.core.util.StringHelper;
 import org.olat.core.util.UserSession;
 import org.olat.core.util.WebappHelper;
 import org.olat.core.util.i18n.I18nManager;
+import org.olat.core.util.session.UserSessionManager;
 import org.olat.login.OLATAuthenticationController;
 import org.olat.restapi.RestModule;
 
@@ -108,7 +109,7 @@ public class RestApiLoginFilter implements Filter {
 				I18nManager.attachI18nInfoToThread(httpRequest);
 				ThreadLocalUserActivityLoggerInstaller.initUserActivityLogger(httpRequest);
 
-				UserSession uress = UserSession.getUserSessionIfAlreadySet(httpRequest);
+				UserSession uress = CoreSpringFactory.getImpl(UserSessionManager.class).getUserSessionIfAlreadySet(httpRequest);
 				if(uress != null && uress.isAuthenticated()) {
 					//use the available session
 					followSession(httpRequest, httpResponse, chain);
@@ -212,7 +213,7 @@ public class RestApiLoginFilter implements Filter {
 	throws IOException, ServletException {
 	//create a session for login without security check
 		if(uress == null) {
-			uress = UserSession.getUserSession(request);
+			uress = CoreSpringFactory.getImpl(UserSessionManager.class).getUserSession(request);
 		}
 		UserRequest ureq = null;
 		try{
@@ -229,7 +230,7 @@ public class RestApiLoginFilter implements Filter {
 	
 	private void followWithoutAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain) 
 	throws IOException, ServletException {
-		UserSession uress = UserSession.getUserSessionIfAlreadySet(request);
+		UserSession uress = CoreSpringFactory.getImpl(UserSessionManager.class).getUserSessionIfAlreadySet(request);
 		if(uress != null && uress.isAuthenticated()) {
 			//is authenticated by session cookie, follow its current session
 			followSession(request, response, chain);
@@ -263,7 +264,7 @@ public class RestApiLoginFilter implements Filter {
 	throws IOException, ServletException {
 		HttpSession session = request.getSession(true);
 		session.setMaxInactiveInterval(TOKEN_BASED_SESSION_TIMEOUT);
-		UserSession uress = UserSession.getUserSession(session);
+		UserSession uress = CoreSpringFactory.getImpl(UserSessionManager.class).getUserSession(session);
 		if(uress != null) {
 			UserRequest ureq = null;
 			try{
@@ -290,7 +291,7 @@ public class RestApiLoginFilter implements Filter {
 	
 	private void followSession(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
 	throws IOException, ServletException {
-		UserSession uress = UserSession.getUserSessionIfAlreadySet(request);
+		UserSession uress = CoreSpringFactory.getImpl(UserSessionManager.class).getUserSessionIfAlreadySet(request);
 		if(uress != null && uress.isAuthenticated()) {
 			UserRequest ureq = null;
 			try{
diff --git a/src/main/java/org/olat/restapi/system/OpenOLATStatisticsWebService.java b/src/main/java/org/olat/restapi/system/OpenOLATStatisticsWebService.java
index 47449d0f665..553deac27c4 100644
--- a/src/main/java/org/olat/restapi/system/OpenOLATStatisticsWebService.java
+++ b/src/main/java/org/olat/restapi/system/OpenOLATStatisticsWebService.java
@@ -34,6 +34,7 @@ import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.services.search.SearchServiceStatus;
 import org.olat.core.util.SessionInfo;
 import org.olat.core.util.UserSession;
+import org.olat.core.util.session.UserSessionManager;
 import org.olat.course.CourseModule;
 import org.olat.group.BusinessGroupService;
 import org.olat.instantMessaging.InstantMessagingModule;
@@ -194,9 +195,11 @@ public class OpenOLATStatisticsWebService {
 	
 	private SessionsVO getSessionsVO() {
 		SessionsVO vo = new SessionsVO();
-		vo.setCount(UserSession.getUserSessionsCnt());
 
-		Set<UserSession> userSessions = UserSession.getAuthenticatedUserSessions();
+		UserSessionManager sessionManager = CoreSpringFactory.getImpl(UserSessionManager.class);
+		vo.setCount(sessionManager.getUserSessionsCnt());
+
+		Set<UserSession> userSessions = sessionManager.getAuthenticatedUserSessions();
 		int webdavcount = 0;
 		int secureWebdavCount = 0;
 		int authenticatedcount = 0;
diff --git a/src/main/java/org/olat/shibboleth/ShibbolethRegistrationController.java b/src/main/java/org/olat/shibboleth/ShibbolethRegistrationController.java
index 4badc1fc5b8..572e754fdf1 100644
--- a/src/main/java/org/olat/shibboleth/ShibbolethRegistrationController.java
+++ b/src/main/java/org/olat/shibboleth/ShibbolethRegistrationController.java
@@ -37,6 +37,7 @@ import org.olat.basesecurity.BaseSecurityManager;
 import org.olat.basesecurity.BaseSecurityModule;
 import org.olat.basesecurity.Constants;
 import org.olat.basesecurity.SecurityGroup;
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.chiefcontrollers.LanguageChangedEvent;
 import org.olat.core.commons.fullWebApp.LayoutMain3ColsController;
 import org.olat.core.dispatcher.DispatcherAction;
@@ -56,17 +57,16 @@ import org.olat.core.id.Identity;
 import org.olat.core.id.User;
 import org.olat.core.id.UserConstants;
 import org.olat.core.logging.AssertException;
-import org.olat.core.util.UserSession;
 import org.olat.core.util.Util;
 import org.olat.core.util.WebappHelper;
 import org.olat.core.util.i18n.I18nManager;
+import org.olat.core.util.session.UserSessionManager;
 import org.olat.dispatcher.LocaleNegotiator;
 import org.olat.registration.DisclaimerController;
 import org.olat.registration.LanguageChooserController;
 import org.olat.registration.RegistrationManager;
 import org.olat.registration.RegistrationModule;
 import org.olat.registration.UserNameCreationInterceptor;
-import org.olat.shibboleth.util.ShibbolethAttribute;
 import org.olat.shibboleth.util.ShibbolethHelper;
 import org.olat.user.UserManager;
 
@@ -224,7 +224,7 @@ public class ShibbolethRegistrationController extends DefaultController implemen
 	 * @param attributes
 	 */
 	public static final void putShibAttributes(HttpServletRequest req, Map<String,String> attributes) {
-		UserSession.getUserSession(req).putEntry(KEY_SHIBATTRIBUTES, attributes);
+		CoreSpringFactory.getImpl(UserSessionManager.class).getUserSession(req).putEntry(KEY_SHIBATTRIBUTES, attributes);
 	}
 	
 	/**
@@ -233,7 +233,7 @@ public class ShibbolethRegistrationController extends DefaultController implemen
 	 * @param uniqueID
 	 */
 	public static final void putShibUniqueID(HttpServletRequest req, String uniqueID) {
-		UserSession.getUserSession(req).putEntry(KEY_SHIBUNIQUEID, uniqueID);
+		CoreSpringFactory.getImpl(UserSessionManager.class).getUserSession(req).putEntry(KEY_SHIBUNIQUEID, uniqueID);
 	}
 
 	/**
diff --git a/src/main/java/org/olat/upgrade/_spring/upgradeContext.xml b/src/main/java/org/olat/upgrade/_spring/upgradeContext.xml
index 1eab4eaf8ed..e329df9dfdd 100644
--- a/src/main/java/org/olat/upgrade/_spring/upgradeContext.xml
+++ b/src/main/java/org/olat/upgrade/_spring/upgradeContext.xml
@@ -8,7 +8,6 @@
   http://www.springframework.org/schema/context 
   http://www.springframework.org/schema/context/spring-context-3.0.xsd">
   
-<context:annotation-config />
 <context:component-scan base-package="org.olat.upgrade" />
 
  	<bean id="olatUpgradeManager.enabled" class="org.olat.upgrade.UpgradeManagerImpl" lazy-init="true"  init-method="init" depends-on="folderModule">
diff --git a/src/main/java/org/olat/user/ChangePrefsController.java b/src/main/java/org/olat/user/ChangePrefsController.java
index 5468bff64c5..e5ebc1457b3 100644
--- a/src/main/java/org/olat/user/ChangePrefsController.java
+++ b/src/main/java/org/olat/user/ChangePrefsController.java
@@ -43,15 +43,16 @@ import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.controller.BasicController;
 import org.olat.core.gui.media.RedirectMediaResource;
 import org.olat.core.id.Identity;
-import org.olat.core.util.WebappHelper;
 import org.olat.core.id.User;
 import org.olat.core.id.context.HistoryManager;
 import org.olat.core.id.context.HistoryModule;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.UserSession;
+import org.olat.core.util.WebappHelper;
 import org.olat.core.util.i18n.I18nManager;
 import org.olat.core.util.prefs.Preferences;
 import org.olat.core.util.prefs.PreferencesFactory;
+import org.olat.core.util.session.UserSessionManager;
 import org.olat.properties.PropertyManager;
 
 
@@ -160,9 +161,12 @@ class SpecialPrefsForm extends FormBasicController {
 	/** The keys for yes/no back. */
 	private String[] yesNoKeys;
 	private String[] yesNoValues;
+
+	private final UserSessionManager sessionManager;
 	
 	public SpecialPrefsForm(final UserRequest ureq, final WindowControl wControl, final Identity changeableIdentity) {
 		super(ureq, wControl);
+		sessionManager = CoreSpringFactory.getImpl(UserSessionManager.class);
 		tobeChangedIdentity = changeableIdentity;
 		
 		// OLAT-6429 load GUI prefs from user session for myself, load it from factory for other users (as user manager)
@@ -202,7 +206,7 @@ class SpecialPrefsForm extends FormBasicController {
 	protected void formOK(UserRequest ureq) {
 		// OLAT-6429 don't change another users GUI prefs when he is logged in 
 		if (!ureq.getIdentity().equalsByPersistableKey(tobeChangedIdentity)) {
-			if (UserSession.isSignedOnIdentity(tobeChangedIdentity.getName())) {
+			if (sessionManager.isSignedOnIdentity(tobeChangedIdentity.getName())) {
 				showError("error.user.logged.in", tobeChangedIdentity.getName());
 				prefsElement.reset();
 				return;
@@ -314,9 +318,12 @@ class UserPrefsResetForm extends FormBasicController {
 	private Identity tobeChangedIdentity;
 	private MultipleSelectionElement resetElements;
 	private String[] keys, values;
+
+	private final UserSessionManager sessionManager;
 	
 	public UserPrefsResetForm(UserRequest ureq, WindowControl wControl, Identity changeableIdentity) {
 		super(ureq, wControl);
+		sessionManager = CoreSpringFactory.getImpl(UserSessionManager.class);
 		tobeChangedIdentity = changeableIdentity;
 		initForm(ureq);
 	}
@@ -343,11 +350,11 @@ class UserPrefsResetForm extends FormBasicController {
 		if (resetElements.isAtLeastSelected(1)) {
 			// Log out user first if logged in
 			boolean logout = false;
-			Set<UserSession> sessions = UserSession.getAuthenticatedUserSessions();
+			Set<UserSession> sessions = sessionManager.getAuthenticatedUserSessions();
 			for (UserSession session : sessions) {
 				Identity ident = session.getIdentity();
 				if (ident != null && tobeChangedIdentity.equalsByPersistableKey(ident)) {
-					session.signOffAndClear();
+					sessionManager.signOffAndClear(session);
 					logout = true;
 					break;
 				}
diff --git a/src/main/resources/serviceconfig/olat.properties b/src/main/resources/serviceconfig/olat.properties
index 40965e11915..e1f81fd9381 100644
--- a/src/main/resources/serviceconfig/olat.properties
+++ b/src/main/resources/serviceconfig/olat.properties
@@ -93,6 +93,10 @@ history.back.enabled.default=true
 history.resume.enabled.default=ondemand
 history.resume.enabled.default.values=none,auto,ondemand
 
+#session timeout in seconds
+session.timeout=7200
+
+
 ########################################################################
 # SMTP (mail) settings
 ########################################################################
diff --git a/src/main/resources/serviceconfig/org/olat/_spring/extensionContext.xml b/src/main/resources/serviceconfig/org/olat/_spring/extensionContext.xml
index 1d3fd15c021..66b7b9ba1cf 100644
--- a/src/main/resources/serviceconfig/org/olat/_spring/extensionContext.xml
+++ b/src/main/resources/serviceconfig/org/olat/_spring/extensionContext.xml
@@ -13,15 +13,31 @@
 	
 <!-- SYSADMIN extension for admin site for OLAT setup -->
 
-	<!--  the sysinfo  menu-entry -->
+
+	<!-- The system menu point -->
+	<bean class="org.olat.core.extensions.action.GenericActionExtension" init-method="initExtensionPoints">
+		<property name="order" value="7100" />
+		<property name="navigationKey" value="system" />
+		<property name="nodeIdentifierIfParent" value="systemParent" />
+		<property name="translationPackage" value="org.olat.admin" />
+		<property name="i18nActionKey" value="menu.system" />
+		<property name="i18nDescriptionKey" value="menu.system.alt" />
+		<property name="extensionPoints">
+			<list>
+				<value>org.olat.admin.SystemAdminMainController</value>
+			</list>
+		</property>
+	</bean>
+	
 	<bean class="org.olat.core.extensions.action.GenericActionExtension"  init-method="initExtensionPoints">
-			<property name="order" value="7100" />
+			<property name="order" value="7110" />
 			<property name="actionController">	
 				<bean class="org.olat.core.gui.control.creator.AutoCreator" scope="prototype">
 					<property name="className" value="org.olat.admin.sysinfo.SysinfoController"/>
 				</bean>
 			</property>
 			<property name="navigationKey" value="sysinfo" />
+			<property name="parentTreeNodeIdentifier" value="systemParent" /> 
 			<property name="translationPackage" value="org.olat.admin"/>
 			<property name="i18nActionKey" value="menu.sysinfo"/>
 			<property name="i18nDescriptionKey" value="menu.sysinfo.alt"/>
@@ -31,6 +47,27 @@
 				</list>
 			</property>
 	</bean>
+	
+	<bean class="org.olat.core.extensions.action.GenericActionExtension"  init-method="initExtensionPoints">
+			<property name="order" value="7120" />
+			<property name="actionController">	
+				<bean class="org.olat.core.gui.control.creator.AutoCreator" scope="prototype">
+					<property name="className" value="org.olat.admin.sysinfo.UserSessionAdminController"/>
+				</bean>
+			</property>
+			<property name="navigationKey" value="sessions" />
+			<property name="parentTreeNodeIdentifier" value="systemParent" /> 
+			<property name="translationPackage" value="org.olat.admin"/>
+			<property name="i18nActionKey" value="menu.session"/>
+			<property name="i18nDescriptionKey" value="menu.session.alt"/>
+			<property name="extensionPoints">
+				<list>	
+					<value>org.olat.admin.SystemAdminMainController</value>		
+				</list>
+			</property>
+	</bean>
+
+
 
 	<!--  the "systemconfig" parent node -->
 	<bean class="org.olat.core.extensions.action.GenericActionExtension"  init-method="initExtensionPoints">
diff --git a/src/test/java/org/olat/core/dispatcher/mapper/MapperServiceTest.java b/src/test/java/org/olat/core/dispatcher/mapper/MapperServiceTest.java
index 8afded127bb..1d465b9cb0b 100644
--- a/src/test/java/org/olat/core/dispatcher/mapper/MapperServiceTest.java
+++ b/src/test/java/org/olat/core/dispatcher/mapper/MapperServiceTest.java
@@ -33,6 +33,7 @@ import org.olat.core.dispatcher.mapper.manager.MapperDAO;
 import org.olat.core.gui.media.MediaResource;
 import org.olat.core.util.SessionInfo;
 import org.olat.core.util.UserSession;
+import org.olat.core.util.session.UserSessionManager;
 import org.olat.test.OlatTestCase;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.mock.web.MockHttpSession;
@@ -49,6 +50,8 @@ public class MapperServiceTest extends OlatTestCase {
 	private MapperService mapperService;
 	@Autowired
 	private DB dbInstance;
+	@Autowired
+	private UserSessionManager sessionManager;
 	
 	@Test
 	public void should_service_present() {
@@ -179,7 +182,7 @@ public class MapperServiceTest extends OlatTestCase {
 	
 	private UserSession createUserSession() {
 		HttpSession httpSession = new MockHttpSession();
-		UserSession userSession = UserSession.getUserSession(httpSession);
+		UserSession userSession = sessionManager.getUserSession(httpSession);
 		SessionInfo infos = new SessionInfo(UUID.randomUUID().toString(), httpSession);
 		userSession.setSessionInfo(infos);
 		//check if our mocked HTTP session makes what we want
diff --git a/src/test/java/org/olat/test/OlatTestCase.java b/src/test/java/org/olat/test/OlatTestCase.java
index b79b648b518..54c47a5fcce 100644
--- a/src/test/java/org/olat/test/OlatTestCase.java
+++ b/src/test/java/org/olat/test/OlatTestCase.java
@@ -54,6 +54,7 @@ import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
 	"classpath:/org/olat/core/util/_spring/utilCorecontext.xml",
 	"classpath:/org/olat/core/util/i18n/devtools/_spring/devtoolsCorecontext.xml",
 	"classpath:/org/olat/core/util/event/_spring/frameworkStartedEventCorecontext.xml",
+	"classpath:/org/olat/core/id/context/_spring/historyCorecontext.xml",
 
 	"classpath:/org/olat/core/commons/persistence/_spring/databaseCorecontext.xml",
 	"classpath:/org/olat/core/commons/taskExecutor/_spring/taskExecutorCorecontext.xml",
-- 
GitLab