@@ -169,7 +170,7 @@
- ${ant.project.name}: Copying additional non-Java sources
+ ${ant.project.name}: Copying additional non-Java resources
@@ -284,7 +285,7 @@
-
+
${ant.project.name}: Building WAR
@@ -416,13 +417,14 @@
-
+
+
+
${ant.project.name}: Copying additional libraries
-
\ No newline at end of file
Index: lams_build/lib/lams/lams.jar
===================================================================
diff -u -rd3c9d3f03c16e8f7025d7b2bfe84e68af4fc0746 -rab2b6923490ce38dc647ea66d6768966fbc40cfd
Binary files differ
Index: lams_common/src/java/org/lamsfoundation/lams/util/hibernate/HibernateSessionManager.java
===================================================================
diff -u
--- lams_common/src/java/org/lamsfoundation/lams/util/hibernate/HibernateSessionManager.java (revision 0)
+++ lams_common/src/java/org/lamsfoundation/lams/util/hibernate/HibernateSessionManager.java (revision ab2b6923490ce38dc647ea66d6768966fbc40cfd)
@@ -0,0 +1,45 @@
+package org.lamsfoundation.lams.util.hibernate;
+
+import org.hibernate.SessionFactory;
+import org.lamsfoundation.lams.web.session.SessionManager;
+import org.springframework.orm.hibernate4.SessionHolder;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.context.support.WebApplicationContextUtils;
+
+/**
+ * Helper for Hibernate sessions.
+ *
+ * @author Marcin Cieslak
+ */
+public class HibernateSessionManager {
+ private static SessionFactory sessionFactory;
+
+ /**
+ * Puts a Hibernate session into the thread. Useful when thread missed the servlet filters but needs access to DB.
+ */
+ public static void bindHibernateSessionToCurrentThread(boolean recreate) {
+ SessionFactory sessionFactory = HibernateSessionManager.getSessionFactory();
+ // is there a session bound to the current thread already?
+ Object session = TransactionSynchronizationManager.getResource(sessionFactory);
+ if (session != null) {
+ if (recreate) {
+ TransactionSynchronizationManager.unbindResource(sessionFactory);
+ } else {
+ return;
+ }
+ }
+
+ SessionHolder sessionHolder = new SessionHolder(sessionFactory.openSession());
+ TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
+ }
+
+ private static SessionFactory getSessionFactory() {
+ if (HibernateSessionManager.sessionFactory == null) {
+ WebApplicationContext wac = WebApplicationContextUtils
+ .getRequiredWebApplicationContext(SessionManager.getServletContext());
+ HibernateSessionManager.sessionFactory = (SessionFactory) wac.getBean("coreSessionFactory");
+ }
+ return HibernateSessionManager.sessionFactory;
+ }
+}
\ No newline at end of file
Index: lams_common/src/java/org/lamsfoundation/lams/util/hibernate/TransactionAwareSessionContext.java
===================================================================
diff -u -reb3bc017634326a3fe46a85f03b31a14adb210b5 -rab2b6923490ce38dc647ea66d6768966fbc40cfd
--- lams_common/src/java/org/lamsfoundation/lams/util/hibernate/TransactionAwareSessionContext.java (.../TransactionAwareSessionContext.java) (revision eb3bc017634326a3fe46a85f03b31a14adb210b5)
+++ lams_common/src/java/org/lamsfoundation/lams/util/hibernate/TransactionAwareSessionContext.java (.../TransactionAwareSessionContext.java) (revision ab2b6923490ce38dc647ea66d6768966fbc40cfd)
@@ -19,144 +19,145 @@
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;
-
-/** Session context that determines whether there exist a transaction in
- * progress in the current thread, and if not, it opens the {@link Session}.
+
+/**
+ * Session context that determines whether there exist a transaction in progress in the current thread, and if not, it
+ * opens the {@link Session}.
*
- * It delegates to {@link SpringSessionContext} to check whether there exist
- * a Session or not. If it doesn't, the Session is created bound to the current
- * thread via {@link ManagedSessionContext}.
+ * It delegates to {@link SpringSessionContext} to check whether there exist a Session or not. If it doesn't, the
+ * Session is created bound to the current thread via {@link ManagedSessionContext}.
*
*
- * Sessions created by this context are registered in the available transaction
- * synchronization strategy in order to cleanup and properly close Sessions
- * when transactions finish. If there's no synchronization strategy available,
- * the session will never be closed.
+ * Sessions created by this context are registered in the available transaction synchronization strategy in order to
+ * cleanup and properly close Sessions when transactions finish. If there's no synchronization strategy available, the
+ * session will never be closed.
*
+ *
* @author Matias Mirabelli
*/
public class TransactionAwareSessionContext implements CurrentSessionContext {
-
- private static final Logger logger = Logger.getLogger(TransactionAwareSessionContext.class);
-
-
- /** ID for serialization.
- */
- private static final long serialVersionUID = -4213662197614198364L;
-
- /** Hibernate session factory; it's never null. */
- private final SessionFactoryImplementor sessionFactory;
-
- /** Default session context to use before creating a new session;
- * it's never null. */
- private final SpringSessionContext defaultSessionContext;
-
- /** Context to store configured sessions; it's never null. */
- private final ManagedSessionContext localSessionContext;
-
- /** Creates a new session context and sets the related session factory.
- *
- * @param theSessionFactory Context session factory. Cannot be null.
- */
- public TransactionAwareSessionContext(
- final SessionFactoryImplementor theSessionFactory) {
- Validate.notNull(theSessionFactory, "The session factory cannot be null.");
-
- defaultSessionContext = new SpringSessionContext(theSessionFactory);
- localSessionContext = new ManagedSessionContext(theSessionFactory);
- sessionFactory = theSessionFactory;
- }
-
- /** Binds the configured session to Spring's transaction manager strategy
- * if there's no session.
- *
- * @return Returns the configured session, or the one managed by Spring.
- * Never returns null.
- */
- public Session currentSession() {
- try {
- Session s = defaultSessionContext.currentSession();
- return s;
- } catch (HibernateException cause) {
-
- // There's no session bound to the current thread. Let's open one if
- // needed.
- if (ManagedSessionContext.hasBind(sessionFactory)) {
- return localSessionContext.currentSession();
- }
-
- Session session;
- session = sessionFactory.openSession();
- logger.warn("No Session bound to current Thread. Opened new Session [" + session + "]. Transaction: " + session.getTransaction());
-
- if (registerSynchronization(session)) {
- // Normalizes Session flush mode, defaulting it to AUTO. Required for
- // synchronization.
- FlushMode flushMode = session.getFlushMode();
-
- if (FlushMode.isManualFlushMode(flushMode)
- && !TransactionSynchronizationManager
- .isCurrentTransactionReadOnly()) {
- session.setFlushMode(FlushMode.AUTO);
- }
- }
- ManagedSessionContext.bind(session);
-
- return session;
+
+ private static final Logger logger = Logger.getLogger(TransactionAwareSessionContext.class);
+
+ /**
+ * ID for serialization.
+ */
+ private static final long serialVersionUID = -4213662197614198364L;
+
+ /** Hibernate session factory; it's never null. */
+ private final SessionFactoryImplementor sessionFactory;
+
+ /**
+ * Default session context to use before creating a new session; it's never null.
+ */
+ private final SpringSessionContext defaultSessionContext;
+
+ /** Context to store configured sessions; it's never null. */
+ private final ManagedSessionContext localSessionContext;
+
+ /**
+ * Creates a new session context and sets the related session factory.
+ *
+ * @param theSessionFactory
+ * Context session factory. Cannot be null.
+ */
+ public TransactionAwareSessionContext(final SessionFactoryImplementor theSessionFactory) {
+ Validate.notNull(theSessionFactory, "The session factory cannot be null.");
+
+ defaultSessionContext = new SpringSessionContext(theSessionFactory);
+ localSessionContext = new ManagedSessionContext(theSessionFactory);
+ sessionFactory = theSessionFactory;
}
- }
-
- /** Registers transaction synchronization with session in order to clean
- * up and close the session when transaction finishes.
- *
- * @param session Session to register into transaction synchronization.
- * Cannot be null.
- * @return Returns true
if the session was register into any
- * available synchronization strategy, false
otherwise.
- */
- private boolean registerSynchronization(final Session session) {
- // Tries Spring's transaction manager synchronization.
- if (TransactionSynchronizationManager.isSynchronizationActive()) {
-
- // If it's allowed, registers synchronization to cleanup session.
- TransactionSynchronizationManager.registerSynchronization(
- createTransactionSynchronization(session));
- return true;
- } else {
- // Tries JTA transaction manager synchronization.
- JtaPlatform jtaPlatform = sessionFactory.getServiceRegistry()
- .getService(JtaPlatform.class);
-
- // If it's allowed, registers synchronization to cleanup session.
- if (jtaPlatform.canRegisterSynchronization()) {
- List synchronizations;
-
- synchronizations = Arrays.asList(
- createTransactionSynchronization(session));
-
- Synchronization jtaSync;
- jtaSync = new JtaAfterCompletionSynchronization(synchronizations);
- jtaPlatform.registerSynchronization(jtaSync);
-
- return true;
- }
+
+ /**
+ * Binds the configured session to Spring's transaction manager strategy if there's no session.
+ *
+ * @return Returns the configured session, or the one managed by Spring. Never returns null.
+ */
+ @Override
+ public Session currentSession() {
+ try {
+ Session s = defaultSessionContext.currentSession();
+ return s;
+ } catch (HibernateException cause) {
+
+ // There's no session bound to the current thread. Let's open one if
+ // needed.
+ if (ManagedSessionContext.hasBind(sessionFactory)) {
+ return localSessionContext.currentSession();
+ }
+
+ Session session;
+ session = sessionFactory.openSession();
+ TransactionAwareSessionContext.logger.warn("No Session bound to current Thread. Opened new Session ["
+ + session + "]. Transaction: " + session.getTransaction());
+
+ if (registerSynchronization(session)) {
+ // Normalizes Session flush mode, defaulting it to AUTO. Required for
+ // synchronization.
+ FlushMode flushMode = session.getFlushMode();
+
+ if (FlushMode.isManualFlushMode(flushMode)
+ && !TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
+ session.setFlushMode(FlushMode.AUTO);
+ }
+ }
+ ManagedSessionContext.bind(session);
+
+ return session;
+ }
}
- return false;
- }
-
- /** Creates a transaction synchronization object for the specified session.
- * @param session Session to synchronize using the created object. Cannot be
- * null.
- * @return A valid transaction synchronization. Never returns null.
- */
- private TransactionSynchronization createTransactionSynchronization(
- final Session session) {
- return new TransactionSynchronizationAdapter() {
- @Override
- public void afterCompletion(final int status) {
- session.close();
- ManagedSessionContext.unbind(sessionFactory);
- }
- };
- }
+
+ /**
+ * Registers transaction synchronization with session in order to clean up and close the session when transaction
+ * finishes.
+ *
+ * @param session
+ * Session to register into transaction synchronization. Cannot be null.
+ * @return Returns true
if the session was register into any available synchronization strategy,
+ * false
otherwise.
+ */
+ private boolean registerSynchronization(final Session session) {
+ // Tries Spring's transaction manager synchronization.
+ if (TransactionSynchronizationManager.isSynchronizationActive()) {
+
+ // If it's allowed, registers synchronization to cleanup session.
+ TransactionSynchronizationManager.registerSynchronization(createTransactionSynchronization(session));
+ return true;
+ } else {
+ // Tries JTA transaction manager synchronization.
+ JtaPlatform jtaPlatform = sessionFactory.getServiceRegistry().getService(JtaPlatform.class);
+
+ // If it's allowed, registers synchronization to cleanup session.
+ if (jtaPlatform.canRegisterSynchronization()) {
+ List synchronizations;
+
+ synchronizations = Arrays.asList(createTransactionSynchronization(session));
+
+ Synchronization jtaSync;
+ jtaSync = new JtaAfterCompletionSynchronization(synchronizations);
+ jtaPlatform.registerSynchronization(jtaSync);
+
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Creates a transaction synchronization object for the specified session.
+ *
+ * @param session
+ * Session to synchronize using the created object. Cannot be null.
+ * @return A valid transaction synchronization. Never returns null.
+ */
+ private TransactionSynchronization createTransactionSynchronization(final Session session) {
+ return new TransactionSynchronizationAdapter() {
+ @Override
+ public void afterCompletion(final int status) {
+ session.close();
+ ManagedSessionContext.unbind(sessionFactory);
+ }
+ };
+ }
}
\ No newline at end of file
Index: lams_learning/web/WEB-INF/tags/Head.tag
===================================================================
diff -u -r2f3129c49cf6a04320cd4d0cd98cec031b7db087 -rab2b6923490ce38dc647ea66d6768966fbc40cfd
--- lams_learning/web/WEB-INF/tags/Head.tag (.../Head.tag) (revision 2f3129c49cf6a04320cd4d0cd98cec031b7db087)
+++ lams_learning/web/WEB-INF/tags/Head.tag (.../Head.tag) (revision ab2b6923490ce38dc647ea66d6768966fbc40cfd)
@@ -1,42 +1,42 @@
-<%/****************************************************************
- * Copyright (C) 2005 LAMS Foundation (http://lamsfoundation.org)
- * =============================================================
- * License Information: http://lamsfoundation.org/licensing/lams/2.0/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2.0
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
- * USA
- *
- * http://www.gnu.org/licenses/gpl.txt
- * ****************************************************************
- */
-
-/**
- * Head.tag
- * Author: Fiona Malikoff
+<%/****************************************************************
+ * Copyright (C) 2005 LAMS Foundation (http://lamsfoundation.org)
+ * =============================================================
+ * License Information: http://lamsfoundation.org/licensing/lams/2.0/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2.0
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ *
+ * http://www.gnu.org/licenses/gpl.txt
+ * ****************************************************************
+ */
+
+/**
+ * Head.tag
+ * Author: Fiona Malikoff
* Description: Sets up the non-cache pragma statements and the UTF-8
- * encoding. Use in place of the normal head tag.
- */
+ * encoding. Use in place of the normal head tag.
+ */
%>
-
-<%@ tag body-content="scriptless"%>
+<%@ tag body-content="scriptless"%>
+
-
+
-
+
Index: lams_tool_chat/.classpath
===================================================================
diff -u -r0fdf00ad8ffebc0cc6d79de96a216c08ce0d4cdf -rab2b6923490ce38dc647ea66d6768966fbc40cfd
--- lams_tool_chat/.classpath (.../.classpath) (revision 0fdf00ad8ffebc0cc6d79de96a216c08ce0d4cdf)
+++ lams_tool_chat/.classpath (.../.classpath) (revision ab2b6923490ce38dc647ea66d6768966fbc40cfd)
@@ -25,5 +25,6 @@
+
Index: lams_tool_chat/build.xml
===================================================================
diff -u -re59bc835a5ec91886980d67af70c0f05a0f7ae73 -rab2b6923490ce38dc647ea66d6768966fbc40cfd
--- lams_tool_chat/build.xml (.../build.xml) (revision e59bc835a5ec91886980d67af70c0f05a0f7ae73)
+++ lams_tool_chat/build.xml (.../build.xml) (revision ab2b6923490ce38dc647ea66d6768966fbc40cfd)
@@ -1,7 +1,25 @@
+
+
+
+
-
-
+
+
+ ${ant.project.name}: Copying additional Java classes to WAR
+
+
\ No newline at end of file
Index: lams_tool_chat/src/java/org/lamsfoundation/lams/tool/chat/dao/IChatMessageDAO.java
===================================================================
diff -u -rcd0d0b28a7c27711a74ce2b41821f3ccf5c80df9 -rab2b6923490ce38dc647ea66d6768966fbc40cfd
--- lams_tool_chat/src/java/org/lamsfoundation/lams/tool/chat/dao/IChatMessageDAO.java (.../IChatMessageDAO.java) (revision cd0d0b28a7c27711a74ce2b41821f3ccf5c80df9)
+++ lams_tool_chat/src/java/org/lamsfoundation/lams/tool/chat/dao/IChatMessageDAO.java (.../IChatMessageDAO.java) (revision ab2b6923490ce38dc647ea66d6768966fbc40cfd)
@@ -45,7 +45,7 @@
ChatMessage getByUID(Long uid);
- List getLatest(ChatSession chatSession, int max);
+ List getLatest(ChatSession chatSession, Integer max, boolean orderAsc);
Map getCountBySession(Long chatUID);
Index: lams_tool_chat/src/java/org/lamsfoundation/lams/tool/chat/dao/hibernate/ChatMessageDAO.java
===================================================================
diff -u -r597801af2488d7e993718336c4983ec91a758808 -rab2b6923490ce38dc647ea66d6768966fbc40cfd
--- lams_tool_chat/src/java/org/lamsfoundation/lams/tool/chat/dao/hibernate/ChatMessageDAO.java (.../ChatMessageDAO.java) (revision 597801af2488d7e993718336c4983ec91a758808)
+++ lams_tool_chat/src/java/org/lamsfoundation/lams/tool/chat/dao/hibernate/ChatMessageDAO.java (.../ChatMessageDAO.java) (revision ab2b6923490ce38dc647ea66d6768966fbc40cfd)
@@ -44,22 +44,21 @@
@Repository
public class ChatMessageDAO extends LAMSBaseDAO implements IChatMessageDAO {
- protected final Log logger = LogFactory.getLog(getClass());
-
+ protected final Log logger = LogFactory.getLog(getClass());
+
// public static final String SQL_QUERY_FIND_USER_MESSAGE_HISTORY = "from "
// + ChatMessage.class.getName() + " as f where "
// + "f.chatSession=? and (f.type='groupchat' or "
// + "(f.type='chat' and (f.fromUser.userId=? or f.toUser.userId=?)))";
- public static final String SQL_QUERY_FIND_USER_MESSAGE_HISTORY = "from "
- + ChatMessage.class.getName()
+ public static final String SQL_QUERY_FIND_USER_MESSAGE_HISTORY = "from " + ChatMessage.class.getName()
+ " as f where "
+ "f.chatSession.uid=? and f.hidden='false' and (f.type='groupchat' or (f.type='chat' and (f.fromUser.uid=? or f.toUser.uid=?)))";
public static final String SQL_QUERY_FIND_MESSAGE_BY_UID = "from " + ChatMessage.class.getName() + " where uid=?";
- public static final String SQL_QUERY_FIND_MESSAGE_BY_SESSION_ORDER_BY_DATE_ASC = "from "
- + ChatMessage.class.getName() + " as f where f.chatSession=? order by f.sendDate desc";
+ public static final String SQL_QUERY_FIND_MESSAGE_BY_SESSION_ORDER_BY_DATE = "from " + ChatMessage.class.getName()
+ + " as f where f.chatSession=? order by f.sendDate ";
public static final String SQL_QUERY_FIND_MESSAGE_COUNT_BY_FROM_USER = "select f.fromUser.uid, count(*) from "
+ ChatMessage.class.getName() + " as f where f.chatSession.uid=? group by f.fromUser";
@@ -70,65 +69,75 @@
public static final String SQL_QUERY_FIND_MESSAGES_SENT_BY_USER = "FROM " + ChatMessage.class.getName()
+ " AS f WHERE f.fromUser.uid=?";
- public void saveOrUpdate(ChatMessage chatMessage) {
- getSession().saveOrUpdate(chatMessage);
- getSession().flush();
- }
+ @Override
+ public void saveOrUpdate(ChatMessage chatMessage) {
+ getSession().saveOrUpdate(chatMessage);
+ getSession().flush();
+ }
- public List getForUser(ChatUser chatUser) {
- return doFind(ChatMessageDAO.SQL_QUERY_FIND_USER_MESSAGE_HISTORY, new Object[] {
- chatUser.getChatSession().getUid(), chatUser.getUid(), chatUser.getUid() });
- }
+ @Override
+ public List getForUser(ChatUser chatUser) {
+ return doFind(ChatMessageDAO.SQL_QUERY_FIND_USER_MESSAGE_HISTORY,
+ new Object[] { chatUser.getChatSession().getUid(), chatUser.getUid(), chatUser.getUid() });
+ }
- public ChatMessage getByUID(Long uid) {
- // TODO Auto-generated method stub
- List list = doFind(ChatMessageDAO.SQL_QUERY_FIND_MESSAGE_BY_UID, new Object[] { uid });
+ @Override
+ public ChatMessage getByUID(Long uid) {
+ // TODO Auto-generated method stub
+ List list = doFind(ChatMessageDAO.SQL_QUERY_FIND_MESSAGE_BY_UID, new Object[] { uid });
- if (list != null && list.size() > 0) {
- return (ChatMessage) list.get(0);
- } else {
- return null;
- }
-
+ if ((list != null) && (list.size() > 0)) {
+ return (ChatMessage) list.get(0);
+ } else {
+ return null;
}
- public List getLatest(ChatSession chatSession, int max) {
- try {
- Query query = getSessionFactory().getCurrentSession().createQuery(
- ChatMessageDAO.SQL_QUERY_FIND_MESSAGE_BY_SESSION_ORDER_BY_DATE_ASC);
- query.setLong(0, chatSession.getUid());
- query.setMaxResults(max);
- return query.list();
- } catch (HibernateException he) {
- logger.error("getLatest: hibernate exception");
- return null;
- }
+ }
+
+ @Override
+ public List getLatest(ChatSession chatSession, Integer max, boolean orderAsc) {
+ try {
+ Query query = getSessionFactory().getCurrentSession().createQuery(
+ ChatMessageDAO.SQL_QUERY_FIND_MESSAGE_BY_SESSION_ORDER_BY_DATE + (orderAsc ? "asc" : "desc"));
+ query.setLong(0, chatSession.getUid());
+ if (max != null) {
+ query.setMaxResults(max);
+ }
+ return query.list();
+ } catch (HibernateException he) {
+ logger.error("getLatest: hibernate exception");
+ return null;
}
+ }
- public Map getCountBySession(Long chatUID) {
- List list = doFind(ChatMessageDAO.SQL_QUERY_FIND_MESSAGE_COUNT_BY_SESSION, new Object[] { chatUID });
+ @Override
+ public Map getCountBySession(Long chatUID) {
+ List list = doFind(ChatMessageDAO.SQL_QUERY_FIND_MESSAGE_COUNT_BY_SESSION, new Object[] { chatUID });
- Map resultMap = new HashMap();
- for (Iterator iter = list.iterator(); iter.hasNext();) {
- Object[] row = (Object[]) iter.next();
- resultMap.put((Long) row[0], ((Number) row[1]).intValue());
- }
- return resultMap;
+ Map resultMap = new HashMap();
+ for (Iterator iter = list.iterator(); iter.hasNext();) {
+ Object[] row = (Object[]) iter.next();
+ resultMap.put((Long) row[0], ((Number) row[1]).intValue());
}
+ return resultMap;
+ }
- public Map getCountByFromUser(Long sessionUID) {
- List list = doFind(ChatMessageDAO.SQL_QUERY_FIND_MESSAGE_COUNT_BY_FROM_USER, new Object[] { sessionUID });
+ @Override
+ public Map getCountByFromUser(Long sessionUID) {
+ List list = doFind(ChatMessageDAO.SQL_QUERY_FIND_MESSAGE_COUNT_BY_FROM_USER, new Object[] { sessionUID });
- Map resultMap = new HashMap();
- for (Iterator iter = list.iterator(); iter.hasNext();) {
- Object[] row = (Object[]) iter.next();
- resultMap.put((Long) row[0], ((Number) row[1]).intValue());
- }
- return resultMap;
+ Map resultMap = new HashMap();
+ for (Iterator iter = list.iterator(); iter.hasNext();) {
+ Object[] row = (Object[]) iter.next();
+ resultMap.put((Long) row[0], ((Number) row[1]).intValue());
}
+ return resultMap;
+ }
- @SuppressWarnings("unchecked")
- public List getSentByUser(Long userUid) {
- return (List) doFind(ChatMessageDAO.SQL_QUERY_FIND_MESSAGES_SENT_BY_USER, new Object[] { userUid });
- }
+ @Override
+ @SuppressWarnings("unchecked")
+ public List getSentByUser(Long userUid) {
+ return (List) doFind(ChatMessageDAO.SQL_QUERY_FIND_MESSAGES_SENT_BY_USER,
+ new Object[] { userUid });
+ }
}
Index: lams_tool_chat/src/java/org/lamsfoundation/lams/tool/chat/service/ChatService.java
===================================================================
diff -u -r708bd4d049ae0a59d70c964ef2f864d2b7a352e6 -rab2b6923490ce38dc647ea66d6768966fbc40cfd
--- lams_tool_chat/src/java/org/lamsfoundation/lams/tool/chat/service/ChatService.java (.../ChatService.java) (revision 708bd4d049ae0a59d70c964ef2f864d2b7a352e6)
+++ lams_tool_chat/src/java/org/lamsfoundation/lams/tool/chat/service/ChatService.java (.../ChatService.java) (revision ab2b6923490ce38dc647ea66d6768966fbc40cfd)
@@ -261,7 +261,7 @@
chatDAO.delete(chat);
}
-
+
@Override
@SuppressWarnings("unchecked")
public void removeLearnerContent(Long toolContentId, Integer userId) throws ToolException {
@@ -499,10 +499,11 @@
* Stores information when users with given UIDs were last seen in their Chat session.
*/
@Override
- public void updateUserPresence(Map presence) {
- for (Long userUid : presence.keySet()) {
- ChatUser chatUser = chatUserDAO.getByUID(userUid);
- chatUser.setLastPresence(presence.get(userUid));
+ public void updateUserPresence(Long toolSessionId, Set activeUsers) {
+ Date currentTime = new Date();
+ for (String userName : activeUsers) {
+ ChatUser chatUser = getUserByNicknameAndSessionID(userName, toolSessionId);
+ chatUser.setLastPresence(currentTime);
saveOrUpdateChatUser(chatUser);
}
}
@@ -619,8 +620,8 @@
}
@Override
- public List getLastestMessages(ChatSession chatSession, int max) {
- return chatMessageDAO.getLatest(chatSession, max);
+ public List getLastestMessages(ChatSession chatSession, Integer max, boolean orderAsc) {
+ return chatMessageDAO.getLatest(chatSession, max, orderAsc);
}
public IAuditService getAuditService() {
Index: lams_tool_chat/src/java/org/lamsfoundation/lams/tool/chat/service/ChatServiceProxy.java
===================================================================
diff -u -r08950e1090443c3423a3d1c587416a2fccd8bbdf -rab2b6923490ce38dc647ea66d6768966fbc40cfd
--- lams_tool_chat/src/java/org/lamsfoundation/lams/tool/chat/service/ChatServiceProxy.java (.../ChatServiceProxy.java) (revision 08950e1090443c3423a3d1c587416a2fccd8bbdf)
+++ lams_tool_chat/src/java/org/lamsfoundation/lams/tool/chat/service/ChatServiceProxy.java (.../ChatServiceProxy.java) (revision ab2b6923490ce38dc647ea66d6768966fbc40cfd)
@@ -31,49 +31,43 @@
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
-
/**
- * This class act as the proxy between web layer and service layer. It is
- * designed to decouple the presentation logic and business logic completely.
- * In this way, the presentation tier will no longer be aware of the changes in
- * service layer. Therefore we can feel free to switch the business logic
- * implementation.
+ *
+ * This class act as the proxy between web layer and service layer. It is designed to decouple the presentation logic
+ * and business logic completely. In this way, the presentation tier will no longer be aware of the changes in service
+ * layer. Therefore we can feel free to switch the business logic implementation.
+ *
*/
public class ChatServiceProxy {
- public static final IChatService getChatService(ServletContext servletContext)
- {
- return (IChatService)getChatDomainService(servletContext);
+ public static final IChatService getChatService(ServletContext servletContext) {
+ return (IChatService) ChatServiceProxy.getChatDomainService(servletContext);
}
-
- private static Object getChatDomainService(ServletContext servletContext)
- {
- WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
- return wac.getBean("chatService");
- }
-
- /*
- * Return the chat tool version of tool session manager implementation.
- * It will delegate to the Spring helper method to retrieve the proper
- * bean from Spring bean factory.
- * @param servletContext the servletContext for current application
- * @return noticeboard service object.*/
- public static final ToolSessionManager getChatSessionManager(ServletContext servletContext)
- {
- return (ToolSessionManager)getChatDomainService(servletContext);
+
+ private static Object getChatDomainService(ServletContext servletContext) {
+ WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
+ return wac.getBean("chatService");
}
-
-
+
/*
+ * Return the chat tool version of tool session manager implementation.
+ * It will delegate to the Spring helper method to retrieve the proper
+ * bean from Spring bean factory.
+ * @param servletContext the servletContext for current application
+ * @return noticeboard service object.*/
+ public static final ToolSessionManager getChatSessionManager(ServletContext servletContext) {
+ return (ToolSessionManager) ChatServiceProxy.getChatDomainService(servletContext);
+ }
+
+ /*
* Return the chat tool version of tool content manager implementation.
* It will delegate to the Spring helper method to retrieve the proper
* bean from Spring bean factory.
* @param servletContext the servletContext for current application
* @return noticeboard service object. */
- public static final ToolContentManager getChatContentManager(ServletContext servletContext)
- {
- return (ToolContentManager)getChatDomainService(servletContext);
+ public static final ToolContentManager getChatContentManager(ServletContext servletContext) {
+ return (ToolContentManager) ChatServiceProxy.getChatDomainService(servletContext);
}
}
Index: lams_tool_chat/src/java/org/lamsfoundation/lams/tool/chat/service/IChatService.java
===================================================================
diff -u -ref851974c4dc3f5468b188fab9997a37b73c0e50 -rab2b6923490ce38dc647ea66d6768966fbc40cfd
--- lams_tool_chat/src/java/org/lamsfoundation/lams/tool/chat/service/IChatService.java (.../IChatService.java) (revision ef851974c4dc3f5468b188fab9997a37b73c0e50)
+++ lams_tool_chat/src/java/org/lamsfoundation/lams/tool/chat/service/IChatService.java (.../IChatService.java) (revision ab2b6923490ce38dc647ea66d6768966fbc40cfd)
@@ -28,6 +28,7 @@
import java.util.Date;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import org.apache.struts.upload.FormFile;
import org.lamsfoundation.lams.notebook.model.NotebookEntry;
@@ -120,7 +121,7 @@
*/
public ChatUser getUserByNicknameAndSessionID(String nickname, Long sessionID);
- public void updateUserPresence(Map presence);
+ public void updateUserPresence(Long toolSessionId, Set activeUsers);
/**
*
@@ -165,7 +166,7 @@
*/
public ChatMessage getMessageByUID(Long messageUID);
- public List getLastestMessages(ChatSession chatSession, int max);
+ public List getLastestMessages(ChatSession chatSession, Integer max, boolean orderAsc);
public void auditEditMessage(ChatMessage chatMessage, String messageBody);
Index: lams_tool_chat/src/java/org/lamsfoundation/lams/tool/chat/util/ChatConstants.java
===================================================================
diff -u -ref851974c4dc3f5468b188fab9997a37b73c0e50 -rab2b6923490ce38dc647ea66d6768966fbc40cfd
--- lams_tool_chat/src/java/org/lamsfoundation/lams/tool/chat/util/ChatConstants.java (.../ChatConstants.java) (revision ef851974c4dc3f5468b188fab9997a37b73c0e50)
+++ lams_tool_chat/src/java/org/lamsfoundation/lams/tool/chat/util/ChatConstants.java (.../ChatConstants.java) (revision ab2b6923490ce38dc647ea66d6768966fbc40cfd)
@@ -38,7 +38,7 @@
public static final int MONITORING_SUMMARY_MAX_MESSAGES = 5;
- public static final long PRESENCE_IDLE_TIMEOUT = 15 * 1000;
+ public static final long PRESENCE_IDLE_TIMEOUT = 10 * 1000;
// Attribute names
public static final String ATTR_MESSAGE = "message";
Index: lams_tool_chat/src/java/org/lamsfoundation/lams/tool/chat/web/actions/LearningAction.java
===================================================================
diff -u -ref851974c4dc3f5468b188fab9997a37b73c0e50 -rab2b6923490ce38dc647ea66d6768966fbc40cfd
--- lams_tool_chat/src/java/org/lamsfoundation/lams/tool/chat/web/actions/LearningAction.java (.../LearningAction.java) (revision ef851974c4dc3f5468b188fab9997a37b73c0e50)
+++ lams_tool_chat/src/java/org/lamsfoundation/lams/tool/chat/web/actions/LearningAction.java (.../LearningAction.java) (revision ab2b6923490ce38dc647ea66d6768966fbc40cfd)
@@ -25,27 +25,17 @@
package org.lamsfoundation.lams.tool.chat.web.actions;
import java.io.IOException;
-import java.util.Collections;
import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
import java.util.TimeZone;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
-import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
-import org.apache.tomcat.util.json.JSONArray;
-import org.apache.tomcat.util.json.JSONException;
-import org.apache.tomcat.util.json.JSONObject;
import org.lamsfoundation.lams.learning.web.util.LearningWebUtil;
import org.lamsfoundation.lams.notebook.model.NotebookEntry;
import org.lamsfoundation.lams.notebook.service.CoreNotebookConstants;
@@ -54,7 +44,6 @@
import org.lamsfoundation.lams.tool.chat.dto.ChatDTO;
import org.lamsfoundation.lams.tool.chat.dto.ChatUserDTO;
import org.lamsfoundation.lams.tool.chat.model.Chat;
-import org.lamsfoundation.lams.tool.chat.model.ChatMessage;
import org.lamsfoundation.lams.tool.chat.model.ChatSession;
import org.lamsfoundation.lams.tool.chat.model.ChatUser;
import org.lamsfoundation.lams.tool.chat.service.ChatServiceProxy;
@@ -83,48 +72,9 @@
*/
public class LearningAction extends LamsDispatchAction {
- /**
- * Keeps information of users present in a Chat session. Needs to work with DB so presence is visible on clustered
- * environment.
- */
- private class Roster {
- private long lastCheckTime = 0;
- // users who currently poll messasages
- private final Map activeUsers = new HashMap();
- private final Set roster = new HashSet();
-
- private synchronized JSONArray getRosterJSON(ChatUser user) {
- long currentTime = System.currentTimeMillis();
- activeUsers.put(user.getUid(), new Date(currentTime));
-
- if (currentTime - lastCheckTime > ChatConstants.PRESENCE_IDLE_TIMEOUT) {
- // store active users
- chatService.updateUserPresence(activeUsers);
- activeUsers.clear();
-
- // read active users from all nodes
- List storedActiveUsers = chatService.getUsersActiveBySessionId(user.getChatSession()
- .getSessionId());
- roster.clear();
- for (ChatUser activeUser : storedActiveUsers) {
- roster.add(activeUser.getNickname());
- }
-
- lastCheckTime = currentTime;
- } else {
- roster.add(user.getNickname());
- }
-
- return new JSONArray(roster);
- }
- }
-
private static Logger log = Logger.getLogger(LearningAction.class);
+ private static IChatService chatService;
- private IChatService chatService;
-
- private static final Map rosters = Collections.synchronizedMap(new HashMap());
-
@Override
public ActionForward unspecified(ActionMapping mapping, ActionForm form, HttpServletRequest request,
HttpServletResponse response) throws Exception {
@@ -134,12 +84,12 @@
Long toolSessionID = WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_SESSION_ID);
// set up chatService
- if (chatService == null) {
- chatService = ChatServiceProxy.getChatService(this.getServlet().getServletContext());
+ if (LearningAction.chatService == null) {
+ LearningAction.chatService = ChatServiceProxy.getChatService(this.getServlet().getServletContext());
}
// Retrieve the session and content.
- ChatSession chatSession = chatService.getSessionBySessionId(toolSessionID);
+ ChatSession chatSession = LearningAction.chatService.getSessionBySessionId(toolSessionID);
if (chatSession == null) {
throw new ChatException("Cannot retrieve session with toolSessionID" + toolSessionID);
}
@@ -162,8 +112,8 @@
ChatUserDTO chatUserDTO = new ChatUserDTO(chatUser);
if (chatUser.isFinishedActivity()) {
// get the notebook entry.
- NotebookEntry notebookEntry = chatService.getEntry(toolSessionID, CoreNotebookConstants.NOTEBOOK_TOOL,
- ChatConstants.TOOL_SIGNATURE, chatUser.getUserId().intValue());
+ NotebookEntry notebookEntry = LearningAction.chatService.getEntry(toolSessionID,
+ CoreNotebookConstants.NOTEBOOK_TOOL, ChatConstants.TOOL_SIGNATURE, chatUser.getUserId().intValue());
if (notebookEntry != null) {
chatUserDTO.notebookEntry = notebookEntry.getEntry();
}
@@ -173,11 +123,11 @@
// Ensure that the content is use flag is set.
if (!chat.isContentInUse()) {
chat.setContentInUse(new Boolean(true));
- chatService.saveOrUpdateChat(chat);
+ LearningAction.chatService.saveOrUpdateChat(chat);
}
- LearningWebUtil.putActivityPositionInRequestByToolSessionId(toolSessionID, request, getServlet()
- .getServletContext());
+ LearningWebUtil.putActivityPositionInRequestByToolSessionId(toolSessionID, request,
+ getServlet().getServletContext());
/* Check if submission deadline is null */
@@ -209,10 +159,10 @@
LearningForm lrnForm = (LearningForm) form;
// set the finished flag
- ChatUser chatUser = chatService.getUserByUID(lrnForm.getChatUserUID());
+ ChatUser chatUser = LearningAction.chatService.getUserByUID(lrnForm.getChatUserUID());
if (chatUser != null) {
chatUser.setFinishedActivity(true);
- chatService.saveOrUpdateChatUser(chatUser);
+ LearningAction.chatService.saveOrUpdateChatUser(chatUser);
} else {
LearningAction.log.error("finishActivity(): couldn't find ChatUser with uid: " + lrnForm.getChatUserUID());
}
@@ -245,12 +195,12 @@
LearningForm lrnForm = (LearningForm) form;
// set the finished flag
- ChatUser chatUser = chatService.getUserByUID(lrnForm.getChatUserUID());
+ ChatUser chatUser = LearningAction.chatService.getUserByUID(lrnForm.getChatUserUID());
ChatDTO chatDTO = new ChatDTO(chatUser.getChatSession().getChat());
request.setAttribute("chatDTO", chatDTO);
- NotebookEntry notebookEntry = chatService.getEntry(chatUser.getChatSession().getSessionId(),
+ NotebookEntry notebookEntry = LearningAction.chatService.getEntry(chatUser.getChatSession().getSessionId(),
CoreNotebookConstants.NOTEBOOK_TOOL, ChatConstants.TOOL_SIGNATURE, chatUser.getUserId().intValue());
if (notebookEntry != null) {
@@ -270,136 +220,38 @@
LearningForm lrnForm = (LearningForm) form;
- ChatUser chatUser = chatService.getUserByUID(lrnForm.getChatUserUID());
+ ChatUser chatUser = LearningAction.chatService.getUserByUID(lrnForm.getChatUserUID());
Long toolSessionID = chatUser.getChatSession().getSessionId();
Integer userID = chatUser.getUserId().intValue();
// check for existing notebook entry
- NotebookEntry entry = chatService.getEntry(toolSessionID, CoreNotebookConstants.NOTEBOOK_TOOL,
+ NotebookEntry entry = LearningAction.chatService.getEntry(toolSessionID, CoreNotebookConstants.NOTEBOOK_TOOL,
ChatConstants.TOOL_SIGNATURE, userID);
if (entry == null) {
// create new entry
- chatService.createNotebookEntry(toolSessionID, CoreNotebookConstants.NOTEBOOK_TOOL,
+ LearningAction.chatService.createNotebookEntry(toolSessionID, CoreNotebookConstants.NOTEBOOK_TOOL,
ChatConstants.TOOL_SIGNATURE, userID, lrnForm.getEntryText());
} else {
// update existing entry
entry.setEntry(lrnForm.getEntryText());
entry.setLastModified(new Date());
- chatService.updateEntry(entry);
+ LearningAction.chatService.updateEntry(entry);
}
return finishActivity(mapping, form, request, response);
}
- /**
- * Get data displayed in Learner Chat screen.
- */
- public ActionForward getChatContent(ActionMapping mapping, ActionForm form, HttpServletRequest request,
- HttpServletResponse response) throws JSONException, IOException {
- Long toolSessionID = WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_SESSION_ID);
- ChatUser chatUser = getCurrentUser(toolSessionID);
- Long lastMessageUid = WebUtil.readLongParam(request, "lastMessageUid", true);
-
- // build JSON object for Javascript to understand
- JSONObject responseJSON = new JSONObject();
- getMessages(lastMessageUid, chatUser, responseJSON);
- getRoster(chatUser, responseJSON);
-
- response.getWriter().write(responseJSON.toString());
- return null;
- }
-
- /**
- * Stores message sent by user.
- */
- public ActionForward sendMessage(ActionMapping mapping, ActionForm form, HttpServletRequest request,
- HttpServletResponse response) throws JSONException, IOException {
- String message = request.getParameter("message");
- if (StringUtils.isBlank(message)) {
- return null;
- }
- Long toolSessionID = WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_SESSION_ID);
-
- ChatUser toChatUser = null;
- String toUser = request.getParameter(AttributeNames.USER);
- if (!StringUtils.isBlank(toUser)) {
- toChatUser = chatService.getUserByNicknameAndSessionID(toUser, toolSessionID);
- if (toChatUser == null) {
- // there should be an user, but he could not be found, so don't send the message to everyone
- LearningAction.log.error("Could not find nick: " + toUser + " in session: " + toolSessionID);
- return null;
- }
- }
-
- ChatUser chatUser = getCurrentUser(toolSessionID);
-
- ChatMessage chatMessage = new ChatMessage();
- chatMessage.setFromUser(chatUser);
- chatMessage.setChatSession(chatUser.getChatSession());
- chatMessage.setToUser(toChatUser);
- chatMessage.setType(toChatUser == null ? ChatMessage.MESSAGE_TYPE_PUBLIC : ChatMessage.MESSAGE_TYPE_PRIVATE);
- chatMessage.setBody(message);
- chatMessage.setSendDate(new Date());
- chatMessage.setHidden(Boolean.FALSE);
- chatService.saveOrUpdateChatMessage(chatMessage);
-
- return null;
- }
-
- private void getMessages(Long lastMessageUid, ChatUser chatUser, JSONObject responseJSON) throws JSONException {
- List messages = chatService.getMessagesForUser(chatUser);
- if (!messages.isEmpty()) {
- // if last message which is already displayed on Chat screen
- // is the same as newest message in DB, there is nothing new for user, so don't send him anything
- ChatMessage lastMessage = messages.get(messages.size() - 1);
- Long currentLastMessageUid = lastMessage.getUid();
- if ((lastMessageUid == null) || (currentLastMessageUid > lastMessageUid)) {
- responseJSON.put("lastMessageUid", currentLastMessageUid);
-
- for (ChatMessage message : messages) {
- // all messasges need to be written out, not only new ones,
- // as old ones could have been edited or hidden by Monitor
- if (!message.isHidden()) {
- String filteredMessage = chatService.filterMessage(message.getBody(), chatUser.getChatSession()
- .getChat());
-
- JSONObject messageJSON = new JSONObject();
- messageJSON.put("body", filteredMessage);
- messageJSON.put("from", message.getFromUser().getNickname());
- messageJSON.put("type", message.getType());
- responseJSON.append("messages", messageJSON);
- }
- }
- }
- }
- }
-
- /**
- * Gets users currently using the Chat instance.
- */
- private void getRoster(ChatUser chatUser, JSONObject responseJSON) throws JSONException {
- Long sessionId = chatUser.getChatSession().getSessionId();
- // this is equivalent of a chat room
- Roster sessionRoster = LearningAction.rosters.get(sessionId);
- if (sessionRoster == null) {
- sessionRoster = new Roster();
- LearningAction.rosters.put(sessionId, sessionRoster);
- }
-
- responseJSON.put("roster", sessionRoster.getRosterJSON(chatUser));
- }
-
private ChatUser getCurrentUser(Long toolSessionId) {
UserDTO user = (UserDTO) SessionManager.getSession().getAttribute(AttributeNames.USER);
// attempt to retrieve user using userId and toolSessionId
- ChatUser chatUser = chatService.getUserByUserIdAndSessionId(new Long(user.getUserID().intValue()),
- toolSessionId);
+ ChatUser chatUser = LearningAction.chatService
+ .getUserByUserIdAndSessionId(new Long(user.getUserID().intValue()), toolSessionId);
if (chatUser == null) {
- ChatSession chatSession = chatService.getSessionBySessionId(toolSessionId);
- chatUser = chatService.createChatUser(user, chatSession);
+ ChatSession chatSession = LearningAction.chatService.getSessionBySessionId(toolSessionId);
+ chatUser = LearningAction.chatService.createChatUser(user, chatSession);
}
return chatUser;
Index: lams_tool_chat/src/java/org/lamsfoundation/lams/tool/chat/web/actions/LearningWebsocketServer.java
===================================================================
diff -u
--- lams_tool_chat/src/java/org/lamsfoundation/lams/tool/chat/web/actions/LearningWebsocketServer.java (revision 0)
+++ lams_tool_chat/src/java/org/lamsfoundation/lams/tool/chat/web/actions/LearningWebsocketServer.java (revision ab2b6923490ce38dc647ea66d6768966fbc40cfd)
@@ -0,0 +1,370 @@
+package org.lamsfoundation.lams.tool.chat.web.actions;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import javax.websocket.CloseReason;
+import javax.websocket.CloseReason.CloseCodes;
+import javax.websocket.OnClose;
+import javax.websocket.OnMessage;
+import javax.websocket.OnOpen;
+import javax.websocket.Session;
+import javax.websocket.server.ServerEndpoint;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
+import org.apache.tomcat.util.json.JSONArray;
+import org.apache.tomcat.util.json.JSONException;
+import org.apache.tomcat.util.json.JSONObject;
+import org.lamsfoundation.lams.tool.chat.model.ChatMessage;
+import org.lamsfoundation.lams.tool.chat.model.ChatSession;
+import org.lamsfoundation.lams.tool.chat.model.ChatUser;
+import org.lamsfoundation.lams.tool.chat.service.IChatService;
+import org.lamsfoundation.lams.tool.chat.util.ChatConstants;
+import org.lamsfoundation.lams.util.HashUtil;
+import org.lamsfoundation.lams.util.hibernate.HibernateSessionManager;
+import org.lamsfoundation.lams.web.session.SessionManager;
+import org.lamsfoundation.lams.web.util.AttributeNames;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.context.support.WebApplicationContextUtils;
+
+/**
+ * Receives, processes and sends Chat messages to Learners.
+ *
+ * @author Marcin Cieslak
+ */
+@ServerEndpoint("/learningWebsocket")
+public class LearningWebsocketServer {
+
+ /**
+ * Identifies a single connection. There can be more than one connection for the same user: multiple windows open or
+ * the same user in an another role.
+ */
+ private static class Websocket {
+ private Session session;
+ private String userName;
+ private String nickName;
+ private String hash;
+
+ private Websocket(Session session, String nickName) {
+ this.session = session;
+ this.userName = session.getUserPrincipal().getName();
+ this.nickName = nickName;
+ }
+ }
+
+ /**
+ * A singleton which updates Learners with messages and presence.
+ */
+ private static class SendWorker extends Thread {
+ private boolean stopFlag = false;
+ // how ofter the thread runs
+ private static final long CHECK_INTERVAL = 2000;
+ // mapping toolSessionId -> timestamp when the check was last performed, so the thread does not run too often
+ private final Map lastSendTimes = new TreeMap();
+
+ @Override
+ public void run() {
+ while (!stopFlag) {
+ try {
+ // websocket communication bypasses standard HTTP filters, so Hibernate session needs to be initialised manually
+ // A new session needs to be created on each thread run as the session keeps stale Hibernate data (single transaction).
+ HibernateSessionManager.bindHibernateSessionToCurrentThread(true);
+
+ // synchronize websockets as a new Learner entering Chat could modify this collection
+ synchronized (LearningWebsocketServer.websockets) {
+ Iterator>> entryIterator = LearningWebsocketServer.websockets
+ .entrySet().iterator();
+ // go throus Tool Session and update registered users with messages and roster
+ while (entryIterator.hasNext()) {
+ Entry> entry = entryIterator.next();
+ Long toolSessionId = entry.getKey();
+ Long lastSendTime = lastSendTimes.get(toolSessionId);
+ if ((lastSendTime == null)
+ || ((System.currentTimeMillis() - lastSendTime) >= SendWorker.CHECK_INTERVAL)) {
+ send(toolSessionId);
+ }
+
+ // if all users left the chat, remove the obsolete mapping
+ Set sessionWebsockets = entry.getValue();
+ if (sessionWebsockets.isEmpty()) {
+ entryIterator.remove();
+ LearningWebsocketServer.rosters.remove(toolSessionId);
+ }
+ }
+ }
+
+ Thread.sleep(SendWorker.CHECK_INTERVAL);
+ } catch (InterruptedException e) {
+ LearningWebsocketServer.log.warn("Stopping Chat worker thread");
+ stopFlag = true;
+ } catch (Exception e) {
+ // error caught, but carry on
+ LearningWebsocketServer.log.error("Error in Chat worker thread", e);
+ }
+ }
+ }
+
+ /**
+ * Cheks for stale connections and feeds the opened ones with messages and roster.
+ */
+ private void send(Long toolSessionId) {
+ // update the timestamp
+ lastSendTimes.put(toolSessionId, System.currentTimeMillis());
+
+ ChatSession chatSession = LearningWebsocketServer.getChatService().getSessionBySessionId(toolSessionId);
+ List messages = LearningWebsocketServer.getChatService().getLastestMessages(chatSession, null,
+ true);
+ Set sessionWebsockets = LearningWebsocketServer.websockets.get(toolSessionId);
+ Roster roster = null;
+ JSONArray rosterJSON = null;
+ String rosterString = null;
+ // synchronize websockets as a new Learner entering chat could modify this collection
+ synchronized (sessionWebsockets) {
+ Iterator websocketIterator = sessionWebsockets.iterator();
+ while (websocketIterator.hasNext()) {
+ Websocket websocket = websocketIterator.next();
+
+ // check whether the connection is not stale
+ if (!websocket.session.isOpen()) {
+ // remove the closed connection
+ websocketIterator.remove();
+
+ if (LearningWebsocketServer.log.isDebugEnabled()) {
+ LearningWebsocketServer.log.debug(
+ "User " + websocket.userName + " left Chat with toolSessionId: " + toolSessionId);
+ }
+ continue;
+ }
+
+ // the connection is valid, carry on
+ JSONObject responseJSON = new JSONObject();
+ // fetch roster only once, but messages are personalised
+ if (rosterJSON == null) {
+ roster = LearningWebsocketServer.rosters.get(toolSessionId);
+ if (roster == null) {
+ // build a new roster object
+ roster = new Roster(toolSessionId);
+ LearningWebsocketServer.rosters.put(toolSessionId, roster);
+ }
+
+ rosterJSON = roster.getRosterJSON();
+ rosterString = rosterJSON.toString();
+ }
+
+ try {
+ String userName = websocket.userName;
+ JSONArray messagesJSON = LearningWebsocketServer.getMessages(chatSession, messages, userName);
+ // if hash of roster and messages is the same as before, do not send the message, save the bandwidth
+ String hash = HashUtil.sha1(rosterString + messagesJSON.toString());
+ if ((websocket.hash == null) || !websocket.hash.equals(hash)) {
+ websocket.hash = hash;
+
+ responseJSON.put("messages", messagesJSON);
+ responseJSON.put("roster", rosterJSON);
+
+ // send the payload to the Learner's browser
+ websocket.session.getBasicRemote().sendText(responseJSON.toString());
+ }
+ } catch (Exception e) {
+ LearningWebsocketServer.log.error("Error while building message JSON", e);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Keeps information of users present in a Chat session. Needs to work with DB so presence is visible in clustered
+ * environment.
+ */
+ private static class Roster {
+ private Long toolSessionId = null;
+ // timestamp when DB was last hit
+ private long lastDBCheckTime = 0;
+
+ // Learners who are currently active
+ private final Set activeUsers = new TreeSet();
+
+ private Roster(Long toolSessionId) {
+ this.toolSessionId = toolSessionId;
+ }
+
+ /**
+ * Checks which Learners
+ */
+ private JSONArray getRosterJSON() {
+ Set localActiveUsers = new TreeSet();
+ Set sessionWebsockets = LearningWebsocketServer.websockets.get(toolSessionId);
+ // find out who is active locally
+ for (Websocket websocket : sessionWebsockets) {
+ localActiveUsers.add(websocket.nickName);
+ }
+
+ // is it time to sync with the DB yet?
+ long currentTime = System.currentTimeMillis();
+ if ((currentTime - lastDBCheckTime) > ChatConstants.PRESENCE_IDLE_TIMEOUT) {
+ // store Learners active on this node
+ LearningWebsocketServer.getChatService().updateUserPresence(toolSessionId, localActiveUsers);
+
+ // read active Learners from all nodes
+ List storedActiveUsers = LearningWebsocketServer.getChatService()
+ .getUsersActiveBySessionId(toolSessionId);
+ // refresh current collection
+ activeUsers.clear();
+ for (ChatUser activeUser : storedActiveUsers) {
+ activeUsers.add(activeUser.getNickname());
+ }
+
+ lastDBCheckTime = currentTime;
+ } else {
+ // add users active on this node; no duplicates - it is a set, not a list
+ activeUsers.addAll(localActiveUsers);
+ }
+
+ return new JSONArray(activeUsers);
+ }
+ }
+
+ private static Logger log = Logger.getLogger(LearningWebsocketServer.class);
+
+ private static IChatService chatService;
+
+ private static final SendWorker sendWorker = new SendWorker();
+ private static final Map rosters = Collections.synchronizedMap(new TreeMap());
+ private static final Map> websockets = Collections
+ .synchronizedMap(new TreeMap>());
+
+ static {
+ // run the singleton thread
+ LearningWebsocketServer.sendWorker.start();
+ }
+
+ /**
+ * Registeres the Learner for processing by SendWorker.
+ */
+ @OnOpen
+ public void registerUser(Session session) throws IOException {
+ Long toolSessionId = Long
+ .valueOf(session.getRequestParameterMap().get(AttributeNames.PARAM_TOOL_SESSION_ID).get(0));
+ Set sessionWebsockets = LearningWebsocketServer.websockets.get(toolSessionId);
+ if (sessionWebsockets == null) {
+ sessionWebsockets = Collections.synchronizedSet(new HashSet());
+ LearningWebsocketServer.websockets.put(toolSessionId, sessionWebsockets);
+ }
+ String userName = session.getUserPrincipal().getName();
+ ChatUser chatUser = LearningWebsocketServer.getChatService().getUserByLoginNameAndSessionId(userName,
+ toolSessionId);
+ Websocket websocket = new Websocket(session, chatUser.getNickname());
+ sessionWebsockets.add(websocket);
+
+ // websocket communication bypasses standard HTTP filters, so Hibernate session needs to be initialised manually
+ HibernateSessionManager.bindHibernateSessionToCurrentThread(false);
+ // update the chat window immediatelly
+ LearningWebsocketServer.sendWorker.send(toolSessionId);
+
+ if (LearningWebsocketServer.log.isDebugEnabled()) {
+ LearningWebsocketServer.log
+ .debug("User " + userName + " entered Chat with toolSessionId: " + toolSessionId);
+ }
+ }
+
+ /**
+ * If there was something wrong with the connection, put it into logs.
+ */
+ @OnClose
+ public void unregisterUser(CloseReason reason) {
+ if (!(reason.getCloseCode().equals(CloseCodes.GOING_AWAY)
+ || reason.getCloseCode().equals(CloseCodes.NORMAL_CLOSURE))) {
+ LearningWebsocketServer.log.warn("Abnormal Chat websocket close. Code: " + reason.getCloseCode()
+ + ". Reason: " + reason.getReasonPhrase());
+ }
+ }
+
+ /**
+ * Stores a message sent by a Learner.
+ */
+ @OnMessage
+ public void receiveMessage(String input, Session session) throws JSONException {
+ if (StringUtils.isBlank(input)) {
+ return;
+ }
+ JSONObject messageJSON = new JSONObject(input);
+ String message = messageJSON.getString("message");
+ if (StringUtils.isBlank(message)) {
+ return;
+ }
+ Long toolSessionId = messageJSON.getLong("toolSessionID");
+
+ // websocket communication bypasses standard HTTP filters, so Hibernate session needs to be initialised manually
+ HibernateSessionManager.bindHibernateSessionToCurrentThread(false);
+
+ ChatUser toChatUser = null;
+ String toUser = messageJSON.getString("toUser");
+ if (!StringUtils.isBlank(toUser)) {
+ toChatUser = LearningWebsocketServer.getChatService().getUserByNicknameAndSessionID(toUser, toolSessionId);
+ if (toChatUser == null) {
+ // there should be an user, but he could not be found, so don't send the message to everyone
+ LearningWebsocketServer.log.error("Could not find nick: " + toUser + " in session: " + toolSessionId);
+ return;
+ }
+ }
+
+ ChatUser chatUser = LearningWebsocketServer.getChatService()
+ .getUserByLoginNameAndSessionId(session.getUserPrincipal().getName(), toolSessionId);
+
+ ChatMessage chatMessage = new ChatMessage();
+ chatMessage.setFromUser(chatUser);
+ chatMessage.setChatSession(chatUser.getChatSession());
+ chatMessage.setToUser(toChatUser);
+ chatMessage.setType(toChatUser == null ? ChatMessage.MESSAGE_TYPE_PUBLIC : ChatMessage.MESSAGE_TYPE_PRIVATE);
+ chatMessage.setBody(message);
+ chatMessage.setSendDate(new Date());
+ chatMessage.setHidden(Boolean.FALSE);
+ LearningWebsocketServer.getChatService().saveOrUpdateChatMessage(chatMessage);
+ }
+
+ /**
+ * Filteres messages meant for the given user (group or personal).
+ */
+ private static JSONArray getMessages(ChatSession chatSession, List messages, String userName)
+ throws JSONException {
+ JSONArray messagesJSON = new JSONArray();
+
+ for (ChatMessage message : messages) {
+ // all messasges need to be written out, not only new ones,
+ // as old ones could have been edited or hidden by Monitor
+ if (!message.isHidden() && (message.getType().equals(ChatMessage.MESSAGE_TYPE_PUBLIC)
+ || message.getFromUser().getLoginName().equals(userName)
+ || message.getToUser().getLoginName().equals(userName))) {
+ String filteredMessage = LearningWebsocketServer.getChatService().filterMessage(message.getBody(),
+ chatSession.getChat());
+ JSONObject messageJSON = new JSONObject();
+ messageJSON.put("body", filteredMessage);
+ messageJSON.put("from", message.getFromUser().getNickname());
+ messageJSON.put("type", message.getType());
+ messagesJSON.put(messageJSON);
+ }
+ }
+
+ return messagesJSON;
+ }
+
+ private static IChatService getChatService() {
+ if (LearningWebsocketServer.chatService == null) {
+ WebApplicationContext wac = WebApplicationContextUtils
+ .getRequiredWebApplicationContext(SessionManager.getServletContext());
+ LearningWebsocketServer.chatService = (IChatService) wac.getBean("chatService");
+ }
+ return LearningWebsocketServer.chatService;
+ }
+}
\ No newline at end of file
Index: lams_tool_chat/src/java/org/lamsfoundation/lams/tool/chat/web/actions/MonitoringAction.java
===================================================================
diff -u -r9f7df51118e418eead64378c028572b0baf39196 -rab2b6923490ce38dc647ea66d6768966fbc40cfd
--- lams_tool_chat/src/java/org/lamsfoundation/lams/tool/chat/web/actions/MonitoringAction.java (.../MonitoringAction.java) (revision 9f7df51118e418eead64378c028572b0baf39196)
+++ lams_tool_chat/src/java/org/lamsfoundation/lams/tool/chat/web/actions/MonitoringAction.java (.../MonitoringAction.java) (revision ab2b6923490ce38dc647ea66d6768966fbc40cfd)
@@ -30,9 +30,9 @@
import java.util.Map;
import java.util.TimeZone;
-import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
import org.apache.log4j.Logger;
import org.apache.struts.action.ActionForm;
@@ -62,178 +62,158 @@
* @author
* @version
*
- * @struts.action path="/monitoring" parameter="dispatch" scope="request"
- * name="monitoringForm" validate="false"
+ * @struts.action path="/monitoring" parameter="dispatch" scope="request" name="monitoringForm" validate="false"
*
* @struts.action-forward name="success" path="tiles:/monitoring/main"
- * @struts.action-forward name="chat_client"
- * path="tiles:/monitoring/chat_client"
- * @struts.action-forward name="chat_history"
- * path="tiles:/monitoring/chat_history"
+ * @struts.action-forward name="chat_client" path="tiles:/monitoring/chat_client"
+ * @struts.action-forward name="chat_history" path="tiles:/monitoring/chat_history"
*
* @struts.action-forward name="notebook" path="tiles:/monitoring/notebook"
*
*/
public class MonitoringAction extends LamsDispatchAction {
- private static Logger log = Logger.getLogger(MonitoringAction.class);
+ private static Logger log = Logger.getLogger(MonitoringAction.class);
- public IChatService chatService;
+ public IChatService chatService;
- public ActionForward unspecified(ActionMapping mapping, ActionForm form,
- HttpServletRequest request, HttpServletResponse response) {
- log.info("excuting monitoring action");
+ @Override
+ public ActionForward unspecified(ActionMapping mapping, ActionForm form, HttpServletRequest request,
+ HttpServletResponse response) {
+ MonitoringAction.log.info("excuting monitoring action");
- Long toolContentID = new Long(WebUtil.readLongParam(request,
- AttributeNames.PARAM_TOOL_CONTENT_ID));
-
- String contentFolderID = WebUtil.readStrParam(request,
- AttributeNames.PARAM_CONTENT_FOLDER_ID);
+ Long toolContentID = new Long(WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_CONTENT_ID));
- // set up chatService
- if (chatService == null) {
- chatService = ChatServiceProxy.getChatService(this.getServlet()
- .getServletContext());
- }
- Chat chat = chatService.getChatByContentId(toolContentID);
- ChatDTO chatDTO = new ChatDTO(chat);
+ String contentFolderID = WebUtil.readStrParam(request, AttributeNames.PARAM_CONTENT_FOLDER_ID);
- Long currentTab = WebUtil.readLongParam(request, AttributeNames.PARAM_CURRENT_TAB,true);
- chatDTO.setCurrentTab(currentTab);
+ // set up chatService
+ if (chatService == null) {
+ chatService = ChatServiceProxy.getChatService(this.getServlet().getServletContext());
+ }
+ Chat chat = chatService.getChatByContentId(toolContentID);
+ ChatDTO chatDTO = new ChatDTO(chat);
- /* Check if submission deadline is null */
-
- Date submissionDeadline = chatDTO.getSubmissionDeadline();
-
- if (submissionDeadline != null) {
-
- HttpSession ss = SessionManager.getSession();
- UserDTO learnerDto = (UserDTO) ss.getAttribute(AttributeNames.USER);
- TimeZone learnerTimeZone = learnerDto.getTimeZone();
- Date tzSubmissionDeadline = DateUtil.convertToTimeZoneFromDefault(learnerTimeZone, submissionDeadline);
- request.setAttribute("submissionDeadline", tzSubmissionDeadline.getTime());
-
- }
-
-
-
- Map sessCountMap = chatService
- .getMessageCountBySession(chat.getUid());
+ Long currentTab = WebUtil.readLongParam(request, AttributeNames.PARAM_CURRENT_TAB, true);
+ chatDTO.setCurrentTab(currentTab);
- for (Iterator sessIter = chat.getChatSessions().iterator(); sessIter
- .hasNext();) {
- ChatSession session = (ChatSession) sessIter.next();
+ /* Check if submission deadline is null */
- List latestMessages = chatService.getLastestMessages(session,
- ChatConstants.MONITORING_SUMMARY_MAX_MESSAGES);
- ChatSessionDTO sessionDTO = new ChatSessionDTO(session,
- latestMessages);
+ Date submissionDeadline = chatDTO.getSubmissionDeadline();
- Integer count = sessCountMap.get(session.getUid());
- if (count == null) {
- count = 0;
- }
- sessionDTO.setNumberOfPosts(count);
+ if (submissionDeadline != null) {
- // constructing userDTOs
- Map userCountMap = chatService
- .getMessageCountByFromUser(session.getUid());
-
- sessionDTO.setNumberOfLearners(userCountMap.size());
-
- for (Iterator userIter = session.getChatUsers().iterator(); userIter
- .hasNext();) {
- ChatUser user = (ChatUser) userIter.next();
- ChatUserDTO userDTO = new ChatUserDTO(user);
- count = userCountMap.get(user.getUid());
- if (count == null) {
- count = 0;
- }
- userDTO.setPostCount(count);
-
- // get the notebook entry.
- NotebookEntry notebookEntry = chatService.getEntry(session.getSessionId(),
- CoreNotebookConstants.NOTEBOOK_TOOL,
- ChatConstants.TOOL_SIGNATURE, user.getUserId()
- .intValue());
- if (notebookEntry != null) {
- userDTO.finishedReflection = true;
- } else {
- userDTO.finishedReflection = false;
- }
-
- sessionDTO.getUserDTOs().add(userDTO);
- }
+ HttpSession ss = SessionManager.getSession();
+ UserDTO learnerDto = (UserDTO) ss.getAttribute(AttributeNames.USER);
+ TimeZone learnerTimeZone = learnerDto.getTimeZone();
+ Date tzSubmissionDeadline = DateUtil.convertToTimeZoneFromDefault(learnerTimeZone, submissionDeadline);
+ request.setAttribute("submissionDeadline", tzSubmissionDeadline.getTime());
- chatDTO.getSessionDTOs().add(sessionDTO);
- }
-
- boolean isGroupedActivity = chatService.isGroupedActivity(toolContentID);
- request.setAttribute("isGroupedActivity", isGroupedActivity);
- request.setAttribute("monitoringDTO", chatDTO);
- request.setAttribute("contentFolderID", contentFolderID);
-
- return mapping.findForward("success");
}
- public ActionForward openChatHistory(ActionMapping mapping,
- ActionForm form, HttpServletRequest request,
- HttpServletResponse response) {
+ Map sessCountMap = chatService.getMessageCountBySession(chat.getUid());
- MonitoringForm monitoringForm = (MonitoringForm) form;
- // TODO check for null from chatService. forward to appropriate page.
- ChatSession chatSession = chatService
- .getSessionBySessionId(monitoringForm.getToolSessionID());
- ChatSessionDTO sessionDTO = new ChatSessionDTO(chatSession);
- request.setAttribute("sessionDTO", sessionDTO);
- return mapping.findForward("chat_history");
- }
-
- public ActionForward openNotebook(ActionMapping mapping,
- ActionForm form, HttpServletRequest request,
- HttpServletResponse response) {
-
- Long uid = WebUtil.readLongParam(request, "uid", false);
-
- ChatUser chatUser = chatService.getUserByUID(uid);
- NotebookEntry notebookEntry = chatService.getEntry(chatUser.getChatSession().getSessionId(), CoreNotebookConstants.NOTEBOOK_TOOL, ChatConstants.TOOL_SIGNATURE, chatUser.getUserId().intValue());
-
- ChatUserDTO chatUserDTO = new ChatUserDTO(chatUser);
- chatUserDTO.setNotebookEntry(notebookEntry.getEntry());
-
- request.setAttribute("chatUserDTO", chatUserDTO);
-
- return mapping.findForward("notebook");
- }
-
- public ActionForward editMessage(ActionMapping mapping, ActionForm form,
- HttpServletRequest request, HttpServletResponse response) {
- MonitoringForm monitoringForm = (MonitoringForm) form;
- ChatMessage chatMessage = chatService.getMessageByUID(monitoringForm
- .getMessageUID());
+ for (Iterator sessIter = chat.getChatSessions().iterator(); sessIter.hasNext();) {
+ ChatSession session = (ChatSession) sessIter.next();
- boolean hasChanged = false;
- if (chatMessage.isHidden() != monitoringForm
- .isMessageHidden()) {
- hasChanged = true;
- chatService.auditHideShowMessage(chatMessage, monitoringForm
- .isMessageHidden());
- }
+ List latestMessages = chatService.getLastestMessages(session, ChatConstants.MONITORING_SUMMARY_MAX_MESSAGES,
+ false);
+ ChatSessionDTO sessionDTO = new ChatSessionDTO(session, latestMessages);
- if (!chatMessage.getBody().equals(monitoringForm.getMessageBody())) {
- hasChanged = true;
- chatService.auditEditMessage(chatMessage, monitoringForm
- .getMessageBody());
+ Integer count = sessCountMap.get(session.getUid());
+ if (count == null) {
+ count = 0;
+ }
+ sessionDTO.setNumberOfPosts(count);
+
+ // constructing userDTOs
+ Map userCountMap = chatService.getMessageCountByFromUser(session.getUid());
+
+ sessionDTO.setNumberOfLearners(userCountMap.size());
+
+ for (Iterator userIter = session.getChatUsers().iterator(); userIter.hasNext();) {
+ ChatUser user = (ChatUser) userIter.next();
+ ChatUserDTO userDTO = new ChatUserDTO(user);
+ count = userCountMap.get(user.getUid());
+ if (count == null) {
+ count = 0;
}
+ userDTO.setPostCount(count);
- if (hasChanged) {
- chatMessage.setBody(monitoringForm.getMessageBody());
- chatMessage.setHidden(monitoringForm.isMessageHidden());
- chatService.saveOrUpdateChatMessage(chatMessage);
+ // get the notebook entry.
+ NotebookEntry notebookEntry = chatService.getEntry(session.getSessionId(),
+ CoreNotebookConstants.NOTEBOOK_TOOL, ChatConstants.TOOL_SIGNATURE, user.getUserId().intValue());
+ if (notebookEntry != null) {
+ userDTO.finishedReflection = true;
+ } else {
+ userDTO.finishedReflection = false;
}
- return openChatHistory(mapping, form, request, response);
+
+ sessionDTO.getUserDTOs().add(userDTO);
+ }
+
+ chatDTO.getSessionDTOs().add(sessionDTO);
}
+ boolean isGroupedActivity = chatService.isGroupedActivity(toolContentID);
+ request.setAttribute("isGroupedActivity", isGroupedActivity);
+ request.setAttribute("monitoringDTO", chatDTO);
+ request.setAttribute("contentFolderID", contentFolderID);
+
+ return mapping.findForward("success");
+ }
+
+ public ActionForward openChatHistory(ActionMapping mapping, ActionForm form, HttpServletRequest request,
+ HttpServletResponse response) {
+
+ MonitoringForm monitoringForm = (MonitoringForm) form;
+ // TODO check for null from chatService. forward to appropriate page.
+ ChatSession chatSession = chatService.getSessionBySessionId(monitoringForm.getToolSessionID());
+ ChatSessionDTO sessionDTO = new ChatSessionDTO(chatSession);
+ request.setAttribute("sessionDTO", sessionDTO);
+ return mapping.findForward("chat_history");
+ }
+
+ public ActionForward openNotebook(ActionMapping mapping, ActionForm form, HttpServletRequest request,
+ HttpServletResponse response) {
+
+ Long uid = WebUtil.readLongParam(request, "uid", false);
+
+ ChatUser chatUser = chatService.getUserByUID(uid);
+ NotebookEntry notebookEntry = chatService.getEntry(chatUser.getChatSession().getSessionId(),
+ CoreNotebookConstants.NOTEBOOK_TOOL, ChatConstants.TOOL_SIGNATURE, chatUser.getUserId().intValue());
+
+ ChatUserDTO chatUserDTO = new ChatUserDTO(chatUser);
+ chatUserDTO.setNotebookEntry(notebookEntry.getEntry());
+
+ request.setAttribute("chatUserDTO", chatUserDTO);
+
+ return mapping.findForward("notebook");
+ }
+
+ public ActionForward editMessage(ActionMapping mapping, ActionForm form, HttpServletRequest request,
+ HttpServletResponse response) {
+ MonitoringForm monitoringForm = (MonitoringForm) form;
+ ChatMessage chatMessage = chatService.getMessageByUID(monitoringForm.getMessageUID());
+
+ boolean hasChanged = false;
+ if (chatMessage.isHidden() != monitoringForm.isMessageHidden()) {
+ hasChanged = true;
+ chatService.auditHideShowMessage(chatMessage, monitoringForm.isMessageHidden());
+ }
+
+ if (!chatMessage.getBody().equals(monitoringForm.getMessageBody())) {
+ hasChanged = true;
+ chatService.auditEditMessage(chatMessage, monitoringForm.getMessageBody());
+ }
+
+ if (hasChanged) {
+ chatMessage.setBody(monitoringForm.getMessageBody());
+ chatMessage.setHidden(monitoringForm.isMessageHidden());
+ chatService.saveOrUpdateChatMessage(chatMessage);
+ }
+ return openChatHistory(mapping, form, request, response);
+ }
+
/**
* Set Submission Deadline
*
@@ -245,48 +225,44 @@
*/
public ActionForward setSubmissionDeadline(ActionMapping mapping, ActionForm form, HttpServletRequest request,
HttpServletResponse response) {
-
- // set up chatService
- if (chatService == null) {
- chatService = ChatServiceProxy.getChatService(this.getServlet()
- .getServletContext());
- }
-
- Long contentID = WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_CONTENT_ID);
- Chat chat = chatService.getChatByContentId(contentID);
-
- Long dateParameter = WebUtil.readLongParam(request, ChatConstants.ATTR_SUBMISSION_DEADLINE, true);
- Date tzSubmissionDeadline = null;
- if (dateParameter != null) {
- Date submissionDeadline = new Date(dateParameter);
- HttpSession ss = SessionManager.getSession();
- UserDTO teacher = (UserDTO) ss.getAttribute(AttributeNames.USER);
- TimeZone teacherTimeZone = teacher.getTimeZone();
- tzSubmissionDeadline = DateUtil.convertFromTimeZoneToDefault(teacherTimeZone, submissionDeadline);
- }
- chat.setSubmissionDeadline(tzSubmissionDeadline);
- chatService.saveOrUpdateChat(chat);
- return null;
- }
+ // set up chatService
+ if (chatService == null) {
+ chatService = ChatServiceProxy.getChatService(this.getServlet().getServletContext());
+ }
-
- /* Private Methods */
+ Long contentID = WebUtil.readLongParam(request, AttributeNames.PARAM_TOOL_CONTENT_ID);
+ Chat chat = chatService.getChatByContentId(contentID);
- private ChatUser getCurrentUser(Long toolSessionId) {
- UserDTO user = (UserDTO) SessionManager.getSession().getAttribute(
- AttributeNames.USER);
+ Long dateParameter = WebUtil.readLongParam(request, ChatConstants.ATTR_SUBMISSION_DEADLINE, true);
+ Date tzSubmissionDeadline = null;
+ if (dateParameter != null) {
+ Date submissionDeadline = new Date(dateParameter);
+ HttpSession ss = SessionManager.getSession();
+ UserDTO teacher = (UserDTO) ss.getAttribute(AttributeNames.USER);
+ TimeZone teacherTimeZone = teacher.getTimeZone();
+ tzSubmissionDeadline = DateUtil.convertFromTimeZoneToDefault(teacherTimeZone, submissionDeadline);
+ }
+ chat.setSubmissionDeadline(tzSubmissionDeadline);
+ chatService.saveOrUpdateChat(chat);
- // attempt to retrieve user using userId and toolSessionId
- ChatUser chatUser = chatService.getUserByUserIdAndSessionId(new Long(
- user.getUserID().intValue()), toolSessionId);
+ return null;
+ }
- if (chatUser == null) {
- ChatSession chatSession = chatService
- .getSessionBySessionId(toolSessionId);
- chatUser = chatService.createChatUser(user, chatSession);
- }
+ /* Private Methods */
- return chatUser;
+ private ChatUser getCurrentUser(Long toolSessionId) {
+ UserDTO user = (UserDTO) SessionManager.getSession().getAttribute(AttributeNames.USER);
+
+ // attempt to retrieve user using userId and toolSessionId
+ ChatUser chatUser = chatService.getUserByUserIdAndSessionId(new Long(user.getUserID().intValue()),
+ toolSessionId);
+
+ if (chatUser == null) {
+ ChatSession chatSession = chatService.getSessionBySessionId(toolSessionId);
+ chatUser = chatService.createChatUser(user, chatSession);
}
+
+ return chatUser;
+ }
}
Index: lams_tool_chat/src/java/org/lamsfoundation/lams/tool/chat/web/servlets/ExportServlet.java
===================================================================
diff -u -ref851974c4dc3f5468b188fab9997a37b73c0e50 -rab2b6923490ce38dc647ea66d6768966fbc40cfd
--- lams_tool_chat/src/java/org/lamsfoundation/lams/tool/chat/web/servlets/ExportServlet.java (.../ExportServlet.java) (revision ef851974c4dc3f5468b188fab9997a37b73c0e50)
+++ lams_tool_chat/src/java/org/lamsfoundation/lams/tool/chat/web/servlets/ExportServlet.java (.../ExportServlet.java) (revision ab2b6923490ce38dc647ea66d6768966fbc40cfd)
@@ -56,147 +56,134 @@
public class ExportServlet extends AbstractExportPortfolioServlet {
- private static final long serialVersionUID = -2829707715037631881L;
+ private static final long serialVersionUID = -2829707715037631881L;
- private static Logger logger = Logger.getLogger(ExportServlet.class);
+ private static Logger logger = Logger.getLogger(ExportServlet.class);
- private final String FILENAME = "chat_main.html";
+ private final String FILENAME = "chat_main.html";
- private IChatService chatService;
+ private IChatService chatService;
- protected String doExport(HttpServletRequest request,
- HttpServletResponse response, String directoryName, Cookie[] cookies) {
+ protected String doExport(HttpServletRequest request, HttpServletResponse response, String directoryName,
+ Cookie[] cookies) {
- if (chatService == null) {
- chatService = ChatServiceProxy.getChatService(getServletContext());
- }
+ if (chatService == null) {
+ chatService = ChatServiceProxy.getChatService(getServletContext());
+ }
- try {
- if (StringUtils.equals(mode, ToolAccessMode.LEARNER.toString())) {
- request.getSession().setAttribute(AttributeNames.ATTR_MODE,
- ToolAccessMode.LEARNER);
- doLearnerExport(request, response, directoryName, cookies);
- } else if (StringUtils.equals(mode, ToolAccessMode.TEACHER
- .toString())) {
- request.getSession().setAttribute(AttributeNames.ATTR_MODE,
- ToolAccessMode.TEACHER);
- doTeacherExport(request, response, directoryName, cookies);
- }
- } catch (ChatException e) {
- logger.error("Cannot perform export for chat tool.");
- }
-
- String basePath = WebUtil.getBaseServerURL() + request.getContextPath();
- writeResponseToFile(basePath + "/pages/export/exportPortfolio.jsp",
- directoryName, FILENAME, cookies);
-
- return FILENAME;
+ try {
+ if (StringUtils.equals(mode, ToolAccessMode.LEARNER.toString())) {
+ request.getSession().setAttribute(AttributeNames.ATTR_MODE, ToolAccessMode.LEARNER);
+ doLearnerExport(request, response, directoryName, cookies);
+ } else if (StringUtils.equals(mode, ToolAccessMode.TEACHER.toString())) {
+ request.getSession().setAttribute(AttributeNames.ATTR_MODE, ToolAccessMode.TEACHER);
+ doTeacherExport(request, response, directoryName, cookies);
+ }
+ } catch (ChatException e) {
+ logger.error("Cannot perform export for chat tool.");
}
- private void doLearnerExport(HttpServletRequest request,
- HttpServletResponse response, String directoryName, Cookie[] cookies)
- throws ChatException {
+ String basePath = WebUtil.getBaseServerURL() + request.getContextPath();
+ writeResponseToFile(basePath + "/pages/export/exportPortfolio.jsp", directoryName, FILENAME, cookies);
- logger.debug("doExportTeacher: toolContentID:" + toolSessionID);
+ return FILENAME;
+ }
- // check if toolContentID available
- if (toolSessionID == null) {
- String error = "Tool Session ID is missing. Unable to continue";
- logger.error(error);
- throw new ChatException(error);
- }
+ private void doLearnerExport(HttpServletRequest request, HttpServletResponse response, String directoryName,
+ Cookie[] cookies) throws ChatException {
- ChatSession chatSession = chatService
- .getSessionBySessionId(toolSessionID);
+ logger.debug("doExportTeacher: toolContentID:" + toolSessionID);
- // get all messages for current user and filter.
- UserDTO user = (UserDTO) SessionManager.getSession().getAttribute(
- AttributeNames.USER);
+ // check if toolContentID available
+ if (toolSessionID == null) {
+ String error = "Tool Session ID is missing. Unable to continue";
+ logger.error(error);
+ throw new ChatException(error);
+ }
- // get the chat user
- ChatUser chatUser = chatService.getUserByUserIdAndSessionId(new Long(
- user.getUserID()), toolSessionID);
+ ChatSession chatSession = chatService.getSessionBySessionId(toolSessionID);
- // get messages for this user.
- List messageList = chatService.getMessagesForUser(chatUser);
+ // get all messages for current user and filter.
+ UserDTO user = (UserDTO) SessionManager.getSession().getAttribute(AttributeNames.USER);
- // construct session DTO.
- ChatSessionDTO sessionDTO = new ChatSessionDTO(chatSession, messageList);
+ // get the chat user
+ ChatUser chatUser = chatService.getUserByUserIdAndSessionId(new Long(user.getUserID()), toolSessionID);
- // if reflectOnActivity is enabled add userDTO.
- if (chatSession.getChat().isReflectOnActivity()) {
- ChatUserDTO chatUserDTO = new ChatUserDTO(chatUser);
+ // get messages for this user.
+ List messageList = chatService.getMessagesForUser(chatUser);
- // get the entry.
- NotebookEntry entry = chatService.getEntry(toolSessionID,
- CoreNotebookConstants.NOTEBOOK_TOOL,
- ChatConstants.TOOL_SIGNATURE, chatUser.getUserId()
- .intValue());
+ // construct session DTO.
+ ChatSessionDTO sessionDTO = new ChatSessionDTO(chatSession, messageList);
- if (entry != null) {
- chatUserDTO.finishedReflection = true;
- chatUserDTO.notebookEntry = entry.getEntry();
- } else {
- chatUserDTO.finishedReflection = false;
- }
- sessionDTO.getUserDTOs().add(chatUserDTO);
- }
+ // if reflectOnActivity is enabled add userDTO.
+ if (chatSession.getChat().isReflectOnActivity()) {
+ ChatUserDTO chatUserDTO = new ChatUserDTO(chatUser);
- // filter messages
- for (ChatMessageDTO msg : sessionDTO.getMessageDTOs()) {
- msg.setBody(chatService.filterMessage(msg.getBody(), chatSession.getChat()));
- }
+ // get the entry.
+ NotebookEntry entry = chatService.getEntry(toolSessionID, CoreNotebookConstants.NOTEBOOK_TOOL,
+ ChatConstants.TOOL_SIGNATURE, chatUser.getUserId().intValue());
- ChatDTO chatDTO = new ChatDTO(chatSession.getChat());
- chatDTO.getSessionDTOs().add(sessionDTO);
+ if (entry != null) {
+ chatUserDTO.finishedReflection = true;
+ chatUserDTO.notebookEntry = entry.getEntry();
+ } else {
+ chatUserDTO.finishedReflection = false;
+ }
+ sessionDTO.getUserDTOs().add(chatUserDTO);
+ }
- request.getSession().setAttribute("chatDTO", chatDTO);
+ // filter messages
+ for (ChatMessageDTO msg : sessionDTO.getMessageDTOs()) {
+ msg.setBody(chatService.filterMessage(msg.getBody(), chatSession.getChat()));
}
- private void doTeacherExport(HttpServletRequest request,
- HttpServletResponse response, String directoryName, Cookie[] cookies)
- throws ChatException {
+ ChatDTO chatDTO = new ChatDTO(chatSession.getChat());
+ chatDTO.getSessionDTOs().add(sessionDTO);
- logger.debug("doExportTeacher: toolContentID:" + toolContentID);
+ request.getSession().setAttribute("chatDTO", chatDTO);
+ }
- // check if toolContentID available
- if (toolContentID == null) {
- String error = "Tool Content ID is missing. Unable to continue";
- logger.error(error);
- throw new ChatException(error);
- }
+ private void doTeacherExport(HttpServletRequest request, HttpServletResponse response, String directoryName,
+ Cookie[] cookies) throws ChatException {
- Chat chat = chatService.getChatByContentId(toolContentID);
- ChatDTO chatDTO = new ChatDTO(chat);
- for (Iterator iter = chat.getChatSessions().iterator(); iter.hasNext();) {
- // NB session DTO will contain all messages in session unfiltered.
+ logger.debug("doExportTeacher: toolContentID:" + toolContentID);
- ChatSession session = (ChatSession) iter.next();
- ChatSessionDTO sessionDTO = new ChatSessionDTO(session);
+ // check if toolContentID available
+ if (toolContentID == null) {
+ String error = "Tool Content ID is missing. Unable to continue";
+ logger.error(error);
+ throw new ChatException(error);
+ }
- // if reflectOnActivity is enabled add all userDTO.
- if (session.getChat().isReflectOnActivity()) {
+ Chat chat = chatService.getChatByContentId(toolContentID);
+ ChatDTO chatDTO = new ChatDTO(chat);
+ for (Iterator iter = chat.getChatSessions().iterator(); iter.hasNext();) {
+ // NB session DTO will contain all messages in session unfiltered.
- for (Iterator iterator = session.getChatUsers().iterator(); iterator
- .hasNext();) {
- ChatUser user = (ChatUser) iterator.next();
- ChatUserDTO userDTO = new ChatUserDTO(user);
- // get the entry.
- NotebookEntry entry = chatService.getEntry(session.getSessionId(),
- CoreNotebookConstants.NOTEBOOK_TOOL,
- ChatConstants.TOOL_SIGNATURE, user.getUserId()
- .intValue());
- if (entry != null) {
- userDTO.finishedReflection = true;
- userDTO.notebookEntry = entry.getEntry();
- } else {
- userDTO.finishedReflection = false;
- }
- sessionDTO.getUserDTOs().add(userDTO);
- }
- }
- chatDTO.getSessionDTOs().add(sessionDTO);
+ ChatSession session = (ChatSession) iter.next();
+ ChatSessionDTO sessionDTO = new ChatSessionDTO(session);
+
+ // if reflectOnActivity is enabled add all userDTO.
+ if (session.getChat().isReflectOnActivity()) {
+
+ for (Iterator iterator = session.getChatUsers().iterator(); iterator.hasNext();) {
+ ChatUser user = (ChatUser) iterator.next();
+ ChatUserDTO userDTO = new ChatUserDTO(user);
+ // get the entry.
+ NotebookEntry entry = chatService.getEntry(session.getSessionId(),
+ CoreNotebookConstants.NOTEBOOK_TOOL, ChatConstants.TOOL_SIGNATURE,
+ user.getUserId().intValue());
+ if (entry != null) {
+ userDTO.finishedReflection = true;
+ userDTO.notebookEntry = entry.getEntry();
+ } else {
+ userDTO.finishedReflection = false;
+ }
+ sessionDTO.getUserDTOs().add(userDTO);
}
- request.getSession().setAttribute("chatDTO", chatDTO);
+ }
+ chatDTO.getSessionDTOs().add(sessionDTO);
}
+ request.getSession().setAttribute("chatDTO", chatDTO);
+ }
}
Index: lams_tool_chat/web/includes/javascript/learning.js
===================================================================
diff -u -ref851974c4dc3f5468b188fab9997a37b73c0e50 -rab2b6923490ce38dc647ea66d6768966fbc40cfd
--- lams_tool_chat/web/includes/javascript/learning.js (.../learning.js) (revision ef851974c4dc3f5468b188fab9997a37b73c0e50)
+++ lams_tool_chat/web/includes/javascript/learning.js (.../learning.js) (revision ab2b6923490ce38dc647ea66d6768966fbc40cfd)
@@ -1,73 +1,74 @@
-// for chat users to be indetified by different colours
-var PALETTE = ["#008CD2", "#DF7C08", "#83B532", "#E0BE40", "#AE8124", "#5F0704", "#004272", "#CD322B", "#254806"];
-// only Monitor can send a personal message
-var selectedUser = null;
-// last message in chat window
-var lastMessageUid = null;
-var pollInProgress = false;
+$(document).ready(function() {
+ messageDiv = $("#messages");
+ rosterDiv = $("#roster");
+ sendToUserSpan = $('#sendToUser');
+ sendToEveryoneSpan = $('#sendToEveryone');
+ sendMessageArea = $('#sendMessageArea');
+ sendMessageButton = $('#sendMessageButton');
-function updateChat() {
- if (!pollInProgress) {
- // synchronise: if polling takes too long, don't try to do it again
- pollInProgress = true;
- $.ajax({
- url : LEARNING_ACTION,
- data : {'dispatch' : 'getChatContent',
- 'toolSessionID' : TOOL_SESSION_ID,
- 'lastMessageUid' : lastMessageUid
- },
- cache : false,
- dataType : 'json',
- success : handleUpdateChatResult,
- complete : function(){
- pollInProgress = false;
- }
- });
- }
-}
+ // react to Enter key
+ sendMessageArea.keydown(function(e) {
+ if (e.which == 13) {
+ e.preventDefault();
+ sendMessage();
+ }
+ });
+});
-function handleUpdateChatResult(result) {
- if (result.lastMessageUid) {
- messageDiv.html('');
- // all messasges need to be written out, not only new ones,
- // as old ones could have been edited or hidden by Monitor
-
- jQuery.each(result.messages, function(){
+
+ // for chat users to be indetified by different colours
+var PALETTE = ["#008CD2", "#DF7C08", "#83B532", "#E0BE40", "#AE8124", "#5F0704", "#004272", "#CD322B", "#254806"],
+ // only Monitor can send a personal message
+ selectedUser = null,
+ // init the connection with server using server URL but with different protocol
+ websocket = new WebSocket(APP_URL.replace('http', 'ws') + 'learningWebsocket?toolSessionID=' + TOOL_SESSION_ID);
+
+websocket.onmessage = function(e){
+ // create JSON object
+ var input = JSON.parse(e.data);
+ // clear old messages
+ messageDiv.html('');
+
+ // all messasges need to be written out, not only new ones,
+ // as old ones could have been edited or hidden by Monitor
+ jQuery.each(input.messages, function(){
var container = $('',{
'class' : 'message ' + (this.type == 'chat' ? 'private_message' : '')
- });
+ });
$('',{
'class' : 'messageFrom',
'text' : this.from
- }).css('color' , getColour(this.from)).appendTo(container);
+ }).css('color' , getColour(this.from)).appendTo(container);
$('',{
'text' : this.body
- }).appendTo(container);
-
+ }).appendTo(container);
+
container.appendTo(messageDiv);
- });
-
- lastMessageUid = result.lastMessageUid;
- messageDiv.scrollTop(messageDiv.prop('scrollHeight'));
- }
+ });
- rosterDiv.html('');
- jQuery.each(result.roster, function(index, value){
- var userDiv = $('', {
- 'class' : (value == selectedUser ? 'selected' : 'unselected'),
- 'text' : value
- }).css('color', getColour(value))
- .appendTo(rosterDiv);
-
- // only Monitor can send a personal message
- if (MODE == 'teacher') {
- userDiv.click(function(){
- userSelected($(this));
- });
- }
- });
+ // move to the bottom
+ messageDiv.scrollTop(messageDiv.prop('scrollHeight'));
+ rosterDiv.html('');
+ jQuery.each(input.roster, function(index, value){
+ var userDiv = $('', {
+ 'class' : (value == selectedUser ? 'selected' : 'unselected'),
+ 'text' : value
+ }).css('color', getColour(value))
+ .appendTo(rosterDiv);
+
+ // only Monitor can send a personal message
+ if (MODE == 'teacher') {
+ userDiv.click(function(){
+ userSelected($(this));
+ });
+ }
+ });
}
+websocket.onerror = function(e){
+ alert("Error estabilishing connection to server: " + e.data);
+}
+
function userSelected(userDiv) {
var userDivContent = userDiv.html();
// is Monitor clicked the already selectedd user, desect him and make message go to everyone
@@ -91,18 +92,15 @@
sendMessageArea.val('');
// only Monitor can send a personal message
- var isPrivate = MODE == 'teacher' && selectedUser;
+ var isPrivate = MODE == 'teacher' && selectedUser,
+ output = {
+ 'toolSessionID' : TOOL_SESSION_ID,
+ 'toUser' : isPrivate ? selectedUser : '',
+ 'message' : isPrivate ? '[' + selectedUser + '] ' + message : message
+ };
- $.ajax({
- url : LEARNING_ACTION,
- data : {'dispatch' : 'sendMessage',
- 'toolSessionID' : TOOL_SESSION_ID,
- 'message' : isPrivate ? '[' + selectedUser + '] ' + message : message,
- 'user' : isPrivate ? selectedUser : null
- },
- cache : false,
- success : updateChat
- });
+ // send it to server
+ websocket.send(JSON.stringify(output));
}
function getColour(nick) {
Index: lams_tool_chat/web/pages/learning/learning.jsp
===================================================================
diff -u -r98424ecde9e3fa1c56c4477b6a555bdfe0a310d2 -rab2b6923490ce38dc647ea66d6768966fbc40cfd
--- lams_tool_chat/web/pages/learning/learning.jsp (.../learning.jsp) (revision 98424ecde9e3fa1c56c4477b6a555bdfe0a310d2)
+++ lams_tool_chat/web/pages/learning/learning.jsp (.../learning.jsp) (revision ab2b6923490ce38dc647ea66d6768966fbc40cfd)
@@ -1,33 +1,13 @@
<%@ include file="/common/taglibs.jsp"%>
-
+