diff --git a/src/main/java/org/olat/admin/sysinfo/UserSessionController.java b/src/main/java/org/olat/admin/sysinfo/UserSessionController.java index b7a14a3702421254a9dbad9a4ebce1947d8617f5..d3746db85c71d268e8572a2b759b753a28e1b4a6 100644 --- a/src/main/java/org/olat/admin/sysinfo/UserSessionController.java +++ b/src/main/java/org/olat/admin/sysinfo/UserSessionController.java @@ -26,6 +26,7 @@ package org.olat.admin.sysinfo; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import org.olat.admin.sysinfo.model.UserSessionView; @@ -112,7 +113,7 @@ public class UserSessionController extends BasicController implements Breadcrumb * Re-initialize this controller. Fetches sessions again. */ public void reset() { - List<UserSession> authUserSessions = new ArrayList<UserSession>(sessionManager.getAuthenticatedUserSessions()); + Collection<UserSession> authUserSessions = sessionManager.getAuthenticatedUserSessions(); List<UserSessionView> authUserSessionViews = new ArrayList<UserSessionView>(authUserSessions.size()); for(UserSession authUserSession:authUserSessions) { authUserSessionViews.add(new UserSessionView(authUserSession)); diff --git a/src/main/java/org/olat/admin/sysinfo/manager/SessionStatsManager.java b/src/main/java/org/olat/admin/sysinfo/manager/SessionStatsManager.java index e6418b5fff007356aabf54f2a4d5096533b675b5..54ad0624e8c12cbd37f54d5b4a1fb5b6a70f7b3f 100644 --- a/src/main/java/org/olat/admin/sysinfo/manager/SessionStatsManager.java +++ b/src/main/java/org/olat/admin/sysinfo/manager/SessionStatsManager.java @@ -20,6 +20,7 @@ package org.olat.admin.sysinfo.manager; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; @@ -99,7 +100,7 @@ public class SessionStatsManager implements Sampler { public long getActiveSessions(int numOfSeconds) { long diff = numOfSeconds * 1000; - List<UserSession> authUserSessions = new ArrayList<UserSession>(sessionManager.getAuthenticatedUserSessions()); + Collection<UserSession> authUserSessions = sessionManager.getAuthenticatedUserSessions(); long now = System.currentTimeMillis(); long counter = 0; for (UserSession usess : authUserSessions) { diff --git a/src/main/java/org/olat/core/logging/OLogImpl.java b/src/main/java/org/olat/core/logging/OLogImpl.java index 0a2cd99dd63438388e149b16831d834a26c88a03..809c66f34642c748a8931567cc7212d31442fd96 100644 --- a/src/main/java/org/olat/core/logging/OLogImpl.java +++ b/src/main/java/org/olat/core/logging/OLogImpl.java @@ -25,6 +25,8 @@ */ package org.olat.core.logging; +import org.apache.log4j.Logger; + /** * Description:<br> * Log Impl class, for method details see Tracing.java in the same package @@ -34,35 +36,38 @@ package org.olat.core.logging; * @author Felix Jost, http://www.goodsolutions.ch */ public class OLogImpl implements OLog { - Class loggingClazz; - OLogImpl(Class clazz) { - this.loggingClazz = clazz; + private final Class<?> loggingClazz; + private final Logger logger; + + OLogImpl(Class<?> clazz) { + loggingClazz = clazz; + logger = Tracing.getLogger(clazz); } public boolean isDebug() { - return Tracing.isDebugEnabled(loggingClazz); + return logger.isDebugEnabled(); } public void error(String logMsg, Throwable cause) { - Tracing.logError(logMsg, cause, loggingClazz); + Tracing.logError(logMsg, cause, logger, loggingClazz); } public void error(String logMsg) { - Tracing.logError(logMsg, loggingClazz); + Tracing.logError(logMsg, null, logger, loggingClazz); } /** * See package.html for proper usage! */ public void warn(String logMsg, Throwable cause) { - Tracing.logWarn(logMsg, cause, loggingClazz); + Tracing.logWarn(logMsg, cause, logger, loggingClazz); } /** * See package.html for proper usage! */ public void warn(String logMsg) { - Tracing.logWarn(logMsg, loggingClazz); + Tracing.logWarn(logMsg, null, logger, loggingClazz); } /** @@ -72,36 +77,36 @@ public class OLogImpl implements OLog { * */ public void debug(String logMsg, String userObj) { - Tracing.logDebug(logMsg, userObj, loggingClazz); + Tracing.logDebug(logMsg, userObj, logger, loggingClazz); } /** * Add debug log entry */ public void debug(String logMsg) { - Tracing.logDebug(logMsg, loggingClazz); + Tracing.logDebug(logMsg, null, logger, loggingClazz); } public void info(String logMsg, String userObject) { - Tracing.logInfo(logMsg, userObject, loggingClazz); + Tracing.logInfo(logMsg, userObject, logger, loggingClazz); } public void info(String logMsg) { - Tracing.logInfo(logMsg, loggingClazz); + Tracing.logInfo(logMsg, null, logger, loggingClazz); } /** * Add audit log entry. */ public void audit(String logMsg) { - Tracing.logAudit(logMsg, loggingClazz); + Tracing.logAudit(logMsg, null, logger, loggingClazz); } /** * Add audit log entry with a user object. */ public void audit(String logMsg, String userObj) { - Tracing.logAudit(logMsg, userObj, loggingClazz); + Tracing.logAudit(logMsg, userObj, logger, loggingClazz); } } diff --git a/src/main/java/org/olat/core/logging/Tracing.java b/src/main/java/org/olat/core/logging/Tracing.java index fc208c707ba717f0eeaea64f1bbc7065d708fd0e..93b7f8c69f3f5f671d537d35c5d0995e52a15aa6 100644 --- a/src/main/java/org/olat/core/logging/Tracing.java +++ b/src/main/java/org/olat/core/logging/Tracing.java @@ -30,8 +30,8 @@ import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; -import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import javax.servlet.http.HttpServletRequest; @@ -106,7 +106,7 @@ public class Tracing { private static long __debugRefNum__ = 0; // VM local cache to have one logger object per class - private static final Map<Class<?>, OLog> loggerLookupMap = new ConcurrentHashMap<Class<?>, OLog>(); + private static final ConcurrentMap<Class<?>, OLog> loggerLookupMap = new ConcurrentHashMap<Class<?>, OLog>(); /** * per-thread singleton holding the actual HttpServletRequest which is the @@ -135,16 +135,14 @@ public class Tracing { public static OLog createLoggerFor(Class<?> loggingClass) { // Share logger object to reduce memory footprint OLog logger = loggerLookupMap.get(loggingClass); - if (logger == null) { - synchronized (loggerLookupMap) { - logger = loggerLookupMap.get(loggingClass); - if (logger == null) { - logger = new OLogImpl(loggingClass); - loggerLookupMap.put(loggingClass, logger); - } - } + if (logger == null) { + OLog newLogger = new OLogImpl(loggingClass); + logger = loggerLookupMap.putIfAbsent(loggingClass, newLogger); + if(logger == null) { + logger = newLogger; + } } - return logger; + return logger; } @@ -169,6 +167,12 @@ public class Tracing { getLogger(callingClass).error(assembleThrowableMessage(ERROR, 'E',refNum, callingClass, logMsg, cause)); return refNum; } + + public static long logError(String logMsg, Throwable cause, Logger logger, Class<?> callingClass) { + long refNum = getErrorRefNum(); + logger.error(assembleThrowableMessage(ERROR, 'E',refNum, callingClass, logMsg, cause)); + return refNum; + } /** * @param callingClass @@ -193,6 +197,12 @@ public class Tracing { getLogger(callingClass).warn(assembleThrowableMessage(WARN, 'W', refNum, callingClass, logMsg, cause)); return refNum; } + + protected static long logWarn(String logMsg, Throwable cause, Logger logger, Class<?> callingClass) { + long refNum = getWarnRefNum(); + logger.warn(assembleThrowableMessage(WARN, 'W', refNum, callingClass, logMsg, cause)); + return refNum; + } /** * @param callingClass @@ -222,6 +232,14 @@ public class Tracing { } return refNum; } + + protected static long logDebug(String logMsg, String userObj, Logger logger, Class<?> callingClass) { + long refNum = getDebugRefNum(); + if (logger.isDebugEnabled()) { + logger.debug(assembleMsg(DEBUG, 'D', refNum, callingClass, userObj, logMsg)); + } + return refNum; + } /** * Add debug log entry @@ -246,6 +264,12 @@ public class Tracing { getLogger(callingClass).info(assembleMsg(INFO, 'I', refNum, callingClass, userObject, logMsg)); return refNum; } + + protected static long logInfo(String logMsg, String userObject, Logger logger, Class<?> callingClass) { + long refNum = getInfoRefNum(); + logger.info(assembleMsg(INFO, 'I', refNum, callingClass, userObject, logMsg)); + return refNum; + } /** * @param callingClass @@ -284,6 +308,12 @@ public class Tracing { getLogger(callingClass).info(assembleMsg(AUDIT, 'A', refNum, callingClass, userObj, logMsg)); return refNum; } + + protected static long logAudit(String logMsg, String userObj, Logger logger, Class<?> callingClass) { + long refNum = getAuditRefNum(); + logger.info(assembleMsg(AUDIT, 'A', refNum, callingClass, userObj, logMsg)); + return refNum; + } /** * Method getStackTrace returns the first few (stacklen) lines of the diff --git a/src/main/java/org/olat/core/util/session/UserSessionManager.java b/src/main/java/org/olat/core/util/session/UserSessionManager.java index 85dd416bac9ebe8ab56cb877fb558632766804ab..fef0bd553d6d0d1215480a2c8eb97c95b8b57fc0 100644 --- a/src/main/java/org/olat/core/util/session/UserSessionManager.java +++ b/src/main/java/org/olat/core/util/session/UserSessionManager.java @@ -19,14 +19,13 @@ */ 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.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; import javax.annotation.PostConstruct; @@ -76,10 +75,10 @@ public class UserSessionManager implements GenericEventListener { 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>(2500); - private static final Set<Long> userNameToIdentity = new HashSet<Long>(2500); - private static final Set<Long> authUsersNamesOtherNodes = new HashSet<Long>(2500); + //clusterNOK cache ?? + private static final Set<UserSession> authUserSessions = ConcurrentHashMap.newKeySet(); + private static final Set<Long> userNameToIdentity = ConcurrentHashMap.newKeySet(); + private static final Set<Long> authUsersNamesOtherNodes = ConcurrentHashMap.newKeySet(); private static final AtomicInteger sessionCountWeb = new AtomicInteger(); private static final AtomicInteger sessionCountRest = new AtomicInteger(); @@ -107,14 +106,16 @@ public class UserSessionManager implements GenericEventListener { * @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 + UserSession us = (UserSession) session.getAttribute(USERSESSIONKEY); + if(us == null) { + 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 @@ -148,15 +149,13 @@ public class UserSessionManager implements GenericEventListener { 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; + UserSession us = (UserSession) session.getAttribute(USERSESSIONKEY); + if(us != null && us.isAuthenticated()) { + session.setMaxInactiveInterval(sessionModule.getSessionTimeoutAuthenticated()); + } else { + session.setMaxInactiveInterval(sessionModule.getSessionTimeout()); } + return us; } /** @@ -165,42 +164,27 @@ public class UserSessionManager implements GenericEventListener { * on */ public boolean isSignedOnIdentity(Long identityKey) { - synchronized (authUserSessions) { //o_clusterOK by:fj - return userNameToIdentity.contains(identityKey); - } - } - - public List<Long> getAuthenticatedIdentityKey() { - synchronized (authUserSessions) { //o_clusterOK by:fj - return new ArrayList<Long>(userNameToIdentity); - } + return userNameToIdentity.contains(identityKey); } /** * @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; + return new HashSet<UserSession>(authUserSessions); } public int getNumberOfAuthenticatedUserSessions() { - synchronized(authUserSessions) { - return authUserSessions.size(); - } + return authUserSessions.size(); } /** + * This method returns only the number of local sessions. + * * @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 authUserSessions.size(); } /** @@ -211,10 +195,6 @@ public class UserSessionManager implements GenericEventListener { return userSessionCache.size(); } - public Collection<Long> getUsersOnline() { - return userSessionCache.getKeys(); - } - public boolean isOnline(Long identityKey) { return userSessionCache.containsKey(identityKey); } @@ -246,96 +226,93 @@ public class UserSessionManager implements GenericEventListener { /** * 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 - + public void signOn(UserSession usess) { 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 + // Added synchronized to be symmetric with sign off and to + // fix a possible dead-lock see also OLAT-3390 + synchronized(usess) { + 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); + } + usess.setAuthenticated(true); + + if (sessionInfo.isWebDAV()) { + // load user prefs + usess.reloadPreferences(); // 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.getKey())); - } - - UserSession invalidatedSession = null; - synchronized (authUserSessions) { //o_clusterOK by:fj - // check if already a session exist for this user - if ( (userNameToIdentity.contains(identity.getKey()) || userSessionCache.containsKey(identity.getKey()) ) - && !sessionInfo.isWebDAV() && !sessionInfo.isREST() && !usess.getRoles().isGuestOnly()) { - log.info("Loggin-process II: User has already a session => signOffAndClear existing session"); - - invalidatedSession = getUserSessionForGui(identity.getKey()); - //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); + log.audit("Logged on [via webdav]: " + sessionInfo.toString()); + } else { + UserSession invalidatedSession = null; + + if(isDebug) { + log.debug("signOn() authUsersNamesOtherNodes.contains " + identity.getName() + ": " + authUsersNamesOtherNodes.contains(identity.getKey())); + } + + // check if already a session exist for this user + if ( (userNameToIdentity.contains(identity.getKey()) || userSessionCache.containsKey(identity.getKey()) ) + && !sessionInfo.isWebDAV() && !sessionInfo.isREST() && !usess.getRoles().isGuestOnly()) { + log.info("Loggin-process II: User has already a session => signOffAndClear existing session"); + + invalidatedSession = getUserSessionForGui(identity.getKey()); + //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.getKey()); userSessionCache.put(identity.getKey(), new Integer(Settings.getNodeId())); - } - - //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.getKey())) { - // 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.getKey()); - //OLAT-3381 & OLAT-3382 - if(invalidatedSession != null) { - signOffAndClear(invalidatedSession); + + + //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.getKey())) { + // 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.getKey()); + //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(); } - - 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(); } } @@ -385,7 +362,7 @@ public class UserSessionManager implements GenericEventListener { * 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) { + private void signOffAndClearWithout(final UserSession usess) { boolean isDebug = log.isDebug(); if(isDebug) log.debug("signOffAndClearWithout() START"); @@ -394,7 +371,6 @@ public class UserSessionManager implements GenericEventListener { 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()); } @@ -403,6 +379,7 @@ public class UserSessionManager implements GenericEventListener { * use not RunnableWithException, as exceptionHandlng is inside the run */ Runnable run = new Runnable() { + @Override public void run() { Object obj = null; try { @@ -449,20 +426,19 @@ public class UserSessionManager implements GenericEventListener { 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.getKey()); - userSessionCache.remove(previousSignedOn.getKey()); - } - } else if (isDebug) { - log.info("UserSession already removed! for ["+ident+"]"); + 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.getKey()); + userSessionCache.remove(previousSignedOn.getKey()); } + } else if (isDebug) { + log.info("UserSession already removed! for ["+ident+"]"); } + // update logged in users counters if (sessionInfo != null) { if (sessionInfo.isREST()) { @@ -535,9 +511,8 @@ public class UserSessionManager implements GenericEventListener { 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(); + Set<UserSession> userSessions = getAuthenticatedUserSessions(); + for (UserSession userSession : userSessions) { Roles userRoles = userSession != null ? userSession.getRoles() : null; if (userRoles != null && !userRoles.isOLATAdmin()) { //do not logout administrators @@ -566,6 +541,7 @@ public class UserSessionManager implements GenericEventListener { // 1. Copy authUserSessions in sorted TreeMap // This is the Comparator that will be used to sort the TreeSet: Comparator<UserSession> sessionComparator = new Comparator<UserSession>() { + @Override public int compare(UserSession o1, UserSession o2) { Long long1 = new Long((o1).getSessionInfo().getLastClickTime()); Long long2 = new Long((o2).getSessionInfo().getLastClickTime()); @@ -595,8 +571,7 @@ public class UserSessionManager implements GenericEventListener { * @param sessionTimeoutInSec */ public void setGlobalSessionTimeout(int sessionTimeoutInSec) { - Collection<UserSession> sessionSnapShot = getAuthenticatedUserSessions(); - for (UserSession session : sessionSnapShot) { + authUserSessions.forEach(session -> { try{ SessionInfo sessionInfo = session.getSessionInfo(); if(sessionInfo != null && sessionInfo.getSession() != null) { @@ -605,28 +580,29 @@ public class UserSessionManager implements GenericEventListener { } catch(Throwable th){ log.error("error setting sesssionTimeout", th); } - } + }); } /** - * Lookup non-webdav, non-REST UserSession for username. + * Lookup non-webdav, non-REST UserSession for identity key. * @param identityKey * @return user-session or null when no session was founded. */ private UserSession getUserSessionForGui(Long identityKey) { + UserSession identitySession = null; if(identityKey != null) { //do not call from somewhere else then signOffAndClear!! - Collection<UserSession> authUserSessionsCopy = getAuthenticatedUserSessions(); - for (UserSession userSession : authUserSessionsCopy) { + identitySession = authUserSessions.stream().filter(userSession -> { Identity identity = userSession.getIdentity(); if (identity != null && identityKey.equals(identity.getKey()) && userSession.getSessionInfo() != null && !userSession.getSessionInfo().isWebDAV() && !userSession.getSessionInfo().isREST()) { - return userSession; + return true; } - } + return false; + }).findFirst().get(); } - return null; + return identitySession; } } diff --git a/src/main/java/org/olat/course/assessment/AssessmentHelper.java b/src/main/java/org/olat/course/assessment/AssessmentHelper.java index ddf4c264e5b4d9c9df8a60c05b3398af6364b63e..61cba544f3ad7fd3a1e1b414e39ff315f64cdf4c 100644 --- a/src/main/java/org/olat/course/assessment/AssessmentHelper.java +++ b/src/main/java/org/olat/course/assessment/AssessmentHelper.java @@ -437,8 +437,11 @@ public class AssessmentHelper { // - it is of an assessable course node type boolean hasDisplayableValuesConfigured = false; boolean hasDisplayableUserValues = false; - if ((numOfChildren > 0 || courseNode instanceof AssessableCourseNode) && !(courseNode instanceof ProjectBrokerCourseNode) ) { - if (courseNode instanceof AssessableCourseNode) { + if (numOfChildren > 0 || courseNode instanceof AssessableCourseNode) { + if(courseNode instanceof ProjectBrokerCourseNode) { + //ProjectBroker : no assessment-tool in V1.0 , remove project broker completely form assessment-tool gui + assessmentNodeData.setSelectable(false); + } else if (courseNode instanceof AssessableCourseNode) { AssessableCourseNode assessableCourseNode = (AssessableCourseNode) courseNode; AssessmentEvaluation scoreEvaluation = scoreAccounting.evalCourseNode(assessableCourseNode); if(scoreEvaluation != null) { diff --git a/src/main/java/org/olat/course/assessment/AssessmentMainController.java b/src/main/java/org/olat/course/assessment/AssessmentMainController.java index a2467f376943521a784131bd745a39db7a1d68e9..4232fe35af10c6fe79d40c98cf241964c0b5c615 100644 --- a/src/main/java/org/olat/course/assessment/AssessmentMainController.java +++ b/src/main/java/org/olat/course/assessment/AssessmentMainController.java @@ -409,7 +409,6 @@ public class AssessmentMainController extends MainLayoutBasicController implemen } else if (cmd.equals(CMD_USERFOCUS)) { mode = MODE_USERFOCUS; identitiesList = getAllAssessableIdentities(); - //fxdiff FXOLAT-108: improve results table of tests doUserChooseWithData(ureq, identitiesList, null, null); } else if (cmd.equals(CMD_GROUPFOCUS)) { mode = MODE_GROUPFOCUS; @@ -1117,8 +1116,7 @@ public class AssessmentMainController extends MainLayoutBasicController implemen } boolean hasDisplayableValuesConfigured = false; - if ( (childrenData.size() > 0 || courseNode instanceof AssessableCourseNode) && !(courseNode instanceof ProjectBrokerCourseNode) ) { - // TODO:cg 04.11.2010 ProjectBroker : no assessment-tool in V1.0 , remove projectbroker completely form assessment-tool gui // Store node data in hash map. This hash map serves as data model for + if (childrenData.size() > 0 || courseNode instanceof AssessableCourseNode) { // the user assessment overview table. Leave user data empty since not used in // this table. (use only node data) AssessmentNodeData nodeData = new AssessmentNodeData(recursionLevel, courseNode); @@ -1133,9 +1131,11 @@ public class AssessmentMainController extends MainLayoutBasicController implemen nodeData.setOnyx(false); } } - - if (courseNode instanceof AssessableCourseNode) { + if(courseNode instanceof ProjectBrokerCourseNode) { + //ProjectBroker : no assessment-tool in V1.0 , remove project broker completely form assessment-tool gui + nodeData.setSelectable(false); + } else if (courseNode instanceof AssessableCourseNode) { AssessableCourseNode assessableCourseNode = (AssessableCourseNode) courseNode; if ( assessableCourseNode.hasDetails() || assessableCourseNode.hasAttemptsConfigured() diff --git a/src/main/java/org/olat/course/nodes/CourseNodeFactory.java b/src/main/java/org/olat/course/nodes/CourseNodeFactory.java index 4cd2375a1c012245331999139cb0e571f7636dcc..675156d733b7d8970d2941764a2315bbbfa7ebbb 100644 --- a/src/main/java/org/olat/course/nodes/CourseNodeFactory.java +++ b/src/main/java/org/olat/course/nodes/CourseNodeFactory.java @@ -35,6 +35,7 @@ import java.util.Map; import org.olat.NewControllerFactory; import org.olat.core.CoreSpringFactory; +import org.olat.core.configuration.PreWarm; import org.olat.core.gui.UserRequest; import org.olat.core.gui.control.WindowControl; import org.olat.core.logging.OLog; @@ -51,7 +52,7 @@ import org.olat.repository.handlers.RepositoryHandlerFactory; * @author Mike Stock * @author guido */ -public class CourseNodeFactory { +public class CourseNodeFactory implements PreWarm { private static final OLog log = Tracing.createLoggerFor(CourseNodeFactory.class); @@ -73,6 +74,12 @@ public class CourseNodeFactory { return INSTANCE; } + @Override + public void run() { + getAllCourseNodeConfigurations(); + } + + /** * @return the list of enabled aliases */ @@ -88,13 +95,18 @@ public class CourseNodeFactory { return alias; } - private synchronized Map<String,CourseNodeConfiguration> getAllCourseNodeConfigurations() { + private Map<String,CourseNodeConfiguration> getAllCourseNodeConfigurations() { if(allCourseNodeConfigurations == null) { - allCourseNodeConfigurations = new HashMap<String, CourseNodeConfiguration>(); - Map<String, CourseNodeConfiguration> courseNodeConfigurationMap = CoreSpringFactory.getBeansOfType(CourseNodeConfiguration.class); - Collection<CourseNodeConfiguration> courseNodeConfigurationValues = courseNodeConfigurationMap.values(); - for (CourseNodeConfiguration courseNodeConfiguration : courseNodeConfigurationValues) { - allCourseNodeConfigurations.put(courseNodeConfiguration.getAlias(), courseNodeConfiguration); + synchronized(INSTANCE) { + if(allCourseNodeConfigurations == null) { + Map<String, CourseNodeConfiguration> configurationMap = new HashMap<>(); + Map<String, CourseNodeConfiguration> courseNodeConfigurationMap = CoreSpringFactory.getBeansOfType(CourseNodeConfiguration.class); + Collection<CourseNodeConfiguration> courseNodeConfigurationValues = courseNodeConfigurationMap.values(); + for (CourseNodeConfiguration courseNodeConfiguration : courseNodeConfigurationValues) { + configurationMap.put(courseNodeConfiguration.getAlias(), courseNodeConfiguration); + } + allCourseNodeConfigurations = Collections.unmodifiableMap(configurationMap); + } } } return allCourseNodeConfigurations; diff --git a/src/main/java/org/olat/course/nodes/feed/FeedNodeSecurityCallback.java b/src/main/java/org/olat/course/nodes/feed/FeedNodeSecurityCallback.java index 7f8fbc9cbee4df1fe2f0120e6778c82ac4482092..f064daf1ec71d0d46271553e44e8fe216b92f236 100644 --- a/src/main/java/org/olat/course/nodes/feed/FeedNodeSecurityCallback.java +++ b/src/main/java/org/olat/course/nodes/feed/FeedNodeSecurityCallback.java @@ -48,6 +48,7 @@ public class FeedNodeSecurityCallback implements FeedSecurityCallback { /** * @see org.olat.modules.webFeed.FeedSecurityCallback#mayEditMetadata() */ + @Override public boolean mayEditMetadata() { if (isGuestOnly) return false; return ne.isCapabilityAccessible("moderator") || isOlatAdmin; @@ -56,6 +57,7 @@ public class FeedNodeSecurityCallback implements FeedSecurityCallback { /** * @see org.olat.modules.webFeed.FeedSecurityCallback#mayCreateItems() */ + @Override public boolean mayCreateItems() { if (isGuestOnly) return false; return ne.isCapabilityAccessible("poster") || ne.isCapabilityAccessible("moderator") || isOlatAdmin; @@ -64,6 +66,7 @@ public class FeedNodeSecurityCallback implements FeedSecurityCallback { /** * @see org.olat.modules.webFeed.FeedSecurityCallback#mayDeleteItems() */ + @Override public boolean mayDeleteItems() { if (isGuestOnly) return false; return ne.isCapabilityAccessible("moderator") || isOlatAdmin; @@ -72,6 +75,7 @@ public class FeedNodeSecurityCallback implements FeedSecurityCallback { /** * @see org.olat.modules.webFeed.FeedSecurityCallback#mayEditItems() */ + @Override public boolean mayEditItems() { if (isGuestOnly) return false; return ne.isCapabilityAccessible("moderator") || isOlatAdmin; @@ -81,7 +85,6 @@ public class FeedNodeSecurityCallback implements FeedSecurityCallback { * @see org.olat.modules.webFeed.FeedSecurityCallback#mayViewAllDrafts() */ @Override - //fxdiff BAKS-18 public boolean mayViewAllDrafts() { return isOwner || isOlatAdmin; } diff --git a/src/main/java/org/olat/course/nodes/projectbroker/ProjectEditDetailsFormController.java b/src/main/java/org/olat/course/nodes/projectbroker/ProjectEditDetailsFormController.java index 80afc9276d1dcea021418ffd6ca1b6792aca98fb..7aa0b6976b6dc05aed387aa2ed0fc55bc1e4fb78 100644 --- a/src/main/java/org/olat/course/nodes/projectbroker/ProjectEditDetailsFormController.java +++ b/src/main/java/org/olat/course/nodes/projectbroker/ProjectEditDetailsFormController.java @@ -34,7 +34,6 @@ import java.util.List; import java.util.Map; import java.util.StringTokenizer; -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; @@ -56,6 +55,7 @@ import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.id.Identity; import org.olat.core.id.UserConstants; +import org.olat.core.util.StringHelper; import org.olat.core.util.vfs.LocalFileImpl; import org.olat.core.util.vfs.VFSLeaf; import org.olat.course.nodes.CourseNode; @@ -68,6 +68,7 @@ import org.olat.course.nodes.projectbroker.service.ProjectBrokerModuleConfigurat import org.olat.course.nodes.projectbroker.service.ProjectGroupManager; import org.olat.course.run.environment.CourseEnvironment; import org.olat.resource.OLATResource; +import org.springframework.beans.factory.annotation.Autowired; /** * @@ -86,7 +87,7 @@ public class ProjectEditDetailsFormController extends FormBasicController { private RichTextElement projectDescription; private IntegerElement maxMembers; private StaticTextElement projectState; - FormLayoutContainer stateLayout; + private FormLayoutContainer stateLayout; private FileElement attachmentFileName; private TextElement projectLeaders; @@ -111,9 +112,12 @@ public class ProjectEditDetailsFormController extends FormBasicController { private final static String[] values = new String[] { "" }; private static final int MAX_MEMBERS_DEFAULT = 1; - private final ProjectBrokerMailer projectBrokerMailer; - private final ProjectGroupManager projectGroupManager; - private final ProjectBrokerManager projectBrokerManager; + @Autowired + private ProjectBrokerMailer projectBrokerMailer; + @Autowired + private ProjectGroupManager projectGroupManager; + @Autowired + private ProjectBrokerManager projectBrokerManager; /** * Modules selection form. @@ -127,12 +131,9 @@ public class ProjectEditDetailsFormController extends FormBasicController { this.courseNode = courseNode; this.projectBrokerModuleConfiguration = projectBrokerModuleConfiguration; this.enableCancel = enableCancel; - projectBrokerMailer = CoreSpringFactory.getImpl(ProjectBrokerMailer.class); - projectGroupManager = CoreSpringFactory.getImpl(ProjectGroupManager.class); - projectBrokerManager = CoreSpringFactory.getImpl(ProjectBrokerManager.class); - customfieldElementList = new ArrayList<FormItem>(); - eventStartElementList = new HashMap<Project.EventType, DateChooser>(); - eventEndElementList = new HashMap<Project.EventType, DateChooser>(); + customfieldElementList = new ArrayList<>(); + eventStartElementList = new HashMap<>(); + eventEndElementList = new HashMap<>(); initForm(ureq); } @@ -343,12 +344,13 @@ public class ProjectEditDetailsFormController extends FormBasicController { projectGroupManager.setProjectGroupMaxMembers(getIdentity(), project.getProjectGroup(), maxMembers.getIntValue()); projectChanged = true; } - if (attachmentFileName.getUploadFileName() != null && !attachmentFileName.getUploadFileName().equals("")) { + if (StringHelper.containsNonWhitespace(attachmentFileName.getUploadFileName())) { // First call uploadFiles than setAttachedFileName because uploadFiles needs old attachment name uploadFiles(attachmentFileName); project.setAttachedFileName(attachmentFileName.getUploadFileName()); projectChanged = true; - } else if (project.getAttachmentFileName() != null && !project.getAttachmentFileName().equals("")) { + } else if (StringHelper.containsNonWhitespace(project.getAttachmentFileName()) + && attachmentFileName.getInitialFile() == null) { // Attachment file has been removed project.setAttachedFileName(""); projectChanged = true; @@ -396,7 +398,7 @@ public class ProjectEditDetailsFormController extends FormBasicController { projectBrokerManager.updateProject(project); projectBrokerMailer.sendProjectChangedEmailToParticipants(ureq.getIdentity(), project, this.getTranslator()); } else { - this.showInfo("info.project.nolonger.exist", project.getTitle()); + showInfo("info.project.nolonger.exist", project.getTitle()); } } fireEvent(ureq, Event.DONE_EVENT); diff --git a/src/main/java/org/olat/course/nodes/projectbroker/service/ProjectDAO.java b/src/main/java/org/olat/course/nodes/projectbroker/service/ProjectDAO.java new file mode 100644 index 0000000000000000000000000000000000000000..dc8e9377d47226afb2b37a70ec14d2fb6ad10c0b --- /dev/null +++ b/src/main/java/org/olat/course/nodes/projectbroker/service/ProjectDAO.java @@ -0,0 +1,66 @@ +/** + * <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.course.nodes.projectbroker.service; + +import java.util.List; + +import org.olat.core.commons.persistence.DB; +import org.olat.course.nodes.projectbroker.datamodel.Project; +import org.olat.course.nodes.projectbroker.datamodel.ProjectImpl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * Project queries must migrate here. + * + * + * Initial date: 01.02.2016<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +@Service +public class ProjectDAO { + @Autowired + private DB dbInstance; + + /** + * The method load the project or return null if not found. The query fetch + * all dependencies but the custom fields. + * + * @param projectKey + * @return The project + */ + public Project loadProject(Long projectKey) { + StringBuilder sb = new StringBuilder(); + sb.append("select project from ").append(ProjectImpl.class.getName()).append(" as project ") + .append(" left join fetch project.projectGroup pGroup") + .append(" left join fetch pGroup.baseGroup bGroup") + .append(" left join fetch project.candidateGroup cGroup") + .append(" left join fetch project.projectBroker pBroker") + .append(" where project.key=:projectKey"); + + List<Project> projects = dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), Project.class) + .setParameter("projectKey", projectKey) + .getResultList(); + return projects == null || projects.isEmpty() ? null : projects.get(0); + } + +} diff --git a/src/main/java/org/olat/course/nodes/projectbroker/service/ProjectGroupManagerImpl.java b/src/main/java/org/olat/course/nodes/projectbroker/service/ProjectGroupManagerImpl.java index d0710faafc39a6405ac29de56a5e352ab1700aca..7982fe3c8f4675b24f4aeed8757e429b99e04b63 100644 --- a/src/main/java/org/olat/course/nodes/projectbroker/service/ProjectGroupManagerImpl.java +++ b/src/main/java/org/olat/course/nodes/projectbroker/service/ProjectGroupManagerImpl.java @@ -68,6 +68,8 @@ public class ProjectGroupManagerImpl extends BasicManager implements ProjectGrou @Autowired private DB dbInstance; @Autowired + private ProjectDAO projectDao; + @Autowired private BaseSecurity securityManager; @Autowired private ProjectBrokerManager projectBrokerManager; @@ -260,7 +262,7 @@ public class ProjectGroupManagerImpl extends BasicManager implements ProjectGrou @Override public BusinessGroupAddResponse acceptCandidates(final List<Identity> identities, final Project project, final Identity actionIdentity, final boolean autoSignOut, final boolean isAcceptSelectionManually) { - final Project reloadedProject = (Project) dbInstance.loadObject(project, true); + final Project reloadedProject = projectDao.loadProject(project.getKey()); final BusinessGroupAddResponse response = new BusinessGroupAddResponse(); BusinessGroupAddResponse state = businessGroupService.addParticipants(actionIdentity, null, identities, reloadedProject.getProjectGroup(), null); response.getAddedIdentities().addAll(state.getAddedIdentities()); diff --git a/src/main/java/org/olat/ims/qti/questionimport/CSVToQuestionConverter.java b/src/main/java/org/olat/ims/qti/questionimport/CSVToQuestionConverter.java index 5fc846efd173e23c85af8f13718872487244a1fb..c5cc4fbb04c8d7bbad94ce63b0e0cf3097b71fc1 100644 --- a/src/main/java/org/olat/ims/qti/questionimport/CSVToQuestionConverter.java +++ b/src/main/java/org/olat/ims/qti/questionimport/CSVToQuestionConverter.java @@ -372,8 +372,7 @@ public class CSVToQuestionConverter { private void processPoints(String[] parts) { if(currentItem == null) return; - String pointsStr = parts[1]; - float points = Float.parseFloat(pointsStr); + float points = parseFloat(parts[1], 1.0f); Question question = currentItem.getItem().getQuestion(); int type = question.getType(); @@ -402,7 +401,7 @@ public class CSVToQuestionConverter { Question question = currentItem.getItem().getQuestion(); int type = question.getType(); if (type == Question.TYPE_MC || type == Question.TYPE_SC) { - float point = Float.parseFloat(parts[0]); + float point = parseFloat(parts[0], 1.0f); String content = parts[1]; ChoiceQuestion choice = (ChoiceQuestion)question; @@ -424,7 +423,7 @@ public class CSVToQuestionConverter { response.setContent(mat); fib.getResponses().add(response); } else { - float point = Float.parseFloat(parts[0]); + float point = parseFloat(parts[0], 1.0f); String correctBlank = parts[1]; FIBResponse response = new FIBResponse(); @@ -451,6 +450,18 @@ public class CSVToQuestionConverter { } } + private float parseFloat(String value, float defaultValue) { + float floatValue = defaultValue; + + if(value != null) { + if(value.indexOf(",") >= 0) { + value = value.replace(",", "."); + } + floatValue = Float.parseFloat(value); + } + return floatValue; + } + private Material createMaterialWithText(String text) { Material material = new Material(); material.add(createMattext(text)); diff --git a/src/main/java/org/olat/modules/dialog/DialogElementsController.java b/src/main/java/org/olat/modules/dialog/DialogElementsController.java index 98e9d039fd32448ccf50e30de739aa0a163cd27d..098a06eceb4588312195f5d4e0e7fb4e311f6a4c 100644 --- a/src/main/java/org/olat/modules/dialog/DialogElementsController.java +++ b/src/main/java/org/olat/modules/dialog/DialogElementsController.java @@ -222,7 +222,7 @@ public class DialogElementsController extends BasicController { TableEvent te = (TableEvent) event; String command = te.getActionId(); int row = te.getRowId(); - entry = tableModel.getEntryAt(row); + entry = tableModel.getEntryAt(tableCtr.getSortedRow(row)); if (command.equals(ACTION_START_FORUM)) { selectedElement = dialogElmsMgr.findDialogElement(coursePropMgr, courseNode, entry.getForumKey()); if(selectedElement == null){ diff --git a/src/main/java/org/olat/modules/webFeed/FeedPreviewSecurityCallback.java b/src/main/java/org/olat/modules/webFeed/FeedPreviewSecurityCallback.java index d70092b0eab42eb6acf428fc14b28f116e13fd14..088c2d14e7b7a381893331ccf7e069b8199c1c2c 100644 --- a/src/main/java/org/olat/modules/webFeed/FeedPreviewSecurityCallback.java +++ b/src/main/java/org/olat/modules/webFeed/FeedPreviewSecurityCallback.java @@ -60,7 +60,6 @@ public class FeedPreviewSecurityCallback implements FeedSecurityCallback { /** * @see org.olat.modules.webFeed.FeedSecurityCallback#mayViewAllDrafts() */ - //fxdiff BAKS-18 @Override public boolean mayViewAllDrafts() { return false; diff --git a/src/main/java/org/olat/modules/webFeed/FeedResourceSecurityCallback.java b/src/main/java/org/olat/modules/webFeed/FeedResourceSecurityCallback.java index 4e19ba8999322c2dd3bed6f5070018c0b34e2444..22e935f953bae97546cce76bb28d06b8663b7a02 100644 --- a/src/main/java/org/olat/modules/webFeed/FeedResourceSecurityCallback.java +++ b/src/main/java/org/olat/modules/webFeed/FeedResourceSecurityCallback.java @@ -67,7 +67,6 @@ public class FeedResourceSecurityCallback implements FeedSecurityCallback { /** * @see org.olat.modules.webFeed.FeedSecurityCallback#mayViewAllDrafts() */ - //fxdiff BAKS-18 @Override public boolean mayViewAllDrafts() { return isAdmin || isOwner; diff --git a/src/main/java/org/olat/modules/webFeed/RSSFeed.java b/src/main/java/org/olat/modules/webFeed/RSSFeed.java index 9b62d55e0e2ed22a221836fbeda4bb45bb7506f0..51f1a38ccd6e8c241f35ff6fff91f58cc1b161a0 100644 --- a/src/main/java/org/olat/modules/webFeed/RSSFeed.java +++ b/src/main/java/org/olat/modules/webFeed/RSSFeed.java @@ -49,6 +49,8 @@ import com.sun.syndication.feed.synd.SyndImageImpl; */ public class RSSFeed extends SyndFeedImpl { + private static final long serialVersionUID = 4010701266801565756L; + /** * Constructor. The identityKey is needed to generate personal URLs for the * corresponding user. diff --git a/src/main/java/org/olat/modules/webFeed/ui/ItemController.java b/src/main/java/org/olat/modules/webFeed/ui/ItemController.java index 38b2c1baa56cc98d42d96e032fa9b7d599ecde44..3578b30f235ccdf12be800adc0a1f8cda70271ab 100644 --- a/src/main/java/org/olat/modules/webFeed/ui/ItemController.java +++ b/src/main/java/org/olat/modules/webFeed/ui/ItemController.java @@ -73,9 +73,15 @@ public class ItemController extends BasicController implements Activateable2 { vcItem.contextPut("helper", helper); vcItem.contextPut("callback", callback); if (feed.isInternal()) { - if (editButton != null) vcItem.put("editButton", editButton); - if (deleteButton != null) vcItem.put("deleteButton", deleteButton); - if (artefactLink != null) vcItem.put("artefactLink", artefactLink.getInitialComponent()); + if (editButton != null) { + vcItem.put("editButton", editButton); + } + if (deleteButton != null) { + vcItem.put("deleteButton", deleteButton); + } + if (artefactLink != null) { + vcItem.put("artefactLink", artefactLink.getInitialComponent()); + } } backLink = LinkFactory.createLinkBack(vcItem, this); // Add date component @@ -91,7 +97,7 @@ public class ItemController extends BasicController implements Activateable2 { vcItem.put("commentsAndRating", commentsCtr.getInitialComponent()); } // - this.putInitialPanel(vcItem); + putInitialPanel(vcItem); // do logging ThreadLocalUserActivityLogger.log(FeedLoggingAction.FEED_ITEM_READ, getClass(), LoggingResourceable.wrap(item)); } @@ -99,6 +105,7 @@ public class ItemController extends BasicController implements Activateable2 { /** * @see org.olat.core.gui.control.DefaultController#doDispose() */ + @Override protected void doDispose() { // nothing to do } @@ -127,5 +134,4 @@ public class ItemController extends BasicController implements Activateable2 { } } } - -} +} \ No newline at end of file diff --git a/src/main/java/org/olat/modules/webFeed/ui/ItemsController.java b/src/main/java/org/olat/modules/webFeed/ui/ItemsController.java index c25701fb2571455ed9b2133c805bd8ad7b07bf82..7ce99ded690ebf0e0cddcb3f691185a6a9a2e417 100644 --- a/src/main/java/org/olat/modules/webFeed/ui/ItemsController.java +++ b/src/main/java/org/olat/modules/webFeed/ui/ItemsController.java @@ -169,9 +169,9 @@ public class ItemsController extends BasicController implements Activateable2 { startpageLink = LinkFactory.createLink("feed.startpage", vcItems, this); startpageLink.setCustomEnabledLinkCSS("o_first_page"); - if (callback.mayEditItems() || callback.mayCreateItems()) { - createEditButtons(ureq, feed); - } + + createEditButtons(ureq, feed); + // Add item details page link createItemLinks(feed); // Add item user comments link and rating @@ -218,9 +218,9 @@ public class ItemsController extends BasicController implements Activateable2 { private void createEditButtons(UserRequest ureq, Feed feed) { List<Item> items = feed.getCopiedListOfItems(); - editButtons = new ArrayList<Link>(); - deleteButtons = new ArrayList<Link>(); - artefactLinks = new HashMap<Item,Controller>(); + editButtons = new ArrayList<>(); + deleteButtons = new ArrayList<>(); + artefactLinks = new HashMap<>(); if (feed.isInternal()) { addItemButton = LinkFactory.createButtonSmall("feed.add.item", vcItems, this); addItemButton.setElementCssClass("o_sel_feed_item_new"); @@ -332,20 +332,32 @@ public class ItemsController extends BasicController implements Activateable2 { * the items velocity container's context. */ public void makeInternalAndExternalButtons() { - makeInternalButton = LinkFactory.createButton("feed.make.internal", vcItems, this); - makeExternalButton = LinkFactory.createButton("feed.make.external", vcItems, this); + if (callback.mayEditItems() || callback.mayCreateItems()) { + makeInternalButton = LinkFactory.createButton("feed.make.internal", vcItems, this); + makeExternalButton = LinkFactory.createButton("feed.make.external", vcItems, this); + } } /** * @param item */ private void createButtonsForItem(UserRequest ureq, Item item) { + boolean author = getIdentity().getKey().equals(item.getAuthorKey()); + boolean edit = callback.mayEditItems() || author; + boolean delete = callback.mayDeleteItems() || author; + String guid = item.getGuid(); - Link editButton = LinkFactory.createCustomLink("feed.edit.item." + guid, "feed.edit.item." + guid, "feed.edit.item", - Link.BUTTON_SMALL, vcItems, this); + String editId = "feed.edit.item.".concat(guid); + Link editButton = LinkFactory.createCustomLink(editId, editId, "feed.edit.item", Link.BUTTON_SMALL, vcItems, this); editButton.setElementCssClass("o_sel_feed_item_edit"); - Link deleteButton = LinkFactory.createCustomLink("delete." + guid, "delete." + guid, "delete", Link.BUTTON_SMALL, vcItems, this); + editButton.setEnabled(edit); + editButton.setVisible(edit); + + String deleteId = "delete.".concat(guid); + Link deleteButton = LinkFactory.createCustomLink(deleteId, deleteId, "delete", Link.BUTTON_SMALL, vcItems, this); deleteButton.setElementCssClass("o_sel_feed_item_delete"); + deleteButton.setEnabled(delete); + deleteButton.setVisible(delete); if(feedResource.isInternal() && getIdentity().getKey() != null && getIdentity().getKey().equals(item.getAuthorKey())) { String businessPath = BusinessControlFactory.getInstance().getAsString(getWindowControl().getBusinessControl()); @@ -353,7 +365,7 @@ public class ItemsController extends BasicController implements Activateable2 { Controller artefactCtrl = EPUIFactory.createArtefactCollectWizzardController(ureq, getWindowControl(), feedResource, businessPath); if(artefactCtrl != null) { artefactLinks.put(item, artefactCtrl); - vcItems.put("feed.artefact.item." + guid, artefactCtrl.getInitialComponent()); + vcItems.put("feed.artefact.item.".concat(guid), artefactCtrl.getInitialComponent()); } } @@ -477,25 +489,19 @@ public class ItemsController extends BasicController implements Activateable2 { } else if (source == olderItemsLink) { helper.olderItems(); - if (callback.mayEditItems() || callback.mayCreateItems()) { - createEditButtons(ureq, feed); - } + createEditButtons(ureq, feed); createCommentsAndRatingsLinks(ureq, feed); vcItems.setDirty(true); } else if (source == newerItemsLink) { helper.newerItems(); - if (callback.mayEditItems() || callback.mayCreateItems()) { - createEditButtons(ureq, feed); - } + createEditButtons(ureq, feed); createCommentsAndRatingsLinks(ureq, feed); vcItems.setDirty(true); } else if (source == startpageLink) { helper.startpage(); - if (callback.mayEditItems() || callback.mayCreateItems()) { - createEditButtons(ureq, feed); - } + createEditButtons(ureq, feed); createCommentsAndRatingsLinks(ureq, feed); vcItems.setDirty(true); diff --git a/src/main/java/org/olat/modules/webFeed/ui/blog/_content/post.html b/src/main/java/org/olat/modules/webFeed/ui/blog/_content/post.html index 95e565a16bd9fabfbd493e6fbd9077ba5e880a8e..8fcaa01173e5804d28111577d0fd4d6b20b492d6 100644 --- a/src/main/java/org/olat/modules/webFeed/ui/blog/_content/post.html +++ b/src/main/java/org/olat/modules/webFeed/ui/blog/_content/post.html @@ -35,18 +35,16 @@ #end </div> - #if (( $callback.mayEditItems() || ($callback.mayCreateItems() && $item.isDraft())) && $feed.isInternal()) - #if ($r.available("editButton")) + #if(($r.available("editButton") && $r.visible("editButton")) || ($r.available("deleteButton") && $r.visible("deleteButton"))) <div class="o_button_group"> - ## special case: this item has been added by another user and thus we - ## don't yet have links for this item. But we can still display the content - $r.render("editButton") - #if ($callback.mayDeleteItems() || ($callback.mayCreateItems() && $item.isDraft())) + #if ($r.available("editButton") && $r.visible("editButton")) + $r.render("editButton") + #end + #if ($r.available("deleteButton") && $r.visible("deleteButton")) $r.render("deleteButton") #end </div> - #end - #end + #end </div> <div class="o_block_footer"> diff --git a/src/main/java/org/olat/modules/webFeed/ui/blog/_content/posts.html b/src/main/java/org/olat/modules/webFeed/ui/blog/_content/posts.html index c3972bae7977313eaa5993646e5c8c35fc2b52cb..d52aa4e5bbf5106d90b11e71d5027cdd31a9bb7d 100644 --- a/src/main/java/org/olat/modules/webFeed/ui/blog/_content/posts.html +++ b/src/main/java/org/olat/modules/webFeed/ui/blog/_content/posts.html @@ -79,15 +79,13 @@ </div> </div> - #if (( $callback.mayEditItems() || ($callback.mayCreateItems() && $post.isDraft())) && $feed.isInternal()) + #if($feed.isInternal()) <div class="o_button_group"> - #if ($r.available("feed.edit.item.$post.getGuid()")) - ## special case: this item has been added by another user and thus we - ## don't yet have links for this item. But we can still display the content + #if ($r.available("feed.edit.item.$post.getGuid()") && $r.visible("feed.edit.item.$post.getGuid()")) $r.render("feed.edit.item.$post.getGuid()") - #if ($callback.mayDeleteItems() || ($callback.mayCreateItems() && $post.isDraft())) - $r.render("delete.$post.getGuid()") - #end + #end + #if ($r.available("delete.$post.getGuid()") && $r.visible("delete.$post.getGuid()")) + $r.render("delete.$post.getGuid()") #end </div> #end diff --git a/src/main/java/org/olat/modules/wiki/WikiMainController.java b/src/main/java/org/olat/modules/wiki/WikiMainController.java index f7ff86a931290f198d4e15ccc0cdc0e5cf282839..4ac6f0846142640e225054b50dae30d5731bf8e8 100644 --- a/src/main/java/org/olat/modules/wiki/WikiMainController.java +++ b/src/main/java/org/olat/modules/wiki/WikiMainController.java @@ -1172,7 +1172,7 @@ public class WikiMainController extends BasicController implements CloneableCont } private void clearPortfolioLink(){ - content.put("portfolio-link", new Panel("empty")); + navigationContent.put("portfolio-link", new Panel("empty")); } private Wiki getWiki(){ diff --git a/src/main/java/org/olat/modules/wiki/gui/components/wikiToHtml/WikiMarkupRenderer.java b/src/main/java/org/olat/modules/wiki/gui/components/wikiToHtml/WikiMarkupRenderer.java index 85d1d0cee066ed9774691f03584e75ed59912d6e..2db789b8f2d47a58bc35ea8661a31a1a7099407e 100644 --- a/src/main/java/org/olat/modules/wiki/gui/components/wikiToHtml/WikiMarkupRenderer.java +++ b/src/main/java/org/olat/modules/wiki/gui/components/wikiToHtml/WikiMarkupRenderer.java @@ -93,7 +93,7 @@ public class WikiMarkupRenderer extends DefaultComponentRenderer { uri = URLDecoder.decode(uri, "utf-8"); input.setVirtualWiki(uri.substring(1, uri.length()-1)); if (iframePostEnabled) { - String targetUrl = " onclick='o_XHREvent(jQuery(this).attr(\"href\"),false,true); return false;'"; + String targetUrl = " onclick=\"o_XHREvent(jQuery(this).attr('href'),false,true); return false;\""; input.setURLTarget(targetUrl); } sb.append("<div style=\"min-height:"+ wikiComp.getMinHeight() +"px\" id=\""); diff --git a/src/main/java/org/olat/portfolio/ui/structel/edit/EPCollectRestrictionResultController.java b/src/main/java/org/olat/portfolio/ui/structel/edit/EPCollectRestrictionResultController.java index 927989691261c0a53f39a0aac44a8adaa9593321..9c0321fb59baf27ef2a14af1ff196dec653a4686 100644 --- a/src/main/java/org/olat/portfolio/ui/structel/edit/EPCollectRestrictionResultController.java +++ b/src/main/java/org/olat/portfolio/ui/structel/edit/EPCollectRestrictionResultController.java @@ -22,6 +22,7 @@ package org.olat.portfolio.ui.structel.edit; import java.util.ArrayList; import java.util.List; import java.util.Locale; +import java.util.concurrent.atomic.AtomicLong; import org.olat.core.CoreSpringFactory; import org.olat.core.gui.UserRequest; @@ -49,11 +50,13 @@ import org.olat.portfolio.ui.filter.PortfolioFilterController; public class EPCollectRestrictionResultController extends BasicController { private final VelocityContainer mainVc; + private static final AtomicLong restrictionsCounter = new AtomicLong(1l); public EPCollectRestrictionResultController(UserRequest ureq, WindowControl wControl) { super(ureq, wControl); mainVc = createVelocityContainer("restrictions_msg"); + mainVc.contextPut("restrictionId", Long.toString(restrictionsCounter.getAndIncrement())); putInitialPanel(mainVc); } diff --git a/src/main/java/org/olat/portfolio/ui/structel/edit/_content/restrictions_msg.html b/src/main/java/org/olat/portfolio/ui/structel/edit/_content/restrictions_msg.html index 27870125841d08dfb7ebd5533c6b86909931ad96..af2db8790a2b5bc6aa4f7e2ff89125358f42e44f 100644 --- a/src/main/java/org/olat/portfolio/ui/structel/edit/_content/restrictions_msg.html +++ b/src/main/java/org/olat/portfolio/ui/structel/edit/_content/restrictions_msg.html @@ -1,12 +1,12 @@ #if($messages) -<div class="panel-group" id="o_ep_restrictions"> +<div class="panel-group" id="o_ep_restrictions_$restrictionId"> <div class="panel #if($restrictionsPassed) panel-success #else panel-warning #end"> <div class="panel-heading"> <h4 class="panel-title"> - <a data-toggle="collapse" data-parent="#o_ep_restrictions" href="#collapseMessages">$r.translate("collect.restriction")</a> + <a data-toggle="collapse" data-parent="#o_ep_restrictions_$restrictionId" href="#collapseMessages_$restrictionId">$r.translate("collect.restriction")</a> </h4> </div> - <div id="collapseMessages" class="panel-collapse collapse"> + <div id="collapseMessages_$restrictionId" class="panel-collapse collapse"> <div class="panel-body"> #foreach($message in $messages) <p>$message</p> diff --git a/src/main/java/org/olat/search/EmptySearchResults.java b/src/main/java/org/olat/search/EmptySearchResults.java index c67bf7ad5647b2a677b004c1171c61e94c1572a6..b3ddce3f06ad8345a2562ec4ab809cde16ee9896 100644 --- a/src/main/java/org/olat/search/EmptySearchResults.java +++ b/src/main/java/org/olat/search/EmptySearchResults.java @@ -47,8 +47,8 @@ public class EmptySearchResults implements SearchResults { } @Override - public String getLength() { - return "0"; + public int size() { + return 0; } @Override diff --git a/src/main/java/org/olat/search/SearchResults.java b/src/main/java/org/olat/search/SearchResults.java index 5d4d1a18a9c33108397a7fd91d478eafeb03284d..9b6e37ebad4a69e9d56e59069f5a02e4d2fbb59f 100644 --- a/src/main/java/org/olat/search/SearchResults.java +++ b/src/main/java/org/olat/search/SearchResults.java @@ -36,7 +36,7 @@ import org.olat.search.model.ResultDocument; public interface SearchResults extends Serializable { public static final EmptySearchResults EMPTY_SEARCH_RESULTS = new EmptySearchResults(); - public String getLength(); + public int size(); public List<ResultDocument> getList(); diff --git a/src/main/java/org/olat/search/service/searcher/JmsSearchProvider.java b/src/main/java/org/olat/search/service/searcher/JmsSearchProvider.java index b22c4d7d27fc579bfc5419a7a96f90915a863457..926b9de6c6d3e8ee5fedb2f79547f2832eb59bb2 100644 --- a/src/main/java/org/olat/search/service/searcher/JmsSearchProvider.java +++ b/src/main/java/org/olat/search/service/searcher/JmsSearchProvider.java @@ -236,7 +236,7 @@ public class JmsSearchProvider implements MessageListener { SearchResults searchResults = this.doSearch(searchRequest.getQueryString(), searchRequest.getCondQueries(), identity, searchRequest.getRoles(), searchRequest.getFirstResult(), searchRequest.getMaxResults(), searchRequest.isDoHighlighting()); if (log_.isDebug()) { - log_.debug("searchResults: " + searchResults.getLength()); + log_.debug("searchResults: " + searchResults.size()); } if (searchResults != null) { session = acquireSession(); diff --git a/src/main/java/org/olat/search/service/searcher/SearchResultsImpl.java b/src/main/java/org/olat/search/service/searcher/SearchResultsImpl.java index e29e51fae32e4c0b62f55722915640735bef4d32..f2e5c23fa2dff914446d957f1ff09806f56faa1f 100644 --- a/src/main/java/org/olat/search/service/searcher/SearchResultsImpl.java +++ b/src/main/java/org/olat/search/service/searcher/SearchResultsImpl.java @@ -106,13 +106,15 @@ public class SearchResultsImpl implements SearchResults { * * @return Length of result-list. */ - public String getLength() { - return Integer.toString(resultList.size()); + @Override + public int size() { + return resultList == null ? 0 : resultList.size(); } /** * @return List of ResultDocument. */ + @Override public List<ResultDocument> getList() { return resultList; } diff --git a/src/main/java/org/olat/search/ui/SearchInputController.java b/src/main/java/org/olat/search/ui/SearchInputController.java index f068623d1fa19b66ecb4bcdaabb2383d03c2ebcf..7d6c247e6a47b2dd42c6070ab5a45bc9db3c0c24 100644 --- a/src/main/java/org/olat/search/ui/SearchInputController.java +++ b/src/main/java/org/olat/search/ui/SearchInputController.java @@ -478,19 +478,18 @@ public class SearchInputController extends FormBasicController implements Generi searchResults = searchClient.doSearch(query, condQueries, ureq.getIdentity(), ureq.getUserSession().getRoles(), firstResult, maxReturns, true); searchCache.put(getQueryCacheKey(firstResult, query, condQueries), searchResults); } - if ((firstResult == 0 && searchResults.getList().isEmpty()) - && !query.endsWith(FUZZY_SEARCH)) { + if (firstResult == 0 && searchResults.size() == 0 && !query.endsWith(FUZZY_SEARCH)) { // result-list was empty => first try to find word via spell-checker - if (doSpellCheck) { - Set<String> didYouMeansWords = searchClient.spellCheck(searchString); - if (didYouMeansWords != null && !didYouMeansWords.isEmpty()) { - setDidYouMeanWords(didYouMeansWords); + if (doSpellCheck) { + Set<String> didYouMeansWords = searchClient.spellCheck(searchString); + if (didYouMeansWords != null && !didYouMeansWords.isEmpty()) { + setDidYouMeanWords(didYouMeansWords); + } else { + searchResults = doFuzzySearch(ureq, searchString, null, parentCtxt, docType, rsrcUrl, firstResult, maxReturns); + } } else { searchResults = doFuzzySearch(ureq, searchString, null, parentCtxt, docType, rsrcUrl, firstResult, maxReturns); } - } else { - searchResults = doFuzzySearch(ureq, searchString, null, parentCtxt, docType, rsrcUrl, firstResult, maxReturns); - } } if(firstResult == 0 && searchResults.getList().isEmpty()) { diff --git a/src/main/webapp/static/js/openolat/wiki.js b/src/main/webapp/static/js/openolat/wiki.js index 8abde178882ff061c278090540fafc67c69f5e87..43383f118c8a57e5d25ea903e38937a5888720f0 100644 --- a/src/main/webapp/static/js/openolat/wiki.js +++ b/src/main/webapp/static/js/openolat/wiki.js @@ -35,6 +35,7 @@ function changeAnchorTargets(id) { var pre = href.substr(0, href.indexOf(":1/")); var post = href.substr(href.indexOf(":1/")+3, href.length); anchor.attr("href", pre+":0/"+post); + anchor.prop('onclick', null).off('click'); } } else if (anchor.attr("class") == "edit" && anchor.attr("title").indexOf("Media:") != -1) { //media file not found href = href.substr(0, href.indexOf("Edit:topic"));