You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openmeetings.apache.org by so...@apache.org on 2018/02/25 15:01:55 UTC

[openmeetings] branch master updated (a2e2095 -> 202b74f)

This is an automated email from the ASF dual-hosted git repository.

solomax pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/openmeetings.git.


    from a2e2095  Documentation update: 4.0.2 release
     new 9ee9c31  [OPENMEETINGS-1791] polls menu is extracted from Actions
     new be11b9f  [OPENMEETINGS-1791] quick poll menu item and labels are added
     new 92c2cee  [OPENMEETINGS-1791] hazelcast related maps are refactored
     new 202b74f  [OPENMEETINGS-1791] quick polls seems to work

The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 ...pLoginManagement.java => LdapLoginManager.java} |   6 +-
 .../apache/openmeetings/core/ldap/LdapOptions.java |   6 +-
 .../openmeetings/core/remote/MobileService.java    |  26 +-
 .../core/remote/ScopeApplicationAdapter.java       |  82 +--
 .../core/service/RecordingService.java             |  31 +-
 .../openmeetings/core/session/SessionManager.java  | 162 ------
 .../openmeetings/core/util/WebSocketHelper.java    |   5 +-
 .../java/org/apache/openmeetings/IApplication.java |  26 -
 .../openmeetings/db/dao/server/SessiondataDao.java |   5 +-
 .../openmeetings/db/entity/basic/Client.java       |   4 +-
 .../IClientManager.java}                           |  35 +-
 .../IStreamClientManager.java}                     |  37 +-
 .../db/manager/IWhiteboardManager.java             |  12 +-
 .../apache/openmeetings/db/util/RoomHelper.java    |   4 +-
 .../openmeetings/db/util/ws/RoomMessage.java       |   1 +
 .../java/org/apache/openmeetings/cli/Admin.java    |   4 +-
 .../service/quartz/scheduler/CleanupJob.java       |  12 +-
 .../openmeetings/service/user/UserManager.java     |  12 +-
 openmeetings-web/pom.xml                           |   3 +
 .../web/admin/connection/ConnectionsPanel.java     |  10 +-
 .../openmeetings/web/admin/rooms/RoomForm.java     |   4 +-
 .../apache/openmeetings/web/app/Application.java   | 393 +-------------
 .../web/app/Application.properties.xml             |   3 +
 .../web/app/Application_ar.properties.xml          |   3 +
 .../web/app/Application_bg.properties.xml          |   3 +
 .../web/app/Application_ca.properties.xml          |   3 +
 .../web/app/Application_cs.properties.xml          |   3 +
 .../web/app/Application_da.properties.xml          |   3 +
 .../web/app/Application_de.properties.xml          |   3 +
 .../web/app/Application_el.properties.xml          |   3 +
 .../web/app/Application_es.properties.xml          |   3 +
 .../web/app/Application_fa.properties.xml          |   3 +
 .../web/app/Application_fi.properties.xml          |   3 +
 .../web/app/Application_fr.properties.xml          |   3 +
 .../web/app/Application_gl.properties.xml          |   3 +
 .../web/app/Application_he.properties.xml          |   3 +
 .../web/app/Application_hu.properties.xml          |   3 +
 .../web/app/Application_id.properties.xml          |   3 +
 .../web/app/Application_it.properties.xml          |   3 +
 .../web/app/Application_ja.properties.xml          |   3 +
 .../web/app/Application_ko.properties.xml          |   3 +
 .../web/app/Application_nl.properties.xml          |   3 +
 .../web/app/Application_pl.properties.xml          |   3 +
 .../web/app/Application_pt.properties.xml          |   3 +
 .../web/app/Application_pt_BR.properties.xml       |   3 +
 .../web/app/Application_ru.properties.xml          |   3 +
 .../web/app/Application_sk.properties.xml          |   3 +
 .../web/app/Application_sv.properties.xml          |   3 +
 .../web/app/Application_th.properties.xml          |   3 +
 .../web/app/Application_tr.properties.xml          |   3 +
 .../web/app/Application_uk.properties.xml          |   3 +
 .../web/app/Application_zh_CN.properties.xml       |   3 +
 .../web/app/Application_zh_TW.properties.xml       |   3 +
 .../apache/openmeetings/web/app/ClientManager.java | 287 ++++++++++
 .../openmeetings/web/app/QuickPollManager.java     | 110 ++++
 .../openmeetings/web/app/StreamClientManager.java  | 303 +++++++++++
 .../apache/openmeetings/web/app/WebSession.java    |   6 +-
 .../openmeetings/web/app/WhiteboardManager.java    |  51 +-
 .../apache/openmeetings/web/common/MainPanel.java  |   9 +-
 .../openmeetings/web/room/NicknameDialog.java      |   5 +-
 .../openmeetings/web/room/RoomBroadcaster.java     |  13 +-
 .../apache/openmeetings/web/room/RoomPanel.html    |   9 +
 .../apache/openmeetings/web/room/RoomPanel.java    | 100 ++--
 .../web/room/RoomResourceReference.java            |   8 +-
 .../openmeetings/web/room/VideoSettings.java       |   4 +-
 .../web/room/activities/ActivitiesPanel.java       |   5 +-
 .../openmeetings/web/room/menu/PollsSubMenu.java   | 174 ++++++
 .../openmeetings/web/room/menu/RoomMenuPanel.java  |  89 +--
 .../web/room/menu/StartSharingButton.java          |  14 +-
 .../web/room/poll/PollResultsDialog.java           |  12 +-
 .../org/apache/openmeetings/web/room/room-base.js  | 598 ++-------------------
 .../openmeetings/web/room/sidebar/RoomSidebar.java |  17 +-
 .../web/room/sidebar/icon/ClientIcon.java          |   5 +-
 .../apache/openmeetings/web/room/video-manager.js  | 169 ++++++
 .../org/apache/openmeetings/web/room/video-util.js | 111 ++++
 .../java/org/apache/openmeetings/web/room/video.js | 268 +++++++++
 .../openmeetings/web/room/wb/InterviewWbPanel.java |   6 +-
 .../apache/openmeetings/web/room/wb/WbPanel.java   |  80 +--
 .../apache/openmeetings/web/user/chat/Chat.java    |   4 +-
 .../openmeetings/web/user/chat/ChatForm.java       |   4 +-
 .../web/user/profile/UserSearchPanel.java          |   4 +-
 .../user/record/RecordingResourceReference.java    |   8 +-
 .../openmeetings/web/user/rooms/RoomListPanel.java |   7 +-
 .../openmeetings/web/user/rooms/RoomsPanel.java    |   4 +-
 openmeetings-web/src/main/webapp/css/wb.css        |  26 +
 .../openmeetings/webservice/RoomWebService.java    |   5 +-
 .../openmeetings/webservice/UserWebService.java    |   3 +-
 87 files changed, 1975 insertions(+), 1516 deletions(-)
 rename openmeetings-core/src/main/java/org/apache/openmeetings/core/ldap/{LdapLoginManagement.java => LdapLoginManager.java} (99%)
 delete mode 100644 openmeetings-core/src/main/java/org/apache/openmeetings/core/session/SessionManager.java
 copy openmeetings-db/src/main/java/org/apache/openmeetings/db/{util/ws/TextRoomMessage.java => manager/IClientManager.java} (62%)
 rename openmeetings-db/src/main/java/org/apache/openmeetings/db/{dao/server/ISessionManager.java => manager/IStreamClientManager.java} (85%)
 copy openmeetings-core/src/test/java/org/apache/openmeetings/TestConnection.java => openmeetings-db/src/main/java/org/apache/openmeetings/db/manager/IWhiteboardManager.java (82%)
 create mode 100644 openmeetings-web/src/main/java/org/apache/openmeetings/web/app/ClientManager.java
 create mode 100644 openmeetings-web/src/main/java/org/apache/openmeetings/web/app/QuickPollManager.java
 create mode 100644 openmeetings-web/src/main/java/org/apache/openmeetings/web/app/StreamClientManager.java
 rename openmeetings-core/src/main/java/org/apache/openmeetings/core/data/whiteboard/WhiteboardCache.java => openmeetings-web/src/main/java/org/apache/openmeetings/web/app/WhiteboardManager.java (68%)
 create mode 100644 openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/PollsSubMenu.java
 create mode 100644 openmeetings-web/src/main/java/org/apache/openmeetings/web/room/video-manager.js
 create mode 100644 openmeetings-web/src/main/java/org/apache/openmeetings/web/room/video-util.js
 create mode 100644 openmeetings-web/src/main/java/org/apache/openmeetings/web/room/video.js

-- 
To stop receiving notification emails like this one, please contact
solomax@apache.org.

[openmeetings] 02/04: [OPENMEETINGS-1791] quick poll menu item and labels are added

Posted by so...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

solomax pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/openmeetings.git

commit be11b9f4e66f2651490281ac8754257d4176be23
Author: Maxim Solodovnik <so...@gmail.com>
AuthorDate: Thu Jan 11 22:05:17 2018 +0700

    [OPENMEETINGS-1791] quick poll menu item and labels are added
---
 .../apache/openmeetings/web/app/Application.properties.xml   |  2 ++
 .../openmeetings/web/app/Application_ar.properties.xml       |  2 ++
 .../openmeetings/web/app/Application_bg.properties.xml       |  2 ++
 .../openmeetings/web/app/Application_ca.properties.xml       |  2 ++
 .../openmeetings/web/app/Application_cs.properties.xml       |  2 ++
 .../openmeetings/web/app/Application_da.properties.xml       |  2 ++
 .../openmeetings/web/app/Application_de.properties.xml       |  2 ++
 .../openmeetings/web/app/Application_el.properties.xml       |  2 ++
 .../openmeetings/web/app/Application_es.properties.xml       |  2 ++
 .../openmeetings/web/app/Application_fa.properties.xml       |  2 ++
 .../openmeetings/web/app/Application_fi.properties.xml       |  2 ++
 .../openmeetings/web/app/Application_fr.properties.xml       |  2 ++
 .../openmeetings/web/app/Application_gl.properties.xml       |  2 ++
 .../openmeetings/web/app/Application_he.properties.xml       |  2 ++
 .../openmeetings/web/app/Application_hu.properties.xml       |  2 ++
 .../openmeetings/web/app/Application_id.properties.xml       |  2 ++
 .../openmeetings/web/app/Application_it.properties.xml       |  2 ++
 .../openmeetings/web/app/Application_ja.properties.xml       |  2 ++
 .../openmeetings/web/app/Application_ko.properties.xml       |  2 ++
 .../openmeetings/web/app/Application_nl.properties.xml       |  2 ++
 .../openmeetings/web/app/Application_pl.properties.xml       |  2 ++
 .../openmeetings/web/app/Application_pt.properties.xml       |  2 ++
 .../openmeetings/web/app/Application_pt_BR.properties.xml    |  2 ++
 .../openmeetings/web/app/Application_ru.properties.xml       |  2 ++
 .../openmeetings/web/app/Application_sk.properties.xml       |  2 ++
 .../openmeetings/web/app/Application_sv.properties.xml       |  2 ++
 .../openmeetings/web/app/Application_th.properties.xml       |  2 ++
 .../openmeetings/web/app/Application_tr.properties.xml       |  2 ++
 .../openmeetings/web/app/Application_uk.properties.xml       |  2 ++
 .../openmeetings/web/app/Application_zh_CN.properties.xml    |  2 ++
 .../openmeetings/web/app/Application_zh_TW.properties.xml    |  2 ++
 .../org/apache/openmeetings/web/room/menu/RoomMenuPanel.java | 12 ++++++++++++
 32 files changed, 74 insertions(+)

diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application.properties.xml
index 18c2c3b..38b1d9e 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application.properties.xml
@@ -1006,4 +1006,6 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
 	<entry key="menu.polls"><![CDATA[Polls]]></entry>
+	<entry key="menu.polls.quick.title"><![CDATA[Create Quick Poll]]></entry>
+	<entry key="menu.polls.quick.descr"><![CDATA[Gather feedback without creating a poll]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_ar.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_ar.properties.xml
index 496dda7..a578f36 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_ar.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_ar.properties.xml
@@ -1006,4 +1006,6 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
 	<entry key="menu.polls"><![CDATA[Polls]]></entry>
+	<entry key="menu.polls.quick.title"><![CDATA[Create Quick Poll]]></entry>
+	<entry key="menu.polls.quick.descr"><![CDATA[Gather feedback without creating a poll]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_bg.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_bg.properties.xml
index f19111e..8152706 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_bg.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_bg.properties.xml
@@ -1006,4 +1006,6 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
 	<entry key="menu.polls"><![CDATA[Polls]]></entry>
+	<entry key="menu.polls.quick.title"><![CDATA[Create Quick Poll]]></entry>
+	<entry key="menu.polls.quick.descr"><![CDATA[Gather feedback without creating a poll]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_ca.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_ca.properties.xml
index 1cc7942..dc492fd 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_ca.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_ca.properties.xml
@@ -1006,4 +1006,6 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
 	<entry key="menu.polls"><![CDATA[Polls]]></entry>
+	<entry key="menu.polls.quick.title"><![CDATA[Create Quick Poll]]></entry>
+	<entry key="menu.polls.quick.descr"><![CDATA[Gather feedback without creating a poll]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_cs.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_cs.properties.xml
index 2083d2e..e7d8b30 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_cs.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_cs.properties.xml
@@ -1006,4 +1006,6 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
 	<entry key="menu.polls"><![CDATA[Polls]]></entry>
+	<entry key="menu.polls.quick.title"><![CDATA[Create Quick Poll]]></entry>
+	<entry key="menu.polls.quick.descr"><![CDATA[Gather feedback without creating a poll]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_da.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_da.properties.xml
index a09489d..dfd7056 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_da.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_da.properties.xml
@@ -1006,4 +1006,6 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
 	<entry key="menu.polls"><![CDATA[Polls]]></entry>
+	<entry key="menu.polls.quick.title"><![CDATA[Create Quick Poll]]></entry>
+	<entry key="menu.polls.quick.descr"><![CDATA[Gather feedback without creating a poll]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_de.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_de.properties.xml
index d09c91f..f17b2cc 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_de.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_de.properties.xml
@@ -1011,4 +1011,6 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
 	<entry key="menu.polls"><![CDATA[Polls]]></entry>
+	<entry key="menu.polls.quick.title"><![CDATA[Create Quick Poll]]></entry>
+	<entry key="menu.polls.quick.descr"><![CDATA[Gather feedback without creating a poll]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_el.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_el.properties.xml
index 442242e..89c99f7 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_el.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_el.properties.xml
@@ -1006,4 +1006,6 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
 	<entry key="menu.polls"><![CDATA[Polls]]></entry>
+	<entry key="menu.polls.quick.title"><![CDATA[Create Quick Poll]]></entry>
+	<entry key="menu.polls.quick.descr"><![CDATA[Gather feedback without creating a poll]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_es.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_es.properties.xml
index 050d51e..a8458c9 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_es.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_es.properties.xml
@@ -1004,4 +1004,6 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
 	<entry key="menu.polls"><![CDATA[Polls]]></entry>
+	<entry key="menu.polls.quick.title"><![CDATA[Create Quick Poll]]></entry>
+	<entry key="menu.polls.quick.descr"><![CDATA[Gather feedback without creating a poll]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_fa.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_fa.properties.xml
index 7583812..c71b38a 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_fa.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_fa.properties.xml
@@ -998,4 +998,6 @@ target="_blank">Custom Crypt Mechanism</a>
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
 	<entry key="menu.polls"><![CDATA[Polls]]></entry>
+	<entry key="menu.polls.quick.title"><![CDATA[Create Quick Poll]]></entry>
+	<entry key="menu.polls.quick.descr"><![CDATA[Gather feedback without creating a poll]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_fi.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_fi.properties.xml
index 912ae5a..1f6dea4 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_fi.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_fi.properties.xml
@@ -1006,4 +1006,6 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
 	<entry key="menu.polls"><![CDATA[Polls]]></entry>
+	<entry key="menu.polls.quick.title"><![CDATA[Create Quick Poll]]></entry>
+	<entry key="menu.polls.quick.descr"><![CDATA[Gather feedback without creating a poll]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_fr.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_fr.properties.xml
index fda19b4..03920a7 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_fr.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_fr.properties.xml
@@ -998,4 +998,6 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
 	<entry key="menu.polls"><![CDATA[Polls]]></entry>
+	<entry key="menu.polls.quick.title"><![CDATA[Create Quick Poll]]></entry>
+	<entry key="menu.polls.quick.descr"><![CDATA[Gather feedback without creating a poll]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_gl.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_gl.properties.xml
index c45c788..de449db 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_gl.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_gl.properties.xml
@@ -1006,4 +1006,6 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
 	<entry key="menu.polls"><![CDATA[Polls]]></entry>
+	<entry key="menu.polls.quick.title"><![CDATA[Create Quick Poll]]></entry>
+	<entry key="menu.polls.quick.descr"><![CDATA[Gather feedback without creating a poll]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_he.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_he.properties.xml
index 18c2c3b..38b1d9e 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_he.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_he.properties.xml
@@ -1006,4 +1006,6 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
 	<entry key="menu.polls"><![CDATA[Polls]]></entry>
+	<entry key="menu.polls.quick.title"><![CDATA[Create Quick Poll]]></entry>
+	<entry key="menu.polls.quick.descr"><![CDATA[Gather feedback without creating a poll]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_hu.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_hu.properties.xml
index b76c80b..9d0c205 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_hu.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_hu.properties.xml
@@ -994,4 +994,6 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
 	<entry key="menu.polls"><![CDATA[Polls]]></entry>
+	<entry key="menu.polls.quick.title"><![CDATA[Create Quick Poll]]></entry>
+	<entry key="menu.polls.quick.descr"><![CDATA[Gather feedback without creating a poll]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_id.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_id.properties.xml
index 2a42eec..91fc993 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_id.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_id.properties.xml
@@ -1006,4 +1006,6 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
 	<entry key="menu.polls"><![CDATA[Polls]]></entry>
+	<entry key="menu.polls.quick.title"><![CDATA[Create Quick Poll]]></entry>
+	<entry key="menu.polls.quick.descr"><![CDATA[Gather feedback without creating a poll]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_it.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_it.properties.xml
index 17beae1..b671d17 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_it.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_it.properties.xml
@@ -1007,4 +1007,6 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
 	<entry key="menu.polls"><![CDATA[Polls]]></entry>
+	<entry key="menu.polls.quick.title"><![CDATA[Create Quick Poll]]></entry>
+	<entry key="menu.polls.quick.descr"><![CDATA[Gather feedback without creating a poll]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_ja.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_ja.properties.xml
index a7ad255..3d4012d 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_ja.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_ja.properties.xml
@@ -1006,4 +1006,6 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
 	<entry key="menu.polls"><![CDATA[Polls]]></entry>
+	<entry key="menu.polls.quick.title"><![CDATA[Create Quick Poll]]></entry>
+	<entry key="menu.polls.quick.descr"><![CDATA[Gather feedback without creating a poll]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_ko.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_ko.properties.xml
index 87a2985..1ec4b38 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_ko.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_ko.properties.xml
@@ -1006,4 +1006,6 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
 	<entry key="menu.polls"><![CDATA[Polls]]></entry>
+	<entry key="menu.polls.quick.title"><![CDATA[Create Quick Poll]]></entry>
+	<entry key="menu.polls.quick.descr"><![CDATA[Gather feedback without creating a poll]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_nl.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_nl.properties.xml
index bdd4173..f94c27d 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_nl.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_nl.properties.xml
@@ -1006,4 +1006,6 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
 	<entry key="menu.polls"><![CDATA[Polls]]></entry>
+	<entry key="menu.polls.quick.title"><![CDATA[Create Quick Poll]]></entry>
+	<entry key="menu.polls.quick.descr"><![CDATA[Gather feedback without creating a poll]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_pl.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_pl.properties.xml
index 938fa48..b03a26f 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_pl.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_pl.properties.xml
@@ -1006,4 +1006,6 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
 	<entry key="menu.polls"><![CDATA[Polls]]></entry>
+	<entry key="menu.polls.quick.title"><![CDATA[Create Quick Poll]]></entry>
+	<entry key="menu.polls.quick.descr"><![CDATA[Gather feedback without creating a poll]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_pt.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_pt.properties.xml
index 3cd7ec9..f776aa3 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_pt.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_pt.properties.xml
@@ -1006,4 +1006,6 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
 	<entry key="menu.polls"><![CDATA[Polls]]></entry>
+	<entry key="menu.polls.quick.title"><![CDATA[Create Quick Poll]]></entry>
+	<entry key="menu.polls.quick.descr"><![CDATA[Gather feedback without creating a poll]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_pt_BR.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_pt_BR.properties.xml
index 6772054..19788aa 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_pt_BR.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_pt_BR.properties.xml
@@ -1006,4 +1006,6 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
 	<entry key="menu.polls"><![CDATA[Polls]]></entry>
+	<entry key="menu.polls.quick.title"><![CDATA[Create Quick Poll]]></entry>
+	<entry key="menu.polls.quick.descr"><![CDATA[Gather feedback without creating a poll]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_ru.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_ru.properties.xml
index c6dfc77..2cfaf8a 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_ru.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_ru.properties.xml
@@ -1007,4 +1007,6 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="send.on.enter"><![CDATA[Отправить по Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Отправить по Ctrl+Enter]]></entry>
 	<entry key="menu.polls"><![CDATA[Голосования]]></entry>
+	<entry key="menu.polls.quick.title"><![CDATA[Создать быстрый опрос]]></entry>
+	<entry key="menu.polls.quick.descr"><![CDATA[Собрать отзывы без создания голосования]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_sk.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_sk.properties.xml
index 3d67bb6..1f28fae 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_sk.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_sk.properties.xml
@@ -1006,4 +1006,6 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
 	<entry key="menu.polls"><![CDATA[Polls]]></entry>
+	<entry key="menu.polls.quick.title"><![CDATA[Create Quick Poll]]></entry>
+	<entry key="menu.polls.quick.descr"><![CDATA[Gather feedback without creating a poll]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_sv.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_sv.properties.xml
index 71d8cc9..88b0a70 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_sv.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_sv.properties.xml
@@ -1006,4 +1006,6 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
 	<entry key="menu.polls"><![CDATA[Polls]]></entry>
+	<entry key="menu.polls.quick.title"><![CDATA[Create Quick Poll]]></entry>
+	<entry key="menu.polls.quick.descr"><![CDATA[Gather feedback without creating a poll]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_th.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_th.properties.xml
index ce97830..68c4d52 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_th.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_th.properties.xml
@@ -1006,4 +1006,6 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
 	<entry key="menu.polls"><![CDATA[Polls]]></entry>
+	<entry key="menu.polls.quick.title"><![CDATA[Create Quick Poll]]></entry>
+	<entry key="menu.polls.quick.descr"><![CDATA[Gather feedback without creating a poll]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_tr.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_tr.properties.xml
index 6cb17c0..6c22637 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_tr.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_tr.properties.xml
@@ -1006,4 +1006,6 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
 	<entry key="menu.polls"><![CDATA[Polls]]></entry>
+	<entry key="menu.polls.quick.title"><![CDATA[Create Quick Poll]]></entry>
+	<entry key="menu.polls.quick.descr"><![CDATA[Gather feedback without creating a poll]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_uk.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_uk.properties.xml
index b2757ee..35ad1db 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_uk.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_uk.properties.xml
@@ -1007,4 +1007,6 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
 	<entry key="menu.polls"><![CDATA[Polls]]></entry>
+	<entry key="menu.polls.quick.title"><![CDATA[Create Quick Poll]]></entry>
+	<entry key="menu.polls.quick.descr"><![CDATA[Gather feedback without creating a poll]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_zh_CN.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_zh_CN.properties.xml
index 75f795e..8acdf99 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_zh_CN.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_zh_CN.properties.xml
@@ -996,4 +996,6 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
 	<entry key="menu.polls"><![CDATA[Polls]]></entry>
+	<entry key="menu.polls.quick.title"><![CDATA[Create Quick Poll]]></entry>
+	<entry key="menu.polls.quick.descr"><![CDATA[Gather feedback without creating a poll]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_zh_TW.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_zh_TW.properties.xml
index 39c008d..3496640 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_zh_TW.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_zh_TW.properties.xml
@@ -1006,4 +1006,6 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
 	<entry key="menu.polls"><![CDATA[Polls]]></entry>
+	<entry key="menu.polls.quick.title"><![CDATA[Create Quick Poll]]></entry>
+	<entry key="menu.polls.quick.descr"><![CDATA[Gather feedback without creating a poll]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/RoomMenuPanel.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/RoomMenuPanel.java
index fd1ba8e..655c234 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/RoomMenuPanel.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/RoomMenuPanel.java
@@ -107,6 +107,7 @@ public class RoomMenuPanel extends Panel {
 	private RoomMenuItem applyModerMenuItem;
 	private RoomMenuItem applyWbMenuItem;
 	private RoomMenuItem applyAvMenuItem;
+	private RoomMenuItem pollQuickMenuItem;
 	private RoomMenuItem pollCreateMenuItem;
 	private RoomMenuItem pollVoteMenuItem;
 	private RoomMenuItem pollResultMenuItem;
@@ -205,6 +206,15 @@ public class RoomMenuPanel extends Panel {
 				room.requestRight(Room.Right.video, target);
 			}
 		};
+		pollQuickMenuItem = new RoomMenuItem(getString("menu.polls.quick.title"), getString("menu.polls.quick.descr"), false) {
+			private static final long serialVersionUID = 1L;
+
+			@Override
+			public void onClick(AjaxRequestTarget target) {
+				//createPoll.updateModel(target);
+				//createPoll.open(target);
+			}
+		};
 		pollCreateMenuItem = new RoomMenuItem(getString("24"), getString("1483"), false) {
 			private static final long serialVersionUID = 1L;
 
@@ -319,6 +329,7 @@ public class RoomMenuPanel extends Panel {
 		menu.add(actionsMenu);
 
 		pollsMenu.setTop(true);
+		pollsMenu.getItems().add(pollQuickMenuItem);
 		pollsMenu.getItems().add(pollCreateMenuItem);
 		pollsMenu.getItems().add(pollResultMenuItem);
 		pollsMenu.getItems().add(pollVoteMenuItem);
@@ -350,6 +361,7 @@ public class RoomMenuPanel extends Panel {
 		applyModerMenuItem.setEnabled(!moder);
 		applyWbMenuItem.setEnabled(!room.getClient().hasRight(Room.Right.whiteBoard));
 		applyAvMenuItem.setEnabled(!room.getClient().hasRight(Room.Right.audio) || !room.getClient().hasRight(Room.Right.video));
+		pollQuickMenuItem.setEnabled(moder);
 		pollCreateMenuItem.setEnabled(moder);
 		pollVoteMenuItem.setEnabled(pollExists && notExternalUser && !pollDao.hasVoted(r.getId(), getUserId()));
 		pollResultMenuItem.setEnabled(pollExists || !pollDao.getArchived(r.getId()).isEmpty());

-- 
To stop receiving notification emails like this one, please contact
solomax@apache.org.

[openmeetings] 01/04: [OPENMEETINGS-1791] polls menu is extracted from Actions

Posted by so...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

solomax pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/openmeetings.git

commit 9ee9c31bbc74cd18d580aba5ee3b4612924f8831
Author: Maxim Solodovnik <so...@gmail.com>
AuthorDate: Sat Jan 6 13:27:33 2018 +0700

    [OPENMEETINGS-1791] polls menu is extracted from Actions
---
 .../apache/openmeetings/web/app/Application.properties.xml  |  1 +
 .../openmeetings/web/app/Application_ar.properties.xml      |  1 +
 .../openmeetings/web/app/Application_bg.properties.xml      |  1 +
 .../openmeetings/web/app/Application_ca.properties.xml      |  1 +
 .../openmeetings/web/app/Application_cs.properties.xml      |  1 +
 .../openmeetings/web/app/Application_da.properties.xml      |  1 +
 .../openmeetings/web/app/Application_de.properties.xml      |  1 +
 .../openmeetings/web/app/Application_el.properties.xml      |  1 +
 .../openmeetings/web/app/Application_es.properties.xml      |  1 +
 .../openmeetings/web/app/Application_fa.properties.xml      |  1 +
 .../openmeetings/web/app/Application_fi.properties.xml      |  1 +
 .../openmeetings/web/app/Application_fr.properties.xml      |  1 +
 .../openmeetings/web/app/Application_gl.properties.xml      |  1 +
 .../openmeetings/web/app/Application_he.properties.xml      |  1 +
 .../openmeetings/web/app/Application_hu.properties.xml      |  1 +
 .../openmeetings/web/app/Application_id.properties.xml      |  1 +
 .../openmeetings/web/app/Application_it.properties.xml      |  1 +
 .../openmeetings/web/app/Application_ja.properties.xml      |  1 +
 .../openmeetings/web/app/Application_ko.properties.xml      |  1 +
 .../openmeetings/web/app/Application_nl.properties.xml      |  1 +
 .../openmeetings/web/app/Application_pl.properties.xml      |  1 +
 .../openmeetings/web/app/Application_pt.properties.xml      |  1 +
 .../openmeetings/web/app/Application_pt_BR.properties.xml   |  1 +
 .../openmeetings/web/app/Application_ru.properties.xml      |  1 +
 .../openmeetings/web/app/Application_sk.properties.xml      |  1 +
 .../openmeetings/web/app/Application_sv.properties.xml      |  1 +
 .../openmeetings/web/app/Application_th.properties.xml      |  1 +
 .../openmeetings/web/app/Application_tr.properties.xml      |  1 +
 .../openmeetings/web/app/Application_uk.properties.xml      |  1 +
 .../openmeetings/web/app/Application_zh_CN.properties.xml   |  1 +
 .../openmeetings/web/app/Application_zh_TW.properties.xml   |  1 +
 .../apache/openmeetings/web/room/menu/RoomMenuPanel.java    | 13 ++++++++++---
 .../openmeetings/web/room/poll/PollResultsDialog.java       | 12 ++++++------
 33 files changed, 47 insertions(+), 9 deletions(-)

diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application.properties.xml
index d52e9f5..18c2c3b 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application.properties.xml
@@ -1005,4 +1005,5 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="lbl.update"><![CDATA[Update]]></entry>
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
+	<entry key="menu.polls"><![CDATA[Polls]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_ar.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_ar.properties.xml
index d98e6e7..496dda7 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_ar.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_ar.properties.xml
@@ -1005,4 +1005,5 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="lbl.update"><![CDATA[Update]]></entry>
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
+	<entry key="menu.polls"><![CDATA[Polls]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_bg.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_bg.properties.xml
index 67f6bb3..f19111e 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_bg.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_bg.properties.xml
@@ -1005,4 +1005,5 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="lbl.update"><![CDATA[Update]]></entry>
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
+	<entry key="menu.polls"><![CDATA[Polls]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_ca.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_ca.properties.xml
index 1334ef7..1cc7942 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_ca.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_ca.properties.xml
@@ -1005,4 +1005,5 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="lbl.update"><![CDATA[Update]]></entry>
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
+	<entry key="menu.polls"><![CDATA[Polls]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_cs.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_cs.properties.xml
index e7c9f4b..2083d2e 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_cs.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_cs.properties.xml
@@ -1005,4 +1005,5 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="lbl.update"><![CDATA[Update]]></entry>
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
+	<entry key="menu.polls"><![CDATA[Polls]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_da.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_da.properties.xml
index eaac5be..a09489d 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_da.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_da.properties.xml
@@ -1005,4 +1005,5 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="lbl.update"><![CDATA[Update]]></entry>
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
+	<entry key="menu.polls"><![CDATA[Polls]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_de.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_de.properties.xml
index 4065c1a..d09c91f 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_de.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_de.properties.xml
@@ -1010,4 +1010,5 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="lbl.update"><![CDATA[Update]]></entry>
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
+	<entry key="menu.polls"><![CDATA[Polls]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_el.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_el.properties.xml
index 79aa33f..442242e 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_el.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_el.properties.xml
@@ -1005,4 +1005,5 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="lbl.update"><![CDATA[Update]]></entry>
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
+	<entry key="menu.polls"><![CDATA[Polls]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_es.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_es.properties.xml
index 6415c2b..050d51e 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_es.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_es.properties.xml
@@ -1003,4 +1003,5 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="lbl.update"><![CDATA[Update]]></entry>
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
+	<entry key="menu.polls"><![CDATA[Polls]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_fa.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_fa.properties.xml
index 1e19bbb..7583812 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_fa.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_fa.properties.xml
@@ -997,4 +997,5 @@ target="_blank">Custom Crypt Mechanism</a>
 	<entry key="lbl.update"><![CDATA[Update]]></entry>
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
+	<entry key="menu.polls"><![CDATA[Polls]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_fi.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_fi.properties.xml
index 2c55743..912ae5a 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_fi.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_fi.properties.xml
@@ -1005,4 +1005,5 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="lbl.update"><![CDATA[Update]]></entry>
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
+	<entry key="menu.polls"><![CDATA[Polls]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_fr.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_fr.properties.xml
index ecb3108..fda19b4 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_fr.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_fr.properties.xml
@@ -997,4 +997,5 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="lbl.update"><![CDATA[Update]]></entry>
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
+	<entry key="menu.polls"><![CDATA[Polls]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_gl.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_gl.properties.xml
index a623a89..c45c788 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_gl.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_gl.properties.xml
@@ -1005,4 +1005,5 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="lbl.update"><![CDATA[Update]]></entry>
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
+	<entry key="menu.polls"><![CDATA[Polls]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_he.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_he.properties.xml
index d52e9f5..18c2c3b 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_he.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_he.properties.xml
@@ -1005,4 +1005,5 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="lbl.update"><![CDATA[Update]]></entry>
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
+	<entry key="menu.polls"><![CDATA[Polls]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_hu.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_hu.properties.xml
index 1d0d32c..b76c80b 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_hu.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_hu.properties.xml
@@ -993,4 +993,5 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="lbl.update"><![CDATA[Update]]></entry>
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
+	<entry key="menu.polls"><![CDATA[Polls]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_id.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_id.properties.xml
index cfc4187..2a42eec 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_id.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_id.properties.xml
@@ -1005,4 +1005,5 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="lbl.update"><![CDATA[Update]]></entry>
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
+	<entry key="menu.polls"><![CDATA[Polls]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_it.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_it.properties.xml
index aad4f40..17beae1 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_it.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_it.properties.xml
@@ -1006,4 +1006,5 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="lbl.update"><![CDATA[Update]]></entry>
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
+	<entry key="menu.polls"><![CDATA[Polls]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_ja.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_ja.properties.xml
index 2d83344..a7ad255 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_ja.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_ja.properties.xml
@@ -1005,4 +1005,5 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="lbl.update"><![CDATA[Update]]></entry>
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
+	<entry key="menu.polls"><![CDATA[Polls]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_ko.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_ko.properties.xml
index 70b97b2..87a2985 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_ko.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_ko.properties.xml
@@ -1005,4 +1005,5 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="lbl.update"><![CDATA[Update]]></entry>
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
+	<entry key="menu.polls"><![CDATA[Polls]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_nl.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_nl.properties.xml
index 3ef8c59..bdd4173 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_nl.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_nl.properties.xml
@@ -1005,4 +1005,5 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="lbl.update"><![CDATA[Update]]></entry>
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
+	<entry key="menu.polls"><![CDATA[Polls]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_pl.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_pl.properties.xml
index 8ceaeb7..938fa48 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_pl.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_pl.properties.xml
@@ -1005,4 +1005,5 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="lbl.update"><![CDATA[Update]]></entry>
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
+	<entry key="menu.polls"><![CDATA[Polls]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_pt.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_pt.properties.xml
index fe65abd..3cd7ec9 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_pt.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_pt.properties.xml
@@ -1005,4 +1005,5 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="lbl.update"><![CDATA[Update]]></entry>
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
+	<entry key="menu.polls"><![CDATA[Polls]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_pt_BR.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_pt_BR.properties.xml
index ed4bb90..6772054 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_pt_BR.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_pt_BR.properties.xml
@@ -1005,4 +1005,5 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="lbl.update"><![CDATA[Update]]></entry>
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
+	<entry key="menu.polls"><![CDATA[Polls]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_ru.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_ru.properties.xml
index fddc01a..c6dfc77 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_ru.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_ru.properties.xml
@@ -1006,4 +1006,5 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="lbl.update"><![CDATA[Изменить]]></entry>
 	<entry key="send.on.enter"><![CDATA[Отправить по Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Отправить по Ctrl+Enter]]></entry>
+	<entry key="menu.polls"><![CDATA[Голосования]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_sk.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_sk.properties.xml
index 8a781cb..3d67bb6 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_sk.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_sk.properties.xml
@@ -1005,4 +1005,5 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="lbl.update"><![CDATA[Update]]></entry>
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
+	<entry key="menu.polls"><![CDATA[Polls]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_sv.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_sv.properties.xml
index 0411ff0..71d8cc9 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_sv.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_sv.properties.xml
@@ -1005,4 +1005,5 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="lbl.update"><![CDATA[Update]]></entry>
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
+	<entry key="menu.polls"><![CDATA[Polls]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_th.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_th.properties.xml
index 2edf215..ce97830 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_th.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_th.properties.xml
@@ -1005,4 +1005,5 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="lbl.update"><![CDATA[Update]]></entry>
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
+	<entry key="menu.polls"><![CDATA[Polls]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_tr.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_tr.properties.xml
index 118c956..6cb17c0 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_tr.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_tr.properties.xml
@@ -1005,4 +1005,5 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="lbl.update"><![CDATA[Update]]></entry>
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
+	<entry key="menu.polls"><![CDATA[Polls]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_uk.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_uk.properties.xml
index ae77f7e..b2757ee 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_uk.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_uk.properties.xml
@@ -1006,4 +1006,5 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="lbl.update"><![CDATA[Update]]></entry>
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
+	<entry key="menu.polls"><![CDATA[Polls]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_zh_CN.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_zh_CN.properties.xml
index 3ad56c5..75f795e 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_zh_CN.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_zh_CN.properties.xml
@@ -995,4 +995,5 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="lbl.update"><![CDATA[Update]]></entry>
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
+	<entry key="menu.polls"><![CDATA[Polls]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_zh_TW.properties.xml b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_zh_TW.properties.xml
index b095b61..39c008d 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_zh_TW.properties.xml
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application_zh_TW.properties.xml
@@ -1005,4 +1005,5 @@ see http://openmeetings.apache.org/LanguageEditor.html for Details
 	<entry key="lbl.update"><![CDATA[Update]]></entry>
 	<entry key="send.on.enter"><![CDATA[Send on Enter]]></entry>
 	<entry key="send.on.ctrl.enter"><![CDATA[Send on Ctrl+Enter]]></entry>
+	<entry key="menu.polls"><![CDATA[Polls]]></entry>
 </properties>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/RoomMenuPanel.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/RoomMenuPanel.java
index 239ffca..fd1ba8e 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/RoomMenuPanel.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/RoomMenuPanel.java
@@ -101,6 +101,7 @@ public class RoomMenuPanel extends Panel {
 	private RoomMenuItem exitMenuItem;
 	private RoomMenuItem filesMenu;
 	private RoomMenuItem actionsMenu;
+	private RoomMenuItem pollsMenu;
 	private RoomMenuItem inviteMenuItem;
 	private RoomMenuItem shareMenuItem;
 	private RoomMenuItem applyModerMenuItem;
@@ -161,6 +162,8 @@ public class RoomMenuPanel extends Panel {
 		};
 		filesMenu = new RoomMenuItem(getString("245"), null, false);
 		actionsMenu = new RoomMenuItem(getString("635"), null, false);
+		pollsMenu = new RoomMenuItem(getString("menu.polls"), null, false);
+
 		inviteMenuItem = new RoomMenuItem(getString("213"), getString("1489"), false) {
 			private static final long serialVersionUID = 1L;
 
@@ -309,14 +312,17 @@ public class RoomMenuPanel extends Panel {
 		actionsMenu.getItems().add(applyModerMenuItem);
 		actionsMenu.getItems().add(applyWbMenuItem);
 		actionsMenu.getItems().add(applyAvMenuItem);
-		actionsMenu.getItems().add(pollCreateMenuItem);
-		actionsMenu.getItems().add(pollResultMenuItem);
-		actionsMenu.getItems().add(pollVoteMenuItem);
 		actionsMenu.getItems().add(sipDialerMenuItem);
 		actionsMenu.getItems().add(downloadPngMenuItem);
 		actionsMenu.getItems().add(downloadJpgMenuItem);
 		actionsMenu.getItems().add(downloadPdfMenuItem);
 		menu.add(actionsMenu);
+
+		pollsMenu.setTop(true);
+		pollsMenu.getItems().add(pollCreateMenuItem);
+		pollsMenu.getItems().add(pollResultMenuItem);
+		pollsMenu.getItems().add(pollVoteMenuItem);
+		menu.add(pollsMenu);
 		return menu;
 	}
 
@@ -337,6 +343,7 @@ public class RoomMenuPanel extends Panel {
 		filesMenu.setEnabled(!isInterview && room.getSidebar().isShowFiles());
 		boolean moder = room.getClient().hasRight(Room.Right.moderator);
 		actionsMenu.setEnabled((moder && !r.isHidden(RoomElement.ActionMenu)) || (!moder && r.isAllowUserQuestions()));
+		pollsMenu.setEnabled((moder && !r.isHidden(RoomElement.ActionMenu)) || (!moder && r.isAllowUserQuestions()));
 		inviteMenuItem.setEnabled(notExternalUser && moder);
 		boolean shareVisible = room.screenShareAllowed();
 		shareMenuItem.setEnabled(shareVisible);
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/poll/PollResultsDialog.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/poll/PollResultsDialog.java
index a621fbe..97576ac 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/poll/PollResultsDialog.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/poll/PollResultsDialog.java
@@ -230,13 +230,13 @@ public class PollResultsDialog extends AbstractDialog<RoomPoll> {
 
 	private static Integer[] getValues(RoomPoll p) {
 		Integer[] values = initValues(p != null && RoomPoll.Type.numeric == p.getType() ? 10 : 2);
-		if (p != null && RoomPoll.Type.numeric == p.getType()) {
+		if (p != null) {
 			for (RoomPollAnswer a : p.getAnswers()) {
-				values[a.getPointList() - 1] ++;
-			}
-		} else if (p != null) {
-			for (RoomPollAnswer a : p.getAnswers()) {
-				values[a.getAnswer() ? 0 : 1] ++;
+				if (RoomPoll.Type.numeric == p.getType()) {
+					values[a.getPointList() - 1] ++;
+				} else {
+					values[Boolean.FALSE.equals(a.getAnswer()) ? 0 : 1] ++;
+				}
 			}
 		}
 		return values;

-- 
To stop receiving notification emails like this one, please contact
solomax@apache.org.

[openmeetings] 03/04: [OPENMEETINGS-1791] hazelcast related maps are refactored

Posted by so...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

solomax pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/openmeetings.git

commit 92c2cee362ac5e3f72e58a6cac693d9e517b0676
Author: Maxim Solodovnik <so...@gmail.com>
AuthorDate: Sun Feb 25 00:04:30 2018 +0700

    [OPENMEETINGS-1791] hazelcast related maps are refactored
---
 ...pLoginManagement.java => LdapLoginManager.java} |   6 +-
 .../apache/openmeetings/core/ldap/LdapOptions.java |   6 +-
 .../openmeetings/core/remote/MobileService.java    |  26 +-
 .../core/remote/ScopeApplicationAdapter.java       |  82 ++---
 .../core/service/RecordingService.java             |  31 +-
 .../openmeetings/core/session/SessionManager.java  | 162 ---------
 .../openmeetings/core/util/WebSocketHelper.java    |   5 +-
 .../java/org/apache/openmeetings/IApplication.java |  26 --
 .../openmeetings/db/dao/server/SessiondataDao.java |   5 +-
 .../openmeetings/db/entity/basic/Client.java       |   4 +-
 .../openmeetings/db/manager/IClientManager.java    |  42 +++
 .../IStreamClientManager.java}                     |  37 +-
 .../db/manager/IWhiteboardManager.java             |  25 ++
 .../apache/openmeetings/db/util/RoomHelper.java    |   4 +-
 .../java/org/apache/openmeetings/cli/Admin.java    |   4 +-
 .../service/quartz/scheduler/CleanupJob.java       |  12 +-
 .../openmeetings/service/user/UserManager.java     |  12 +-
 .../web/admin/connection/ConnectionsPanel.java     |  10 +-
 .../openmeetings/web/admin/rooms/RoomForm.java     |   4 +-
 .../apache/openmeetings/web/app/Application.java   | 393 +--------------------
 .../apache/openmeetings/web/app/ClientManager.java | 287 +++++++++++++++
 .../openmeetings/web/app/StreamClientManager.java  | 303 ++++++++++++++++
 .../apache/openmeetings/web/app/WebSession.java    |   6 +-
 .../openmeetings/web/app/WhiteboardManager.java    |  51 ++-
 .../apache/openmeetings/web/common/MainPanel.java  |   9 +-
 .../openmeetings/web/room/NicknameDialog.java      |   5 +-
 .../openmeetings/web/room/RoomBroadcaster.java     |  13 +-
 .../apache/openmeetings/web/room/RoomPanel.java    |  86 +++--
 .../web/room/RoomResourceReference.java            |   8 +-
 .../openmeetings/web/room/VideoSettings.java       |   4 +-
 .../web/room/activities/ActivitiesPanel.java       |   5 +-
 .../openmeetings/web/room/menu/RoomMenuPanel.java  |  10 +-
 .../web/room/menu/StartSharingButton.java          |  14 +-
 .../openmeetings/web/room/sidebar/RoomSidebar.java |  15 +-
 .../web/room/sidebar/icon/ClientIcon.java          |   5 +-
 .../openmeetings/web/room/wb/InterviewWbPanel.java |   6 +-
 .../apache/openmeetings/web/room/wb/WbPanel.java   |  80 +++--
 .../apache/openmeetings/web/user/chat/Chat.java    |   4 +-
 .../openmeetings/web/user/chat/ChatForm.java       |   4 +-
 .../web/user/profile/UserSearchPanel.java          |   4 +-
 .../user/record/RecordingResourceReference.java    |   8 +-
 .../openmeetings/web/user/rooms/RoomListPanel.java |   7 +-
 .../openmeetings/web/user/rooms/RoomsPanel.java    |   4 +-
 .../openmeetings/webservice/RoomWebService.java    |   5 +-
 .../openmeetings/webservice/UserWebService.java    |   3 +-
 45 files changed, 971 insertions(+), 871 deletions(-)

diff --git a/openmeetings-core/src/main/java/org/apache/openmeetings/core/ldap/LdapLoginManagement.java b/openmeetings-core/src/main/java/org/apache/openmeetings/core/ldap/LdapLoginManager.java
similarity index 99%
rename from openmeetings-core/src/main/java/org/apache/openmeetings/core/ldap/LdapLoginManagement.java
rename to openmeetings-core/src/main/java/org/apache/openmeetings/core/ldap/LdapLoginManager.java
index be64e94..1b3a6a3 100644
--- a/openmeetings-core/src/main/java/org/apache/openmeetings/core/ldap/LdapLoginManagement.java
+++ b/openmeetings-core/src/main/java/org/apache/openmeetings/core/ldap/LdapLoginManager.java
@@ -79,8 +79,8 @@ import org.springframework.stereotype.Component;
  *
  */
 @Component
-public class LdapLoginManagement {
-	private static final Logger log = Red5LoggerFactory.getLogger(LdapLoginManagement.class, getWebAppRootKey());
+public class LdapLoginManager {
+	private static final Logger log = Red5LoggerFactory.getLogger(LdapLoginManager.class, getWebAppRootKey());
 	// LDAP custom attribute mapping keys
 	private static final String CONFIGKEY_LDAP_KEY_LOGIN = "ldap_user_attr_login";
 	private static final String CONFIGKEY_LDAP_KEY_LASTNAME = "ldap_user_attr_lastname";
@@ -171,7 +171,7 @@ public class LdapLoginManagement {
 	 * @throws OmException - in case of any error
 	 */
 	public User login(String _login, String passwd, Long domainId) throws OmException {
-		log.debug("LdapLoginmanagement.doLdapLogin");
+		log.debug("LdapLoginmanager.doLdapLogin");
 		if (!userDao.validLogin(_login)) {
 			log.error("Invalid login provided");
 			return null;
diff --git a/openmeetings-core/src/main/java/org/apache/openmeetings/core/ldap/LdapOptions.java b/openmeetings-core/src/main/java/org/apache/openmeetings/core/ldap/LdapOptions.java
index 8c9d542..95851ee 100644
--- a/openmeetings-core/src/main/java/org/apache/openmeetings/core/ldap/LdapOptions.java
+++ b/openmeetings-core/src/main/java/org/apache/openmeetings/core/ldap/LdapOptions.java
@@ -25,9 +25,9 @@ import java.util.Properties;
 
 import org.apache.directory.api.ldap.model.message.AliasDerefMode;
 import org.apache.directory.api.ldap.model.message.SearchScope;
-import org.apache.openmeetings.core.ldap.LdapLoginManagement.AuthType;
-import org.apache.openmeetings.core.ldap.LdapLoginManagement.GroupMode;
-import org.apache.openmeetings.core.ldap.LdapLoginManagement.Provisionning;
+import org.apache.openmeetings.core.ldap.LdapLoginManager.AuthType;
+import org.apache.openmeetings.core.ldap.LdapLoginManager.GroupMode;
+import org.apache.openmeetings.core.ldap.LdapLoginManager.Provisionning;
 import org.red5.logging.Red5LoggerFactory;
 import org.slf4j.Logger;
 
diff --git a/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/MobileService.java b/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/MobileService.java
index caa1026..4260bae 100644
--- a/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/MobileService.java
+++ b/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/MobileService.java
@@ -51,7 +51,6 @@ import org.apache.openmeetings.db.dao.basic.ChatDao;
 import org.apache.openmeetings.db.dao.basic.ConfigurationDao;
 import org.apache.openmeetings.db.dao.label.LabelDao;
 import org.apache.openmeetings.db.dao.room.RoomDao;
-import org.apache.openmeetings.db.dao.server.ISessionManager;
 import org.apache.openmeetings.db.dao.server.SessiondataDao;
 import org.apache.openmeetings.db.dao.user.IUserManager;
 import org.apache.openmeetings.db.dao.user.UserDao;
@@ -64,6 +63,7 @@ import org.apache.openmeetings.db.entity.server.Sessiondata;
 import org.apache.openmeetings.db.entity.user.Group;
 import org.apache.openmeetings.db.entity.user.GroupUser;
 import org.apache.openmeetings.db.entity.user.User;
+import org.apache.openmeetings.db.manager.IStreamClientManager;
 import org.apache.openmeetings.db.util.FormatHelper;
 import org.apache.openmeetings.util.OmException;
 import org.apache.wicket.util.string.Strings;
@@ -87,7 +87,7 @@ public class MobileService {
 	@Autowired
 	private SessiondataDao sessionDao;
 	@Autowired
-	private ISessionManager sessionManager;
+	private IStreamClientManager streamClientManager;
 	@Autowired
 	private RoomDao roomDao;
 	@Autowired
@@ -249,7 +249,7 @@ public class MobileService {
 			Sessiondata sd = sessionDao.create(u.getId(), u.getLanguageId());
 			StreamClient c = create(u, sd);
 			c.setScope(conn.getScope().getName());
-			sessionManager.add(c);
+			streamClientManager.add(c);
 			IClientUtil.init(conn.getClient(), c.getUid(), false);
 
 			add(result, "sid", sd.getSessionId());
@@ -272,7 +272,7 @@ public class MobileService {
 		IConnection current = Red5.getConnectionLocal();
 		for (IConnection conn : current.getScope().getClientConnections()) {
 			if (conn != null && conn instanceof IServiceCapableConnection) {
-				StreamClient c = sessionManager.get(IClientUtil.getId(conn.getClient()));
+				StreamClient c = streamClientManager.get(IClientUtil.getId(conn.getClient()));
 				if (!Strings.isEmpty(c.getAvsettings()) && Client.Type.sharing != c.getType()) {
 					Map<String, Object> map = new HashMap<>();
 					add(map, "streamId", c.getId());
@@ -304,7 +304,7 @@ public class MobileService {
 			room.put("org", org);
 		}
 		room.put("first", first);
-		room.put("users", sessionManager.listByRoom(r.getId()).size());
+		room.put("users", streamClientManager.list(r.getId()).size());
 		room.put("total", r.getCapacity());
 		room.put("audioOnly", r.isAudioOnly());
 		result.add(room);
@@ -313,7 +313,7 @@ public class MobileService {
 	public List<Map<String, Object>> getRooms() {
 		List<Map<String, Object>> result = new ArrayList<>();
 		IConnection current = Red5.getConnectionLocal();
-		StreamClient c = sessionManager.get(IClientUtil.getId(current.getClient()));
+		StreamClient c = streamClientManager.get(IClientUtil.getId(current.getClient()));
 		User u = userDao.get(c.getUserId());
 		if (cfgDao.getBool(CONFIG_MYROOMS_ENABLED, true)) {
 			//my rooms
@@ -353,7 +353,7 @@ public class MobileService {
 	public Map<String, Object> roomConnect(String sid, Long userId) {
 		// publicSid is changed on mobile room connect
 		IConnection current = Red5.getConnectionLocal();
-		StreamClient c = sessionManager.get(IClientUtil.getId(current.getClient()));
+		StreamClient c = streamClientManager.get(IClientUtil.getId(current.getClient()));
 		Map<String, Object> result = new HashMap<>();
 		result.put("publicSid", c.getUid());
 		result.put("broadCastId", c.getBroadcastId());
@@ -362,7 +362,7 @@ public class MobileService {
 
 	public Map<String, Object> updateAvMode(String avMode, String width, String height, Integer interviewPodId) {
 		IConnection current = Red5.getConnectionLocal();
-		StreamClient c = sessionManager.get(IClientUtil.getId(current.getClient()));
+		StreamClient c = streamClientManager.get(IClientUtil.getId(current.getClient()));
 		c.setAvsettings(avMode);
 		if (!"n".equals(avMode)) {
 			c.setBroadcastId(UUID.randomUUID().toString());
@@ -373,7 +373,7 @@ public class MobileService {
 		if (interviewPodId > 0) {
 			c.setInterviewPodId(interviewPodId);
 		}
-		sessionManager.update(c);
+		streamClientManager.update(c);
 		Map<String, Object> hsm = new HashMap<>();
 		hsm.put("client", c);
 		hsm.put("message", new String[]{"avsettings", "0", avMode});
@@ -388,7 +388,7 @@ public class MobileService {
 
 	public void sendChatMessage(String msg) {
 		IConnection current = Red5.getConnectionLocal();
-		StreamClient c = sessionManager.get(IClientUtil.getId(current.getClient()));
+		StreamClient c = streamClientManager.get(IClientUtil.getId(current.getClient()));
 
 		ChatMessage m = new ChatMessage();
 		m.setMessage(msg);
@@ -405,7 +405,7 @@ public class MobileService {
 	}
 
 	public void sendChatMessage(String uid, ChatMessage m, FastDateFormat fmt) {
-		sendChatMessage(sessionManager.get(uid), m, fmt);
+		sendChatMessage(streamClientManager.get(uid), m, fmt);
 	}
 
 	public void sendChatMessage(StreamClient c, ChatMessage m, FastDateFormat fmt) {
@@ -421,7 +421,7 @@ public class MobileService {
 		new MessageSender(scopeAdapter.getChildScope(roomId), "sendVarsToMessageWithClient", hsm, scopeAdapter) {
 			@Override
 			public boolean filter(IConnection conn) {
-				StreamClient rcl = sessionManager.get(IClientUtil.getId(conn.getClient()));
+				StreamClient rcl = streamClientManager.get(IClientUtil.getId(conn.getClient()));
 				return Client.Type.sharing == rcl.getType()
 						|| rcl.getRoomId() == null || !rcl.getRoomId().equals(roomId);
 			}
@@ -444,7 +444,7 @@ public class MobileService {
 		List<Map<String,Object>> myChatList = new ArrayList<>();
 		try {
 			IConnection current = Red5.getConnectionLocal();
-			StreamClient c = sessionManager.get(IClientUtil.getId(current.getClient()));
+			StreamClient c = streamClientManager.get(IClientUtil.getId(current.getClient()));
 			Long roomId = c.getRoomId();
 
 			log.debug("GET CHATROOM: " + roomId);
diff --git a/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/ScopeApplicationAdapter.java b/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/ScopeApplicationAdapter.java
index 08ffdd4..b06e0af 100644
--- a/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/ScopeApplicationAdapter.java
+++ b/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/ScopeApplicationAdapter.java
@@ -46,13 +46,14 @@ import org.apache.openmeetings.db.dao.log.ConferenceLogDao;
 import org.apache.openmeetings.db.dao.record.RecordingDao;
 import org.apache.openmeetings.db.dao.room.RoomDao;
 import org.apache.openmeetings.db.dao.room.SipDao;
-import org.apache.openmeetings.db.dao.server.ISessionManager;
 import org.apache.openmeetings.db.dao.user.UserDao;
 import org.apache.openmeetings.db.dto.room.CheckDto;
 import org.apache.openmeetings.db.entity.basic.Client;
 import org.apache.openmeetings.db.entity.log.ConferenceLog;
 import org.apache.openmeetings.db.entity.room.Room;
 import org.apache.openmeetings.db.entity.room.StreamClient;
+import org.apache.openmeetings.db.manager.IClientManager;
+import org.apache.openmeetings.db.manager.IStreamClientManager;
 import org.apache.openmeetings.db.util.ws.RoomMessage;
 import org.apache.openmeetings.db.util.ws.TextRoomMessage;
 import org.apache.openmeetings.util.NullStringer;
@@ -88,7 +89,9 @@ public class ScopeApplicationAdapter extends MultiThreadedApplicationAdapter imp
 	private static final String HEIGHT_PARAM = "height";
 
 	@Autowired
-	private ISessionManager sessionManager;
+	private IStreamClientManager streamClientManager;
+	@Autowired
+	private IClientManager clientManager;
 	@Autowired
 	private RecordingService recordingService;
 	@Autowired
@@ -213,7 +216,6 @@ public class ScopeApplicationAdapter extends MultiThreadedApplicationAdapter imp
 		rcm.setRemoteAddress(conn.getRemoteAddress());
 		rcm.setSwfurl(swfURL);
 		rcm.setTcUrl(tcUrl);
-		IApplication iapp = getApp();
 		Number width = (Number)connParams.get(WIDTH_PARAM);
 		Number height = (Number)connParams.get(HEIGHT_PARAM);
 		if (width != null && height != null) {
@@ -224,7 +226,7 @@ public class ScopeApplicationAdapter extends MultiThreadedApplicationAdapter imp
 		if (map.containsKey("screenClient")) {
 			rcm.setType(Client.Type.sharing);
 		}
-		rcm = sessionManager.add(iapp.updateClient(rcm, false));
+		rcm = streamClientManager.add(streamClientManager.update(rcm, false));
 		if (rcm == null) {
 			_log.warn("Failed to create Client on room connect");
 			return false;
@@ -261,7 +263,7 @@ public class ScopeApplicationAdapter extends MultiThreadedApplicationAdapter imp
 			_log.debug("-----------  screenSharerAction ENTER");
 			IConnection current = Red5.getConnectionLocal();
 
-			StreamClient client = sessionManager.get(IClientUtil.getId(current.getClient()));
+			StreamClient client = streamClientManager.get(IClientUtil.getId(current.getClient()));
 
 			if (client != null) {
 				boolean changed = false;
@@ -292,7 +294,7 @@ public class ScopeApplicationAdapter extends MultiThreadedApplicationAdapter imp
 				}
 
 				if (changed) {
-					sessionManager.update(client);
+					streamClientManager.update(client);
 
 					if (!client.isSharingStarted() && !client.isRecordingStarted() && !client.isPublishStarted()) {
 						returnMap.put("result", "stopAll");
@@ -317,11 +319,11 @@ public class ScopeApplicationAdapter extends MultiThreadedApplicationAdapter imp
 			_log.debug("-----------  setConnectionAsSharingClient");
 			IConnection current = Red5.getConnectionLocal();
 
-			StreamClient client = sessionManager.get(IClientUtil.getId(current.getClient()));
+			StreamClient client = streamClientManager.get(IClientUtil.getId(current.getClient()));
 
 			if (client != null) {
-				boolean startRecording = Boolean.parseBoolean("" + map.get("startRecording")) && (0 == sessionManager.getRecordingCount(client.getRoomId()));
-				boolean startStreaming = Boolean.parseBoolean("" + map.get("startStreaming")) && (0 == sessionManager.getSharingCount(client.getRoomId()));
+				boolean startRecording = Boolean.parseBoolean("" + map.get("startRecording")) && (0 == streamClientManager.getRecordingCount(client.getRoomId()));
+				boolean startStreaming = Boolean.parseBoolean("" + map.get("startStreaming")) && (0 == streamClientManager.getSharingCount(client.getRoomId()));
 				boolean startPublishing = Boolean.parseBoolean("" + map.get("startPublishing"));
 
 				boolean alreadyStreaming = client.isSharingStarted();
@@ -339,7 +341,7 @@ public class ScopeApplicationAdapter extends MultiThreadedApplicationAdapter imp
 
 				client.setWidth(Double.valueOf("" + map.get("screenWidth")).intValue());
 				client.setHeight(Double.valueOf("" + map.get("screenHeight")).intValue());
-				sessionManager.update(client);
+				streamClientManager.update(client);
 
 				Map<String, Object> returnMap = new HashMap<>();
 				returnMap.put("alreadyPublished", alreadyPublishing);
@@ -391,7 +393,7 @@ public class ScopeApplicationAdapter extends MultiThreadedApplicationAdapter imp
 		try {
 			_log.debug("[roomLeave] {} {} {} {}", client.getId(), room.getClients().size(), room.getContextPath(), room.getName());
 
-			StreamClient rcl = sessionManager.get(IClientUtil.getId(client));
+			StreamClient rcl = streamClientManager.get(IClientUtil.getId(client));
 
 			// The Room Client can be null if the Client left the room by using
 			// logicalRoomLeave
@@ -410,7 +412,7 @@ public class ScopeApplicationAdapter extends MultiThreadedApplicationAdapter imp
 		new MessageSender(scope, "stopStream", new Object(), this) {
 			@Override
 			public boolean filter(IConnection conn) {
-				StreamClient rcl = sessionManager.get(IClientUtil.getId(conn.getClient()));
+				StreamClient rcl = streamClientManager.get(IClientUtil.getId(conn.getClient()));
 				return rcl == null
 						|| Client.Type.sharing != rcl.getType()
 						|| !c.getSid().equals(rcl.getSid());
@@ -419,7 +421,7 @@ public class ScopeApplicationAdapter extends MultiThreadedApplicationAdapter imp
 	}
 
 	public void roomLeaveByScope(org.apache.openmeetings.db.entity.basic.IClient c, Long roomId) {
-		StreamClient rcl = sessionManager.get(c.getUid());
+		StreamClient rcl = streamClientManager.get(c.getUid());
 		IScope scope = getChildScope(roomId);
 		_log.debug("[roomLeaveByScope] {} {} {} {}", c.getUid(), roomId, rcl, scope);
 		if (rcl != null && scope != null) {
@@ -463,9 +465,9 @@ public class ScopeApplicationAdapter extends MultiThreadedApplicationAdapter imp
 			_log.debug("currentScope " + scope);
 
 			if (Client.Type.mobile == client.getType() || Client.Type.sip == client.getType()) {
-				getApp().exit(client);
+				clientManager.exit(client);
 			}
-			sessionManager.remove(client.getUid());
+			streamClientManager.remove(client.getUid());
 		} catch (Exception err) {
 			_log.error("[roomLeaveByScope]", err);
 		}
@@ -484,7 +486,7 @@ public class ScopeApplicationAdapter extends MultiThreadedApplicationAdapter imp
 		try {
 			_log.debug("-----------  streamPublishStart");
 			IConnection current = Red5.getConnectionLocal();
-			final StreamClient c = sessionManager.get(IClientUtil.getId(current.getClient()));
+			final StreamClient c = streamClientManager.get(IClientUtil.getId(current.getClient()));
 
 			// Notify all the clients that the stream had been started
 			String streamName = stream.getPublishedName();
@@ -500,13 +502,13 @@ public class ScopeApplicationAdapter extends MultiThreadedApplicationAdapter imp
 				}
 			}
 			if (Client.Type.sip == c.getType()) {
-				Client cl = getApp().getOmClientBySid(c.getSid());
+				Client cl = clientManager.getBySid(c.getSid());
 				String newNumber = getSipTransportLastname(c.getRoomId());
 				cl.getUser().setLastname(newNumber);
 				c.setLastname(newNumber);
 				c.setLastname(getSipTransportLastname(c.getRoomId()));
 			}
-			sessionManager.update(c);
+			streamClientManager.update(c);
 			if (Client.Type.sharing == c.getType() && c.isRecordingStarted()) {
 				recordingService.startRecording(current.getScope(), c, false);
 			}
@@ -518,7 +520,7 @@ public class ScopeApplicationAdapter extends MultiThreadedApplicationAdapter imp
 			new MessageSender(current, "newStream", c, this) {
 				@Override
 				public boolean filter(IConnection conn) {
-					StreamClient rcl = sessionManager.get(IClientUtil.getId(conn.getClient()));
+					StreamClient rcl = streamClientManager.get(IClientUtil.getId(conn.getClient()));
 
 					if (rcl == null || Strings.isEmpty(rcl.getUid())) {
 						_log.debug("Invalid client");
@@ -564,7 +566,7 @@ public class ScopeApplicationAdapter extends MultiThreadedApplicationAdapter imp
 		_log.debug("start streamBroadcastClose broadcast close: {}", stream.getPublishedName());
 		try {
 			IConnection current = Red5.getConnectionLocal();
-			StreamClient rcl = sessionManager.get(IClientUtil.getId(current.getClient()));
+			StreamClient rcl = streamClientManager.get(IClientUtil.getId(current.getClient()));
 
 			if (rcl == null) {
 
@@ -589,10 +591,10 @@ public class ScopeApplicationAdapter extends MultiThreadedApplicationAdapter imp
 				rcl.setBroadcasting(false);
 				rcl.setAvsettings("n");
 			}
-			sessionManager.update(rcl);
+			streamClientManager.update(rcl);
 			Room r = roomDao.get(rcl.getRoomId());
 			if ((Client.Type.sharing == rcl.getType() && rcl.isRecordingStarted())
-					|| (r != null && Room.Type.interview == r.getType() && sessionManager.getBroadcastingCount(rcl.getRoomId()) == 0))
+					|| (r != null && Room.Type.interview == r.getType() && streamClientManager.getBroadcastingCount(rcl.getRoomId()) == 0))
 			{
 				_log.debug("*** Screen sharing client stoped recording, or last broadcasting user stoped in interview room");
 				recordingService.stopRecording(scope, rcl);
@@ -610,7 +612,7 @@ public class ScopeApplicationAdapter extends MultiThreadedApplicationAdapter imp
 	public void setNewCursorPosition(Double x, Double y) {
 		try {
 			IConnection current = Red5.getConnectionLocal();
-			StreamClient c = sessionManager.get(IClientUtil.getId(current.getClient()));
+			StreamClient c = streamClientManager.get(IClientUtil.getId(current.getClient()));
 
 			sendMessageToCurrentScope("newScreenCursor", new Object[] {c.getUid(), x, y}, true, false);
 		} catch (Exception err) {
@@ -636,13 +638,13 @@ public class ScopeApplicationAdapter extends MultiThreadedApplicationAdapter imp
 		try {
 			_log.debug("-----------  switchMicMuted: " + publicSID);
 
-			StreamClient currentClient = sessionManager.get(publicSID);
+			StreamClient currentClient = streamClientManager.get(publicSID);
 			if (currentClient == null) {
 				return -1L;
 			}
 
 			currentClient.setMicMuted(mute);
-			sessionManager.update(currentClient);
+			streamClientManager.update(currentClient);
 
 			Map<Integer, Object> newMessage = new HashMap<>();
 			newMessage.put(0, "updateMuteStatus");
@@ -700,7 +702,7 @@ public class ScopeApplicationAdapter extends MultiThreadedApplicationAdapter imp
 		new MessageSender(getChildScope(roomId), method, obj, this) {
 			@Override
 			public boolean filter(IConnection conn) {
-				StreamClient rcl = sessionManager.get(IClientUtil.getId(conn.getClient()));
+				StreamClient rcl = streamClientManager.get(IClientUtil.getId(conn.getClient()));
 				return rcl == null || Client.Type.sharing == rcl.getType()
 						|| rcl.getRoomId() == null || !rcl.getRoomId().equals(roomId) || userDao.get(rcl.getUserId()) == null;
 			}
@@ -828,7 +830,7 @@ public class ScopeApplicationAdapter extends MultiThreadedApplicationAdapter imp
 	public int sendMessageWithClientWithSyncObject(Object newMessage, boolean sync) {
 		try {
 			IConnection current = Red5.getConnectionLocal();
-			StreamClient currentClient = sessionManager.get(IClientUtil.getId(current.getClient()));
+			StreamClient currentClient = streamClientManager.get(IClientUtil.getId(current.getClient()));
 
 			Map<String, Object> hsm = new HashMap<>();
 			hsm.put("client", currentClient);
@@ -918,7 +920,7 @@ public class ScopeApplicationAdapter extends MultiThreadedApplicationAdapter imp
 	public void startInterviewRecording(Client c) {
 		_log.debug("-----------  startInterviewRecording");
 
-		if (c == null || sessionManager.getRecordingCount(c.getRoom().getId()) > 0) {
+		if (c == null || streamClientManager.getRecordingCount(c.getRoom().getId()) > 0) {
 			return;
 		}
 
@@ -937,7 +939,7 @@ public class ScopeApplicationAdapter extends MultiThreadedApplicationAdapter imp
 
 	public void micActivity(boolean active) {
 		IConnection current = Red5.getConnectionLocal();
-		StreamClient client = sessionManager.get(IClientUtil.getId(current.getClient()));
+		StreamClient client = streamClientManager.get(IClientUtil.getId(current.getClient()));
 		WebSocketHelper.sendRoom(new TextRoomMessage(client.getRoomId(), client, RoomMessage.Type.audioActivity
 				, new JSONObject().put("sid", client.getSid()).put("active", active).toString()));
 	}
@@ -948,10 +950,10 @@ public class ScopeApplicationAdapter extends MultiThreadedApplicationAdapter imp
 	public List<String> listRoomBroadcast() {
 		List<String> ids = new ArrayList<>();
 		IConnection current = Red5.getConnectionLocal();
-		StreamClient client = sessionManager.get(IClientUtil.getId(current.getClient()));
-		for (Client c: getApp().getOmRoomClients(client.getRoomId()) ) {
+		StreamClient client = streamClientManager.get(IClientUtil.getId(current.getClient()));
+		for (Client c: clientManager.listByRoom(client.getRoomId()) ) {
 			for (String uid : c.getStreams()) {
-				StreamClient rc = sessionManager.get(uid);
+				StreamClient rc = streamClientManager.get(uid);
 				ids.add(rc.getBroadcastId());
 			}
 		}
@@ -986,22 +988,22 @@ public class ScopeApplicationAdapter extends MultiThreadedApplicationAdapter imp
 	}
 
 	public List<Long> getActiveRoomIds() {
-		return new ArrayList<>(getApp().getActiveRoomIds());
+		return new ArrayList<>(clientManager.getActiveRoomIds());
 	}
 
 	public synchronized int updateSipTransport() {
 		_log.debug("-----------  updateSipTransport");
 		IConnection current = Red5.getConnectionLocal();
-		StreamClient client = sessionManager.get(IClientUtil.getId(current.getClient()));
+		StreamClient client = streamClientManager.get(IClientUtil.getId(current.getClient()));
 		Long roomId = client.getRoomId();
 		Integer count = getSipConferenceMembersNumber(roomId);
 		String newNumber = getSipTransportLastname(count);
 		_log.debug("getSipConferenceMembersNumber: " + newNumber);
 		if (!newNumber.equals(client.getLastname())) {
-			Client cl = getApp().getOmClientBySid(client.getSid());
+			Client cl = clientManager.getBySid(client.getSid());
 			cl.getUser().setLastname(newNumber);
 			client.setLastname(newNumber);
-			sessionManager.update(client);
+			streamClientManager.update(client);
 			_log.debug("updateSipTransport: {}, {}, {}, {}, {}", new Object[] { client.getUid(), client.getRoomId(),
 					client.getFirstname(), client.getLastname(), client.getAvsettings() });
 			WebSocketHelper.sendRoom(new TextRoomMessage(client.getRoomId(), client, RoomMessage.Type.rightUpdated, client.getUid()));
@@ -1012,8 +1014,8 @@ public class ScopeApplicationAdapter extends MultiThreadedApplicationAdapter imp
 
 	public CheckDto check() {
 		IConnection current = Red5.getConnectionLocal();
-		StreamClient c = sessionManager.get(IClientUtil.getId(current.getClient()));
-		Client cl = getApp().getOmClientBySid(c.getSid());
+		StreamClient c = streamClientManager.get(IClientUtil.getId(current.getClient()));
+		Client cl = clientManager.getBySid(c.getSid());
 		return new CheckDto(cl);
 	}
 
@@ -1022,10 +1024,10 @@ public class ScopeApplicationAdapter extends MultiThreadedApplicationAdapter imp
 			return;
 		}
 		IConnection current = Red5.getConnectionLocal();
-		StreamClient c = sessionManager.get(IClientUtil.getId(current.getClient()));
+		StreamClient c = streamClientManager.get(IClientUtil.getId(current.getClient()));
 		if (c == null) {
 			return;
 		}
-		sessionManager.update(c.setWidth(width.intValue()).setHeight(height.intValue()));
+		streamClientManager.update(c.setWidth(width.intValue()).setHeight(height.intValue()));
 	}
 }
diff --git a/openmeetings-core/src/main/java/org/apache/openmeetings/core/service/RecordingService.java b/openmeetings-core/src/main/java/org/apache/openmeetings/core/service/RecordingService.java
index 675f403..ca93b4e 100644
--- a/openmeetings-core/src/main/java/org/apache/openmeetings/core/service/RecordingService.java
+++ b/openmeetings-core/src/main/java/org/apache/openmeetings/core/service/RecordingService.java
@@ -19,7 +19,6 @@
 package org.apache.openmeetings.core.service;
 
 import static org.apache.openmeetings.core.converter.BaseConverter.printMetaInfo;
-import static org.apache.openmeetings.core.remote.ScopeApplicationAdapter.getApp;
 import static org.apache.openmeetings.util.OpenmeetingsVariables.getWebAppRootKey;
 
 import java.util.Date;
@@ -27,7 +26,6 @@ import java.util.Map;
 import java.util.UUID;
 import java.util.concurrent.ConcurrentHashMap;
 
-import org.apache.openmeetings.IApplication;
 import org.apache.openmeetings.core.data.record.converter.InterviewConverterTask;
 import org.apache.openmeetings.core.data.record.converter.RecordingConverterTask;
 import org.apache.openmeetings.core.data.record.listener.StreamListener;
@@ -36,7 +34,6 @@ import org.apache.openmeetings.core.util.IClientUtil;
 import org.apache.openmeetings.core.util.WebSocketHelper;
 import org.apache.openmeetings.db.dao.record.RecordingDao;
 import org.apache.openmeetings.db.dao.record.RecordingMetaDataDao;
-import org.apache.openmeetings.db.dao.server.ISessionManager;
 import org.apache.openmeetings.db.dao.user.UserDao;
 import org.apache.openmeetings.db.entity.basic.Client;
 import org.apache.openmeetings.db.entity.basic.IClient;
@@ -46,6 +43,8 @@ import org.apache.openmeetings.db.entity.record.RecordingMetaData;
 import org.apache.openmeetings.db.entity.record.RecordingMetaData.Status;
 import org.apache.openmeetings.db.entity.room.StreamClient;
 import org.apache.openmeetings.db.entity.user.User;
+import org.apache.openmeetings.db.manager.IClientManager;
+import org.apache.openmeetings.db.manager.IStreamClientManager;
 import org.apache.openmeetings.db.util.ws.RoomMessage;
 import org.apache.openmeetings.db.util.ws.TextRoomMessage;
 import org.apache.openmeetings.util.CalendarPatterns;
@@ -73,9 +72,10 @@ public class RecordingService {
 	 */
 	private static final Map<Long, StreamListener> streamListeners = new ConcurrentHashMap<>();
 
-	// Spring Beans
 	@Autowired
-	private ISessionManager sessionManager;
+	private IStreamClientManager streamClientManager;
+	@Autowired
+	private IClientManager clientManager;
 	@Autowired
 	private UserDao userDao;
 	@Autowired
@@ -135,13 +135,11 @@ public class RecordingService {
 			// Update Client and set Flag
 			client.setRecordingStarted(true);
 			if (!(client instanceof Client)) {
-				IApplication iapp = getApp();
-				Client c = iapp.getOmClientBySid(client.getSid());
+				Client c = clientManager.getBySid(client.getSid());
 				c.setRecordingId(recordingId);
 				c.setRecordingStarted(true);
-				iapp.update(c);
 			}
-			sessionManager.update(client);
+			streamClientManager.update(client);
 
 			// get all stream and start recording them
 			for (IConnection conn : scope.getClientConnections()) {
@@ -165,9 +163,8 @@ public class RecordingService {
 				log.error("Unable to find recordingId on recording stop");
 				return;
 			}
-			IApplication iapp = getApp();
 			Client recClient = null;
-			for (Client c : iapp.getOmRoomClients(client.getRoomId())) {
+			for (Client c : clientManager.listByRoom(client.getRoomId())) {
 				if (c.getRecordingId() != null) {
 					recClient = c;
 					break;
@@ -182,13 +179,13 @@ public class RecordingService {
 				// Store to database
 				recClient.setRecordingId(null);
 				recClient.setRecordingStarted(false);
-				sessionManager.update(recClient);
+				streamClientManager.update(recClient);
 			}
 			WebSocketHelper.sendRoom(new TextRoomMessage(stopClient.getRoomId(), stopClient, RoomMessage.Type.recordingStoped, stopClient.getSid()));
 			// get all stream and stop recording them
 			for (IConnection conn : scope.getClientConnections()) {
 				if (conn != null && conn instanceof IServiceCapableConnection) {
-					StreamClient rcl = sessionManager.get(IClientUtil.getId(conn.getClient()));
+					StreamClient rcl = streamClientManager.get(IClientUtil.getId(conn.getClient()));
 					stopStreamRecord(scope, rcl);
 				}
 			}
@@ -319,7 +316,7 @@ public class RecordingService {
 
 		// Remove Meta Data
 		rcl.setMetaId(null);
-		sessionManager.update(rcl);
+		streamClientManager.update(rcl);
 	}
 
 	public void startStreamRecord(IConnection conn) {
@@ -331,7 +328,7 @@ public class RecordingService {
 	private void startStreamRecord(IConnection conn, Long recordingId, boolean isInterview) {
 		Date now = new Date();
 
-		StreamClient rcl = sessionManager.get(IClientUtil.getId(conn.getClient()));
+		StreamClient rcl = streamClientManager.get(IClientUtil.getId(conn.getClient()));
 		String broadcastId = rcl.getBroadcastId();
 		if (rcl.getMetaId() != null && streamListeners.get(rcl.getMetaId()) != null) {
 			log.debug("startStreamRecord[{}]:: existing metaId: {}", broadcastId, rcl.getMetaId());
@@ -353,7 +350,7 @@ public class RecordingService {
 
 					// Add Meta Data
 					rcl.setMetaId(metaId);
-					sessionManager.update(rcl);
+					streamClientManager.update(rcl);
 				}
 			} else if ("av".equals(rcl.getAvsettings()) || audioOnly || videoOnly) {
 				// if the user does publish av, a, v
@@ -368,7 +365,7 @@ public class RecordingService {
 
 				// Add Meta Data
 				rcl.setMetaId(metaId);
-				sessionManager.update(rcl);
+				streamClientManager.update(rcl);
 			}
 		}
 		log.debug("startStreamRecord[{}]:: resulting metaId: {}", broadcastId, rcl.getMetaId());
diff --git a/openmeetings-core/src/main/java/org/apache/openmeetings/core/session/SessionManager.java b/openmeetings-core/src/main/java/org/apache/openmeetings/core/session/SessionManager.java
deleted file mode 100644
index 2fd71a5..0000000
--- a/openmeetings-core/src/main/java/org/apache/openmeetings/core/session/SessionManager.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License") +  you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.openmeetings.core.session;
-
-import static org.apache.openmeetings.core.remote.ScopeApplicationAdapter.getApp;
-import static org.apache.openmeetings.util.OpenmeetingsVariables.getWebAppRootKey;
-
-import java.util.Collection;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-import org.apache.openmeetings.IApplication;
-import org.apache.openmeetings.db.dao.server.ISessionManager;
-import org.apache.openmeetings.db.entity.basic.Client;
-import org.apache.openmeetings.db.entity.basic.IClient;
-import org.apache.openmeetings.db.entity.room.StreamClient;
-import org.red5.logging.Red5LoggerFactory;
-import org.red5.server.Server;
-import org.slf4j.Logger;
-import org.springframework.stereotype.Component;
-
-/**
- * Handle {@link StreamClient} objects.
- *
- * Use a kind of decorator pattern to inject the {@link Server} into every call.
- *
- * @author sebawagner
- *
- */
-@Component
-public class SessionManager implements ISessionManager {
-	protected static final Logger log = Red5LoggerFactory.getLogger(SessionManager.class, getWebAppRootKey());
-
-	private static Map<String, StreamClient> getClients() {
-		return getApp().getStreamClients();
-	}
-
-	@Override
-	public StreamClient add(StreamClient c) {
-		if (c == null) {
-			return null;
-		}
-		IApplication iapp = getApp();
-		c.setServerId(iapp.getServerId());
-		c.setConnectedSince(new Date());
-		c.setRoomEnter(new Date());
-		iapp.update(c);
-		return c;
-	}
-
-	@Override
-	public Collection<StreamClient> list() {
-		return getClients().values();
-	}
-
-	@Override
-	public StreamClient get(String uid) {
-		if (uid == null) {
-			return null;
-		}
-		return getClients().get(uid);
-	}
-
-	@Override
-	public void update(IClient rcm) {
-		getApp().update(rcm);
-	}
-
-	@Override
-	public boolean remove(String uid) {
-		if (uid == null) {
-			return false;
-		}
-		StreamClient c = getClients().remove(uid);
-		return c != null;
-	}
-
-	@Override
-	public List<StreamClient> listByRoom(Long roomId) {
-		return list().stream()
-				.filter(c -> roomId.equals(c.getRoomId()) && Client.Type.sharing != c.getType())
-				.collect(Collectors.toList());
-	}
-
-	@Override
-	public long getRecordingCount(Long roomId) {
-		if (roomId == null) {
-			return 0;
-		}
-		return list().stream()
-				.filter(c -> roomId.equals(c.getRoomId()) && c.isRecordingStarted())
-				.collect(Collectors.toList()).size();
-	}
-
-	@Override
-	public long getPublishingCount(Long roomId) {
-		if (roomId == null) {
-			return 0;
-		}
-		return list().stream()
-				.filter(c -> roomId.equals(c.getRoomId()) && c.isPublishStarted())
-				.collect(Collectors.toList()).size();
-	}
-
-	@Override
-	public long getSharingCount(Long roomId) {
-		if (roomId == null) {
-			return 0;
-		}
-		return list().stream()
-				.filter(c -> roomId.equals(c.getRoomId()) && c.isSharingStarted())
-				.collect(Collectors.toList()).size();
-	}
-
-	@Override
-	public long getBroadcastingCount(Long roomId) {
-		if (roomId == null) {
-			return 0;
-		}
-		return list().stream()
-				.filter(c -> roomId.equals(c.getRoomId()) && c.isBroadcasting() && c.getBroadcastId() != null)
-				.collect(Collectors.toList()).size();
-	}
-
-	@Override
-	public Set<Long> getActiveRoomIds() {
-		return getApp().getActiveRoomIds();
-	}
-
-	@Override
-	public Set<Long> getActiveRoomIds(String serverId) {
-		Set<Long> ids = new HashSet<>();
-		if (serverId != null) {
-			for (Map.Entry<String, StreamClient> e : getClients().entrySet()) {
-				if (serverId.equals(e.getValue().getServerId())) {
-					ids.add(e.getValue().getRoomId());
-				}
-			}
-		}
-		return ids;
-	}
-}
diff --git a/openmeetings-core/src/main/java/org/apache/openmeetings/core/util/WebSocketHelper.java b/openmeetings-core/src/main/java/org/apache/openmeetings/core/util/WebSocketHelper.java
index 8d91e67..a0ede37 100644
--- a/openmeetings-core/src/main/java/org/apache/openmeetings/core/util/WebSocketHelper.java
+++ b/openmeetings-core/src/main/java/org/apache/openmeetings/core/util/WebSocketHelper.java
@@ -41,6 +41,7 @@ import org.apache.openmeetings.db.entity.basic.ChatMessage;
 import org.apache.openmeetings.db.entity.basic.Client;
 import org.apache.openmeetings.db.entity.room.Room.Right;
 import org.apache.openmeetings.db.entity.user.User;
+import org.apache.openmeetings.db.manager.IClientManager;
 import org.apache.openmeetings.db.util.FormatHelper;
 import org.apache.openmeetings.db.util.ws.RoomMessage;
 import org.apache.openmeetings.db.util.ws.TextRoomMessage;
@@ -182,7 +183,7 @@ public class WebSocketHelper {
 		if (publish) {
 			publish(new WsMessageUser(userId, m));
 		}
-		send(a -> ((IApplication)a).getOmClients(userId), (t, c) -> {
+		send(a -> ((IApplication)a).getOmBean(IClientManager.class).listByUser(userId), (t, c) -> {
 			try {
 				t.sendMessage(m);
 			} catch (IOException e) {
@@ -230,7 +231,7 @@ public class WebSocketHelper {
 	}
 
 	private static void sendRoom(final Long roomId, BiConsumer<IWebSocketConnection, Client> consumer, Predicate<Client> check) {
-		send(a -> ((IApplication)a).getOmRoomClients(roomId), consumer, check);
+		send(a -> ((IApplication)a).getOmBean(IClientManager.class).listByRoom(roomId), consumer, check);
 	}
 
 	private static void send(
diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/IApplication.java b/openmeetings-db/src/main/java/org/apache/openmeetings/IApplication.java
index 0ae584a..e107dfd 100644
--- a/openmeetings-db/src/main/java/org/apache/openmeetings/IApplication.java
+++ b/openmeetings-db/src/main/java/org/apache/openmeetings/IApplication.java
@@ -18,27 +18,18 @@
  */
 package org.apache.openmeetings;
 
-import java.util.List;
 import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
 import java.util.function.Supplier;
 
 import javax.servlet.ServletContext;
 
 import org.apache.openmeetings.db.dao.basic.ConfigurationDao;
-import org.apache.openmeetings.db.dto.room.Whiteboards;
-import org.apache.openmeetings.db.entity.basic.Client;
-import org.apache.openmeetings.db.entity.basic.IClient;
 import org.apache.openmeetings.db.entity.room.Invitation;
-import org.apache.openmeetings.db.entity.room.StreamClient;
 import org.apache.openmeetings.util.ws.IClusterWsMessage;
 import org.apache.wicket.request.IExceptionMapper;
 import org.apache.wicket.request.IRequestMapper;
 import org.apache.wicket.request.mapper.parameter.PageParameters;
 
-import com.hazelcast.core.IMap;
-
 public interface IApplication {
 	<T> T getOmBean(Class<T> clazz);
 	<T> T _getOmBean(Class<T> clazz);
@@ -51,31 +42,14 @@ public interface IApplication {
 	String getOmContactsLink();
 	String getOmInvitationLink(Invitation i);
 	String urlForActivatePage(PageParameters pp);
-	void invalidateClient(Long userId, String sessionId);
 	void setXFrameOptions(String xFrameOptions);
 	void setContentSecurityPolicy(String contentSecurityPolicy);
 
-	void exit(IClient c);
-	IClient update(IClient c);
-
-	// web client
-	Client getOmClient(String uid);
-	Client getOmClientBySid(String sid);
-	Client getOmOnlineClient(String uid);
-	List<Client> getOmRoomClients(Long roomId);
-	List<Client> getOmClients(Long userId);
-
-	// stream client
-	StreamClient updateClient(StreamClient rcl, boolean forceSize);
 	String getServerId();
-	Map<String, StreamClient> getStreamClients();
-	Set<Long> getActiveRoomIds();
 
 	//JPA
 	void updateJpaAddresses(ConfigurationDao dao);
 
 	//WS
 	void publishWsTopic(IClusterWsMessage msg);
-
-	IMap<Long, Whiteboards> getWhiteboards();
 }
diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/server/SessiondataDao.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/server/SessiondataDao.java
index e7c800d..b51aae0 100644
--- a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/server/SessiondataDao.java
+++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/server/SessiondataDao.java
@@ -31,6 +31,7 @@ import javax.persistence.TypedQuery;
 
 import org.apache.openmeetings.db.entity.room.StreamClient;
 import org.apache.openmeetings.db.entity.server.Sessiondata;
+import org.apache.openmeetings.db.manager.IStreamClientManager;
 import org.red5.logging.Red5LoggerFactory;
 import org.slf4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -50,7 +51,7 @@ public class SessiondataDao {
 	private EntityManager em;
 
 	@Autowired
-	private ISessionManager sessionManager;
+	private IStreamClientManager streamClientManager;
 
 	private static Sessiondata newInstance() {
 		log.debug("startsession :: startsession");
@@ -170,7 +171,7 @@ public class SessiondataDao {
 	 */
 	public void clearSessionByRoomId(Long roomId) {
 		try {
-			for (StreamClient rcl : sessionManager.listByRoom(roomId)) {
+			for (StreamClient rcl : streamClientManager.list(roomId)) {
 				String aux = rcl.getSwfurl();
 
 				int start = aux.indexOf("sid=") + 4;
diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/basic/Client.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/basic/Client.java
index c73032d..b731dfd 100644
--- a/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/basic/Client.java
+++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/entity/basic/Client.java
@@ -26,12 +26,12 @@ import java.util.List;
 import java.util.Set;
 import java.util.UUID;
 
-import org.apache.openmeetings.db.dao.server.ISessionManager;
 import org.apache.openmeetings.db.dao.user.UserDao;
 import org.apache.openmeetings.db.entity.room.Room;
 import org.apache.openmeetings.db.entity.room.Room.Right;
 import org.apache.openmeetings.db.entity.room.StreamClient;
 import org.apache.openmeetings.db.entity.user.User;
+import org.apache.openmeetings.db.manager.IStreamClientManager;
 import org.apache.openmeetings.db.util.RoomHelper;
 import org.apache.wicket.protocol.ws.api.registry.IKey;
 import org.apache.wicket.util.string.Strings;
@@ -409,7 +409,7 @@ public class Client implements IClient {
 		return json;
 	}
 
-	public JSONObject streamJson(String _sid, boolean self, ISessionManager mgr) {
+	public JSONObject streamJson(String _sid, boolean self, IStreamClientManager mgr) {
 		JSONArray _streams = new JSONArray();
 		boolean avFound = false;
 		for (String _uid : streams) {
diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/manager/IClientManager.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/manager/IClientManager.java
new file mode 100644
index 0000000..cab82c6
--- /dev/null
+++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/manager/IClientManager.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License") +  you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.openmeetings.db.manager;
+
+import java.util.List;
+import java.util.Set;
+
+import org.apache.openmeetings.db.entity.basic.Client;
+import org.apache.openmeetings.db.entity.basic.IClient;
+
+public interface IClientManager {
+	Client get(String uid);
+	Client getBySid(String sid);
+	List<Client> listByRoom(Long roomId);
+	List<Client> listByUser(Long userId);
+	Client update(Client c);
+	void exit(IClient c);
+
+
+	/**
+	 * Get a list of all rooms with users in the system.
+	 *
+	 * @return a set, a roomId can be only one time in this list
+	 */
+	Set<Long> getActiveRoomIds();
+}
diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/server/ISessionManager.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/manager/IStreamClientManager.java
similarity index 85%
rename from openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/server/ISessionManager.java
rename to openmeetings-db/src/main/java/org/apache/openmeetings/db/manager/IStreamClientManager.java
index eaec577..301bd6a 100644
--- a/openmeetings-db/src/main/java/org/apache/openmeetings/db/dao/server/ISessionManager.java
+++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/manager/IStreamClientManager.java
@@ -16,9 +16,8 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.openmeetings.db.dao.server;
+package org.apache.openmeetings.db.manager;
 
-import java.util.Collection;
 import java.util.List;
 import java.util.Set;
 
@@ -32,15 +31,19 @@ import org.apache.openmeetings.db.entity.room.StreamClient;
  * @author sebawagner
  *
  */
-public interface ISessionManager {
+public interface IStreamClientManager {
 	StreamClient add(StreamClient c);
 
 	/**
-	 * loads the server into the client (only if database cache is used)
+	 * Get all ClientList Objects of that room and domain This Function is
+	 * needed cause it is invoked internally AFTER the current user has been
+	 * already removed from the ClientList to see if the Room is empty again and
+	 * the PollList can be removed
 	 *
-	 * @return - list of all clients
+	 * @param roomId - id of the room
+	 * @return - list of all clients in the room
 	 */
-	Collection<StreamClient> list();
+	List<StreamClient> list(Long roomId);
 
 	/**
 	 * Get a client by its UID
@@ -55,7 +58,9 @@ public interface ISessionManager {
 	 *
 	 * @param rcm - client to update
 	 */
-	void update(IClient rcm);
+	IClient update(IClient rcm);
+
+	StreamClient update(StreamClient rcl, boolean forceSize);
 
 	/**
 	 * Remove a client from the session store
@@ -66,17 +71,6 @@ public interface ISessionManager {
 	boolean remove(String uid);
 
 	/**
-	 * Get all ClientList Objects of that room and domain This Function is
-	 * needed cause it is invoked internally AFTER the current user has been
-	 * already removed from the ClientList to see if the Room is empty again and
-	 * the PollList can be removed
-	 *
-	 * @param roomId - id of the room
-	 * @return - list of all clients in the room
-	 */
-	List<StreamClient> listByRoom(Long roomId);
-
-	/**
 	 * returns number of users performing recording
 	 *
 	 * @param roomId - id of the room
@@ -109,13 +103,6 @@ public interface ISessionManager {
 	long getBroadcastingCount(Long roomId);
 
 	/**
-	 * Get a list of all rooms with users in the system.
-	 *
-	 * @return a set, a roomId can be only one time in this list
-	 */
-	Set<Long> getActiveRoomIds();
-
-	/**
 	 * Get a list of rooms with users on particular cluster node.
 	 *
 	 * @param serverId - id of the server
diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/manager/IWhiteboardManager.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/manager/IWhiteboardManager.java
new file mode 100644
index 0000000..b321ab0
--- /dev/null
+++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/manager/IWhiteboardManager.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License") +  you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.openmeetings.db.manager;
+
+import org.apache.openmeetings.db.dto.room.Whiteboards;
+
+public interface IWhiteboardManager {
+	Whiteboards get(Long roomId);
+}
diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/util/RoomHelper.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/util/RoomHelper.java
index db5b50f..47cd8cd 100644
--- a/openmeetings-db/src/main/java/org/apache/openmeetings/db/util/RoomHelper.java
+++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/util/RoomHelper.java
@@ -18,9 +18,9 @@
  */
 package org.apache.openmeetings.db.util;
 
-import org.apache.openmeetings.db.dao.server.ISessionManager;
 import org.apache.openmeetings.db.entity.basic.Client;
 import org.apache.openmeetings.db.entity.room.StreamClient;
+import org.apache.openmeetings.db.manager.IStreamClientManager;
 
 import com.github.openjson.JSONArray;
 import com.github.openjson.JSONObject;
@@ -28,7 +28,7 @@ import com.github.openjson.JSONObject;
 public class RoomHelper {
 	private RoomHelper() {}
 
-	public static JSONObject videoJson(Client c, boolean self, String sid, ISessionManager mgr, String uid) {
+	public static JSONObject videoJson(Client c, boolean self, String sid, IStreamClientManager mgr, String uid) {
 		StreamClient sc = mgr.get(uid);
 		if (sc == null) {
 			return new JSONObject();
diff --git a/openmeetings-install/src/main/java/org/apache/openmeetings/cli/Admin.java b/openmeetings-install/src/main/java/org/apache/openmeetings/cli/Admin.java
index 0eee165..6d21419 100644
--- a/openmeetings-install/src/main/java/org/apache/openmeetings/cli/Admin.java
+++ b/openmeetings-install/src/main/java/org/apache/openmeetings/cli/Admin.java
@@ -52,7 +52,7 @@ import org.apache.openjpa.lib.log.LogFactoryImpl.LogImpl;
 import org.apache.openmeetings.backup.BackupExport;
 import org.apache.openmeetings.backup.BackupImport;
 import org.apache.openmeetings.backup.ProgressHolder;
-import org.apache.openmeetings.core.ldap.LdapLoginManagement;
+import org.apache.openmeetings.core.ldap.LdapLoginManager;
 import org.apache.openmeetings.core.util.StrongPasswordValidator;
 import org.apache.openmeetings.db.dao.basic.ConfigurationDao;
 import org.apache.openmeetings.db.dao.file.FileItemDao;
@@ -380,7 +380,7 @@ public class Admin {
 			throw new ExitException();
 		}
 		Long domainId = Long.valueOf(cmdl.getOptionValue('d'));
-		getApplicationContext().getBean(LdapLoginManagement.class).importUsers(domainId, cmdl.hasOption("print-only"));
+		getApplicationContext().getBean(LdapLoginManager.class).importUsers(domainId, cmdl.hasOption("print-only"));
 	}
 
 	private void reportUploads(StringBuilder report, boolean cleanup) throws IOException {
diff --git a/openmeetings-service/src/main/java/org/apache/openmeetings/service/quartz/scheduler/CleanupJob.java b/openmeetings-service/src/main/java/org/apache/openmeetings/service/quartz/scheduler/CleanupJob.java
index a858035..33b34b1 100644
--- a/openmeetings-service/src/main/java/org/apache/openmeetings/service/quartz/scheduler/CleanupJob.java
+++ b/openmeetings-service/src/main/java/org/apache/openmeetings/service/quartz/scheduler/CleanupJob.java
@@ -30,13 +30,13 @@ import java.util.Map;
 
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.lang3.math.NumberUtils;
-import org.apache.openmeetings.core.data.whiteboard.WhiteboardCache;
-import org.apache.openmeetings.db.dao.server.ISessionManager;
 import org.apache.openmeetings.db.dao.server.SessiondataDao;
 import org.apache.openmeetings.db.dao.user.UserDao;
 import org.apache.openmeetings.db.dto.room.Whiteboard;
 import org.apache.openmeetings.db.dto.room.Whiteboards;
 import org.apache.openmeetings.db.entity.user.User;
+import org.apache.openmeetings.db.manager.IStreamClientManager;
+import org.apache.openmeetings.db.manager.IWhiteboardManager;
 import org.red5.logging.Red5LoggerFactory;
 import org.slf4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -51,9 +51,11 @@ public class CleanupJob extends AbstractJob {
 	@Autowired
 	private SessiondataDao sessionDao;
 	@Autowired
-	private ISessionManager sessionManager;
+	private IStreamClientManager streamClientManager;
 	@Autowired
 	private UserDao userDao;
+	@Autowired
+	private IWhiteboardManager wbManager;
 
 	public void setSessionTimeout(long sessionTimeout) {
 		this.sessionTimeout = sessionTimeout;
@@ -114,7 +116,7 @@ public class CleanupJob extends AbstractJob {
 				Long roomId = null;
 				if (NumberUtils.isCreatable(folder.getName())) {
 					roomId = Long.valueOf(folder.getName());
-					Whiteboards wbList = WhiteboardCache.get(roomId);
+					Whiteboards wbList = wbManager.get(roomId);
 					for (Map.Entry<Long, Whiteboard> e : wbList.getWhiteboards().entrySet()) {
 						if (!e.getValue().isEmpty()) {
 							roomId = null;
@@ -122,7 +124,7 @@ public class CleanupJob extends AbstractJob {
 						}
 					}
 				}
-				if (roomId != null && sessionManager.listByRoom(roomId).isEmpty()) {
+				if (roomId != null && streamClientManager.list(roomId).isEmpty()) {
 					File[] files = folder.listFiles(fi -> fi.isFile() && fi.lastModified() + roomFilesTtl < now);
 					if (files != null && files.length > 0) {
 						log.debug("Room files are too old and no users in the room: " + roomId);
diff --git a/openmeetings-service/src/main/java/org/apache/openmeetings/service/user/UserManager.java b/openmeetings-service/src/main/java/org/apache/openmeetings/service/user/UserManager.java
index b93bbf7..057e364 100644
--- a/openmeetings-service/src/main/java/org/apache/openmeetings/service/user/UserManager.java
+++ b/openmeetings-service/src/main/java/org/apache/openmeetings/service/user/UserManager.java
@@ -46,7 +46,6 @@ import org.apache.commons.codec.binary.Base64;
 import org.apache.openmeetings.core.remote.ScopeApplicationAdapter;
 import org.apache.openmeetings.db.dao.basic.ConfigurationDao;
 import org.apache.openmeetings.db.dao.label.LabelDao;
-import org.apache.openmeetings.db.dao.server.ISessionManager;
 import org.apache.openmeetings.db.dao.server.SessiondataDao;
 import org.apache.openmeetings.db.dao.user.GroupDao;
 import org.apache.openmeetings.db.dao.user.IUserManager;
@@ -59,6 +58,7 @@ import org.apache.openmeetings.db.entity.user.User;
 import org.apache.openmeetings.db.entity.user.User.Right;
 import org.apache.openmeetings.db.entity.user.User.Salutation;
 import org.apache.openmeetings.db.entity.user.User.Type;
+import org.apache.openmeetings.db.manager.IStreamClientManager;
 import org.apache.openmeetings.service.mail.EmailManager;
 import org.apache.openmeetings.util.OmException;
 import org.apache.wicket.util.string.Strings;
@@ -86,11 +86,11 @@ public class UserManager implements IUserManager {
 	@Autowired
 	private UserDao userDao;
 	@Autowired
-	private EmailManager emailManagement;
+	private EmailManager emailManager;
 	@Autowired
 	private ScopeApplicationAdapter scopeAdapter;
 	@Autowired
-	private ISessionManager sessionManager;
+	private IStreamClientManager streamClientManager;
 
 	/**
 	 * Method to register a new User, User will automatically be added to the
@@ -203,7 +203,7 @@ public class UserManager implements IUserManager {
 			if (checkName && checkEmail) {
 				String hash = Strings.isEmpty(activatedHash) ? UUID.randomUUID().toString() : activatedHash;
 				if (sendWelcomeMessage && email.length() != 0) {
-					emailManagement.sendMail(login, email, hash, sendConfirmation, languageId);
+					emailManager.sendMail(login, email, hash, sendConfirmation, languageId);
 				}
 				Address a =  new Address();
 				a.setStreet(street);
@@ -282,7 +282,7 @@ public class UserManager implements IUserManager {
 		try {
 			sessionDao.clearSessionByRoomId(roomId);
 
-			for (StreamClient rcl : sessionManager.listByRoom(roomId)) {
+			for (StreamClient rcl : streamClientManager.list(roomId)) {
 				if (rcl == null) {
 					return true;
 				}
@@ -304,7 +304,7 @@ public class UserManager implements IUserManager {
 	@Override
 	public boolean kickById(String uid) {
 		try {
-			StreamClient rcl = sessionManager.get(uid);
+			StreamClient rcl = streamClientManager.get(uid);
 
 			if (rcl == null) {
 				return true;
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/connection/ConnectionsPanel.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/connection/ConnectionsPanel.java
index b01b08b..6fbbbb8 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/connection/ConnectionsPanel.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/connection/ConnectionsPanel.java
@@ -27,14 +27,14 @@ import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 
-import org.apache.openmeetings.db.dao.server.ISessionManager;
 import org.apache.openmeetings.db.dao.user.IUserManager;
 import org.apache.openmeetings.db.entity.basic.Client;
 import org.apache.openmeetings.db.entity.basic.IClient;
 import org.apache.openmeetings.db.entity.room.StreamClient;
 import org.apache.openmeetings.web.admin.AdminBasePanel;
 import org.apache.openmeetings.web.admin.SearchableDataView;
-import org.apache.openmeetings.web.app.Application;
+import org.apache.openmeetings.web.app.ClientManager;
+import org.apache.openmeetings.web.app.StreamClientManager;
 import org.apache.openmeetings.web.common.ConfirmableAjaxBorder;
 import org.apache.openmeetings.web.common.PagedEntityListPanel;
 import org.apache.openmeetings.web.data.SearchableDataProvider;
@@ -59,8 +59,8 @@ public class ConnectionsPanel extends AdminBasePanel {
 
 			private List<IClient> list() {
 				List<IClient> l = new ArrayList<>();
-				l.addAll(getBean(ISessionManager.class).list());
-				l.addAll(Application.getClients());
+				l.addAll(getBean(StreamClientManager.class).list());
+				l.addAll(getBean(ClientManager.class).list());
 				return l;
 			}
 
@@ -93,7 +93,7 @@ public class ConnectionsPanel extends AdminBasePanel {
 							getBean(IUserManager.class).kickById(_c.getUid());
 						} else {
 							Client c = (Client)_c;
-							Application.get().invalidateClient(c.getUserId(), c.getSessionId());
+							getBean(ClientManager.class).invalidate(c.getUserId(), c.getSessionId());
 						}
 						target.add(container, details.setVisible(false));
 					}
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/rooms/RoomForm.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/rooms/RoomForm.java
index 998c195..a9ad590 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/rooms/RoomForm.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/rooms/RoomForm.java
@@ -49,7 +49,7 @@ import org.apache.openmeetings.db.entity.user.Group;
 import org.apache.openmeetings.db.entity.user.User;
 import org.apache.openmeetings.web.admin.AdminBaseForm;
 import org.apache.openmeetings.web.admin.AdminUserChoiceProvider;
-import org.apache.openmeetings.web.app.Application;
+import org.apache.openmeetings.web.app.ClientManager;
 import org.apache.openmeetings.web.common.ConfirmableAjaxBorder;
 import org.apache.openmeetings.web.util.RestrictiveChoiceProvider;
 import org.apache.openmeetings.web.util.RoomTypeDropDown;
@@ -419,7 +419,7 @@ public class RoomForm extends AdminBaseForm<Room> {
 
 	void updateClients(AjaxRequestTarget target) {
 		long roomId = getModelObject().getId() != null ? getModelObject().getId() : 0;
-		final List<Client> clientsInRoom = Application.getRoomClients(roomId);
+		final List<Client> clientsInRoom = getBean(ClientManager.class).listByRoom(roomId);
 		clients.setDefaultModelObject(clientsInRoom);
 		target.add(clientsContainer);
 	}
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application.java
index 374afe6..7571782 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/Application.java
@@ -18,10 +18,6 @@
  */
 package org.apache.openmeetings.web.app;
 
-import static org.apache.openmeetings.core.util.WebSocketHelper.sendRoom;
-import static org.apache.openmeetings.db.dao.room.SipDao.SIP_FIRST_NAME;
-import static org.apache.openmeetings.db.dao.room.SipDao.SIP_USER_NAME;
-import static org.apache.openmeetings.util.OmFileHelper.SIP_USER_ID;
 import static org.apache.openmeetings.util.OpenmeetingsVariables.HEADER_XFRAME_SAMEORIGIN;
 import static org.apache.openmeetings.util.OpenmeetingsVariables.getApplicationName;
 import static org.apache.openmeetings.util.OpenmeetingsVariables.getBaseUrl;
@@ -41,38 +37,22 @@ import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
-import java.util.Map.Entry;
 import java.util.Set;
-import java.util.function.Predicate;
 
 import org.apache.directory.api.util.Strings;
 import org.apache.openmeetings.IApplication;
-import org.apache.openmeetings.core.remote.MobileService;
-import org.apache.openmeetings.core.remote.ScopeApplicationAdapter;
 import org.apache.openmeetings.core.service.MainService;
 import org.apache.openmeetings.core.util.WebSocketHelper;
 import org.apache.openmeetings.db.dao.basic.ConfigurationDao;
 import org.apache.openmeetings.db.dao.label.LabelDao;
-import org.apache.openmeetings.db.dao.log.ConferenceLogDao;
-import org.apache.openmeetings.db.dao.room.RoomDao;
-import org.apache.openmeetings.db.dao.server.SessiondataDao;
 import org.apache.openmeetings.db.dao.user.UserDao;
-import org.apache.openmeetings.db.dto.room.Whiteboards;
 import org.apache.openmeetings.db.entity.basic.Client;
-import org.apache.openmeetings.db.entity.basic.Client.Activity;
-import org.apache.openmeetings.db.entity.basic.Client.Pod;
-import org.apache.openmeetings.db.entity.basic.IClient;
-import org.apache.openmeetings.db.entity.log.ConferenceLog;
 import org.apache.openmeetings.db.entity.record.Recording;
 import org.apache.openmeetings.db.entity.room.Invitation;
 import org.apache.openmeetings.db.entity.room.Room;
-import org.apache.openmeetings.db.entity.room.Room.Right;
-import org.apache.openmeetings.db.entity.room.StreamClient;
-import org.apache.openmeetings.db.entity.server.Sessiondata;
 import org.apache.openmeetings.db.entity.user.User;
 import org.apache.openmeetings.db.entity.user.User.Type;
 import org.apache.openmeetings.db.util.ws.RoomMessage;
@@ -127,9 +107,7 @@ import org.apache.wicket.request.http.WebResponse;
 import org.apache.wicket.request.mapper.info.PageComponentInfo;
 import org.apache.wicket.request.mapper.parameter.PageParameters;
 import org.apache.wicket.request.mapper.parameter.PageParametersEncoder;
-import org.apache.wicket.util.collections.ConcurrentHashSet;
 import org.apache.wicket.validation.validator.UrlValidator;
-import org.red5.server.api.scope.IScope;
 import org.slf4j.Logger;
 import org.springframework.web.context.WebApplicationContext;
 import org.wicketstuff.dashboard.WidgetRegistry;
@@ -141,7 +119,6 @@ import org.wicketstuff.datastores.hazelcast.HazelcastDataStore;
 import com.hazelcast.config.XmlConfigBuilder;
 import com.hazelcast.core.Hazelcast;
 import com.hazelcast.core.HazelcastInstance;
-import com.hazelcast.core.IMap;
 import com.hazelcast.core.ITopic;
 import com.hazelcast.core.Member;
 import com.hazelcast.core.MemberAttributeEvent;
@@ -151,12 +128,7 @@ import com.hazelcast.core.MembershipListener;
 public class Application extends AuthenticatedWebApplication implements IApplication {
 	private static final Logger log = getLogger(Application.class, getWebAppRootKey());
 	private static boolean isInstalled;
-	private static final String ONLINE_USERS_KEY = "ONLINE_USERS_KEY";
-	private static final String UID_BY_SID_KEY = "UID_BY_SID_KEY";
 	private static final String INVALID_SESSIONS_KEY = "INVALID_SESSIONS_KEY";
-	private static final String ROOMS_KEY = "ROOMS_KEY";
-	private static final String WBS_KEY = "WBS_KEY";
-	private static final String STREAM_CLIENT_KEY = "STREAM_CLIENT_KEY";
 	public static final String NAME_ATTR_KEY = "name";
 	//additional maps for faster searching should be created
 	private DashboardContext dashboardContext;
@@ -169,9 +141,9 @@ public class Application extends AuthenticatedWebApplication implements IApplica
 	public static final String HASH_MAPPING = "/hash";
 	public static final String SIGNIN_MAPPING = "/signin";
 	public static final String NOTINIT_MAPPING = "/notinited";
+	private final HazelcastInstance hazelcast = Hazelcast.getOrCreateHazelcastInstance(new XmlConfigBuilder().build());
 	private String xFrameOptions = HEADER_XFRAME_SAMEORIGIN;
 	private String contentSecurityPolicy = OpenmeetingsVariables.HEADER_CSP_SELF;
-	private final HazelcastInstance hazelcast = Hazelcast.getOrCreateHazelcastInstance(new XmlConfigBuilder().build());
 	private ITopic<IClusterWsMessage> hazelWsTopic;
 
 	@Override
@@ -194,18 +166,8 @@ public class Application extends AuthenticatedWebApplication implements IApplica
 			public void memberRemoved(MembershipEvent evt) {
 				//server down, need to remove all online clients, process persistent addresses
 				String serverId = evt.getMember().getStringAttribute(NAME_ATTR_KEY);
-				for (Map.Entry<String, Client> e : getOnlineUsers().entrySet()) {
-					if (serverId.equals(e.getValue().getServerId())) {
-						exit(e.getValue());
-					}
-				}
-				Map<String, StreamClient> streams = getStreamClients();
-				for (Iterator<Map.Entry<String, StreamClient>> iter = streams.entrySet().iterator(); iter.hasNext(); ) {
-					Map.Entry<String, StreamClient> e = iter.next();
-					if (serverId.equals(e.getValue().getServerId())) {
-						iter.remove();
-					}
-				}
+				getBean(ClientManager.class).clean(serverId);
+				getBean(StreamClientManager.class).clean(serverId);
 				updateJpaAddresses(_getBean(ConfigurationDao.class));
 			}
 
@@ -260,7 +222,6 @@ public class Application extends AuthenticatedWebApplication implements IApplica
 				}
 			}
 		});
-
 		super.init();
 
 		// register some widgets
@@ -345,246 +306,20 @@ public class Application extends AuthenticatedWebApplication implements IApplica
 		return get().dashboardContext;
 	}
 
-	private Map<String, Client> getOnlineUsers() {
-		return hazelcast.getMap(ONLINE_USERS_KEY);
+	//package private
+	static HazelcastInstance getHazelcast() {
+		return get().hazelcast;
 	}
 
-	private Map<String, String> getInvalidSessions() {
+	//package private
+	Map<String, String> getInvalidSessions() {
 		return hazelcast.getMap(INVALID_SESSIONS_KEY);
 	}
 
-	private IMap<Long, Set<String>> getRooms() {
-		return hazelcast.getMap(ROOMS_KEY);
-	}
-
-	private Map<String, String> getUidBySid() {
-		return hazelcast.getMap(UID_BY_SID_KEY);
-	}
-
-	@Override
-	public IMap<Long, Whiteboards> getWhiteboards() {
-		return hazelcast.getMap(WBS_KEY);
-	}
-
-	@Override
-	public Set<Long> getActiveRoomIds() {
-		return getRooms().keySet();
-	}
-
-	@Override
-	public Map<String, StreamClient> getStreamClients() {
-		return hazelcast.getMap(STREAM_CLIENT_KEY);
-	}
-
-	@Override
-	public IClient update(IClient c) {
-		if (c instanceof StreamClient) {
-			hazelcast.getMap(STREAM_CLIENT_KEY).put(c.getUid(), c);
-		} else {
-			update((Client)c);
-		}
-		return c;
-	}
-
-	public static void addOnlineUser(Client c) {
-		log.debug("Adding online client: {}, room: {}", c.getUid(), c.getRoom());
-		c.setServerId(get().getServerId());
-		get().getOnlineUsers().put(c.getUid(), c);
-		get().getUidBySid().put(c.getSid(), c.getUid());
-	}
-
-	public static void exitRoom(IClient c) {
-		Long roomId = c.getRoomId();
-		removeUserFromRoom(c);
-		if (roomId != null) {
-			sendRoom(new RoomMessage(roomId, c, RoomMessage.Type.roomExit));
-			getBean(ConferenceLogDao.class).add(
-					ConferenceLog.Type.roomLeave
-					, c.getUserId(), "0", roomId
-					, c.getRemoteAddress()
-					, String.valueOf(roomId));
-		}
-	}
-
-	@Override
-	public void exit(IClient c) {
-		if (c != null) {
-			exitRoom(c);
-			log.debug("Removing online client: {}, roomId: {}", c.getUid(), c.getRoomId());
-			get().getOnlineUsers().remove(c.getUid());
-			get().getUidBySid().remove(c.getSid());
-		}
-	}
-
 	public static void kickUser(Client client) {
 		WebSocketHelper.sendRoom(new TextRoomMessage(client.getRoom().getId(), client, RoomMessage.Type.kick, client.getUid()));
 	}
 
-	private static boolean hasVideo(StreamClient rcl) {
-		return rcl != null && rcl.getAvsettings().contains("v");
-	}
-
-	private static boolean hasVideo(Client c) {
-		return c != null && c.hasActivity(Activity.broadcastV);
-	}
-
-	@Override
-	public StreamClient updateClient(StreamClient rcl, boolean forceSize) {
-		if (rcl == null) {
-			return null;
-		}
-		Client client = getClientBySid(rcl.getSid());
-		if (client == null) {
-			if (Client.Type.mobile == rcl.getType()) {
-				Sessiondata sd = getBean(SessiondataDao.class).check(rcl.getSid());
-				UserDao udao = getBean(UserDao.class);
-				User u = udao.get(sd.getUserId());
-				rcl = getBean(MobileService.class).create(rcl, u);
-				//Mobile client enters the room
-				client = new Client(rcl, udao.get(rcl.getUserId()));
-				addOnlineUser(client);
-				if (rcl.getRoomId() != null) {
-					client.setCam(0);
-					client.setMic(0);
-					client.setRoom(getBean(RoomDao.class).get(rcl.getRoomId()));
-					addUserToRoom(client);
-					WebSocketHelper.sendRoom(new RoomMessage(client.getRoom().getId(), client, RoomMessage.Type.roomEnter));
-				}
-			} else if (client == null && Client.Type.sip == rcl.getType()) {
-				rcl.setLogin(SIP_USER_NAME);
-				rcl.setUserId(SIP_USER_ID);
-				//SipTransport enters the room
-				User u = new User();
-				u.setId(SIP_USER_ID);
-				u.setLogin(SIP_USER_NAME);
-				u.setFirstname(SIP_FIRST_NAME);
-				client = new Client(rcl, u);
-				addOnlineUser(client);
-				client.setCam(0);
-				client.setMic(0);
-				client.allow(Room.Right.audio, Room.Right.video);
-				client.set(Activity.broadcastA);
-				addUserToRoom(client);
-				WebSocketHelper.sendRoom(new RoomMessage(client.getRoom().getId(), client, RoomMessage.Type.roomEnter));
-			} else {
-				return null;
-			}
-		}
-		if (rcl.getRoomId() == null || !rcl.getRoomId().equals(client.getRoom().getId())) {
-			return null;
-		}
-		User u = client.getUser();
-		rcl.setUserId(u.getId());
-		rcl.setLogin(u.getLogin());
-		rcl.setFirstname(u.getFirstname());
-		rcl.setLastname(u.getLastname());
-		rcl.setEmail(u.getAddress() == null ? null : u.getAddress().getEmail());
-		rcl.setSuperMod(client.hasRight(Right.superModerator));
-		rcl.setMod(client.hasRight(Right.moderator));
-		if (client.hasActivity(Activity.broadcastA) && client.getMic() < 0) {
-			client.remove(Activity.broadcastA);
-		}
-		if (client.hasActivity(Activity.broadcastV) && client.getCam() < 0) {
-			client.remove(Activity.broadcastV);
-		}
-		if (client.hasActivity(Activity.broadcastA) || client.hasActivity(Activity.broadcastV)) {
-			if (forceSize || rcl.getWidth() == 0 || rcl.getHeight() == 0) {
-				rcl.setWidth(client.getWidth());
-				rcl.setHeight(client.getHeight());
-			}
-			if (client.getPod() != Pod.none) {
-				rcl.setInterviewPodId(client.getPod() == Pod.left ? 1 : 2);
-			}
-			StringBuilder sb = new StringBuilder();
-			if (client.hasActivity(Activity.broadcastA)) {
-				sb.append('a');
-			}
-			if (client.hasActivity(Activity.broadcastV)) {
-				sb.append('v');
-			}
-			if (!rcl.isBroadcasting() || hasVideo(rcl) != hasVideo(client)) {
-				rcl.setBroadcasting(true);
-			}
-			rcl.setAvsettings(sb.toString());
-		} else {
-			rcl.setAvsettings("n");
-			rcl.setBroadcasting(false);
-		}
-		return rcl;
-	}
-
-	public static Client getOnlineClient(String uid) {
-		return uid == null ? null : get().getOnlineUsers().get(uid);
-	}
-
-	@Override
-	public Client getOmOnlineClient(String uid) {
-		return getOnlineClient(uid);
-	}
-
-	@Override
-	public Client getOmClientBySid(String sid) {
-		return getClientBySid(sid);
-	}
-
-	public static Client getClientBySid(String sid) {
-		if (sid == null) {
-			return null;
-		}
-		String uid = get().getUidBySid().get(sid);
-		return uid == null ? null : get().getOnlineUsers().get(uid);
-	}
-
-	public static boolean isUserOnline(Long userId) {
-		boolean isUserOnline = false;
-		for (Map.Entry<String, Client> e : get().getOnlineUsers().entrySet()) {
-			if (e.getValue().getUserId().equals(userId)) {
-				isUserOnline = true;
-				break;
-			}
-		}
-		return isUserOnline;
-	}
-
-	public static List<Client> getClients() {
-		return new ArrayList<>(get().getOnlineUsers().values());
-	}
-
-	public static List<Client> getClients(Long userId) {
-		List<Client> result =  new ArrayList<>();
-		for (Map.Entry<String, Client> e : get().getOnlineUsers().entrySet()) {
-			if (e.getValue().getUserId().equals(userId)) {
-				result.add(e.getValue());
-				break;
-			}
-		}
-		return result;
-	}
-
-	public static Client getClientByKeys(Long userId, String sessionId) {
-		Client client = null;
-		for (Map.Entry<String, Client> e : get().getOnlineUsers().entrySet()) {
-			Client c = e.getValue();
-			if (c.getUserId().equals(userId) && c.getSessionId().equals(sessionId)) {
-				client = c;
-				break;
-			}
-		}
-		return client;
-	}
-
-	@Override
-	public void invalidateClient(Long userId, String sessionId) {
-		Client client = getClientByKeys(userId, sessionId);
-		if (client != null) {
-			Map<String, String> invalid = getInvalidSessions();
-			if (!invalid.containsKey(client.getSessionId())) {
-				invalid.put(client.getSessionId(), client.getUid());
-				exit(client);
-			}
-		}
-	}
-
 	public static boolean isInvaldSession(String sessionId) {
 		return sessionId == null ? false : get().getInvalidSessions().containsKey(sessionId);
 	}
@@ -595,113 +330,6 @@ public class Application extends AuthenticatedWebApplication implements IApplica
 		}
 	}
 
-	public static Client update(Client c) {
-		get().getOnlineUsers().put(c.getUid(), c); // update in storage
-		return c;
-	}
-
-	public static Client addUserToRoom(Client c) {
-		Long roomId = c.getRoom().getId();
-		log.debug("Adding online room client: {}, room: {}", c.getUid(), roomId);
-		IMap<Long, Set<String>> rooms = get().getRooms();
-		rooms.lock(roomId);
-		rooms.putIfAbsent(roomId, new ConcurrentHashSet<String>());
-		Set<String> set = rooms.get(roomId);
-		set.add(c.getUid());
-		rooms.put(roomId, set);
-		rooms.unlock(roomId);
-		update(c);
-		return c;
-	}
-
-	public static IClient removeUserFromRoom(IClient _c) {
-		Long roomId = _c.getRoomId();
-		log.debug("Removing online room client: {}, room: {}", _c.getUid(), roomId);
-		if (roomId != null) {
-			Map<Long, Set<String>> rooms = get().getRooms();
-			Set<String> clients = rooms.get(roomId);
-			if (clients != null) {
-				clients.remove(_c.getUid());
-				rooms.put(roomId, clients);
-			}
-			if (_c instanceof StreamClient) {
-				StreamClient sc = (StreamClient)_c;
-				if (Client.Type.mobile != sc.getType() && Client.Type.sip != sc.getType()) {
-					getBean(ScopeApplicationAdapter.class).roomLeaveByScope(_c, roomId);
-				}
-			}
-			if (_c instanceof Client) {
-				ScopeApplicationAdapter scApp = getBean(ScopeApplicationAdapter.class);
-				scApp.dropSharing(_c, roomId);
-				Client c = (Client)_c;
-				IScope sc = scApp.getChildScope(roomId);
-				for (String uid : c.getStreams()) {
-					scApp.sendMessageById("quit", uid, sc);
-				}
-				c.setRoom(null);
-				c.clear();
-				update(c);
-			}
-		}
-		return _c;
-	}
-
-	@Override
-	public List<Client> getOmRoomClients(Long roomId) {
-		return getRoomClients(roomId);
-	}
-
-	@Override
-	public List<Client> getOmClients(Long userId) {
-		return getClients(userId);
-	}
-
-	public static List<Client> getRoomClients(Long roomId) {
-		return getRoomClients(roomId, null);
-	}
-
-	public static List<Client> getRoomClients(Long roomId, Predicate<Client> filter) {
-		List<Client> clients = new ArrayList<>();
-		if (roomId != null) {
-			Set<String> uids = get().getRooms().get(roomId);
-			if (uids != null) {
-				for (String uid : uids) {
-					Client c = getOnlineClient(uid);
-					if (c != null && (filter == null || filter.test(c))) {
-						clients.add(c);
-					}
-				}
-			}
-		}
-		return clients;
-	}
-
-	public static Set<Long> getUserRooms(Long userId) {
-		Set<Long> result = new HashSet<>();
-		for (Entry<Long, Set<String>> me : get().getRooms().entrySet()) {
-			for (String uid : me.getValue()) {
-				Client c = getOnlineClient(uid);
-				if (c != null && c.getUserId().equals(userId)) {
-					result.add(me.getKey());
-				}
-			}
-		}
-		return result;
-	}
-
-	public static boolean isUserInRoom(long roomId, long userId) {
-		Set<String> clients = get().getRooms().get(roomId);
-		if (clients != null) {
-			for (String uid : clients) {
-				Client c = getOnlineClient(uid);
-				if (c != null && c.getUserId().equals(userId)) {
-					return true;
-				}
-			}
-		}
-		return false;
-	}
-
 	public <T> T _getBean(Class<T> clazz) {
 		WebApplicationContext wac = getWebApplicationContext(getServletContext());
 		return wac == null ? null : wac.getBean(clazz);
@@ -849,11 +477,6 @@ public class Application extends AuthenticatedWebApplication implements IApplica
 	}
 
 	@Override
-	public Client getOmClient(String uid) {
-		return getOnlineClient(uid);
-	}
-
-	@Override
 	public void setXFrameOptions(String xFrameOptions) {
 		this.xFrameOptions = xFrameOptions;
 	}
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/ClientManager.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/ClientManager.java
new file mode 100644
index 0000000..d3b8e85
--- /dev/null
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/ClientManager.java
@@ -0,0 +1,287 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License") +  you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.openmeetings.web.app;
+
+import static org.apache.openmeetings.core.util.WebSocketHelper.sendRoom;
+import static org.apache.openmeetings.util.OpenmeetingsVariables.getWebAppRootKey;
+import static org.apache.openmeetings.web.app.Application.getHazelcast;
+import static org.red5.logging.Red5LoggerFactory.getLogger;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.function.Predicate;
+
+import javax.annotation.PostConstruct;
+
+import org.apache.openmeetings.core.remote.ScopeApplicationAdapter;
+import org.apache.openmeetings.db.dao.log.ConferenceLogDao;
+import org.apache.openmeetings.db.entity.basic.Client;
+import org.apache.openmeetings.db.entity.basic.IClient;
+import org.apache.openmeetings.db.entity.log.ConferenceLog;
+import org.apache.openmeetings.db.entity.room.StreamClient;
+import org.apache.openmeetings.db.manager.IClientManager;
+import org.apache.openmeetings.db.util.ws.RoomMessage;
+import org.apache.wicket.util.collections.ConcurrentHashSet;
+import org.red5.server.api.scope.IScope;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import com.hazelcast.core.HazelcastInstance;
+import com.hazelcast.core.IMap;
+
+@Component
+public class ClientManager implements IClientManager {
+	private static final Logger log = getLogger(ClientManager.class, getWebAppRootKey());
+	private static final String ROOMS_KEY = "ROOMS_KEY";
+	private static final String ONLINE_USERS_KEY = "ONLINE_USERS_KEY";
+	private static final String UID_BY_SID_KEY = "UID_BY_SID_KEY";
+	private HazelcastInstance hazelcast;
+
+	@Autowired
+	private ConferenceLogDao confLogDao;
+	@Autowired
+	private ScopeApplicationAdapter scopeAdapter;
+
+	@PostConstruct
+	private void init() {
+		this.hazelcast = getHazelcast();
+	}
+
+	private Map<String, Client> map() {
+		return hazelcast.getMap(ONLINE_USERS_KEY);
+	}
+
+	private Map<String, String> mapUidBySid() {
+		return hazelcast.getMap(UID_BY_SID_KEY);
+	}
+
+	private IMap<Long, Set<String>> getRooms() {
+		return hazelcast.getMap(ROOMS_KEY);
+	}
+
+	public void add(Client c) {
+		log.debug("Adding online client: {}, room: {}", c.getUid(), c.getRoom());
+		c.setServerId(Application.get().getServerId());
+		map().put(c.getUid(), c);
+		mapUidBySid().put(c.getSid(), c.getUid());
+	}
+
+	@Override
+	public Client update(Client c) {
+		map().put(c.getUid(), c); // update in storage
+		return c;
+	}
+	@Override
+	public Client get(String uid) {
+		return uid == null ? null : map().get(uid);
+	}
+
+	@Override
+	public Client getBySid(String sid) {
+		if (sid == null) {
+			return null;
+		}
+		String uid = mapUidBySid().get(sid);
+		return uid == null ? null : map().get(uid);
+	}
+
+	public void exitRoom(IClient c) {
+		Long roomId = c.getRoomId();
+		removeFromRoom(c);
+		if (roomId != null) {
+			sendRoom(new RoomMessage(roomId, c, RoomMessage.Type.roomExit));
+			confLogDao.add(
+					ConferenceLog.Type.roomLeave
+					, c.getUserId(), "0", roomId
+					, c.getRemoteAddress()
+					, String.valueOf(roomId));
+		}
+	}
+
+	@Override
+	public void exit(IClient c) {
+		if (c != null) {
+			exitRoom(c);
+			log.debug("Removing online client: {}, roomId: {}", c.getUid(), c.getRoomId());
+			map().remove(c.getUid());
+			mapUidBySid().remove(c.getSid());
+		}
+	}
+
+	public void clean(String serverId) {
+		Map<String, Client> clients = map();
+		for (Map.Entry<String, Client> e : clients.entrySet()) {
+			if (serverId.equals(e.getValue().getServerId())) {
+				exit(e.getValue());
+			}
+		}
+	}
+
+	@Override
+	public Set<Long> getActiveRoomIds() {
+		return getRooms().keySet();
+	}
+
+	public Client addToRoom(Client c) {
+		Long roomId = c.getRoom().getId();
+		log.debug("Adding online room client: {}, room: {}", c.getUid(), roomId);
+		IMap<Long, Set<String>> rooms = getRooms();
+		rooms.lock(roomId);
+		rooms.putIfAbsent(roomId, new ConcurrentHashSet<String>());
+		Set<String> set = rooms.get(roomId);
+		set.add(c.getUid());
+		rooms.put(roomId, set);
+		rooms.unlock(roomId);
+		update(c);
+		return c;
+	}
+
+	public IClient removeFromRoom(IClient _c) {
+		Long roomId = _c.getRoomId();
+		log.debug("Removing online room client: {}, room: {}", _c.getUid(), roomId);
+		if (roomId != null) {
+			Map<Long, Set<String>> rooms = getRooms();
+			Set<String> clients = rooms.get(roomId);
+			if (clients != null) {
+				clients.remove(_c.getUid());
+				rooms.put(roomId, clients);
+			}
+			if (_c instanceof StreamClient) {
+				StreamClient sc = (StreamClient)_c;
+				if (Client.Type.mobile != sc.getType() && Client.Type.sip != sc.getType()) {
+					scopeAdapter.roomLeaveByScope(_c, roomId);
+				}
+			}
+			if (_c instanceof Client) {
+				scopeAdapter.dropSharing(_c, roomId);
+				Client c = (Client)_c;
+				IScope sc = scopeAdapter.getChildScope(roomId);
+				for (String uid : c.getStreams()) {
+					scopeAdapter.sendMessageById("quit", uid, sc);
+				}
+				c.setRoom(null);
+				c.clear();
+				update(c);
+			}
+		}
+		return _c;
+	}
+
+	public boolean isOnline(Long userId) {
+		boolean isUserOnline = false;
+		for (Map.Entry<String, Client> e : map().entrySet()) {
+			if (e.getValue().getUserId().equals(userId)) {
+				isUserOnline = true;
+				break;
+			}
+		}
+		return isUserOnline;
+	}
+
+	public List<Client> list() {
+		return new ArrayList<>(map().values());
+	}
+
+	@Override
+	public List<Client> listByUser(Long userId) {
+		List<Client> result =  new ArrayList<>();
+		for (Map.Entry<String, Client> e : map().entrySet()) {
+			if (e.getValue().getUserId().equals(userId)) {
+				result.add(e.getValue());
+				break;
+			}
+		}
+		return result;
+	}
+
+	@Override
+	public List<Client> listByRoom(Long roomId) {
+		return listByRoom(roomId, null);
+	}
+
+	public List<Client> listByRoom(Long roomId, Predicate<Client> filter) {
+		List<Client> clients = new ArrayList<>();
+		if (roomId != null) {
+			Set<String> uids = getRooms().get(roomId);
+			if (uids != null) {
+				for (String uid : uids) {
+					Client c = get(uid);
+					if (c != null && (filter == null || filter.test(c))) {
+						clients.add(c);
+					}
+				}
+			}
+		}
+		return clients;
+	}
+
+	public Set<Long> listRoomIds(Long userId) {
+		Set<Long> result = new HashSet<>();
+		for (Entry<Long, Set<String>> me : getRooms().entrySet()) {
+			for (String uid : me.getValue()) {
+				Client c = get(uid);
+				if (c != null && c.getUserId().equals(userId)) {
+					result.add(me.getKey());
+				}
+			}
+		}
+		return result;
+	}
+
+	public boolean isInRoom(long roomId, long userId) {
+		Set<String> clients = getRooms().get(roomId);
+		if (clients != null) {
+			for (String uid : clients) {
+				Client c = get(uid);
+				if (c != null && c.getUserId().equals(userId)) {
+					return true;
+				}
+			}
+		}
+		return false;
+	}
+
+	private Client getByKeys(Long userId, String sessionId) {
+		Client client = null;
+		for (Map.Entry<String, Client> e : map().entrySet()) {
+			Client c = e.getValue();
+			if (c.getUserId().equals(userId) && c.getSessionId().equals(sessionId)) {
+				client = c;
+				break;
+			}
+		}
+		return client;
+	}
+
+	public void invalidate(Long userId, String sessionId) {
+		Client client = getByKeys(userId, sessionId);
+		if (client != null) {
+			Map<String, String> invalid = Application.get().getInvalidSessions();
+			if (!invalid.containsKey(client.getSessionId())) {
+				invalid.put(client.getSessionId(), client.getUid());
+				exit(client);
+			}
+		}
+	}
+}
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/StreamClientManager.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/StreamClientManager.java
new file mode 100644
index 0000000..74ad459
--- /dev/null
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/StreamClientManager.java
@@ -0,0 +1,303 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License") +  you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.openmeetings.web.app;
+
+import static org.apache.openmeetings.core.remote.ScopeApplicationAdapter.getApp;
+import static org.apache.openmeetings.db.dao.room.SipDao.SIP_FIRST_NAME;
+import static org.apache.openmeetings.db.dao.room.SipDao.SIP_USER_NAME;
+import static org.apache.openmeetings.util.OmFileHelper.SIP_USER_ID;
+import static org.apache.openmeetings.util.OpenmeetingsVariables.getWebAppRootKey;
+import static org.apache.openmeetings.web.app.Application.getHazelcast;
+
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import javax.annotation.PostConstruct;
+
+import org.apache.openmeetings.IApplication;
+import org.apache.openmeetings.core.remote.MobileService;
+import org.apache.openmeetings.core.util.WebSocketHelper;
+import org.apache.openmeetings.db.dao.room.RoomDao;
+import org.apache.openmeetings.db.dao.server.SessiondataDao;
+import org.apache.openmeetings.db.dao.user.UserDao;
+import org.apache.openmeetings.db.entity.basic.Client;
+import org.apache.openmeetings.db.entity.basic.Client.Activity;
+import org.apache.openmeetings.db.entity.basic.Client.Pod;
+import org.apache.openmeetings.db.entity.basic.IClient;
+import org.apache.openmeetings.db.entity.room.Room;
+import org.apache.openmeetings.db.entity.room.Room.Right;
+import org.apache.openmeetings.db.entity.room.StreamClient;
+import org.apache.openmeetings.db.entity.server.Sessiondata;
+import org.apache.openmeetings.db.entity.user.User;
+import org.apache.openmeetings.db.manager.IStreamClientManager;
+import org.apache.openmeetings.db.util.ws.RoomMessage;
+import org.red5.logging.Red5LoggerFactory;
+import org.red5.server.Server;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import com.hazelcast.core.HazelcastInstance;
+
+/**
+ * Handle {@link StreamClient} objects.
+ *
+ * Use a kind of decorator pattern to inject the {@link Server} into every call.
+ *
+ * @author sebawagner
+ *
+ */
+@Component
+public class StreamClientManager implements IStreamClientManager {
+	protected static final Logger log = Red5LoggerFactory.getLogger(StreamClientManager.class, getWebAppRootKey());
+	private static final String STREAM_CLIENT_KEY = "STREAM_CLIENT_KEY";
+	private HazelcastInstance hazelcast;
+
+	@Autowired
+	private ClientManager clientManager;
+	@Autowired
+	private SessiondataDao sessionDao;
+	@Autowired
+	private UserDao userDao;
+	@Autowired
+	private MobileService mobileService;
+	@Autowired
+	private RoomDao roomDao;
+
+	@PostConstruct
+	private void init() {
+		this.hazelcast = getHazelcast();
+	}
+
+	public Map<String, StreamClient> map() {
+		return hazelcast.getMap(STREAM_CLIENT_KEY);
+	}
+
+	@Override
+	public StreamClient add(StreamClient c) {
+		if (c == null) {
+			return null;
+		}
+		IApplication iapp = getApp();
+		c.setServerId(iapp.getServerId());
+		c.setConnectedSince(new Date());
+		c.setRoomEnter(new Date());
+		update(c);
+		return c;
+	}
+
+	public Collection<StreamClient> list() {
+		return map().values();
+	}
+
+	@Override
+	public StreamClient get(String uid) {
+		if (uid == null) {
+			return null;
+		}
+		return map().get(uid);
+	}
+
+	@Override
+	public IClient update(IClient c) {
+		if (c instanceof StreamClient) {
+			hazelcast.getMap(STREAM_CLIENT_KEY).put(c.getUid(), c);
+		} else {
+			clientManager.update((Client)c);
+		}
+		return c;
+	}
+
+	private static boolean hasVideo(StreamClient rcl) {
+		return rcl != null && rcl.getAvsettings().contains("v");
+	}
+
+	private static boolean hasVideo(Client c) {
+		return c != null && c.hasActivity(Activity.broadcastV);
+	}
+
+	@Override
+	public StreamClient update(StreamClient rcl, boolean forceSize) {
+		if (rcl == null) {
+			return null;
+		}
+		Client client = clientManager.getBySid(rcl.getSid());
+		if (client == null) {
+			if (Client.Type.mobile == rcl.getType()) {
+				Sessiondata sd = sessionDao.check(rcl.getSid());
+				User u = userDao.get(sd.getUserId());
+				rcl = mobileService.create(rcl, u);
+				//Mobile client enters the room
+				client = new Client(rcl, userDao.get(rcl.getUserId()));
+				clientManager.add(client);
+				if (rcl.getRoomId() != null) {
+					client.setCam(0);
+					client.setMic(0);
+					client.setRoom(roomDao.get(rcl.getRoomId()));
+					clientManager.add(client);
+					WebSocketHelper.sendRoom(new RoomMessage(client.getRoom().getId(), client, RoomMessage.Type.roomEnter));
+				}
+			} else if (client == null && Client.Type.sip == rcl.getType()) {
+				rcl.setLogin(SIP_USER_NAME);
+				rcl.setUserId(SIP_USER_ID);
+				//SipTransport enters the room
+				User u = new User();
+				u.setId(SIP_USER_ID);
+				u.setLogin(SIP_USER_NAME);
+				u.setFirstname(SIP_FIRST_NAME);
+				client = new Client(rcl, u);
+				clientManager.add(client);
+				client.setCam(0);
+				client.setMic(0);
+				client.allow(Room.Right.audio, Room.Right.video);
+				client.set(Activity.broadcastA);
+				clientManager.addToRoom(client);
+				WebSocketHelper.sendRoom(new RoomMessage(client.getRoom().getId(), client, RoomMessage.Type.roomEnter));
+			} else {
+				return null;
+			}
+		}
+		if (rcl.getRoomId() == null || !rcl.getRoomId().equals(client.getRoom().getId())) {
+			return null;
+		}
+		User u = client.getUser();
+		rcl.setUserId(u.getId());
+		rcl.setLogin(u.getLogin());
+		rcl.setFirstname(u.getFirstname());
+		rcl.setLastname(u.getLastname());
+		rcl.setEmail(u.getAddress() == null ? null : u.getAddress().getEmail());
+		rcl.setSuperMod(client.hasRight(Right.superModerator));
+		rcl.setMod(client.hasRight(Right.moderator));
+		if (client.hasActivity(Activity.broadcastA) && client.getMic() < 0) {
+			client.remove(Activity.broadcastA);
+		}
+		if (client.hasActivity(Activity.broadcastV) && client.getCam() < 0) {
+			client.remove(Activity.broadcastV);
+		}
+		if (client.hasActivity(Activity.broadcastA) || client.hasActivity(Activity.broadcastV)) {
+			if (forceSize || rcl.getWidth() == 0 || rcl.getHeight() == 0) {
+				rcl.setWidth(client.getWidth());
+				rcl.setHeight(client.getHeight());
+			}
+			if (client.getPod() != Pod.none) {
+				rcl.setInterviewPodId(client.getPod() == Pod.left ? 1 : 2);
+			}
+			StringBuilder sb = new StringBuilder();
+			if (client.hasActivity(Activity.broadcastA)) {
+				sb.append('a');
+			}
+			if (client.hasActivity(Activity.broadcastV)) {
+				sb.append('v');
+			}
+			if (!rcl.isBroadcasting() || hasVideo(rcl) != hasVideo(client)) {
+				rcl.setBroadcasting(true);
+			}
+			rcl.setAvsettings(sb.toString());
+		} else {
+			rcl.setAvsettings("n");
+			rcl.setBroadcasting(false);
+		}
+		return rcl;
+	}
+
+	@Override
+	public boolean remove(String uid) {
+		if (uid == null) {
+			return false;
+		}
+		StreamClient c = map().remove(uid);
+		return c != null;
+	}
+
+	@Override
+	public List<StreamClient> list(Long roomId) {
+		return list().stream()
+				.filter(c -> roomId.equals(c.getRoomId()) && Client.Type.sharing != c.getType())
+				.collect(Collectors.toList());
+	}
+
+	@Override
+	public long getRecordingCount(Long roomId) {
+		if (roomId == null) {
+			return 0;
+		}
+		return list().stream()
+				.filter(c -> roomId.equals(c.getRoomId()) && c.isRecordingStarted())
+				.collect(Collectors.toList()).size();
+	}
+
+	@Override
+	public long getPublishingCount(Long roomId) {
+		if (roomId == null) {
+			return 0;
+		}
+		return list().stream()
+				.filter(c -> roomId.equals(c.getRoomId()) && c.isPublishStarted())
+				.collect(Collectors.toList()).size();
+	}
+
+	@Override
+	public long getSharingCount(Long roomId) {
+		if (roomId == null) {
+			return 0;
+		}
+		return list().stream()
+				.filter(c -> roomId.equals(c.getRoomId()) && c.isSharingStarted())
+				.collect(Collectors.toList()).size();
+	}
+
+	@Override
+	public long getBroadcastingCount(Long roomId) {
+		if (roomId == null) {
+			return 0;
+		}
+		return list().stream()
+				.filter(c -> roomId.equals(c.getRoomId()) && c.isBroadcasting() && c.getBroadcastId() != null)
+				.collect(Collectors.toList()).size();
+	}
+
+	@Override
+	public Set<Long> getActiveRoomIds(String serverId) {
+		Set<Long> ids = new HashSet<>();
+		if (serverId != null) {
+			for (Map.Entry<String, StreamClient> e : map().entrySet()) {
+				if (serverId.equals(e.getValue().getServerId())) {
+					ids.add(e.getValue().getRoomId());
+				}
+			}
+		}
+		return ids;
+	}
+
+	public void clean(String serverId) {
+		Map<String, StreamClient> streams = map();
+		for (Iterator<Map.Entry<String, StreamClient>> iter = streams.entrySet().iterator(); iter.hasNext(); ) {
+			Map.Entry<String, StreamClient> e = iter.next();
+			if (serverId.equals(e.getValue().getServerId())) {
+				iter.remove();
+			}
+		}
+	}
+}
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/WebSession.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/WebSession.java
index 9483562..b2c7386 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/WebSession.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/WebSession.java
@@ -45,7 +45,7 @@ import java.util.TimeZone;
 
 import org.apache.commons.lang3.time.FastDateFormat;
 import org.apache.openmeetings.IWebSession;
-import org.apache.openmeetings.core.ldap.LdapLoginManagement;
+import org.apache.openmeetings.core.ldap.LdapLoginManager;
 import org.apache.openmeetings.db.dao.basic.ConfigurationDao;
 import org.apache.openmeetings.db.dao.room.InvitationDao;
 import org.apache.openmeetings.db.dao.server.SOAPLoginDao;
@@ -118,7 +118,7 @@ public class WebSession extends AbstractAuthenticatedWebSession implements IWebS
 
 	@Override
 	public void invalidate() {
-		Application.get().invalidateClient(userId, getId());
+		getBean(ClientManager.class).invalidate(userId, getId());
 		super.invalidate();
 		userId = null;
 		rights = Collections.unmodifiableSet(Collections.<Right>emptySet());
@@ -312,7 +312,7 @@ public class WebSession extends AbstractAuthenticatedWebSession implements IWebS
 		User u;
 		switch (type) {
 			case ldap:
-				u = getBean(LdapLoginManagement.class).login(login, password, domainId);
+				u = getBean(LdapLoginManager.class).login(login, password, domainId);
 				break;
 			case user:
 				/* we will allow login against internal DB in case user 'guess' LDAP password */
diff --git a/openmeetings-core/src/main/java/org/apache/openmeetings/core/data/whiteboard/WhiteboardCache.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/WhiteboardManager.java
similarity index 68%
rename from openmeetings-core/src/main/java/org/apache/openmeetings/core/data/whiteboard/WhiteboardCache.java
rename to openmeetings-web/src/main/java/org/apache/openmeetings/web/app/WhiteboardManager.java
index 9bba020..de0b351 100644
--- a/openmeetings-core/src/main/java/org/apache/openmeetings/core/data/whiteboard/WhiteboardCache.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/WhiteboardManager.java
@@ -16,38 +16,50 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.openmeetings.core.data.whiteboard;
+package org.apache.openmeetings.web.app;
 
-import static org.apache.openmeetings.core.remote.ScopeApplicationAdapter.getApp;
 import static org.apache.openmeetings.util.OpenmeetingsVariables.getDefaultLang;
+import static org.apache.openmeetings.web.app.Application.getHazelcast;
 
 import java.util.Map.Entry;
 import java.util.Set;
 
+import javax.annotation.PostConstruct;
+
 import org.apache.openmeetings.db.dao.label.LabelDao;
 import org.apache.openmeetings.db.dto.room.Whiteboard;
 import org.apache.openmeetings.db.dto.room.Whiteboards;
+import org.apache.openmeetings.db.manager.IWhiteboardManager;
+import org.springframework.stereotype.Component;
 
+import com.hazelcast.core.HazelcastInstance;
 import com.hazelcast.core.IMap;
 
 /**
- * Memory based cache, configured as singleton in spring configuration
+ * Hazelcast based Whiteboard manager
  *
  * @author sebawagner
  *
  */
-public class WhiteboardCache {
-	private WhiteboardCache() {}
+@Component
+public class WhiteboardManager implements IWhiteboardManager {
+	private static final String WBS_KEY = "WBS_KEY";
+	private HazelcastInstance hazelcast;
+
+	@PostConstruct
+	private void init() {
+		this.hazelcast = getHazelcast();
+	}
 
-	private static IMap<Long, Whiteboards> getCache() {
-		return getApp().getWhiteboards();
+	private IMap<Long, Whiteboards> getCache() {
+		return hazelcast.getMap(WBS_KEY);
 	}
 
-	public static boolean tryLock(Long roomId) {
+	public boolean tryLock(Long roomId) {
 		return getCache().tryLock(roomId);
 	}
 
-	public static void unlock(Long roomId) {
+	public void unlock(Long roomId) {
 		getCache().unlock(roomId);
 	}
 
@@ -59,15 +71,16 @@ public class WhiteboardCache {
 		return sb.toString();
 	}
 
-	public static boolean contains(Long roomId) {
+	public boolean contains(Long roomId) {
 		return getCache().containsKey(roomId);
 	}
 
-	public static Whiteboards get(Long roomId) {
+	@Override
+	public Whiteboards get(Long roomId) {
 		return get(roomId, null);
 	}
 
-	public static Whiteboards get(Long roomId, Long langId) {
+	public Whiteboards get(Long roomId, Long langId) {
 		if (roomId == null) {
 			return null;
 		}
@@ -81,12 +94,12 @@ public class WhiteboardCache {
 		return wbs;
 	}
 
-	public static Set<Entry<Long, Whiteboard>> list(long roomId) {
+	public Set<Entry<Long, Whiteboard>> list(long roomId) {
 		Whiteboards wbs = get(roomId);
 		return wbs.getWhiteboards().entrySet();
 	}
 
-	public static Whiteboard add(long roomId, Long langId) {
+	public Whiteboard add(long roomId, Long langId) {
 		Whiteboards wbs = get(roomId);
 		Whiteboard wb = add(wbs, langId);
 		update(wbs);
@@ -99,7 +112,7 @@ public class WhiteboardCache {
 		return wb;
 	}
 
-	public static Whiteboard clear(long roomId, Long wbId) {
+	public Whiteboard clear(long roomId, Long wbId) {
 		Whiteboards wbs = get(roomId);
 		Whiteboard wb = wbs.get(wbId);
 		if (wb != null) {
@@ -109,26 +122,26 @@ public class WhiteboardCache {
 		return wb;
 	}
 
-	public static Whiteboard remove(long roomId, Long wbId) {
+	public Whiteboard remove(long roomId, Long wbId) {
 		Whiteboards wbs = get(roomId);
 		Whiteboard wb = wbs.getWhiteboards().remove(wbId);
 		update(wbs);
 		return wb;
 	}
 
-	public static void activate(long roomId, Long wbId) {
+	public void activate(long roomId, Long wbId) {
 		Whiteboards wbs = get(roomId);
 		wbs.setActiveWb(wbId);
 		update(wbs);
 	}
 
-	public static void update(long roomId, Whiteboard wb) {
+	public void update(long roomId, Whiteboard wb) {
 		Whiteboards wbs = get(roomId);
 		wbs.update(wb);
 		update(wbs);
 	}
 
-	private static void update(Whiteboards wbs) {
+	private void update(Whiteboards wbs) {
 		getCache().put(wbs.getRoomId(), wbs);
 	}
 }
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/MainPanel.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/MainPanel.java
index 3fb2554..10eb391 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/MainPanel.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/MainPanel.java
@@ -23,9 +23,7 @@ import static org.apache.openmeetings.db.util.AuthLevelUtil.hasGroupAdminLevel;
 import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_MYROOMS_ENABLED;
 import static org.apache.openmeetings.util.OpenmeetingsVariables.PARAM_USER_ID;
 import static org.apache.openmeetings.util.OpenmeetingsVariables.getWebAppRootKey;
-import static org.apache.openmeetings.web.app.Application.addOnlineUser;
 import static org.apache.openmeetings.web.app.Application.getBean;
-import static org.apache.openmeetings.web.app.Application.getOnlineClient;
 import static org.apache.openmeetings.web.app.WebSession.getUserId;
 import static org.apache.openmeetings.web.util.CallbackFunctionHelper.getNamedFunction;
 import static org.apache.openmeetings.web.util.CallbackFunctionHelper.getParam;
@@ -48,6 +46,7 @@ import org.apache.openmeetings.db.entity.room.Room;
 import org.apache.openmeetings.db.entity.user.PrivateMessage;
 import org.apache.openmeetings.db.entity.user.User.Right;
 import org.apache.openmeetings.web.app.Application;
+import org.apache.openmeetings.web.app.ClientManager;
 import org.apache.openmeetings.web.app.WebSession;
 import org.apache.openmeetings.web.common.menu.MainMenuItem;
 import org.apache.openmeetings.web.common.menu.MenuPanel;
@@ -139,7 +138,7 @@ public class MainPanel extends Panel {
 				ExtendedClientProperties cp = WebSession.get().getExtendedProperties();
 				final Client client = new Client(getSession().getId(), msg.getKey().hashCode(), getUserId(), getBean(UserDao.class));
 				uid = client.getUid();
-				addOnlineUser(cp.update(client));
+				getBean(ClientManager.class).add(cp.update(client));
 				log.debug("WebSocketBehavior::onConnect [uid: {}, session: {}, key: {}]", client.getUid(), msg.getSessionId(), msg.getKey());
 			}
 
@@ -176,7 +175,7 @@ public class MainPanel extends Panel {
 				log.debug("WebSocketBehavior::closeHandler [uid: {}, session: {}, key: {}]", uid, msg.getSessionId(), msg.getKey());
 				//no chance to stop pingTimer here :(
 				if (uid != null) {
-					Application.get().exit(getClient());
+					getBean(ClientManager.class).exit(getClient());
 					uid = null;
 				}
 			}
@@ -436,6 +435,6 @@ public class MainPanel extends Panel {
 	}
 
 	public Client getClient() {
-		return getOnlineClient(uid);
+		return getBean(ClientManager.class).get(uid);
 	}
 }
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/NicknameDialog.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/NicknameDialog.java
index 518cc46..25e5f1c 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/NicknameDialog.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/NicknameDialog.java
@@ -18,7 +18,7 @@
  */
 package org.apache.openmeetings.web.room;
 
-import static org.apache.openmeetings.web.app.Application.update;
+import static org.apache.openmeetings.web.app.Application.getBean;
 import static org.apache.wicket.validation.validator.StringValidator.minimumLength;
 
 import java.util.Arrays;
@@ -28,6 +28,7 @@ import java.util.List;
 import org.apache.commons.lang3.time.FastDateFormat;
 import org.apache.openmeetings.db.entity.basic.Client;
 import org.apache.openmeetings.db.entity.user.User;
+import org.apache.openmeetings.web.app.ClientManager;
 import org.apache.openmeetings.web.util.NonClosableDialog;
 import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.extensions.validation.validator.RfcCompliantEmailAddressValidator;
@@ -110,6 +111,6 @@ public class NicknameDialog extends NonClosableDialog<User> {
 		final User u = form.getModelObject();
 		final Client c = room.getClient();
 		c.getUser().setFirstname(u.getFirstname()).setLastname(u.getLastname());
-		room.broadcast(update(c));
+		room.broadcast(getBean(ClientManager.class).update(c));
 	}
 }
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/RoomBroadcaster.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/RoomBroadcaster.java
index 7d0faae..2d2a3e4 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/RoomBroadcaster.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/RoomBroadcaster.java
@@ -20,13 +20,12 @@ package org.apache.openmeetings.web.room;
 
 import static org.apache.openmeetings.util.OpenmeetingsVariables.getWebAppRootKey;
 import static org.apache.openmeetings.web.app.Application.getBean;
-import static org.apache.openmeetings.web.app.Application.update;
 
 import org.apache.openmeetings.core.remote.ScopeApplicationAdapter;
-import org.apache.openmeetings.db.dao.server.ISessionManager;
 import org.apache.openmeetings.db.entity.basic.Client;
 import org.apache.openmeetings.db.entity.room.StreamClient;
-import org.apache.openmeetings.web.app.Application;
+import org.apache.openmeetings.web.app.ClientManager;
+import org.apache.openmeetings.web.app.StreamClientManager;
 import org.red5.logging.Red5LoggerFactory;
 import org.slf4j.Logger;
 
@@ -36,7 +35,7 @@ public class RoomBroadcaster {
 	private RoomBroadcaster() {}
 
 	public static StreamClient getClient(String publicSid) {
-		return getBean(ISessionManager.class).get(publicSid);
+		return getBean(StreamClientManager.class).get(publicSid);
 	}
 
 	public static void broadcast(String publicSid, String method, Object obj) {
@@ -54,10 +53,10 @@ public class RoomBroadcaster {
 
 	public static void sendUpdatedClient(Client client) {
 		String uid = client.getUid();
-		StreamClient rcl = Application.get().updateClient(getClient(uid), true);
+		StreamClient rcl = getBean(StreamClientManager.class).update(getClient(uid), true);
 		log.debug("-----------  sendUpdatedClient ");
 		// Notify all clients of the same scope (room)
-		update(client);
+		getBean(ClientManager.class).update(client);
 		broadcast(client.getRoom().getId(), "clientUpdated", rcl);
 
 		if (rcl == null) {
@@ -65,6 +64,6 @@ public class RoomBroadcaster {
 		}
 
 		// Put the mod-flag to true for this client
-		getBean(ISessionManager.class).update(rcl);
+		getBean(StreamClientManager.class).update(rcl);
 	}
 }
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/RoomPanel.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/RoomPanel.java
index 01079dd..29ddfc4 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/RoomPanel.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/RoomPanel.java
@@ -21,13 +21,7 @@ package org.apache.openmeetings.web.room;
 import static org.apache.openmeetings.db.util.RoomHelper.videoJson;
 import static org.apache.openmeetings.util.OpenmeetingsVariables.ATTR_CLASS;
 import static org.apache.openmeetings.util.OpenmeetingsVariables.getWebAppRootKey;
-import static org.apache.openmeetings.web.app.Application.addUserToRoom;
-import static org.apache.openmeetings.web.app.Application.exitRoom;
 import static org.apache.openmeetings.web.app.Application.getBean;
-import static org.apache.openmeetings.web.app.Application.getClientBySid;
-import static org.apache.openmeetings.web.app.Application.getOnlineClient;
-import static org.apache.openmeetings.web.app.Application.getRoomClients;
-import static org.apache.openmeetings.web.app.Application.update;
 import static org.apache.openmeetings.web.app.WebSession.getDateFormat;
 import static org.apache.openmeetings.web.app.WebSession.getUserId;
 import static org.apache.openmeetings.web.room.wb.InterviewWbPanel.INTERVIEWWB_JS_REFERENCE;
@@ -45,7 +39,6 @@ import java.util.Set;
 import org.apache.openmeetings.core.util.WebSocketHelper;
 import org.apache.openmeetings.db.dao.calendar.AppointmentDao;
 import org.apache.openmeetings.db.dao.log.ConferenceLogDao;
-import org.apache.openmeetings.db.dao.server.ISessionManager;
 import org.apache.openmeetings.db.dao.user.UserDao;
 import org.apache.openmeetings.db.entity.basic.Client;
 import org.apache.openmeetings.db.entity.calendar.Appointment;
@@ -64,7 +57,8 @@ import org.apache.openmeetings.db.util.ws.RoomMessage;
 import org.apache.openmeetings.db.util.ws.RoomMessage.Type;
 import org.apache.openmeetings.db.util.ws.TextRoomMessage;
 import org.apache.openmeetings.util.NullStringer;
-import org.apache.openmeetings.web.app.Application;
+import org.apache.openmeetings.web.app.ClientManager;
+import org.apache.openmeetings.web.app.StreamClientManager;
 import org.apache.openmeetings.web.app.WebSession;
 import org.apache.openmeetings.web.common.BasePanel;
 import org.apache.openmeetings.web.pages.BasePage;
@@ -155,7 +149,7 @@ public class RoomPanel extends BasePanel {
 				sidebar.setFilesActive(target);
 			}
 			if (Room.Type.presentation != r.getType()) {
-				List<Client> mods = Application.getRoomClients(r.getId(), c -> c.hasRight(Room.Right.moderator));
+				List<Client> mods = getBean(ClientManager.class).listByRoom(r.getId(), c -> c.hasRight(Room.Right.moderator));
 				if (mods.isEmpty()) {
 					waitApplyModeration.open(target);
 				}
@@ -167,10 +161,10 @@ public class RoomPanel extends BasePanel {
 			StringBuilder sb = new StringBuilder();
 			boolean hasStreams = false;
 			Client _c = getClient();
-			for (Client c: getRoomClients(getRoom().getId()) ) {
+			for (Client c: getBean(ClientManager.class).listByRoom(getRoom().getId())) {
 				boolean self = _c.getUid().equals(c.getUid());
 				for (String uid : c.getStreams()) {
-					JSONObject jo = videoJson(c, self, c.getSid(), getBean(ISessionManager.class), uid);
+					JSONObject jo = videoJson(c, self, c.getSid(), getBean(StreamClientManager.class), uid);
 					sb.append(String.format("VideoManager.play(%s);", jo));
 					hasStreams = true;
 				}
@@ -243,7 +237,8 @@ public class RoomPanel extends BasePanel {
 	protected void onInitialize() {
 		super.onInitialize();
 		//let's refresh user in client
-		update(getClient().updateUser(getBean(UserDao.class)));
+		ClientManager cm = getBean(ClientManager.class);
+		cm.update(getClient().updateUser(getBean(UserDao.class)));
 		Component accessDenied = new WebMarkupContainer(ACCESS_DENIED_ID).setVisible(false);
 
 		room.add(AttributeModifier.append(ATTR_CLASS, r.getType().name()));
@@ -284,7 +279,7 @@ public class RoomPanel extends BasePanel {
 		add(roomClosed = new RedirectMessageDialog("room-closed", "1098", r.isClosed(), r.getRedirectURL()));
 		if (r.isClosed()) {
 			room.setVisible(false);
-		} else if (getRoomClients(r.getId()).size() >= r.getCapacity()) {
+		} else if (cm.listByRoom(r.getId()).size() >= r.getCapacity()) {
 			accessDenied = new ExpiredMessageDialog(ACCESS_DENIED_ID, getString("99"), menu);
 			room.setVisible(false);
 		} else if (r.getId().equals(WebSession.get().getRoomId())) {
@@ -401,6 +396,7 @@ public class RoomPanel extends BasePanel {
 			if (wsEvent.getMessage() instanceof RoomMessage) {
 				RoomMessage m = (RoomMessage)wsEvent.getMessage();
 				IPartialPageRequestHandler handler = wsEvent.getHandler();
+				ClientManager cm = getBean(ClientManager.class);
 				switch (m.getType()) {
 					case pollCreated:
 						menu.updatePoll(handler, m.getUserId());
@@ -411,13 +407,13 @@ public class RoomPanel extends BasePanel {
 					case recordingStoped:
 						{
 							String uid = ((TextRoomMessage)m).getText();
-							Client c = getClientBySid(uid);
+							Client c = cm.getBySid(uid);
 							if (c == null) {
 								log.error("Not existing/BAD user has stopped recording {} != {} !!!!", uid);
 								return;
 							}
 							recordingUser = null;
-							update(c.remove(Client.Activity.record));
+							cm.update(c.remove(Client.Activity.record));
 							menu.update(handler);
 							updateInterviewRecordingButtons(handler);
 						}
@@ -426,13 +422,13 @@ public class RoomPanel extends BasePanel {
 						{
 							JSONObject obj = new JSONObject(((TextRoomMessage)m).getText());
 							String sid = obj.getString("sid");
-							Client c = getClientBySid(sid);
+							Client c = cm.getBySid(sid);
 							if (c == null) {
 								log.error("Not existing user has started recording {} !!!!", sid);
 								return;
 							}
 							recordingUser = sid;
-							update(c.set(Client.Activity.record));
+							cm.update(c.set(Client.Activity.record));
 							menu.update(handler);
 							updateInterviewRecordingButtons(handler);
 						}
@@ -441,34 +437,34 @@ public class RoomPanel extends BasePanel {
 						{
 							JSONObject obj = new JSONObject(((TextRoomMessage)m).getText());
 							String uid = obj.getString("uid");
-							Client c = getClientBySid(obj.getString("sid"));
+							Client c = cm.getBySid(obj.getString("sid"));
 							if (c == null) {
 								log.error("Not existing user has started sharing {} !!!!", obj);
 								return;
 							}
 							handler.appendJavaScript(String.format("VideoManager.close('%s', true);", uid));
 							sharingUser = null;
-							update(c.removeStream(uid).remove(Client.Activity.share));
+							cm.update(c.removeStream(uid).remove(Client.Activity.share));
 							menu.update(handler);
 						}
 						break;
 					case sharingStarted:
 						{
 							String uid = ((TextRoomMessage)m).getText();
-							Client c = getOnlineClient(uid);
+							Client c = cm.get(uid);
 							if (c == null) {
 								log.error("Not existing user has started sharing {} !!!!", uid);
 								return;
 							}
 							sharingUser = uid;
-							update(c.set(Client.Activity.share));
+							cm.update(c.set(Client.Activity.share));
 							menu.update(handler);
 						}
 						break;
 					case rightUpdated:
 						{
 							String uid = ((TextRoomMessage)m).getText();
-							Client c = getOnlineClient(uid);
+							Client c = cm.get(uid);
 							if (c == null) {
 								log.error("Not existing user in rightUpdated {} !!!!", uid);
 								return;
@@ -476,7 +472,7 @@ public class RoomPanel extends BasePanel {
 							Client _c = getClient();
 							boolean self = _c.getUid().equals(c.getUid());
 							handler.appendJavaScript(String.format("VideoManager.update(%s);"
-									, c.streamJson(_c.getSid(), self, getBean(ISessionManager.class)).toString(new NullStringer())
+									, c.streamJson(_c.getSid(), self, getBean(StreamClientManager.class)).toString(new NullStringer())
 									));
 							sidebar.update(handler);
 							menu.update(handler);
@@ -488,10 +484,10 @@ public class RoomPanel extends BasePanel {
 					{
 						JSONObject obj = new JSONObject(((TextRoomMessage)m).getText());
 						String uid = obj.getString("uid");
-						Client c = getOnlineClient(uid);
+						Client c = cm.get(uid);
 						if (c == null) {
 							// screen client, ext video stream
-							c = getClientBySid(obj.getString("sid"));
+							c = cm.getBySid(obj.getString("sid"));
 						}
 						if (c == null) {
 							log.error("Not existing user in newStream {} !!!!", uid);
@@ -499,13 +495,13 @@ public class RoomPanel extends BasePanel {
 						}
 						Client _c = getClient();
 						boolean self = _c.getSid().equals(c.getSid());
-						ISessionManager mgr = getBean(ISessionManager.class);
+						StreamClientManager mgr = getBean(StreamClientManager.class);
 						if (!self || Client.Type.room != mgr.get(uid).getType()) { // stream from others or self external video
 							JSONObject jo = videoJson(c, false, _c.getSid(), mgr, uid);
 							handler.appendJavaScript(String.format("VideoManager.play(%s);", jo));
 						}
 						if (self) {
-							update(c.addStream(uid));
+							cm.update(c.addStream(uid));
 						}
 						updateInterviewRecordingButtons(handler);
 					}
@@ -514,12 +510,12 @@ public class RoomPanel extends BasePanel {
 					{
 						JSONObject obj = new JSONObject(((TextRoomMessage)m).getText());
 						String uid = obj.getString("uid");
-						Client c = getClientBySid(obj.getString("sid"));
+						Client c = cm.getBySid(obj.getString("sid"));
 						if (c != null) {
 							//c == null means client exits the room
 							Client _c = getClient();
 							if (_c.getUid().equals(c.getUid())) {
-								update(c.removeStream(uid));
+								cm.update(c.removeStream(uid));
 							}
 						}
 						handler.appendJavaScript(String.format("VideoManager.close('%s');", uid));
@@ -581,14 +577,14 @@ public class RoomPanel extends BasePanel {
 								handler.add(room.setVisible(false));
 								getMainPanel().getChat().toggle(handler, false);
 								clientKicked.open(handler);
-								exitRoom(getClient());
+								cm.exitRoom(getClient());
 							}
 						}
 						break;
 					case audioActivity:
 					{
 						JSONObject obj = new JSONObject(((TextRoomMessage)m).getText());
-						Client c = getClientBySid(obj.getString("sid"));
+						Client c = cm.getBySid(obj.getString("sid"));
 						if (c == null) {
 							log.error("Not existing user in audioActivity {} !!!!", obj);
 							return;
@@ -601,7 +597,7 @@ public class RoomPanel extends BasePanel {
 					case mute:
 					{
 						JSONObject obj = new JSONObject(((TextRoomMessage)m).getText());
-						Client c = getClientBySid(obj.getString("sid"));
+						Client c = cm.getBySid(obj.getString("sid"));
 						if (c == null) {
 							log.error("Not existing user in mute {} !!!!", obj);
 							return;
@@ -614,7 +610,7 @@ public class RoomPanel extends BasePanel {
 					case exclusive:
 					{
 						String uid = ((TextRoomMessage)m).getText();
-						Client c = getOnlineClient(uid);
+						Client c = cm.get(uid);
 						if (c == null) {
 							// no luck
 							return;
@@ -633,7 +629,7 @@ public class RoomPanel extends BasePanel {
 		if (interview && _c.hasRight(Right.moderator)) {
 			if (recordingUser == null) {
 				boolean hasStreams = false;
-				for (Client cl : getRoomClients(r.getId())) {
+				for (Client cl : getBean(ClientManager.class).listByRoom(r.getId())) {
 					if (!cl.getStreams().isEmpty()) {
 						hasStreams = true;
 						break;
@@ -652,16 +648,17 @@ public class RoomPanel extends BasePanel {
 		if (room.isVisible()) {
 			//We are setting initial rights here
 			Client c = getClient();
-			addUserToRoom(c.setRoom(getRoom()));
+			ClientManager cm = getBean(ClientManager.class);
+			cm.addToRoom(c.setRoom(getRoom()));
 			SOAPLogin soap = WebSession.get().getSoapLogin();
 			if (soap != null && soap.isModerator()) {
 				c.allow(Right.superModerator);
-				update(c);
+				cm.update(c);
 			} else {
-				Set<Right> rr = AuthLevelUtil.getRoomRight(c.getUser(), r, r.isAppointment() ? getBean(AppointmentDao.class).getByRoom(r.getId()) : null, getRoomClients(r.getId()).size());
+				Set<Right> rr = AuthLevelUtil.getRoomRight(c.getUser(), r, r.isAppointment() ? getBean(AppointmentDao.class).getByRoom(r.getId()) : null, cm.listByRoom(r.getId()).size());
 				if (!rr.isEmpty()) {
 					c.allow(rr);
-					update(c);
+					cm.update(c);
 				}
 			}
 		}
@@ -672,7 +669,7 @@ public class RoomPanel extends BasePanel {
 	}
 
 	public static boolean hasRight(long userId, long roomId, Right r) {
-		for (Client c : getRoomClients(roomId)) {
+		for (Client c : getBean(ClientManager.class).listByRoom(roomId)) {
 			if (c.getUserId().equals(userId) && c.hasRight(r)) {
 				return true;
 			}
@@ -715,7 +712,7 @@ public class RoomPanel extends BasePanel {
 			getMainPanel().getChat().toggle(handler, true);
 		}
 		handler.appendJavaScript("if (typeof(Room) !== 'undefined') { Room.unload(); }");
-		Application.exitRoom(getClient());
+		getBean(ClientManager.class).exitRoom(getClient());
 		getMainPanel().getChat().roomExit(r, handler);
 	}
 
@@ -731,7 +728,8 @@ public class RoomPanel extends BasePanel {
 
 	public void requestRight(Right right, IPartialPageRequestHandler handler) {
 		RoomMessage.Type reqType = null;
-		List<Client> mods = Application.getRoomClients(r.getId(), c -> c.hasRight(Room.Right.moderator));
+		ClientManager cm = getBean(ClientManager.class);
+		List<Client> mods = cm.listByRoom(r.getId(), c -> c.hasRight(Room.Right.moderator));
 		if (mods.isEmpty()) {
 			if (r.isModerated()) {
 				//dialog
@@ -739,7 +737,7 @@ public class RoomPanel extends BasePanel {
 				return;
 			} else {
 				// we found no-one we can ask, allow right
-				broadcast(update(getClient().allow(right)));
+				broadcast(getBean(ClientManager.class).update(getClient().allow(right)));
 			}
 		}
 		// ask
@@ -781,7 +779,7 @@ public class RoomPanel extends BasePanel {
 
 	public void allowRight(Client client, Right... rights) {
 		client.allow(rights);
-		update(client);
+		getBean(ClientManager.class).update(client);
 		broadcast(client);
 	}
 
@@ -795,7 +793,7 @@ public class RoomPanel extends BasePanel {
 		if (client.hasActivity(Client.Activity.broadcastV) && !client.hasRight(Right.video)) {
 			client.remove(Client.Activity.broadcastV);
 		}
-		update(client);
+		getBean(ClientManager.class).update(client);
 		broadcast(client);
 	}
 
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/RoomResourceReference.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/RoomResourceReference.java
index ae84cce..01e54bb 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/RoomResourceReference.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/RoomResourceReference.java
@@ -26,21 +26,21 @@ import static org.apache.openmeetings.util.OmFileHelper.MP4_MIME_TYPE;
 import static org.apache.openmeetings.util.OmFileHelper.PNG_MIME_TYPE;
 import static org.apache.openmeetings.util.OmFileHelper.getOmHome;
 import static org.apache.openmeetings.web.app.Application.getBean;
-import static org.apache.openmeetings.web.app.Application.getOnlineClient;
 import static org.apache.openmeetings.web.app.WebSession.getUserId;
 
 import java.io.File;
 import java.util.Map.Entry;
 
 import org.apache.directory.api.util.Strings;
-import org.apache.openmeetings.core.data.whiteboard.WhiteboardCache;
 import org.apache.openmeetings.db.dao.file.FileItemDao;
 import org.apache.openmeetings.db.dao.user.GroupUserDao;
 import org.apache.openmeetings.db.dto.room.Whiteboard;
 import org.apache.openmeetings.db.dto.room.Whiteboards;
 import org.apache.openmeetings.db.entity.basic.Client;
 import org.apache.openmeetings.db.entity.file.FileItem;
+import org.apache.openmeetings.web.app.ClientManager;
 import org.apache.openmeetings.web.app.WebSession;
+import org.apache.openmeetings.web.app.WhiteboardManager;
 import org.apache.openmeetings.web.util.FileItemResourceReference;
 import org.apache.wicket.request.mapper.parameter.PageParameters;
 import org.apache.wicket.request.resource.IResource.Attributes;
@@ -94,7 +94,7 @@ public class RoomResourceReference extends FileItemResourceReference<FileItem> {
 			//no-op expected
 		}
 		WebSession ws = WebSession.get();
-		Client c = getOnlineClient(uid);
+		Client c = getBean(ClientManager.class).get(uid);
 		if (id == null || !ws.isSignedIn() || c == null) {
 			return null;
 		}
@@ -105,7 +105,7 @@ public class RoomResourceReference extends FileItemResourceReference<FileItem> {
 		String ruid = params.get("ruid").toString();
 		String wuid = params.get("wuid").toString();
 		if (c.getRoom() != null) {
-			Whiteboards wbs = WhiteboardCache.get(c.getRoom().getId());
+			Whiteboards wbs = getBean(WhiteboardManager.class).get(c.getRoom().getId());
 			if (!Strings.isEmpty(wuid) && !Strings.isEmpty(ruid) && ruid.equals(wbs.getUid())) {
 				for (Entry<Long, Whiteboard> e : wbs.getWhiteboards().entrySet()) {
 					JSONObject file = e.getValue().get(wuid);
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/VideoSettings.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/VideoSettings.java
index 76e3875..69892d5 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/VideoSettings.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/VideoSettings.java
@@ -34,10 +34,10 @@ import java.util.Map;
 import java.util.Set;
 
 import org.apache.openmeetings.db.dao.room.RoomDao;
-import org.apache.openmeetings.db.dao.server.ISessionManager;
 import org.apache.openmeetings.util.OmFileHelper;
 import org.apache.openmeetings.util.OpenmeetingsVariables;
 import org.apache.openmeetings.web.app.Application;
+import org.apache.openmeetings.web.app.StreamClientManager;
 import org.apache.openmeetings.web.util.ExtendedClientProperties;
 import org.apache.wicket.markup.head.IHeaderResponse;
 import org.apache.wicket.markup.head.JavaScriptHeaderItem;
@@ -110,7 +110,7 @@ public class VideoSettings extends Panel {
 		if (servers.size() > 1) {
 			for (Member m : servers) {
 				String serverId = m.getStringAttribute(NAME_ATTR_KEY);
-				Set<Long> roomIds = getBean(ISessionManager.class).getActiveRoomIds(serverId);
+				Set<Long> roomIds = getBean(StreamClientManager.class).getActiveRoomIds(serverId);
 				if (roomIds.contains(roomId)) {
 					// if the room is already opened on a server, redirect the user to that one,
 					log.debug("Room is already opened on a server {}", m.getAddress());
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/activities/ActivitiesPanel.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/activities/ActivitiesPanel.java
index 88d52d9..4f8a3f8 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/activities/ActivitiesPanel.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/activities/ActivitiesPanel.java
@@ -20,7 +20,7 @@ package org.apache.openmeetings.web.room.activities;
 
 import static org.apache.openmeetings.core.util.WebSocketHelper.sendRoom;
 import static org.apache.openmeetings.util.OpenmeetingsVariables.getWebAppRootKey;
-import static org.apache.openmeetings.web.app.Application.getOnlineClient;
+import static org.apache.openmeetings.web.app.Application.getBean;
 import static org.apache.openmeetings.web.app.WebSession.getUserId;
 import static org.apache.openmeetings.web.util.CallbackFunctionHelper.getNamedFunction;
 import static org.apache.wicket.ajax.attributes.CallbackParameter.explicit;
@@ -34,6 +34,7 @@ import org.apache.openmeetings.db.entity.room.Room.Right;
 import org.apache.openmeetings.db.entity.room.Room.RoomElement;
 import org.apache.openmeetings.db.util.ws.RoomMessage;
 import org.apache.openmeetings.db.util.ws.TextRoomMessage;
+import org.apache.openmeetings.web.app.ClientManager;
 import org.apache.openmeetings.web.pages.BasePage;
 import org.apache.openmeetings.web.room.RoomPanel;
 import org.apache.wicket.Component;
@@ -95,7 +96,7 @@ public class ActivitiesPanel extends Panel {
 						}
 						break;
 					case accept:
-						Client client = getOnlineClient(a.getUid());
+						Client client = getBean(ClientManager.class).get(a.getUid());
 						if (room.getClient().hasRight(Right.moderator) && client != null && client.getRoom() != null && roomId == client.getRoom().getId()) {
 							switch (a.getType()) {
 								case reqRightModerator:
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/RoomMenuPanel.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/RoomMenuPanel.java
index 655c234..d3aa885 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/RoomMenuPanel.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/RoomMenuPanel.java
@@ -26,9 +26,7 @@ import static org.apache.openmeetings.util.OpenmeetingsVariables.ATTR_TITLE;
 import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_REDIRECT_URL_FOR_EXTERNAL;
 import static org.apache.openmeetings.util.OpenmeetingsVariables.getBaseUrl;
 import static org.apache.openmeetings.util.OpenmeetingsVariables.isSipEnabled;
-import static org.apache.openmeetings.web.app.Application.exitRoom;
 import static org.apache.openmeetings.web.app.Application.getBean;
-import static org.apache.openmeetings.web.app.Application.getClientBySid;
 import static org.apache.openmeetings.web.app.WebSession.getUserId;
 import static org.apache.openmeetings.web.util.GroupLogoResourceReference.getUrl;
 import static org.apache.openmeetings.web.util.OmUrlFragment.ROOMS_PUBLIC;
@@ -48,6 +46,7 @@ import org.apache.openmeetings.db.entity.user.Group;
 import org.apache.openmeetings.db.entity.user.User;
 import org.apache.openmeetings.db.util.ws.RoomMessage.Type;
 import org.apache.openmeetings.db.util.ws.TextRoomMessage;
+import org.apache.openmeetings.web.app.ClientManager;
 import org.apache.openmeetings.web.app.WebSession;
 import org.apache.openmeetings.web.common.ImagePanel;
 import org.apache.openmeetings.web.common.InvitationDialog;
@@ -370,13 +369,14 @@ public class RoomMenuPanel extends Panel {
 		StringBuilder roomClass = new StringBuilder("room name");
 		StringBuilder roomTitle = new StringBuilder();
 		if (room.getRecordingUser() != null) {
-			Client recClient = getClientBySid(room.getRecordingUser());
+			ClientManager cm = getBean(ClientManager.class);
+			Client recClient = cm.getBySid(room.getRecordingUser());
 			if (recClient != null) {
 				roomTitle.append(String.format("%s %s %s %s %s", getString("419")
 						, recClient.getUser().getLogin(), recClient.getUser().getFirstname(), recClient.getUser().getLastname(), df.format(recClient.getConnectedSince())));
 				roomClass.append(" screen");
 			}
-			Client pubClient = getClientBySid(room.getPublishingUser());
+			Client pubClient = cm.getBySid(room.getPublishingUser());
 			if (pubClient != null) {
 				if (recClient != null) {
 					roomTitle.append('\n');
@@ -408,7 +408,7 @@ public class RoomMenuPanel extends Panel {
 	}
 
 	public void exit(IPartialPageRequestHandler handler) {
-		exitRoom(room.getClient());
+		getBean(ClientManager.class).exitRoom(room.getClient());
 		if (WebSession.getRights().contains(User.Right.Dashboard)) {
 			room.getMainPanel().updateContents(ROOMS_PUBLIC, handler);
 		} else {
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/StartSharingButton.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/StartSharingButton.java
index eddb908..d558989 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/StartSharingButton.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/StartSharingButton.java
@@ -28,7 +28,6 @@ import static org.apache.openmeetings.util.OpenmeetingsVariables.FLASH_NATIVE_SS
 import static org.apache.openmeetings.util.OpenmeetingsVariables.getApplicationName;
 import static org.apache.openmeetings.util.OpenmeetingsVariables.getWebAppRootKey;
 import static org.apache.openmeetings.web.app.Application.getBean;
-import static org.apache.openmeetings.web.app.Application.getOnlineClient;
 import static org.apache.openmeetings.web.app.WebSession.getLanguage;
 import static org.apache.wicket.util.time.Duration.NONE;
 
@@ -38,9 +37,10 @@ import org.apache.commons.io.IOUtils;
 import org.apache.openmeetings.db.dao.basic.ConfigurationDao;
 import org.apache.openmeetings.db.dao.label.LabelDao;
 import org.apache.openmeetings.db.dao.room.RoomDao;
-import org.apache.openmeetings.db.dao.server.ISessionManager;
 import org.apache.openmeetings.db.entity.basic.Client;
 import org.apache.openmeetings.db.entity.room.Room;
+import org.apache.openmeetings.web.app.ClientManager;
+import org.apache.openmeetings.web.app.StreamClientManager;
 import org.apache.openmeetings.web.app.WebSession;
 import org.apache.openmeetings.web.common.OmButton;
 import org.apache.openmeetings.web.room.VideoSettings;
@@ -78,7 +78,7 @@ public class StartSharingButton extends OmButton {
 
 			@Override
 			protected IResourceStream getResourceStream(Attributes attributes) {
-				setFileName(String.format("public_%s.jnlp", getOnlineClient(uid).getRoom().getId()));
+				setFileName(String.format("public_%s.jnlp", getBean(ClientManager.class).get(uid).getRoom().getId()));
 				StringResourceStream srs = new StringResourceStream(app, "application/x-java-jnlp-file");
 				srs.setCharset(UTF_8);
 				return srs;
@@ -97,13 +97,13 @@ public class StartSharingButton extends OmButton {
 		try (InputStream jnlp = getClass().getClassLoader().getResourceAsStream("APPLICATION.jnlp")) {
 			ConfigurationDao cfgDao = getBean(ConfigurationDao.class);
 			app = IOUtils.toString(jnlp, UTF_8);
-			Client c = getOnlineClient(uid);
+			Client c = getBean(ClientManager.class).get(uid);
 			String sid = c.getSid();
 			Long roomId = c.getRoom().getId();
 			JSONObject s = VideoSettings.getInitJson(WebSession.get().getExtendedProperties(), roomId, sid);
 			String _url = s.getString(VideoSettings.URL);
 			Room room = getBean(RoomDao.class).get(roomId);
-			ISessionManager sessionManager = getBean(ISessionManager.class);
+			StreamClientManager streamClientManager = getBean(StreamClientManager.class);
 			app = app.replace("$native", String.valueOf(s.getBoolean(FLASH_NATIVE_SSL)))
 					.replace("$codebase", WebSession.get().getExtendedProperties().getCodebase())
 					.replace("$applicationName", getApplicationName())
@@ -122,8 +122,8 @@ public class StartSharingButton extends OmButton {
 					.replace("$defaultFps", String.valueOf(cfgDao.getLong(CONFIG_SCREENSHARING_FPS, 10L)))
 					.replace("$showFps", String.valueOf(cfgDao.getBool(CONFIG_SCREENSHARING_FPS_SHOW, true)))
 					.replace("$allowRemote", String.valueOf(cfgDao.getBool(CONFIG_SCREENSHARING_ALLOW_REMOTE, true)))
-					.replace("$allowRecording", String.valueOf(room.isAllowRecording() && (0 == sessionManager.getRecordingCount(roomId))))
-					.replace("$allowPublishing", String.valueOf(0 == sessionManager.getPublishingCount(roomId)))
+					.replace("$allowRecording", String.valueOf(room.isAllowRecording() && (0 == streamClientManager.getRecordingCount(roomId))))
+					.replace("$allowPublishing", String.valueOf(0 == streamClientManager.getPublishingCount(roomId)))
 					;
 			download.initiate(target);
 		} catch (Exception e) {
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/sidebar/RoomSidebar.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/sidebar/RoomSidebar.java
index 8eaf87f..923d97a 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/sidebar/RoomSidebar.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/sidebar/RoomSidebar.java
@@ -19,8 +19,7 @@
 package org.apache.openmeetings.web.room.sidebar;
 
 import static org.apache.openmeetings.util.OpenmeetingsVariables.getWebAppRootKey;
-import static org.apache.openmeetings.web.app.Application.getOnlineClient;
-import static org.apache.openmeetings.web.app.Application.getRoomClients;
+import static org.apache.openmeetings.web.app.Application.getBean;
 import static org.apache.openmeetings.web.app.Application.kickUser;
 import static org.apache.openmeetings.web.room.RoomBroadcaster.sendUpdatedClient;
 import static org.apache.openmeetings.web.util.CallbackFunctionHelper.getNamedFunction;
@@ -36,6 +35,7 @@ import org.apache.openmeetings.db.entity.room.Room.Right;
 import org.apache.openmeetings.db.entity.room.Room.RoomElement;
 import org.apache.openmeetings.db.util.ws.RoomMessage;
 import org.apache.openmeetings.db.util.ws.TextRoomMessage;
+import org.apache.openmeetings.web.app.ClientManager;
 import org.apache.openmeetings.web.app.WebSession;
 import org.apache.openmeetings.web.common.ConfirmableAjaxBorder;
 import org.apache.openmeetings.web.common.ConfirmableAjaxBorder.ConfirmableBorderDialog;
@@ -110,12 +110,13 @@ public class RoomSidebar extends Panel {
 				if (Strings.isEmpty(uid)) {
 					return;
 				}
+				ClientManager cm = getBean(ClientManager.class);
 				Client cl = room.getClient();
 				Action a = Action.valueOf(getRequest().getRequestParameters().getParameterValue(PARAM_ACTION).toString());
 				switch (a) {
 					case kick:
 						if (cl.hasRight(Right.moderator)) {
-							kickedClient = getOnlineClient(uid);
+							kickedClient = cm.get(uid);
 							if (kickedClient == null) {
 								return;
 							}
@@ -132,7 +133,7 @@ public class RoomSidebar extends Panel {
 					case mute:
 					{
 						JSONObject obj = uid.isEmpty() ? new JSONObject() : new JSONObject(uid);
-						Client _c = getOnlineClient(obj.getString("uid"));
+						Client _c = cm.get(obj.getString("uid"));
 						if (_c == null || !_c.hasActivity(Client.Activity.broadcastA)) {
 							return;
 						}
@@ -163,7 +164,7 @@ public class RoomSidebar extends Panel {
 				}
 				Right right = Right.valueOf(getRequest().getRequestParameters().getParameterValue(PARAM_RIGHT).toString());
 				if (room.getClient().hasRight(Right.moderator)) {
-					Client client = getOnlineClient(uid);
+					Client client = getBean(ClientManager.class).get(uid);
 					if (client == null) {
 						return;
 					}
@@ -201,7 +202,7 @@ public class RoomSidebar extends Panel {
 				Client.Activity a = Client.Activity.valueOf(getRequest().getRequestParameters().getParameterValue(PARAM_ACTIVITY).toString());
 				StringValue podStr = getRequest().getRequestParameters().getParameterValue(PARAM_POD);
 				Pod pod = podStr.isEmpty() ? Pod.none : Pod.valueOf(podStr.toString());
-				Client c = getOnlineClient(uid);
+				Client c = getBean(ClientManager.class).get(uid);
 				toggleActivity(c, a, pod);
 			} catch (Exception e) {
 				log.error("Unexpected exception while toggle 'activity'", e);
@@ -280,7 +281,7 @@ public class RoomSidebar extends Panel {
 	}
 
 	private ListView<Client> updateUsers() {
-		users.setList(getRoomClients(room.getRoom().getId()));
+		users.setList(getBean(ClientManager.class).listByRoom(room.getRoom().getId()));
 		return users;
 	}
 
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/sidebar/icon/ClientIcon.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/sidebar/icon/ClientIcon.java
index 3c7f7ec..0dd3191 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/sidebar/icon/ClientIcon.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/sidebar/icon/ClientIcon.java
@@ -20,12 +20,13 @@ package org.apache.openmeetings.web.room.sidebar.icon;
 
 import static org.apache.openmeetings.util.OpenmeetingsVariables.ATTR_CLASS;
 import static org.apache.openmeetings.util.OpenmeetingsVariables.ATTR_TITLE;
-import static org.apache.openmeetings.web.app.Application.getOnlineClient;
+import static org.apache.openmeetings.web.app.Application.getBean;
 import static org.apache.openmeetings.web.pages.BasePage.ALIGN_LEFT;
 import static org.apache.openmeetings.web.pages.BasePage.ALIGN_RIGHT;
 import static org.apache.openmeetings.web.util.CallbackFunctionHelper.addOnClick;
 
 import org.apache.openmeetings.db.entity.basic.Client;
+import org.apache.openmeetings.web.app.ClientManager;
 import org.apache.openmeetings.web.pages.BasePage;
 import org.apache.openmeetings.web.room.RoomPanel;
 import org.apache.wicket.AttributeModifier;
@@ -90,6 +91,6 @@ public abstract class ClientIcon extends WebMarkupContainer {
 	}
 
 	protected Client getClient() {
-		return getOnlineClient(uid);
+		return getBean(ClientManager.class).get(uid);
 	}
 }
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/wb/InterviewWbPanel.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/wb/InterviewWbPanel.java
index 1aa379e..32f9f87 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/wb/InterviewWbPanel.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/wb/InterviewWbPanel.java
@@ -23,11 +23,11 @@ import static org.apache.openmeetings.web.app.Application.getBean;
 import java.io.IOException;
 
 import org.apache.openmeetings.core.remote.ScopeApplicationAdapter;
-import org.apache.openmeetings.db.dao.server.ISessionManager;
 import org.apache.openmeetings.db.entity.basic.Client;
 import org.apache.openmeetings.db.entity.file.BaseFileItem;
 import org.apache.openmeetings.db.entity.room.Room;
 import org.apache.openmeetings.db.entity.room.Room.Right;
+import org.apache.openmeetings.web.app.StreamClientManager;
 import org.apache.openmeetings.web.room.RoomPanel;
 import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.request.resource.JavaScriptResourceReference;
@@ -59,12 +59,12 @@ public class InterviewWbPanel extends AbstractWbPanel {
 		if (c.hasRight(Room.Right.moderator)) {
 			switch (a) {
 				case startRecording:
-					if (getBean(ISessionManager.class).getRecordingCount(c.getRoomId()) < 1) {
+					if (getBean(StreamClientManager.class).getRecordingCount(c.getRoomId()) < 1) {
 						getBean(ScopeApplicationAdapter.class).startInterviewRecording(c);
 					}
 					break;
 				case stopRecording:
-					if (getBean(ISessionManager.class).getRecordingCount(c.getRoomId()) < 1) {
+					if (getBean(StreamClientManager.class).getRecordingCount(c.getRoomId()) < 1) {
 						getBean(ScopeApplicationAdapter.class).stopInterviewRecording(c);
 					}
 					break;
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/wb/WbPanel.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/wb/WbPanel.java
index ac69890..0265c5d 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/wb/WbPanel.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/wb/WbPanel.java
@@ -56,7 +56,6 @@ import javax.imageio.ImageIO;
 
 import org.apache.commons.codec.binary.Base64;
 import org.apache.directory.api.util.Strings;
-import org.apache.openmeetings.core.data.whiteboard.WhiteboardCache;
 import org.apache.openmeetings.db.dao.file.FileItemDao;
 import org.apache.openmeetings.db.dto.room.Whiteboard;
 import org.apache.openmeetings.db.dto.room.Whiteboard.ZoomMode;
@@ -70,6 +69,7 @@ import org.apache.openmeetings.db.entity.room.Room.RoomElement;
 import org.apache.openmeetings.db.entity.room.RoomFile;
 import org.apache.openmeetings.util.NullStringer;
 import org.apache.openmeetings.util.OmFileHelper;
+import org.apache.openmeetings.web.app.WhiteboardManager;
 import org.apache.openmeetings.web.common.NameDialog;
 import org.apache.openmeetings.web.room.RoomPanel;
 import org.apache.pdfbox.pdmodel.PDDocument;
@@ -155,8 +155,9 @@ public class WbPanel extends AbstractWbPanel {
 	@Override
 	void internalWbLoad(StringBuilder sb) {
 		Long langId = rp.getClient().getUser().getLanguageId();
-		if (!WhiteboardCache.contains(roomId) && rp.getRoom().getFiles() != null && !rp.getRoom().getFiles().isEmpty()) {
-			if (WhiteboardCache.tryLock(roomId)) {
+		WhiteboardManager wbm = getBean(WhiteboardManager.class);
+		if (!wbm.contains(roomId) && rp.getRoom().getFiles() != null && !rp.getRoom().getFiles().isEmpty()) {
+			if (wbm.tryLock(roomId)) {
 				try {
 					TreeMap<Long, List<BaseFileItem>> files = new TreeMap<>();
 					for (RoomFile rf : rp.getRoom().getFiles()) {
@@ -167,21 +168,21 @@ public class WbPanel extends AbstractWbPanel {
 						}
 						bfl.add(rf.getFile());
 					}
-					Whiteboards _wbs = WhiteboardCache.get(roomId, langId);
+					Whiteboards _wbs = wbm.get(roomId, langId);
 					for (Map.Entry<Long, List<BaseFileItem>> e : files.entrySet()) {
-						Whiteboard wb = WhiteboardCache.add(roomId, langId);
+						Whiteboard wb = wbm.add(roomId, langId);
 						_wbs.setActiveWb(wb.getId());
 						for (BaseFileItem fi : e.getValue()) {
 							sendFileToWb(fi, false);
 						}
 					}
 				} finally {
-					WhiteboardCache.unlock(roomId);
+					wbm.unlock(roomId);
 				}
 			}
 		}
-		Whiteboards wbs = WhiteboardCache.get(roomId, langId);
-		loadWhiteboards(sb, rp.getClient(), wbs, WhiteboardCache.list(roomId));
+		Whiteboards wbs = wbm.get(roomId, langId);
+		loadWhiteboards(sb, rp.getClient(), wbs, wbm.list(roomId));
 		JSONObject wbj = getWbJson(wbs.getActiveWb());
 		sb.append("WbArea.activateWb(").append(wbj).append(");");
 		Whiteboard wb = wbs.get(wbs.getActiveWb());
@@ -199,6 +200,7 @@ public class WbPanel extends AbstractWbPanel {
 	@Override
 	protected void processWbAction(WbAction a, JSONObject obj, AjaxRequestTarget target) throws IOException {
 		Client c = rp.getClient();
+		WhiteboardManager wbm = getBean(WhiteboardManager.class);
 		switch (a) {
 			case createObj:
 			case modifyObj:
@@ -241,7 +243,7 @@ public class WbPanel extends AbstractWbPanel {
 			{
 				StringBuilder sb = new StringBuilder("WbArea.initVideos(");
 				JSONArray arr = new JSONArray();
-				for (Entry<Long, Whiteboard> entry : WhiteboardCache.list(roomId)) {
+				for (Entry<Long, Whiteboard> entry : wbm.list(roomId)) {
 					Whiteboard wb = entry.getValue();
 					for (JSONObject o : wb.list()) {
 						String ft = o.optString(ATTR_FILE_TYPE);
@@ -273,7 +275,7 @@ public class WbPanel extends AbstractWbPanel {
 			switch (a) {
 				case createWb:
 				{
-					Whiteboard wb = WhiteboardCache.add(roomId, c.getUser().getLanguageId());
+					Whiteboard wb = wbm.add(roomId, c.getUser().getLanguageId());
 					sendWbAll(WbAction.createWb, getAddWbJson(wb));
 				}
 					break;
@@ -281,7 +283,7 @@ public class WbPanel extends AbstractWbPanel {
 				{
 					long id = obj.optLong("wbId", -1);
 					if (id > -1) {
-						WhiteboardCache.remove(roomId, id);
+						wbm.remove(roomId, id);
 						sendWbAll(WbAction.removeWb, obj);
 					}
 				}
@@ -290,26 +292,26 @@ public class WbPanel extends AbstractWbPanel {
 				{
 					long _id = obj.optLong("wbId", -1);
 					if (_id > -1) {
-						WhiteboardCache.activate(roomId, _id);
+						wbm.activate(roomId, _id);
 						sendWbAll(WbAction.activateWb, obj);
 					}
 				}
 					break;
 				case renameWb:
 				{
-					Whiteboard wb = WhiteboardCache.get(roomId).get(obj.optLong("wbId", -1));
+					Whiteboard wb = wbm.get(roomId).get(obj.optLong("wbId", -1));
 					if (wb != null) {
-						WhiteboardCache.update(roomId, wb.setName(obj.getString("name")));
+						wbm.update(roomId, wb.setName(obj.getString("name")));
 						sendWbAll(WbAction.renameWb, obj);
 					}
 				}
 					break;
 				case setSlide:
 				{
-					Whiteboard wb = WhiteboardCache.get(roomId).get(obj.optLong("wbId", -1));
+					Whiteboard wb = wbm.get(roomId).get(obj.optLong("wbId", -1));
 					if (wb != null) {
 						wb.setSlide(obj.optInt(ATTR_SLIDE, 0));
-						WhiteboardCache.update(roomId, wb);
+						wbm.update(roomId, wb);
 						sendWbOthers(WbAction.setSlide, obj);
 					}
 				}
@@ -321,10 +323,10 @@ public class WbPanel extends AbstractWbPanel {
 					break;
 				case setSize:
 				{
-					Whiteboard wb = WhiteboardCache.get(roomId).get(obj.getLong("wbId"));
+					Whiteboard wb = wbm.get(roomId).get(obj.getLong("wbId"));
 					wb.setZoom(obj.getDouble("zoom"));
 					wb.setZoomMode(ZoomMode.valueOf(obj.getString("zoomMode")));
-					WhiteboardCache.update(roomId, wb);
+					wbm.update(roomId, wb);
 					sendWbOthers(WbAction.setSize, getAddWbJson(wb));
 				}
 					break;
@@ -337,17 +339,17 @@ public class WbPanel extends AbstractWbPanel {
 			switch (a) {
 				case createObj:
 				{
-					Whiteboard wb = WhiteboardCache.get(roomId).get(obj.getLong("wbId"));
+					Whiteboard wb = wbm.get(roomId).get(obj.getLong("wbId"));
 					JSONObject o = obj.getJSONObject("obj");
 					wb.put(o.getString("uid"), o);
-					WhiteboardCache.update(roomId, wb);
+					wbm.update(roomId, wb);
 					addUndo(wb.getId(), new UndoObject(UndoObject.Type.add, o));
 					sendWbOthers(WbAction.createObj, obj);
 				}
 					break;
 				case modifyObj:
 				{
-					Whiteboard wb = WhiteboardCache.get(roomId).get(obj.getLong("wbId"));
+					Whiteboard wb = wbm.get(roomId).get(obj.getLong("wbId"));
 					JSONArray arr = obj.getJSONArray("obj");
 					JSONArray undo = new JSONArray();
 					for (int i = 0; i < arr.length(); ++i) {
@@ -360,7 +362,7 @@ public class WbPanel extends AbstractWbPanel {
 						}
 					}
 					if (arr.length() != 0) {
-						WhiteboardCache.update(roomId, wb);
+						wbm.update(roomId, wb);
 						addUndo(wb.getId(), new UndoObject(UndoObject.Type.modify, undo));
 					}
 					sendWbOthers(WbAction.modifyObj, obj);
@@ -368,7 +370,7 @@ public class WbPanel extends AbstractWbPanel {
 					break;
 				case deleteObj:
 				{
-					Whiteboard wb = WhiteboardCache.get(roomId).get(obj.getLong("wbId"));
+					Whiteboard wb = wbm.get(roomId).get(obj.getLong("wbId"));
 					JSONArray arr = obj.getJSONArray("obj");
 					JSONArray undo = new JSONArray();
 					for (int i = 0; i < arr.length(); ++i) {
@@ -379,7 +381,7 @@ public class WbPanel extends AbstractWbPanel {
 						}
 					}
 					if (undo.length() != 0) {
-						WhiteboardCache.update(roomId, wb);
+						wbm.update(roomId, wb);
 						addUndo(wb.getId(), new UndoObject(UndoObject.Type.remove, undo));
 					}
 					sendWbAll(WbAction.deleteObj, obj);
@@ -387,10 +389,10 @@ public class WbPanel extends AbstractWbPanel {
 					break;
 				case clearSlide:
 				{
-					Whiteboard wb = WhiteboardCache.get(roomId).get(obj.getLong("wbId"));
+					Whiteboard wb = wbm.get(roomId).get(obj.getLong("wbId"));
 					JSONArray arr = wb.clearSlide(obj.getInt(ATTR_SLIDE));
 					if (arr.length() != 0) {
-						WhiteboardCache.update(roomId, wb);
+						wbm.update(roomId, wb);
 						addUndo(wb.getId(), new UndoObject(UndoObject.Type.remove, arr));
 					}
 					sendWbAll(WbAction.clearSlide, obj);
@@ -405,13 +407,13 @@ public class WbPanel extends AbstractWbPanel {
 					Long wbId = obj.getLong("wbId");
 					UndoObject uo = getUndo(wbId);
 					if (uo != null) {
-						Whiteboard wb = WhiteboardCache.get(roomId).get(wbId);
+						Whiteboard wb = wbm.get(roomId).get(wbId);
 						switch (uo.getType()) {
 							case add:
 							{
 								JSONObject o = new JSONObject(uo.getObject());
 								wb.remove(o.getString("uid"));
-								WhiteboardCache.update(roomId, wb);
+								wbm.update(roomId, wb);
 								sendWbAll(WbAction.deleteObj, obj.put("obj", new JSONArray().put(o)));
 							}
 								break;
@@ -422,7 +424,7 @@ public class WbPanel extends AbstractWbPanel {
 									JSONObject o = arr.getJSONObject(i);
 									wb.put(o.getString("uid"), o);
 								}
-								WhiteboardCache.update(roomId, wb);
+								wbm.update(roomId, wb);
 								sendWbAll(WbAction.createObj, obj.put("obj", new JSONArray(uo.getObject())));
 							}
 								break;
@@ -433,7 +435,7 @@ public class WbPanel extends AbstractWbPanel {
 									JSONObject o = arr.getJSONObject(i);
 									wb.put(o.getString("uid"), o);
 								}
-								WhiteboardCache.update(roomId, wb);
+								wbm.update(roomId, wb);
 								sendWbAll(WbAction.modifyObj, obj.put("obj", arr));
 							}
 								break;
@@ -443,13 +445,13 @@ public class WbPanel extends AbstractWbPanel {
 					break;
 				case videoStatus:
 				{
-					Whiteboard wb = WhiteboardCache.get(roomId).get(obj.getLong("wbId"));
+					Whiteboard wb = wbm.get(roomId).get(obj.getLong("wbId"));
 					String uid = obj.getString("uid");
 					JSONObject po = wb.get(uid);
 					if (po != null && "video".equals(po.getString(ATTR_TYPE))) {
 						JSONObject ns = obj.getJSONObject(PARAM_STATUS);
 						po.put(PARAM_STATUS, ns.put("updated", System.currentTimeMillis()));
-						WhiteboardCache.update(roomId, wb.put(uid, po));
+						wbm.update(roomId, wb.put(uid, po));
 						obj.put(ATTR_SLIDE, po.getInt(ATTR_SLIDE));
 						sendWbAll(WbAction.videoStatus, obj);
 					}
@@ -517,7 +519,8 @@ public class WbPanel extends AbstractWbPanel {
 	}
 
 	private void clearAll(Long roomId, long wbId) {
-		Whiteboard wb = WhiteboardCache.get(roomId).get(wbId);
+		WhiteboardManager wbm = getBean(WhiteboardManager.class);
+		Whiteboard wb = wbm.get(roomId).get(wbId);
 		if (wb == null) {
 			return;
 		}
@@ -525,7 +528,7 @@ public class WbPanel extends AbstractWbPanel {
 		if (arr.length() != 0) {
 			addUndo(wb.getId(), new UndoObject(UndoObject.Type.remove, arr));
 		}
-		wb = WhiteboardCache.clear(roomId, wbId);
+		wb = wbm.clear(roomId, wbId);
 		sendWbAll(WbAction.clearAll, new JSONObject().put("wbId", wbId));
 		sendWbAll(WbAction.setSize, getAddWbJson(wb));
 	}
@@ -542,7 +545,8 @@ public class WbPanel extends AbstractWbPanel {
 	@Override
 	public void sendFileToWb(final BaseFileItem fi, boolean clean) {
 		if (isVisible() && fi.getId() != null) {
-			Whiteboards wbs = WhiteboardCache.get(roomId);
+			WhiteboardManager wbm = getBean(WhiteboardManager.class);
+			Whiteboards wbs = wbm.get(roomId);
 			String wuid = UUID.randomUUID().toString();
 			Whiteboard wb = wbs.get(wbs.getActiveWb());
 			switch (fi.getType()) {
@@ -561,7 +565,7 @@ public class WbPanel extends AbstractWbPanel {
 									return addFileUrl(rp.getClient(), wbs.getUid(), o, _f -> updateWbSize(wb, _f));
 								});
 							if (updated[0]) {
-								WhiteboardCache.update(roomId, wb);
+								wbm.update(roomId, wb);
 							}
 							sendWbAll(WbAction.setSize, getAddWbJson(wb));
 							sendWbAll(WbAction.load, getObjWbJson(wb.getId(), arr));
@@ -600,7 +604,7 @@ public class WbPanel extends AbstractWbPanel {
 					}
 					wb.put(wuid, file);
 					updateWbSize(wb, fi);
-					WhiteboardCache.update(roomId, wb);
+					wbm.update(roomId, wb);
 					sendWbAll(WbAction.setSize, getAddWbJson(wb));
 					WbWebSocketHelper.sendWbFile(roomId, wb.getId(), ruid, file, fi);
 				}
@@ -648,7 +652,7 @@ public class WbPanel extends AbstractWbPanel {
 	}
 
 	public static String saveWb(Long roomId, Long wbId, String name) {
-		Whiteboard wb = WhiteboardCache.get(roomId).get(wbId);
+		Whiteboard wb = getBean(WhiteboardManager.class).get(roomId).get(wbId);
 		FileItem f = new FileItem();
 		f.setType(BaseFileItem.Type.WmlFile);
 		f.setRoomId(roomId);
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/chat/Chat.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/chat/Chat.java
index 0607aac..a510f49 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/chat/Chat.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/chat/Chat.java
@@ -23,7 +23,6 @@ import static org.apache.openmeetings.core.util.WebSocketHelper.ID_ROOM_PREFIX;
 import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_DASHBOARD_SHOW_CHAT;
 import static org.apache.openmeetings.util.OpenmeetingsVariables.getWebAppRootKey;
 import static org.apache.openmeetings.web.app.Application.getBean;
-import static org.apache.openmeetings.web.app.Application.getUserRooms;
 import static org.apache.openmeetings.web.app.WebSession.getUserId;
 import static org.apache.openmeetings.web.room.RoomPanel.isModerator;
 import static org.apache.openmeetings.web.util.CallbackFunctionHelper.getNamedFunction;
@@ -46,6 +45,7 @@ import org.apache.openmeetings.db.entity.basic.ChatMessage;
 import org.apache.openmeetings.db.entity.basic.Client;
 import org.apache.openmeetings.db.entity.room.Room;
 import org.apache.openmeetings.db.entity.user.User;
+import org.apache.openmeetings.web.app.ClientManager;
 import org.apache.openmeetings.web.common.MainPanel;
 import org.apache.wicket.ajax.AbstractDefaultAjaxBehavior;
 import org.apache.wicket.ajax.AjaxRequestTarget;
@@ -165,7 +165,7 @@ public class Chat extends Panel {
 			ChatDao dao = getBean(ChatDao.class);
 			StringBuilder sb = new StringBuilder(getReinit());
 			List<ChatMessage> list = new ArrayList<>(dao.getGlobal(0, 30));
-			for(Long roomId : getUserRooms(getUserId())) {
+			for(Long roomId : getBean(ClientManager.class).listRoomIds(getUserId())) {
 				Room r = getBean(RoomDao.class).get(roomId);
 				sb.append(addRoom(r));
 			}
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/chat/ChatForm.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/chat/ChatForm.java
index de5ffa6..257c1bb 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/chat/ChatForm.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/chat/ChatForm.java
@@ -24,7 +24,6 @@ import static org.apache.openmeetings.core.util.WebSocketHelper.ID_USER_PREFIX;
 import static org.apache.openmeetings.db.util.FormatHelper.getDisplayName;
 import static org.apache.openmeetings.util.OpenmeetingsVariables.getWebAppRootKey;
 import static org.apache.openmeetings.web.app.Application.getBean;
-import static org.apache.openmeetings.web.app.Application.isUserInRoom;
 import static org.apache.openmeetings.web.app.WebSession.getDateFormat;
 import static org.apache.openmeetings.web.app.WebSession.getUserId;
 import static org.apache.openmeetings.web.room.RoomPanel.isModerator;
@@ -43,6 +42,7 @@ import org.apache.openmeetings.db.entity.basic.ChatMessage;
 import org.apache.openmeetings.db.entity.basic.Client;
 import org.apache.openmeetings.db.entity.room.Room;
 import org.apache.openmeetings.db.entity.user.User;
+import org.apache.openmeetings.web.app.ClientManager;
 import org.apache.openmeetings.web.common.MainPanel;
 import org.apache.wicket.Component;
 import org.apache.wicket.ajax.AjaxRequestTarget;
@@ -112,7 +112,7 @@ public class ChatForm extends Form<Void> {
 					if (!process(
 							() -> getChat().isShowDashboardChat()
 							, r -> {
-								if (isUserInRoom(r.getId(), getUserId())) {
+								if (getBean(ClientManager.class).isInRoom(r.getId(), getUserId())) {
 									m.setToRoom(r);
 								} else {
 									log.error("It seems like we are being hacked!!!!");
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/profile/UserSearchPanel.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/profile/UserSearchPanel.java
index 941c7f3..f3d1655 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/profile/UserSearchPanel.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/profile/UserSearchPanel.java
@@ -21,7 +21,6 @@ package org.apache.openmeetings.web.user.profile;
 import static org.apache.openmeetings.db.util.TimezoneUtil.getTimeZone;
 import static org.apache.openmeetings.util.OpenmeetingsVariables.ATTR_CLASS;
 import static org.apache.openmeetings.web.app.Application.getBean;
-import static org.apache.openmeetings.web.app.Application.isUserOnline;
 import static org.apache.openmeetings.web.app.WebSession.getUserId;
 import static org.apache.openmeetings.web.util.CallbackFunctionHelper.addOnClick;
 
@@ -33,6 +32,7 @@ import java.util.List;
 import org.apache.openmeetings.db.dao.user.UserContactDao;
 import org.apache.openmeetings.db.dao.user.UserDao;
 import org.apache.openmeetings.db.entity.user.User;
+import org.apache.openmeetings.web.app.ClientManager;
 import org.apache.openmeetings.web.common.PagingNavigatorPanel;
 import org.apache.openmeetings.web.common.UserBasePanel;
 import org.apache.wicket.AttributeModifier;
@@ -116,7 +116,7 @@ public class UserSearchPanel extends UserBasePanel {
 				final UserContactDao contactsDao = getBean(UserContactDao.class);
 				User u = item.getModelObject();
 				final long userId = u.getId();
-				item.add(new WebMarkupContainer("status").add(AttributeModifier.append(ATTR_CLASS, isUserOnline(userId) ? "online" : "offline")));
+				item.add(new WebMarkupContainer("status").add(AttributeModifier.append(ATTR_CLASS, getBean(ClientManager.class).isOnline(userId) ? "online" : "offline")));
 				item.add(new Label("name", getName(u)));
 				item.add(new Label("tz", getTimeZone(u).getID()));
 				item.add(new Label("offer", u.getUserOffers()));
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/record/RecordingResourceReference.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/record/RecordingResourceReference.java
index 771712e..32c6e64 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/record/RecordingResourceReference.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/record/RecordingResourceReference.java
@@ -19,7 +19,6 @@
 package org.apache.openmeetings.web.user.record;
 
 import static org.apache.openmeetings.web.app.Application.getBean;
-import static org.apache.openmeetings.web.app.Application.getOnlineClient;
 import static org.apache.openmeetings.web.app.WebSession.getExternalType;
 import static org.apache.openmeetings.web.app.WebSession.getRecordingId;
 import static org.apache.openmeetings.web.app.WebSession.getUserId;
@@ -27,7 +26,6 @@ import static org.apache.openmeetings.web.app.WebSession.getUserId;
 import java.util.Map.Entry;
 
 import org.apache.directory.api.util.Strings;
-import org.apache.openmeetings.core.data.whiteboard.WhiteboardCache;
 import org.apache.openmeetings.db.dao.record.RecordingDao;
 import org.apache.openmeetings.db.dao.user.GroupUserDao;
 import org.apache.openmeetings.db.dao.user.UserDao;
@@ -37,7 +35,9 @@ import org.apache.openmeetings.db.entity.basic.Client;
 import org.apache.openmeetings.db.entity.file.BaseFileItem.Type;
 import org.apache.openmeetings.db.entity.record.Recording;
 import org.apache.openmeetings.db.entity.user.User;
+import org.apache.openmeetings.web.app.ClientManager;
 import org.apache.openmeetings.web.app.WebSession;
+import org.apache.openmeetings.web.app.WhiteboardManager;
 import org.apache.openmeetings.web.util.FileItemResourceReference;
 import org.apache.wicket.request.mapper.parameter.PageParameters;
 import org.apache.wicket.request.resource.IResource.Attributes;
@@ -88,9 +88,9 @@ public abstract class RecordingResourceReference extends FileItemResourceReferen
 		if (id.equals(getRecordingId())) {
 			return r;
 		}
-		Client c = getOnlineClient(uid);
+		Client c = getBean(ClientManager.class).get(uid);
 		if (c != null && c.getRoom() != null) {
-			Whiteboards wbs = WhiteboardCache.get(c.getRoom().getId());
+			Whiteboards wbs = getBean(WhiteboardManager.class).get(c.getRoom().getId());
 			if (wbs != null && !Strings.isEmpty(ruid) && ruid.equals(wbs.getUid())) {
 				for (Entry<Long, Whiteboard> e : wbs.getWhiteboards().entrySet()) {
 					if (e.getValue().contains(r.getHash())) {
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/rooms/RoomListPanel.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/rooms/RoomListPanel.java
index 5ba829d..c40d635 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/rooms/RoomListPanel.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/rooms/RoomListPanel.java
@@ -19,12 +19,13 @@
 package org.apache.openmeetings.web.user.rooms;
 
 import static org.apache.openmeetings.util.OpenmeetingsVariables.ATTR_TITLE;
+import static org.apache.openmeetings.web.app.Application.getBean;
 import static org.apache.openmeetings.web.common.BasePanel.EVT_CLICK;
 
 import java.util.List;
 
 import org.apache.openmeetings.db.entity.room.Room;
-import org.apache.openmeetings.web.app.Application;
+import org.apache.openmeetings.web.app.ClientManager;
 import org.apache.openmeetings.web.pages.MainPage;
 import org.apache.wicket.AttributeModifier;
 import org.apache.wicket.ajax.AjaxEventBehavior;
@@ -70,7 +71,7 @@ public class RoomListPanel extends Panel {
 				final WebMarkupContainer info = new WebMarkupContainer("info");
 				roomContainer.add(info.setOutputMarkupId(true)
 						.add(AttributeModifier.append(ATTR_TITLE, getString(String.format("room.type.%s.desc", r.getType().name())))));
-				final Label curUsers = new Label("curUsers", new Model<>(Application.getRoomClients(r.getId()).size()));
+				final Label curUsers = new Label("curUsers", new Model<>(getBean(ClientManager.class).listByRoom(r.getId()).size()));
 				roomContainer.add(curUsers.setOutputMarkupId(true));
 				roomContainer.add(new Label("totalUsers", r.getCapacity()));
 				item.add(new Button("btn").add(new Label("label", label)).add(new RoomEnterBehavior(r.getId()) {
@@ -86,7 +87,7 @@ public class RoomListPanel extends Panel {
 
 					@Override
 					public void onClick(AjaxRequestTarget target) {
-						target.add(curUsers.setDefaultModelObject(Application.getRoomClients(r.getId()).size()));
+						target.add(curUsers.setDefaultModelObject(getBean(ClientManager.class).listByRoom(r.getId()).size()));
 						onRefreshClick(target, r);
 					}
 
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/rooms/RoomsPanel.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/rooms/RoomsPanel.java
index 671719b..97a6bb2 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/rooms/RoomsPanel.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/rooms/RoomsPanel.java
@@ -30,7 +30,7 @@ import org.apache.openmeetings.db.dao.user.UserDao;
 import org.apache.openmeetings.db.entity.basic.Client;
 import org.apache.openmeetings.db.entity.room.Room;
 import org.apache.openmeetings.util.OmFileHelper;
-import org.apache.openmeetings.web.app.Application;
+import org.apache.openmeetings.web.app.ClientManager;
 import org.apache.openmeetings.web.common.UserPanel;
 import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.markup.html.WebMarkupContainer;
@@ -123,7 +123,7 @@ public class RoomsPanel extends UserPanel {
 	}
 
 	void updateRoomDetails(AjaxRequestTarget target) {
-		clients.setDefaultModelObject(Application.getRoomClients(roomId));
+		clients.setDefaultModelObject(getBean(ClientManager.class).listByRoom(roomId));
 		Room room = getBean(RoomDao.class).get(roomId);
 		roomIdLbl.setDefaultModelObject(room.getId());
 		roomNameLbl.setDefaultModelObject(room.getName());
diff --git a/openmeetings-webservice/src/main/java/org/apache/openmeetings/webservice/RoomWebService.java b/openmeetings-webservice/src/main/java/org/apache/openmeetings/webservice/RoomWebService.java
index dbbcbfc..fcea5e7 100644
--- a/openmeetings-webservice/src/main/java/org/apache/openmeetings/webservice/RoomWebService.java
+++ b/openmeetings-webservice/src/main/java/org/apache/openmeetings/webservice/RoomWebService.java
@@ -38,7 +38,6 @@ import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.MediaType;
 
 import org.apache.cxf.feature.Features;
-import org.apache.openmeetings.IApplication;
 import org.apache.openmeetings.core.util.WebSocketHelper;
 import org.apache.openmeetings.db.dao.room.InvitationDao;
 import org.apache.openmeetings.db.dao.room.RoomDao;
@@ -53,6 +52,7 @@ import org.apache.openmeetings.db.entity.room.Invitation.MessageType;
 import org.apache.openmeetings.db.entity.room.Room;
 import org.apache.openmeetings.db.entity.room.RoomFile;
 import org.apache.openmeetings.db.entity.user.User;
+import org.apache.openmeetings.db.manager.IClientManager;
 import org.apache.openmeetings.db.util.ws.RoomMessage;
 import org.apache.openmeetings.service.room.InvitationManager;
 import org.apache.openmeetings.webservice.error.ServiceException;
@@ -313,7 +313,6 @@ public class RoomWebService extends BaseWebService {
 	public List<RoomCountDTO> counters(@WebParam(name="sid") @QueryParam("sid") String sid, @WebParam(name="id") @QueryParam("id") List<Long> ids) {
 		return performCall(sid, User.Right.Soap, sd -> {
 			List<RoomCountDTO> roomBeans = new ArrayList<>();
-			IApplication app = getApp();
 			List<Room> rooms = getRoomDao().get(ids);
 
 			for (Room room : rooms) {
@@ -321,7 +320,7 @@ public class RoomWebService extends BaseWebService {
 				rCountBean.setRoomId(room.getId());
 				rCountBean.setRoomName(room.getName());
 				rCountBean.setMaxUser(room.getCapacity());
-				rCountBean.setRoomCount(app.getOmRoomClients(room.getId()).size());
+				rCountBean.setRoomCount(getBean(IClientManager.class).listByRoom(room.getId()).size());
 
 				roomBeans.add(rCountBean);
 			}
diff --git a/openmeetings-webservice/src/main/java/org/apache/openmeetings/webservice/UserWebService.java b/openmeetings-webservice/src/main/java/org/apache/openmeetings/webservice/UserWebService.java
index 86b8764..1e58ae5 100644
--- a/openmeetings-webservice/src/main/java/org/apache/openmeetings/webservice/UserWebService.java
+++ b/openmeetings-webservice/src/main/java/org/apache/openmeetings/webservice/UserWebService.java
@@ -59,6 +59,7 @@ import org.apache.openmeetings.db.entity.server.Sessiondata;
 import org.apache.openmeetings.db.entity.user.Address;
 import org.apache.openmeetings.db.entity.user.User;
 import org.apache.openmeetings.db.entity.user.User.Right;
+import org.apache.openmeetings.db.manager.IClientManager;
 import org.apache.openmeetings.service.user.UserManager;
 import org.apache.openmeetings.util.OmException;
 import org.apache.openmeetings.webservice.error.ServiceException;
@@ -354,6 +355,6 @@ public class UserWebService extends BaseWebService {
 	@GET
 	@Path("/count/{roomid}")
 	public ServiceResult count(@WebParam(name="sid") @QueryParam("sid") String sid, @WebParam(name="roomid") @PathParam("roomid") Long roomId) {
-		return performCall(sid, User.Right.Soap, sd -> new ServiceResult(String.valueOf(getApp().getOmRoomClients(roomId).size()), Type.SUCCESS));
+		return performCall(sid, User.Right.Soap, sd -> new ServiceResult(String.valueOf(getBean(IClientManager.class).listByRoom(roomId).size()), Type.SUCCESS));
 	}
 }

-- 
To stop receiving notification emails like this one, please contact
solomax@apache.org.

[openmeetings] 04/04: [OPENMEETINGS-1791] quick polls seems to work

Posted by so...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

solomax pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/openmeetings.git

commit 202b74f41a90ff64c57d5f15a99f555212353f5e
Author: Maxim Solodovnik <so...@gmail.com>
AuthorDate: Sun Feb 25 21:46:42 2018 +0700

    [OPENMEETINGS-1791] quick polls seems to work
---
 .../openmeetings/db/util/ws/RoomMessage.java       |   1 +
 openmeetings-web/pom.xml                           |   3 +
 .../openmeetings/web/app/QuickPollManager.java     | 110 ++++
 .../apache/openmeetings/web/room/RoomPanel.html    |   9 +
 .../apache/openmeetings/web/room/RoomPanel.java    |  14 +-
 .../openmeetings/web/room/menu/PollsSubMenu.java   | 174 ++++++
 .../openmeetings/web/room/menu/RoomMenuPanel.java  |  96 +---
 .../org/apache/openmeetings/web/room/room-base.js  | 598 ++-------------------
 .../openmeetings/web/room/sidebar/RoomSidebar.java |   2 +-
 .../apache/openmeetings/web/room/video-manager.js  | 169 ++++++
 .../org/apache/openmeetings/web/room/video-util.js | 111 ++++
 .../java/org/apache/openmeetings/web/room/video.js | 268 +++++++++
 openmeetings-web/src/main/webapp/css/wb.css        |  26 +
 13 files changed, 949 insertions(+), 632 deletions(-)

diff --git a/openmeetings-db/src/main/java/org/apache/openmeetings/db/util/ws/RoomMessage.java b/openmeetings-db/src/main/java/org/apache/openmeetings/db/util/ws/RoomMessage.java
index 1e4af48..3c57781 100644
--- a/openmeetings-db/src/main/java/org/apache/openmeetings/db/util/ws/RoomMessage.java
+++ b/openmeetings-db/src/main/java/org/apache/openmeetings/db/util/ws/RoomMessage.java
@@ -58,6 +58,7 @@ public class RoomMessage implements IWebSocketPushMessage {
 		, audioActivity //user speaks
 		, mute
 		, exclusive
+		, quickPollUpdated
 	}
 	private final Date timestamp;
 	private final String uid;
diff --git a/openmeetings-web/pom.xml b/openmeetings-web/pom.xml
index 404788e..0a77370 100644
--- a/openmeetings-web/pom.xml
+++ b/openmeetings-web/pom.xml
@@ -213,6 +213,9 @@
 							<jsSourceDir>../java/org/apache/openmeetings/web/room</jsSourceDir>
 							<jsSourceFiles>
 								<jsSourceFile>jquery.dialogextend.js</jsSourceFile>
+								<jsSourceFile>video-util.js</jsSourceFile>
+								<jsSourceFile>video.js</jsSourceFile>
+								<jsSourceFile>video-manager.js</jsSourceFile>
 								<jsSourceFile>room-base.js</jsSourceFile>
 							</jsSourceFiles>
 							<jsFinalFile>room.js</jsFinalFile>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/QuickPollManager.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/QuickPollManager.java
new file mode 100644
index 0000000..b143603
--- /dev/null
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/QuickPollManager.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License") +  you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.openmeetings.web.app;
+
+import static org.apache.openmeetings.util.OpenmeetingsVariables.getWebAppRootKey;
+import static org.apache.openmeetings.web.app.Application.getHazelcast;
+import static org.apache.openmeetings.web.app.WebSession.getUserId;
+import static org.red5.logging.Red5LoggerFactory.getLogger;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.annotation.PostConstruct;
+
+import org.apache.openmeetings.core.util.WebSocketHelper;
+import org.apache.openmeetings.db.entity.basic.Client;
+import org.apache.openmeetings.db.entity.room.Room;
+import org.apache.openmeetings.db.util.ws.RoomMessage.Type;
+import org.apache.openmeetings.db.util.ws.TextRoomMessage;
+import org.slf4j.Logger;
+import org.springframework.stereotype.Component;
+
+import com.github.openjson.JSONObject;
+import com.hazelcast.core.HazelcastInstance;
+import com.hazelcast.core.IMap;
+
+@Component
+public class QuickPollManager {
+	private static final Logger log = getLogger(QuickPollManager.class, getWebAppRootKey());
+	private static final String QPOLLS_KEY = "QPOLLS_KEY";
+	private HazelcastInstance hazelcast;
+
+	@PostConstruct
+	private void init() {
+		this.hazelcast = getHazelcast();
+	}
+
+	private IMap<Long, Map<Long, Boolean>> map() {
+		return hazelcast.getMap(QPOLLS_KEY);
+	}
+
+	public boolean isStarted(Long roomId) {
+		return map().containsKey(roomId);
+	}
+
+	public void start(Client c) {
+		Long roomId = c.getRoomId();
+		if (!c.hasRight(Room.Right.presenter) || isStarted(roomId)) {
+			return;
+		}
+		log.debug("Starting quick poll, room: {}", roomId);
+		IMap<Long, Map<Long, Boolean>> polls = map();
+		polls.lock(roomId);
+		polls.putIfAbsent(roomId, new ConcurrentHashMap<Long, Boolean>());
+		polls.unlock(roomId);
+		WebSocketHelper.sendRoom(new TextRoomMessage(roomId, c, Type.quickPollUpdated, c.getUid()));
+	}
+
+	public void vote(Client c, boolean vote) {
+		Long roomId = c.getRoomId();
+		IMap<Long, Map<Long, Boolean>> polls = map();
+		polls.lock(roomId);
+		if (polls.containsKey(roomId)) {
+			Map<Long, Boolean> votes = map().get(roomId);
+			if (!votes.containsKey(c.getUserId())) {
+				votes.put(c.getUserId(), vote);
+				polls.put(roomId,  votes);
+				WebSocketHelper.sendRoom(new TextRoomMessage(roomId, c, Type.quickPollUpdated, c.getUid()));
+			}
+		}
+		polls.unlock(roomId);
+	}
+
+	public void close(Client c) {
+		Long roomId = c.getRoomId();
+		if (!c.hasRight(Room.Right.presenter) || !isStarted(roomId)) {
+			return;
+		}
+		map().remove(roomId);
+		WebSocketHelper.sendRoom(new TextRoomMessage(roomId, c, Type.quickPollUpdated, c.getUid()));
+	}
+
+	public JSONObject toJson(Long roomId) {
+		boolean started = isStarted(roomId);
+		JSONObject o = new JSONObject().put("started", started);
+		if (started) {
+			Map<Long, Boolean> votes = map().get(roomId);
+			o.put("voted", votes.containsKey(getUserId()));
+			o.put("pros", votes.entrySet().stream().filter(e -> e.getValue()).count())
+				.put("cons", votes.entrySet().stream().filter(e -> !e.getValue()).count());
+		}
+		return o;
+	}
+}
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/RoomPanel.html b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/RoomPanel.html
index 2b7a90a..d6c38c8 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/RoomPanel.html
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/RoomPanel.html
@@ -75,6 +75,15 @@
 		<div id="clipboard-dialog" wicket:message="title:1121,data-btn-ok:54">
 			<p><span class="ui-icon ui-icon-alert" style="float:left; margin:12px 12px 20px 0;"></span><span class="text"></span></p>
 		</div>
+		<div id="quick-vote-template">
+			<div class="close clickable"><wicket:message key="85" /></div>
+			<div class="control pro">
+				<span class="badge">0</span>
+			</div>
+			<div class="control con">
+				<span class="badge">0</span>
+			</div>
+		</div>
 	</div>
 </wicket:panel>
 </html>
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/RoomPanel.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/RoomPanel.java
index 29ddfc4..2da8a6c 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/RoomPanel.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/RoomPanel.java
@@ -58,6 +58,7 @@ import org.apache.openmeetings.db.util.ws.RoomMessage.Type;
 import org.apache.openmeetings.db.util.ws.TextRoomMessage;
 import org.apache.openmeetings.util.NullStringer;
 import org.apache.openmeetings.web.app.ClientManager;
+import org.apache.openmeetings.web.app.QuickPollManager;
 import org.apache.openmeetings.web.app.StreamClientManager;
 import org.apache.openmeetings.web.app.WebSession;
 import org.apache.openmeetings.web.common.BasePanel;
@@ -139,7 +140,8 @@ public class RoomPanel extends BasePanel {
 			}
 			StringBuilder sb = new StringBuilder("Room.init(").append(options.toString(new NullStringer())).append(");")
 					.append(wb.getInitScript())
-					.append("Room.setSize();");
+					.append("Room.setSize();")
+					.append(getQuickPollJs());
 			target.appendJavaScript(sb);
 			WebSocketHelper.sendRoom(new RoomMessage(r.getId(), _c, RoomMessage.Type.roomEnter));
 			// play video from other participants
@@ -618,12 +620,22 @@ public class RoomPanel extends BasePanel {
 						handler.appendJavaScript(String.format("if (typeof(VideoManager) !== 'undefined') {VideoManager.exclusive('%s');}", uid));
 					}
 						break;
+					case quickPollUpdated:
+					{
+						menu.update(handler);
+						handler.appendJavaScript(getQuickPollJs());
+					}
+						break;
 				}
 			}
 		}
 		super.onEvent(event);
 	}
 
+	private String getQuickPollJs() {
+		return String.format("Room.quickPoll(%s);", getBean(QuickPollManager.class).toJson(r.getId()));
+	}
+
 	private void updateInterviewRecordingButtons(IPartialPageRequestHandler handler) {
 		Client _c = getClient();
 		if (interview && _c.hasRight(Right.moderator)) {
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/PollsSubMenu.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/PollsSubMenu.java
new file mode 100644
index 0000000..15bdcc7
--- /dev/null
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/PollsSubMenu.java
@@ -0,0 +1,174 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License") +  you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.openmeetings.web.room.menu;
+
+import static org.apache.openmeetings.util.OpenmeetingsVariables.getWebAppRootKey;
+import static org.apache.openmeetings.web.app.Application.getBean;
+import static org.apache.openmeetings.web.app.WebSession.getUserId;
+import static org.apache.openmeetings.web.room.sidebar.RoomSidebar.PARAM_ACTION;
+import static org.apache.openmeetings.web.util.CallbackFunctionHelper.getNamedFunction;
+import static org.apache.wicket.ajax.attributes.CallbackParameter.explicit;
+
+import java.io.Serializable;
+
+import org.apache.openmeetings.db.dao.room.PollDao;
+import org.apache.openmeetings.db.entity.basic.Client;
+import org.apache.openmeetings.db.entity.room.Room;
+import org.apache.openmeetings.db.entity.room.Room.RoomElement;
+import org.apache.openmeetings.db.entity.room.RoomPoll;
+import org.apache.openmeetings.web.app.QuickPollManager;
+import org.apache.openmeetings.web.common.menu.RoomMenuItem;
+import org.apache.openmeetings.web.room.RoomPanel;
+import org.apache.openmeetings.web.room.poll.CreatePollDialog;
+import org.apache.openmeetings.web.room.poll.PollResultsDialog;
+import org.apache.openmeetings.web.room.poll.VoteDialog;
+import org.apache.wicket.ajax.AbstractDefaultAjaxBehavior;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.core.request.handler.IPartialPageRequestHandler;
+import org.apache.wicket.markup.head.IHeaderResponse;
+import org.apache.wicket.markup.head.PriorityHeaderItem;
+import org.red5.logging.Red5LoggerFactory;
+import org.slf4j.Logger;
+
+public class PollsSubMenu implements Serializable {
+	private static final long serialVersionUID = 1L;
+	private static final Logger log = Red5LoggerFactory.getLogger(PollsSubMenu.class, getWebAppRootKey());
+	private static final String FUNC_QPOLL_ACTION = "quickPollAction";
+	private static final String PARAM_VOTE = "vote";
+	private static final String ACTION_CLOSE = "close";
+	private final RoomPanel room;
+	private final RoomMenuPanel mp;
+	private final CreatePollDialog createPoll;
+	private final VoteDialog vote;
+	private final PollResultsDialog pollResults;
+	private RoomMenuItem pollsMenu;
+	private RoomMenuItem pollQuickMenuItem;
+	private RoomMenuItem pollCreateMenuItem;
+	private RoomMenuItem pollVoteMenuItem;
+	private RoomMenuItem pollResultMenuItem;
+	private final AbstractDefaultAjaxBehavior quickPollAction = new AbstractDefaultAjaxBehavior() {
+		private static final long serialVersionUID = 1L;
+
+		@Override
+		protected void respond(AjaxRequestTarget target) {
+			try {
+				String action = mp.getRequest().getRequestParameters().getParameterValue(PARAM_ACTION).toString();
+				QuickPollManager qm = getBean(QuickPollManager.class);
+				Client c = room.getClient();
+				if (ACTION_CLOSE.equals(action)) {
+					qm.close(c);
+				} else if (PARAM_VOTE.equals(action)) {
+					boolean vote = mp.getRequest().getRequestParameters().getParameterValue(PARAM_VOTE).toBoolean();
+					qm.vote(c, vote);
+				}
+			} catch (Exception e) {
+				log.error("Unexpected exception while toggle 'quickPollAction'", e);
+			}
+		}
+	};
+
+	public PollsSubMenu(final RoomPanel room, final RoomMenuPanel mp) {
+		this.room = room;
+		this.mp = mp;
+		mp.add(createPoll = new CreatePollDialog("createPoll", room.getRoom().getId()));
+		mp.add(vote = new VoteDialog("vote"));
+		mp.add(pollResults = new PollResultsDialog("pollResults", room.getRoom().getId()));
+	}
+
+	public void init() {
+		pollsMenu = new RoomMenuItem(mp.getString("menu.polls"), null, false);
+		pollQuickMenuItem = new RoomMenuItem(mp.getString("menu.polls.quick.title"), mp.getString("menu.polls.quick.descr"), false) {
+			private static final long serialVersionUID = 1L;
+
+			@Override
+			public void onClick(AjaxRequestTarget target) {
+				getBean(QuickPollManager.class).start(room.getClient());
+			}
+		};
+		pollCreateMenuItem = new RoomMenuItem(mp.getString("24"), mp.getString("1483"), false) {
+			private static final long serialVersionUID = 1L;
+
+			@Override
+			public void onClick(AjaxRequestTarget target) {
+				createPoll.updateModel(target);
+				createPoll.open(target);
+			}
+		};
+		pollVoteMenuItem = new RoomMenuItem(mp.getString("32"), mp.getString("1485"), false) {
+			private static final long serialVersionUID = 1L;
+
+			@Override
+			public void onClick(AjaxRequestTarget target) {
+				RoomPoll rp = getBean(PollDao.class).getByRoom(room.getRoom().getId());
+				if (rp != null) {
+					vote.updateModel(target, rp);
+					vote.open(target);
+				}
+			}
+		};
+		pollResultMenuItem = new RoomMenuItem(mp.getString("37"), mp.getString("1484"), false) {
+			private static final long serialVersionUID = 1L;
+
+			@Override
+			public void onClick(AjaxRequestTarget target) {
+				pollResults.updateModel(target, room.getClient().hasRight(Room.Right.moderator));
+				pollResults.open(target);
+			}
+		};
+		mp.add(quickPollAction);
+	}
+
+	RoomMenuItem getMenu() {
+		pollsMenu.setTop(true);
+		pollsMenu.getItems().add(pollQuickMenuItem);
+		pollsMenu.getItems().add(pollCreateMenuItem);
+		pollsMenu.getItems().add(pollResultMenuItem);
+		pollsMenu.getItems().add(pollVoteMenuItem);
+		return pollsMenu;
+	}
+
+	public void update(final boolean moder, final boolean notExternalUser, final Room r) {
+		PollDao pollDao = getBean(PollDao.class);
+		boolean pollExists = pollDao.hasPoll(r.getId());
+		pollsMenu.setEnabled((moder && !r.isHidden(RoomElement.ActionMenu)) || (!moder && r.isAllowUserQuestions()));
+		pollQuickMenuItem.setEnabled(room.getClient().hasRight(Room.Right.presenter) && !getBean(QuickPollManager.class).isStarted(r.getId()));
+		pollCreateMenuItem.setEnabled(moder);
+		pollVoteMenuItem.setEnabled(pollExists && notExternalUser && !pollDao.hasVoted(r.getId(), getUserId()));
+		pollResultMenuItem.setEnabled(pollExists || !pollDao.getArchived(r.getId()).isEmpty());
+	}
+
+	public void updatePoll(IPartialPageRequestHandler handler, Long createdBy) {
+		RoomPoll rp = getBean(PollDao.class).getByRoom(room.getRoom().getId());
+		if (rp != null) {
+			vote.updateModel(handler, rp);
+		} else {
+			vote.close(handler, null);
+		}
+		if (createdBy != null && !getUserId().equals(createdBy)) {
+			vote.open(handler);
+		}
+		if (pollResults.isOpened()) {
+			pollResults.updateModel(handler, room.getClient().hasRight(Room.Right.moderator));
+		}
+	}
+
+	public void renderHead(IHeaderResponse response) {
+		response.render(new PriorityHeaderItem(getNamedFunction(FUNC_QPOLL_ACTION, quickPollAction, explicit(PARAM_ACTION), explicit(PARAM_VOTE))));
+	}
+}
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/RoomMenuPanel.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/RoomMenuPanel.java
index d3aa885..e3a2f1a 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/RoomMenuPanel.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/menu/RoomMenuPanel.java
@@ -27,7 +27,6 @@ import static org.apache.openmeetings.util.OpenmeetingsVariables.CONFIG_REDIRECT
 import static org.apache.openmeetings.util.OpenmeetingsVariables.getBaseUrl;
 import static org.apache.openmeetings.util.OpenmeetingsVariables.isSipEnabled;
 import static org.apache.openmeetings.web.app.Application.getBean;
-import static org.apache.openmeetings.web.app.WebSession.getUserId;
 import static org.apache.openmeetings.web.util.GroupLogoResourceReference.getUrl;
 import static org.apache.openmeetings.web.util.OmUrlFragment.ROOMS_PUBLIC;
 
@@ -37,11 +36,9 @@ import java.util.List;
 import org.apache.commons.lang3.time.FastDateFormat;
 import org.apache.openmeetings.core.util.WebSocketHelper;
 import org.apache.openmeetings.db.dao.basic.ConfigurationDao;
-import org.apache.openmeetings.db.dao.room.PollDao;
 import org.apache.openmeetings.db.entity.basic.Client;
 import org.apache.openmeetings.db.entity.room.Room;
 import org.apache.openmeetings.db.entity.room.Room.RoomElement;
-import org.apache.openmeetings.db.entity.room.RoomPoll;
 import org.apache.openmeetings.db.entity.user.Group;
 import org.apache.openmeetings.db.entity.user.User;
 import org.apache.openmeetings.db.util.ws.RoomMessage.Type;
@@ -55,12 +52,10 @@ import org.apache.openmeetings.web.common.menu.MenuPanel;
 import org.apache.openmeetings.web.common.menu.RoomMenuItem;
 import org.apache.openmeetings.web.room.OmRedirectTimerBehavior;
 import org.apache.openmeetings.web.room.RoomPanel;
-import org.apache.openmeetings.web.room.poll.CreatePollDialog;
-import org.apache.openmeetings.web.room.poll.PollResultsDialog;
-import org.apache.openmeetings.web.room.poll.VoteDialog;
 import org.apache.wicket.AttributeModifier;
 import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.core.request.handler.IPartialPageRequestHandler;
+import org.apache.wicket.markup.head.IHeaderResponse;
 import org.apache.wicket.markup.html.basic.Label;
 import org.apache.wicket.markup.html.panel.Panel;
 import org.apache.wicket.model.Model;
@@ -72,9 +67,6 @@ import com.googlecode.wicket.jquery.ui.widget.menu.IMenuItem;
 public class RoomMenuPanel extends Panel {
 	private static final long serialVersionUID = 1L;
 	private final InvitationDialog invite;
-	private final CreatePollDialog createPoll;
-	private final VoteDialog vote;
-	private final PollResultsDialog pollResults;
 	private final SipDialerDialog sipDialer;
 	private MenuPanel menuPanel;
 	private final StartSharingButton shareBtn;
@@ -100,16 +92,11 @@ public class RoomMenuPanel extends Panel {
 	private RoomMenuItem exitMenuItem;
 	private RoomMenuItem filesMenu;
 	private RoomMenuItem actionsMenu;
-	private RoomMenuItem pollsMenu;
 	private RoomMenuItem inviteMenuItem;
 	private RoomMenuItem shareMenuItem;
 	private RoomMenuItem applyModerMenuItem;
 	private RoomMenuItem applyWbMenuItem;
 	private RoomMenuItem applyAvMenuItem;
-	private RoomMenuItem pollQuickMenuItem;
-	private RoomMenuItem pollCreateMenuItem;
-	private RoomMenuItem pollVoteMenuItem;
-	private RoomMenuItem pollResultMenuItem;
 	private RoomMenuItem sipDialerMenuItem;
 	private RoomMenuItem downloadPngMenuItem;
 	private RoomMenuItem downloadJpgMenuItem;
@@ -122,6 +109,7 @@ public class RoomMenuPanel extends Panel {
 			return getUrl(getRequestCycle(), getGroup().getId());
 		}
 	};
+	private final PollsSubMenu pollsSubMenu;
 
 	public RoomMenuPanel(String id, final RoomPanel room) {
 		super(id);
@@ -137,10 +125,8 @@ public class RoomMenuPanel extends Panel {
 		RoomInvitationForm rif = new RoomInvitationForm("form", room.getRoom().getId());
 		add(invite = new InvitationDialog("invite", rif));
 		rif.setDialog(invite);
-		add(createPoll = new CreatePollDialog("createPoll", room.getRoom().getId()));
-		add(vote = new VoteDialog("vote"));
-		add(pollResults = new PollResultsDialog("pollResults", room.getRoom().getId()));
 		add(sipDialer = new SipDialerDialog("sipDialer", room));
+		pollsSubMenu = new PollsSubMenu(room, this);
 	}
 
 	private Group getGroup() {
@@ -162,8 +148,7 @@ public class RoomMenuPanel extends Panel {
 		};
 		filesMenu = new RoomMenuItem(getString("245"), null, false);
 		actionsMenu = new RoomMenuItem(getString("635"), null, false);
-		pollsMenu = new RoomMenuItem(getString("menu.polls"), null, false);
-
+		pollsSubMenu.init();
 		inviteMenuItem = new RoomMenuItem(getString("213"), getString("1489"), false) {
 			private static final long serialVersionUID = 1L;
 
@@ -205,45 +190,6 @@ public class RoomMenuPanel extends Panel {
 				room.requestRight(Room.Right.video, target);
 			}
 		};
-		pollQuickMenuItem = new RoomMenuItem(getString("menu.polls.quick.title"), getString("menu.polls.quick.descr"), false) {
-			private static final long serialVersionUID = 1L;
-
-			@Override
-			public void onClick(AjaxRequestTarget target) {
-				//createPoll.updateModel(target);
-				//createPoll.open(target);
-			}
-		};
-		pollCreateMenuItem = new RoomMenuItem(getString("24"), getString("1483"), false) {
-			private static final long serialVersionUID = 1L;
-
-			@Override
-			public void onClick(AjaxRequestTarget target) {
-				createPoll.updateModel(target);
-				createPoll.open(target);
-			}
-		};
-		pollVoteMenuItem = new RoomMenuItem(getString("32"), getString("1485"), false) {
-			private static final long serialVersionUID = 1L;
-
-			@Override
-			public void onClick(AjaxRequestTarget target) {
-				RoomPoll rp = getBean(PollDao.class).getByRoom(room.getRoom().getId());
-				if (rp != null) {
-					vote.updateModel(target, rp);
-					vote.open(target);
-				}
-			}
-		};
-		pollResultMenuItem = new RoomMenuItem(getString("37"), getString("1484"), false) {
-			private static final long serialVersionUID = 1L;
-
-			@Override
-			public void onClick(AjaxRequestTarget target) {
-				pollResults.updateModel(target, room.getClient().hasRight(Room.Right.moderator));
-				pollResults.open(target);
-			}
-		};
 		sipDialerMenuItem = new RoomMenuItem(getString("1447"), getString("1488"), false) {
 			private static final long serialVersionUID = 1L;
 
@@ -300,6 +246,12 @@ public class RoomMenuPanel extends Panel {
 		super.onInitialize();
 	}
 
+	@Override
+	public void renderHead(IHeaderResponse response) {
+		super.renderHead(response);
+		pollsSubMenu.renderHead(response);
+	}
+
 	private List<IMenuItem> getMenu() {
 		List<IMenuItem> menu = new ArrayList<>();
 		exitMenuItem.setEnabled(false);
@@ -327,12 +279,7 @@ public class RoomMenuPanel extends Panel {
 		actionsMenu.getItems().add(downloadPdfMenuItem);
 		menu.add(actionsMenu);
 
-		pollsMenu.setTop(true);
-		pollsMenu.getItems().add(pollQuickMenuItem);
-		pollsMenu.getItems().add(pollCreateMenuItem);
-		pollsMenu.getItems().add(pollResultMenuItem);
-		pollsMenu.getItems().add(pollVoteMenuItem);
-		menu.add(pollsMenu);
+		menu.add(pollsSubMenu.getMenu());
 		return menu;
 	}
 
@@ -345,25 +292,19 @@ public class RoomMenuPanel extends Panel {
 		downloadPngMenuItem.setEnabled(!isInterview);
 		downloadJpgMenuItem.setEnabled(!isInterview);
 		downloadPdfMenuItem.setEnabled(!isInterview);
-		PollDao pollDao = getBean(PollDao.class);
-		boolean pollExists = pollDao.hasPoll(r.getId());
 		User u = room.getClient().getUser();
 		boolean notExternalUser = u.getType() != User.Type.contact;
 		exitMenuItem.setEnabled(notExternalUser);
 		filesMenu.setEnabled(!isInterview && room.getSidebar().isShowFiles());
 		boolean moder = room.getClient().hasRight(Room.Right.moderator);
+		pollsSubMenu.update(moder, notExternalUser, r);
 		actionsMenu.setEnabled((moder && !r.isHidden(RoomElement.ActionMenu)) || (!moder && r.isAllowUserQuestions()));
-		pollsMenu.setEnabled((moder && !r.isHidden(RoomElement.ActionMenu)) || (!moder && r.isAllowUserQuestions()));
 		inviteMenuItem.setEnabled(notExternalUser && moder);
 		boolean shareVisible = room.screenShareAllowed();
 		shareMenuItem.setEnabled(shareVisible);
 		applyModerMenuItem.setEnabled(!moder);
 		applyWbMenuItem.setEnabled(!room.getClient().hasRight(Room.Right.whiteBoard));
 		applyAvMenuItem.setEnabled(!room.getClient().hasRight(Room.Right.audio) || !room.getClient().hasRight(Room.Right.video));
-		pollQuickMenuItem.setEnabled(moder);
-		pollCreateMenuItem.setEnabled(moder);
-		pollVoteMenuItem.setEnabled(pollExists && notExternalUser && !pollDao.hasVoted(r.getId(), getUserId()));
-		pollResultMenuItem.setEnabled(pollExists || !pollDao.getArchived(r.getId()).isEmpty());
 		sipDialerMenuItem.setEnabled(r.isSipEnabled() && isSipEnabled());
 		menuPanel.update(handler);
 		StringBuilder roomClass = new StringBuilder("room name");
@@ -392,18 +333,7 @@ public class RoomMenuPanel extends Panel {
 	}
 
 	public void updatePoll(IPartialPageRequestHandler handler, Long createdBy) {
-		RoomPoll rp = getBean(PollDao.class).getByRoom(room.getRoom().getId());
-		if (rp != null) {
-			vote.updateModel(handler, rp);
-		} else {
-			vote.close(handler, null);
-		}
-		if (createdBy != null && !getUserId().equals(createdBy)) {
-			vote.open(handler);
-		}
-		if (pollResults.isOpened()) {
-			pollResults.updateModel(handler, room.getClient().hasRight(Room.Right.moderator));
-		}
+		pollsSubMenu.updatePoll(handler, createdBy);
 		update(handler);
 	}
 
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/room-base.js b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/room-base.js
index a150835..d89c851 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/room-base.js
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/room-base.js
@@ -1,549 +1,4 @@
 /* Licensed under the Apache License, Version 2.0 (the "License") http://www.apache.org/licenses/LICENSE-2.0 */
-const WB_AREA_SEL = '.room.wb.area';
-const WBA_WB_SEL = '.room.wb.area .ui-tabs-panel.ui-corner-bottom.ui-widget-content:visible';
-var WBA_SEL = WB_AREA_SEL;
-const VID_SEL = '.video.user-video';
-var VideoUtil = (function() {
-	const self = {};
-	function _getVid(uid) {
-		return "video" + uid;
-	}
-	function _isSharing(c) {
-		return 'sharing' === c.type && c.screenActivities.indexOf('sharing') > -1;
-	}
-	function _isRecording(c) {
-		return 'sharing' === c.type
-			&& c.screenActivities.indexOf('recording') > -1
-			&& c.screenActivities.indexOf('sharing') < 0;
-	}
-	function _hasAudio(c) {
-		return c.activities.indexOf('broadcastA') > -1;
-	}
-	function _hasVideo(c) {
-		return c.activities.indexOf('broadcastV') > -1;
-	}
-	function _getRects(sel, excl) {
-		const list = [], elems = $(sel);
-		for (let i = 0; i < elems.length; ++i) {
-			if (excl !== $(elems[i]).attr('aria-describedby')) {
-				list.push(_getRect(elems[i]));
-			}
-		}
-		return list;
-	}
-	function _getRect(e) {
-		const win = $(e), winoff = win.offset();
-		return {left: winoff.left
-			, top: winoff.top
-			, right: winoff.left + win.width()
-			, bottom: winoff.top + win.height()};
-	}
-	function _getPos(list, w, h) {
-		if (Room.getOptions().interview) {
-			return {left: 0, top: 0};
-		}
-		const wba = $(WBA_SEL), woffset = wba.offset()
-			, offsetX = 20, offsetY = 10
-			, area = {left: woffset.left, top: woffset.top, right: woffset.left + wba.width(), bottom: woffset.top + wba.height()};
-		const rectNew = {
-				_left: area.left
-				, _top: area.top
-				, right: area.left + w
-				, bottom: area.top + h
-				, get left() {
-					return this._left
-				}
-				, set left(l) {
-					this._left = l;
-					this.right = l + w;
-				}
-				, get top() {
-					return this._top
-				}
-				, set top(t) {
-					this._top = t;
-					this.bottom = t + h;
-				}
-			};
-		let minY = area.bottom, posFound;
-		do {
-			posFound = true
-			for (let i = 0; i < list.length; ++i) {
-				const rect = list[i];
-				minY = Math.min(minY, rect.bottom);
-
-				if (rectNew.left < rect.right && rectNew.right > rect.left && rectNew.top < rect.bottom && rectNew.bottom > rect.top) {
-					rectNew.left = rect.right + offsetX;
-					posFound = false;
-				}
-				if (rectNew.right >= area.right) {
-					rectNew.left = area.left;
-					rectNew.top = minY + offsetY;
-					posFound = false;
-				}
-				if (rectNew.bottom >= area.bottom) {
-					rectNew.top = area.top;
-					posFound = true;
-					break;
-				}
-			}
-		} while (!posFound);
-		return {left: rectNew.left, top: rectNew.top};
-	}
-	function _arrange() {
-		const list = [], elems = $(VID_SEL);
-		for (let i = 0; i < elems.length; ++i) {
-			const v = $(elems[i]);
-			v.css(_getPos(list, v.width(), v.height()));
-			list.push(_getRect(v));
-		}
-	}
-
-	self.getVid = _getVid;
-	self.isSharing = _isSharing;
-	self.isRecording = _isRecording;
-	self.hasAudio = _hasAudio;
-	self.hasVideo = _hasVideo;
-	self.getRects = _getRects;
-	self.getPos = _getPos;
-	self.arrange = _arrange;
-	return self;
-})();
-var Video = (function() {
-	const self = {};
-	let c, v, vc, t, f, swf, size, vol, slider, handle
-		, lastVolume = 50;
-
-	function _getName() {
-		return c.user.firstName + ' ' + c.user.lastName;
-	}
-	function _resizeDlg(_ww, _hh) {
-		const interview = Room.getOptions().interview;
-		const _w = interview ? 320 : _ww, _h = interview ? 260 : _hh;
-		const h = _h + t.height() + 2 + (f.is(":visible") ? f.height() : 0);
-		v.dialog("option", "width", _w).dialog("option", "height", h);
-		_resize(_w, _h);
-		return h;
-	}
-	function _securityMode(on) {
-		if (Room.getOptions().interview) {
-			return;
-		}
-		if (on) {
-			v.dialog("option", "position", {my: "center", at: "center", of: WBA_SEL});
-		} else {
-			const h = _resizeDlg(size.width, size.height);
-			v.dialog("widget").css(VideoUtil.getPos(VideoUtil.getRects(VID_SEL, VideoUtil.getVid(c.uid)), c.width, h));
-		}
-	}
-	function _resize(w, h) {
-		vc.width(w).height(h);
-		swf.attr('width', w).attr('height', h);
-	}
-	function _handleMicStatus(state) {
-		if (!f.is(":visible")) {
-			return;
-		}
-		if (state) {
-			f.find('.off').hide();
-			f.find('.on').show();
-			f.addClass('ui-state-highlight');
-			t.addClass('ui-state-highlight');
-		} else {
-			f.find('.off').show();
-			f.find('.on').hide();
-			f.removeClass('ui-state-highlight');
-			t.removeClass('ui-state-highlight');
-		}
-	}
-	function _handleVolume(val) {
-		handle.text(val);
-		const ico = vol.find('.ui-icon');
-		if (val > 0 && ico.hasClass('ui-icon-volume-off')) {
-			ico.toggleClass('ui-icon-volume-off ui-icon-volume-on');
-			vol.removeClass('ui-state-error');
-			_handleMicStatus(true);
-		} else if (val === 0 && ico.hasClass('ui-icon-volume-on')) {
-			ico.toggleClass('ui-icon-volume-on ui-icon-volume-off');
-			vol.addClass('ui-state-error');
-			_handleMicStatus(false);
-		}
-		if (typeof(swf[0].setVolume) === 'function') {
-			swf[0].setVolume(val);
-		}
-	}
-	function _mute(mute) {
-		if (!slider) {
-			return;
-		}
-		if (mute) {
-			const val = slider.slider("option", "value");
-			if (val > 0) {
-				lastVolume = val;
-			}
-			slider.slider("option", "value", 0);
-			_handleVolume(0);
-		} else {
-			slider.slider("option", "value", lastVolume);
-			_handleVolume(lastVolume);
-		}
-	}
-	function _init(_c, _pos) {
-		c = _c;
-		size = {width: c.width, height: c.height};
-		const _id = VideoUtil.getVid(c.uid)
-			, name = _getName()
-			, _w = c.self ? Math.max(300, c.width) : c.width
-			, _h = c.self ? Math.max(200, c.height) : c.height
-			, opts = Room.getOptions();
-		{ //scope
-			const cont = opts.interview ? $('.pod.pod-' + c.pod) : $('.room.box');
-			cont.append(OmUtil.tmpl('#user-video', _id).attr('title', name)
-					.attr('data-client-uid', c.type + c.cuid).data(self));
-		}
-		v = $('#' + _id);
-		v.dialog({
-			classes: {
-				'ui-dialog': 'ui-corner-all video user-video' + (opts.showMicStatus ? ' mic-status' : '')
-				, 'ui-dialog-titlebar': 'ui-corner-all' + (opts.showMicStatus ? ' ui-state-highlight' : '')
-			}
-			, width: _w
-			, minWidth: 40
-			, minHeight: 50
-			, autoOpen: true
-			, appendTo: opts.interview ? '.pod.pod-' + c.pod : '.room.box'
-			, draggable: !opts.interview
-			, resizable: !opts.interview
-			, modal: false
-			, resizeStop: function(event, ui) {
-				const w = ui.size.width - 2
-					, h = ui.size.height - t.height() - 4 - (f.is(":visible") ? f.height() : 0);
-				_resize(w, h);
-				swf[0].vidResize(w, h);
-			}
-			, close: function() {
-				VideoManager.close(c.uid, true);
-			}
-		}).dialogExtend({
-			icons: {
-				'collapse': 'ui-icon-minus'
-			}
-			, closable: VideoUtil.isSharing(c)
-			, collapsable: true
-			, dblclick: "collapse"
-		});
-		t = v.parent().find('.ui-dialog-titlebar').attr('title', name);
-		f = v.find('.footer');
-		if (!VideoUtil.isSharing(c)) {
-			v.parent().find('.ui-dialog-titlebar-buttonpane')
-				.append($('#video-volume-btn').children().clone())
-				.append($('#video-refresh-btn').children().clone());
-			const volume = v.parent().find('.dropdown-menu.video.volume');
-			slider = v.parent().find('.slider');
-			if (opts.interview) {
-				v.parent().find('.ui-dialog-titlebar-collapse').hide();
-			}
-			vol = v.parent().find('.ui-dialog-titlebar-volume')
-				.on('mouseenter', function(e) {
-					e.stopImmediatePropagation();
-					volume.toggle();
-				})
-				.click(function(e) {
-					e.stopImmediatePropagation();
-					const muted = $(this).find('.ui-icon').hasClass('ui-icon-volume-off');
-					roomAction('mute', JSON.stringify({uid: c.cuid, mute: !muted}));
-					_mute(!muted);
-					volume.hide();
-					return false;
-				}).dblclick(function(e) {
-					e.stopImmediatePropagation();
-					return false;
-				});
-			v.parent().find('.ui-dialog-titlebar-refresh')
-				.click(function(e) {
-					e.stopImmediatePropagation();
-					_refresh();
-					return false;
-				}).dblclick(function(e) {
-					e.stopImmediatePropagation();
-					return false;
-				});
-			volume.on('mouseleave', function() {
-				$(this).hide();
-			});
-			handle = v.parent().find('.slider .handle');
-			slider.slider({
-				orientation: 'vertical'
-				, range: 'min'
-				, min: 0
-				, max: 100
-				, value: lastVolume
-				, create: function() {
-					handle.text($(this).slider("value"));
-				}
-				, slide: function(event, ui) {
-					_handleVolume(ui.value);
-				}
-			});
-			const hasAudio = VideoUtil.hasAudio(c);
-			_handleMicStatus(hasAudio);
-			if (!hasAudio) {
-				vol.hide();
-			}
-		}
-		vc = v.find('.video');
-		vc.width(_w).height(_h);
-		//broadcast
-		const o = Room.getOptions();
-		if (c.self) {
-			o.cam = c.cam;
-			o.mic = c.mic;
-			o.mode = 'broadcast';
-		} else {
-			o.mode = 'play';
-		}
-		o.av = c.activities.join();
-		o.rights = o.rights.join();
-		o.width = c.width;
-		o.height = c.height;
-		o.sid = c.sid;
-		o.uid = c.uid;
-		o.cuid = c.cuid;
-		o.userId = c.user.id;
-		o.broadcastId = c.broadcastId;
-		o.type = c.type;
-		delete o.keycode;
-		swf = initSwf(vc, 'main.swf', _id + '-swf', o);
-		swf.attr('width', _w).attr('height', _h);
-		v.dialog("widget").css(_pos);
-	}
-	function _update(_c) {
-		const opts = Room.getOptions();
-		c.screenActivities = _c.screenActivities;
-		c.activities = _c.activities;
-		c.user.firstName = _c.user.firstName;
-		c.user.lastName = _c.user.lastName;
-		const hasAudio = VideoUtil.hasAudio(c);
-		_handleMicStatus(hasAudio);
-		if (hasAudio) {
-			vol.show();
-		} else {
-			vol.hide();
-			v.parent().find('.dropdown-menu.video.volume').hide();
-		}
-		if (opts.interview && c.pod !== _c.pod) {
-			c.pod = _c.pod;
-			v.dialog('option', 'appendTo', '.pod.pod-' + c.pod);
-		}
-		const name = _getName();
-		v.dialog('option', 'title', name).parent().find('.ui-dialog-titlebar').attr('title', name);
-		if (typeof(swf[0].update) === 'function') {
-			c.self ? swf[0].update() : swf[0].update(c);
-		}
-	}
-	function _refresh(_opts) {
-		if (typeof(swf[0].refresh) === 'function') {
-			const opts = _opts || {};
-			if (!Room.getOptions().interview && !isNaN(opts.width)) {
-				_resizeDlg(opts.width, opts.height);
-			}
-			try {
-				swf[0].refresh(opts);
-			} catch (e) {
-				//swf might throw
-			}
-		}
-	}
-	function _setRights(_r) {
-		if (typeof(swf[0].setRights) === 'function') {
-			swf[0].setRights(_r);
-		}
-	}
-	function _cleanup() {
-		if (typeof(swf[0].cleanup) === 'function') {
-			swf[0].cleanup();
-		}
-	}
-
-	self.update = _update;
-	self.refresh = _refresh;
-	self.mute = _mute;
-	self.isMuted = function() { return 0 === slider.slider("option", "value"); };
-	self.init = _init;
-	self.securityMode = _securityMode;
-	self.client = function() { return c; };
-	self.setRights = _setRights;
-	self.cleanup = _cleanup;
-	return self;
-});
-var VideoManager = (function() {
-	const self = {};
-	let share, inited = false;
-
-	function _init() {
-		if ($(WB_AREA_SEL + ' .wb-area .tabs').length > 0) {
-			WBA_SEL = WBA_WB_SEL;
-		}
-		VideoSettings.init(Room.getOptions());
-		share = $('.room.box').find('.icon.shared.ui-button');
-		inited = true;
-	}
-	function _update(c) {
-		if (!inited) {
-			return;
-		}
-		for (let i = 0; i < c.streams.length; ++i) {
-			const cl = JSON.parse(JSON.stringify(c)), s = c.streams[i];
-			delete cl.streams;
-			$.extend(cl, s);
-			if (cl.self && VideoUtil.isSharing(cl) || VideoUtil.isRecording(cl)) {
-				continue;
-			}
-			const _id = VideoUtil.getVid(cl.uid)
-				, av = VideoUtil.hasAudio(cl) || VideoUtil.hasVideo(cl)
-				, v = $('#' + _id);
-			if (av && v.length !== 1 && !!cl.self) {
-				Video().init(cl, VideoUtil.getPos(VideoUtil.getRects(VID_SEL), cl.width, cl.height + 25));
-			} else if (av && v.length === 1) {
-				v.data().update(cl);
-			} else if (!av && v.length === 1) {
-				_closeV(v);
-			}
-		}
-		if (c.uid === Room.getOptions().uid) {
-			Room.setRights(c.rights);
-			const windows = $(VID_SEL + ' .ui-dialog-content');
-			for (let i = 0; i < windows.length; ++i) {
-				const w = $(windows[i]);
-				w.data().setRights(c.rights);
-			}
-
-		}
-		if (c.streams.length === 0) {
-			// check for non inited video window
-			const v = $('#' + VideoUtil.getVid(c.uid));
-			if (v.length === 1) {
-				_closeV(v);
-			}
-		}
-	}
-	function _closeV(v) {
-		if (v.dialog('instance') !== undefined) {
-			v.dialog('destroy');
-		}
-		v.remove();
-	}
-	function _play(c) {
-		if (!inited) {
-			return;
-		}
-		if (VideoUtil.isSharing(c)) {
-			_highlight(share
-					.attr('title', share.data('user') + ' ' + c.user.firstName + ' ' + c.user.lastName + ' ' + share.data('text'))
-					.data('uid', c.uid)
-					.show(), 10);
-			share.tooltip().off('click').click(function() {
-				const v = $('#' + VideoUtil.getVid(c.uid))
-				if (v.length !== 1) {
-					Video().init(c, $(WBA_SEL).offset());
-				} else {
-					v.dialog('open');
-				}
-			});
-		} else if ('sharing' !== c.type) {
-			Video().init(c, VideoUtil.getPos(VideoUtil.getRects(VID_SEL), c.width, c.height + 25));
-		}
-	}
-	function _close(uid, showShareBtn) {
-		const _id = VideoUtil.getVid(uid), v = $('#' + _id);
-		if (v.length === 1) {
-			_closeV(v);
-		}
-		if (!showShareBtn && uid === share.data('uid')) {
-			share.off('click').hide();
-		}
-	}
-	function _highlight(el, count) {
-		if (count < 0) {
-			return;
-		}
-		el.addClass('ui-state-highlight', 2000, function() {
-			el.removeClass('ui-state-highlight', 2000, function() {
-				_highlight(el, --count);
-			});
-		});
-	}
-	function _find(uid) {
-		return $(VID_SEL + ' div[data-client-uid="room' + uid + '"]');
-	}
-	function _micActivity(uid, active) {
-		const u = $('#user' + uid + ' .audio-activity.ui-icon')
-			, v = _find(uid).parent();
-		if (active) {
-			u.addClass("speaking");
-			v.addClass('user-speaks')
-		} else {
-			u.removeClass("speaking");
-			v.removeClass('user-speaks')
-		}
-	}
-	function _refresh(uid, opts) {
-		const v = _find(uid);
-		if (v.length > 0) {
-			v.data().refresh(opts);
-		}
-	}
-	function _mute(uid, mute) {
-		const v = _find(uid);
-		if (v.length > 0) {
-			v.data().mute(mute);
-		}
-	}
-	function _clickExclusive(uid) {
-		const s = VideoSettings.load();
-		if (false !== s.video.confirmExclusive) {
-			const dlg = $('#exclusive-confirm');
-			dlg.dialog({
-				buttons: [
-					{
-						text: dlg.data('btn-ok')
-						, click: function() {
-							s.video.confirmExclusive = !$('#exclusive-confirm-dont-show').prop('checked');
-							VideoSettings.save();
-							roomAction('exclusive', uid);
-							$(this).dialog('close');
-						}
-					}
-					, {
-						text: dlg.data('btn-cancel')
-						, click: function() {
-							$(this).dialog('close');
-						}
-					}
-				]
-			})
-		}
-	}
-	function _exclusive(uid) {
-		const windows = $(VID_SEL + ' .ui-dialog-content');
-		for (let i = 0; i < windows.length; ++i) {
-			const w = $(windows[i]);
-			w.data().mute('room' + uid !== w.data('client-uid'));
-		}
-	}
-
-	self.init = _init;
-	self.update = _update;
-	self.play = _play;
-	self.close = _close;
-	self.securityMode = function(uid, on) { $('#' + VideoUtil.getVid(uid)).data().securityMode(on); };
-	self.micActivity = _micActivity;
-	self.refresh = _refresh;
-	self.mute = _mute;
-	self.clickExclusive = _clickExclusive;
-	self.exclusive = _exclusive;
-	return self;
-})();
 var Room = (function() {
 	const self = {}, sbSide = Settings.isRtl ? 'right' : 'left';
 	let options, menuHeight, chat, sb, dock, activities;
@@ -748,15 +203,64 @@ var Room = (function() {
 			]
 		});
 	}
+	function _setQuickPollRights() {
+		const close = $('#quick-vote .close');
+		if (close.length === 1) {
+			close.off();
+			if (options.rights.includes('superModerator') || options.rights.includes('moderator') || options.rights.includes('presenter')) {
+				close.show().click(function() {
+					quickPollAction('close');
+				});
+			} else {
+				close.hide();
+			}
+		}
+	}
+	function _quickPoll(obj) {
+		if (obj.started) {
+			let qv = $('#quick-vote');
+			if (qv.length === 0) {
+				const wbArea = $('.room.wb.area');
+				qv = OmUtil.tmpl('#quick-vote-template', 'quick-vote');
+				wbArea.append(qv);
+			}
+			const pro = qv.find('.control.pro')
+				con = qv.find('.control.con');
+			if (obj.voted) {
+				pro.removeClass('clickable').off();
+				con.removeClass('clickable').off();
+			} else {
+				pro.addClass('clickable').off().click(function() {
+					quickPollAction('vote', true);
+				});
+				con.addClass('clickable').off().click(function() {
+					quickPollAction('vote', false);
+				});
+			}
+			pro.find('.badge').text(obj.pros);
+			con.find('.badge').text(obj.cons);
+			_setQuickPollRights();
+		} else {
+			const qv = $('#quick-vote');
+			if (qv.length === 1) {
+				qv.remove();
+			}
+		}
+		OmUtil.tmpl('#quick-vote-template', 'quick-vote');
+	}
 
 	self.init = _init;
 	self.getMenuHeight = function() { return menuHeight; };
 	self.getOptions = function() { return typeof(options) === 'object' ? JSON.parse(JSON.stringify(options)) : {}; };
-	self.setRights = function(_r) { return options.rights = _r; };
+	self.setRights = function(_r) {
+		options.rights = _r;
+		_setQuickPollRights();
+	};
 	self.setSize = _setSize;
 	self.load = _load;
 	self.unload = _unload;
 	self.showClipboard = _showClipboard;
+	self.quickPoll = _quickPoll;
 	return self;
 })();
 function startPrivateChat(el) {
@@ -773,7 +277,7 @@ function sipBtnEraseClick() {
 	const txt = $('.sip-number')
 		, t = txt.val();
 	if (!!t) {
-		txt.val(t.substring(0, t.length -1));
+		txt.val(t.substring(0, t.length - 1));
 	}
 }
 function sipGetKey(evt) {
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/sidebar/RoomSidebar.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/sidebar/RoomSidebar.java
index 923d97a..c16b630 100644
--- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/sidebar/RoomSidebar.java
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/sidebar/RoomSidebar.java
@@ -148,7 +148,7 @@ public class RoomSidebar extends Panel {
 					default:
 				}
 			} catch (Exception e) {
-				log.error("Unexpected exception while toggle 'action'", e);
+				log.error("Unexpected exception while toggle 'roomAction'", e);
 			}
 		}
 	};
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/video-manager.js b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/video-manager.js
new file mode 100644
index 0000000..66c7e61
--- /dev/null
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/video-manager.js
@@ -0,0 +1,169 @@
+/* Licensed under the Apache License, Version 2.0 (the "License") http://www.apache.org/licenses/LICENSE-2.0 */
+var VideoManager = (function() {
+	const self = {};
+	let share, inited = false;
+
+	function _init() {
+		if ($(WB_AREA_SEL + ' .wb-area .tabs').length > 0) {
+			WBA_SEL = WBA_WB_SEL;
+		}
+		VideoSettings.init(Room.getOptions());
+		share = $('.room.box').find('.icon.shared.ui-button');
+		inited = true;
+	}
+	function _update(c) {
+		if (!inited) {
+			return;
+		}
+		for (let i = 0; i < c.streams.length; ++i) {
+			const cl = JSON.parse(JSON.stringify(c)), s = c.streams[i];
+			delete cl.streams;
+			$.extend(cl, s);
+			if (cl.self && VideoUtil.isSharing(cl) || VideoUtil.isRecording(cl)) {
+				continue;
+			}
+			const _id = VideoUtil.getVid(cl.uid)
+				, av = VideoUtil.hasAudio(cl) || VideoUtil.hasVideo(cl)
+				, v = $('#' + _id);
+			if (av && v.length !== 1 && !!cl.self) {
+				Video().init(cl, VideoUtil.getPos(VideoUtil.getRects(VID_SEL), cl.width, cl.height + 25));
+			} else if (av && v.length === 1) {
+				v.data().update(cl);
+			} else if (!av && v.length === 1) {
+				_closeV(v);
+			}
+		}
+		if (c.uid === Room.getOptions().uid) {
+			Room.setRights(c.rights);
+			const windows = $(VID_SEL + ' .ui-dialog-content');
+			for (let i = 0; i < windows.length; ++i) {
+				const w = $(windows[i]);
+				w.data().setRights(c.rights);
+			}
+
+		}
+		if (c.streams.length === 0) {
+			// check for non inited video window
+			const v = $('#' + VideoUtil.getVid(c.uid));
+			if (v.length === 1) {
+				_closeV(v);
+			}
+		}
+	}
+	function _closeV(v) {
+		if (v.dialog('instance') !== undefined) {
+			v.dialog('destroy');
+		}
+		v.remove();
+	}
+	function _play(c) {
+		if (!inited) {
+			return;
+		}
+		if (VideoUtil.isSharing(c)) {
+			_highlight(share
+					.attr('title', share.data('user') + ' ' + c.user.firstName + ' ' + c.user.lastName + ' ' + share.data('text'))
+					.data('uid', c.uid)
+					.show(), 10);
+			share.tooltip().off('click').click(function() {
+				const v = $('#' + VideoUtil.getVid(c.uid))
+				if (v.length !== 1) {
+					Video().init(c, $(WBA_SEL).offset());
+				} else {
+					v.dialog('open');
+				}
+			});
+		} else if ('sharing' !== c.type) {
+			Video().init(c, VideoUtil.getPos(VideoUtil.getRects(VID_SEL), c.width, c.height + 25));
+		}
+	}
+	function _close(uid, showShareBtn) {
+		const _id = VideoUtil.getVid(uid), v = $('#' + _id);
+		if (v.length === 1) {
+			_closeV(v);
+		}
+		if (!showShareBtn && uid === share.data('uid')) {
+			share.off('click').hide();
+		}
+	}
+	function _highlight(el, count) {
+		if (count < 0) {
+			return;
+		}
+		el.addClass('ui-state-highlight', 2000, function() {
+			el.removeClass('ui-state-highlight', 2000, function() {
+				_highlight(el, --count);
+			});
+		});
+	}
+	function _find(uid) {
+		return $(VID_SEL + ' div[data-client-uid="room' + uid + '"]');
+	}
+	function _micActivity(uid, active) {
+		const u = $('#user' + uid + ' .audio-activity.ui-icon')
+			, v = _find(uid).parent();
+		if (active) {
+			u.addClass("speaking");
+			v.addClass('user-speaks')
+		} else {
+			u.removeClass("speaking");
+			v.removeClass('user-speaks')
+		}
+	}
+	function _refresh(uid, opts) {
+		const v = _find(uid);
+		if (v.length > 0) {
+			v.data().refresh(opts);
+		}
+	}
+	function _mute(uid, mute) {
+		const v = _find(uid);
+		if (v.length > 0) {
+			v.data().mute(mute);
+		}
+	}
+	function _clickExclusive(uid) {
+		const s = VideoSettings.load();
+		if (false !== s.video.confirmExclusive) {
+			const dlg = $('#exclusive-confirm');
+			dlg.dialog({
+				buttons: [
+					{
+						text: dlg.data('btn-ok')
+						, click: function() {
+							s.video.confirmExclusive = !$('#exclusive-confirm-dont-show').prop('checked');
+							VideoSettings.save();
+							roomAction('exclusive', uid);
+							$(this).dialog('close');
+						}
+					}
+					, {
+						text: dlg.data('btn-cancel')
+						, click: function() {
+							$(this).dialog('close');
+						}
+					}
+				]
+			})
+		}
+	}
+	function _exclusive(uid) {
+		const windows = $(VID_SEL + ' .ui-dialog-content');
+		for (let i = 0; i < windows.length; ++i) {
+			const w = $(windows[i]);
+			w.data().mute('room' + uid !== w.data('client-uid'));
+		}
+	}
+
+	self.init = _init;
+	self.update = _update;
+	self.play = _play;
+	self.close = _close;
+	self.securityMode = function(uid, on) { $('#' + VideoUtil.getVid(uid)).data().securityMode(on); };
+	self.micActivity = _micActivity;
+	self.refresh = _refresh;
+	self.mute = _mute;
+	self.clickExclusive = _clickExclusive;
+	self.exclusive = _exclusive;
+	return self;
+})();
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/video-util.js b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/video-util.js
new file mode 100644
index 0000000..5f831ff
--- /dev/null
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/video-util.js
@@ -0,0 +1,111 @@
+/* Licensed under the Apache License, Version 2.0 (the "License") http://www.apache.org/licenses/LICENSE-2.0 */
+const WB_AREA_SEL = '.room.wb.area';
+const WBA_WB_SEL = '.room.wb.area .ui-tabs-panel.ui-corner-bottom.ui-widget-content:visible';
+var WBA_SEL = WB_AREA_SEL;
+const VID_SEL = '.video.user-video';
+var VideoUtil = (function() {
+	const self = {};
+	function _getVid(uid) {
+		return "video" + uid;
+	}
+	function _isSharing(c) {
+		return 'sharing' === c.type && c.screenActivities.indexOf('sharing') > -1;
+	}
+	function _isRecording(c) {
+		return 'sharing' === c.type
+			&& c.screenActivities.indexOf('recording') > -1
+			&& c.screenActivities.indexOf('sharing') < 0;
+	}
+	function _hasAudio(c) {
+		return c.activities.indexOf('broadcastA') > -1;
+	}
+	function _hasVideo(c) {
+		return c.activities.indexOf('broadcastV') > -1;
+	}
+	function _getRects(sel, excl) {
+		const list = [], elems = $(sel);
+		for (let i = 0; i < elems.length; ++i) {
+			if (excl !== $(elems[i]).attr('aria-describedby')) {
+				list.push(_getRect(elems[i]));
+			}
+		}
+		return list;
+	}
+	function _getRect(e) {
+		const win = $(e), winoff = win.offset();
+		return {left: winoff.left
+			, top: winoff.top
+			, right: winoff.left + win.width()
+			, bottom: winoff.top + win.height()};
+	}
+	function _getPos(list, w, h) {
+		if (Room.getOptions().interview) {
+			return {left: 0, top: 0};
+		}
+		const wba = $(WBA_SEL), woffset = wba.offset()
+			, offsetX = 20, offsetY = 10
+			, area = {left: woffset.left, top: woffset.top, right: woffset.left + wba.width(), bottom: woffset.top + wba.height()};
+		const rectNew = {
+				_left: area.left
+				, _top: area.top
+				, right: area.left + w
+				, bottom: area.top + h
+				, get left() {
+					return this._left
+				}
+				, set left(l) {
+					this._left = l;
+					this.right = l + w;
+				}
+				, get top() {
+					return this._top
+				}
+				, set top(t) {
+					this._top = t;
+					this.bottom = t + h;
+				}
+			};
+		let minY = area.bottom, posFound;
+		do {
+			posFound = true
+			for (let i = 0; i < list.length; ++i) {
+				const rect = list[i];
+				minY = Math.min(minY, rect.bottom);
+
+				if (rectNew.left < rect.right && rectNew.right > rect.left && rectNew.top < rect.bottom && rectNew.bottom > rect.top) {
+					rectNew.left = rect.right + offsetX;
+					posFound = false;
+				}
+				if (rectNew.right >= area.right) {
+					rectNew.left = area.left;
+					rectNew.top = minY + offsetY;
+					posFound = false;
+				}
+				if (rectNew.bottom >= area.bottom) {
+					rectNew.top = area.top;
+					posFound = true;
+					break;
+				}
+			}
+		} while (!posFound);
+		return {left: rectNew.left, top: rectNew.top};
+	}
+	function _arrange() {
+		const list = [], elems = $(VID_SEL);
+		for (let i = 0; i < elems.length; ++i) {
+			const v = $(elems[i]);
+			v.css(_getPos(list, v.width(), v.height()));
+			list.push(_getRect(v));
+		}
+	}
+
+	self.getVid = _getVid;
+	self.isSharing = _isSharing;
+	self.isRecording = _isRecording;
+	self.hasAudio = _hasAudio;
+	self.hasVideo = _hasVideo;
+	self.getRects = _getRects;
+	self.getPos = _getPos;
+	self.arrange = _arrange;
+	return self;
+})();
diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/video.js b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/video.js
new file mode 100644
index 0000000..4322f35
--- /dev/null
+++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/video.js
@@ -0,0 +1,268 @@
+/* Licensed under the Apache License, Version 2.0 (the "License") http://www.apache.org/licenses/LICENSE-2.0 */
+var Video = (function() {
+	const self = {};
+	let c, v, vc, t, f, swf, size, vol, slider, handle
+		, lastVolume = 50;
+
+	function _getName() {
+		return c.user.firstName + ' ' + c.user.lastName;
+	}
+	function _resizeDlg(_ww, _hh) {
+		const interview = Room.getOptions().interview;
+		const _w = interview ? 320 : _ww, _h = interview ? 260 : _hh;
+		const h = _h + t.height() + 2 + (f.is(":visible") ? f.height() : 0);
+		v.dialog("option", "width", _w).dialog("option", "height", h);
+		_resize(_w, _h);
+		return h;
+	}
+	function _securityMode(on) {
+		if (Room.getOptions().interview) {
+			return;
+		}
+		if (on) {
+			v.dialog("option", "position", {my: "center", at: "center", of: WBA_SEL});
+		} else {
+			const h = _resizeDlg(size.width, size.height);
+			v.dialog("widget").css(VideoUtil.getPos(VideoUtil.getRects(VID_SEL, VideoUtil.getVid(c.uid)), c.width, h));
+		}
+	}
+	function _resize(w, h) {
+		vc.width(w).height(h);
+		swf.attr('width', w).attr('height', h);
+	}
+	function _handleMicStatus(state) {
+		if (!f.is(":visible")) {
+			return;
+		}
+		if (state) {
+			f.find('.off').hide();
+			f.find('.on').show();
+			f.addClass('ui-state-highlight');
+			t.addClass('ui-state-highlight');
+		} else {
+			f.find('.off').show();
+			f.find('.on').hide();
+			f.removeClass('ui-state-highlight');
+			t.removeClass('ui-state-highlight');
+		}
+	}
+	function _handleVolume(val) {
+		handle.text(val);
+		const ico = vol.find('.ui-icon');
+		if (val > 0 && ico.hasClass('ui-icon-volume-off')) {
+			ico.toggleClass('ui-icon-volume-off ui-icon-volume-on');
+			vol.removeClass('ui-state-error');
+			_handleMicStatus(true);
+		} else if (val === 0 && ico.hasClass('ui-icon-volume-on')) {
+			ico.toggleClass('ui-icon-volume-on ui-icon-volume-off');
+			vol.addClass('ui-state-error');
+			_handleMicStatus(false);
+		}
+		if (typeof(swf[0].setVolume) === 'function') {
+			swf[0].setVolume(val);
+		}
+	}
+	function _mute(mute) {
+		if (!slider) {
+			return;
+		}
+		if (mute) {
+			const val = slider.slider("option", "value");
+			if (val > 0) {
+				lastVolume = val;
+			}
+			slider.slider("option", "value", 0);
+			_handleVolume(0);
+		} else {
+			slider.slider("option", "value", lastVolume);
+			_handleVolume(lastVolume);
+		}
+	}
+	function _init(_c, _pos) {
+		c = _c;
+		size = {width: c.width, height: c.height};
+		const _id = VideoUtil.getVid(c.uid)
+			, name = _getName()
+			, _w = c.self ? Math.max(300, c.width) : c.width
+			, _h = c.self ? Math.max(200, c.height) : c.height
+			, opts = Room.getOptions();
+		{ //scope
+			const cont = opts.interview ? $('.pod.pod-' + c.pod) : $('.room.box');
+			cont.append(OmUtil.tmpl('#user-video', _id).attr('title', name)
+					.attr('data-client-uid', c.type + c.cuid).data(self));
+		}
+		v = $('#' + _id);
+		v.dialog({
+			classes: {
+				'ui-dialog': 'ui-corner-all video user-video' + (opts.showMicStatus ? ' mic-status' : '')
+				, 'ui-dialog-titlebar': 'ui-corner-all' + (opts.showMicStatus ? ' ui-state-highlight' : '')
+			}
+			, width: _w
+			, minWidth: 40
+			, minHeight: 50
+			, autoOpen: true
+			, appendTo: opts.interview ? '.pod.pod-' + c.pod : '.room.box'
+			, draggable: !opts.interview
+			, resizable: !opts.interview
+			, modal: false
+			, resizeStop: function(event, ui) {
+				const w = ui.size.width - 2
+					, h = ui.size.height - t.height() - 4 - (f.is(":visible") ? f.height() : 0);
+				_resize(w, h);
+				swf[0].vidResize(w, h);
+			}
+			, close: function() {
+				VideoManager.close(c.uid, true);
+			}
+		}).dialogExtend({
+			icons: {
+				'collapse': 'ui-icon-minus'
+			}
+			, closable: VideoUtil.isSharing(c)
+			, collapsable: true
+			, dblclick: "collapse"
+		});
+		t = v.parent().find('.ui-dialog-titlebar').attr('title', name);
+		f = v.find('.footer');
+		if (!VideoUtil.isSharing(c)) {
+			v.parent().find('.ui-dialog-titlebar-buttonpane')
+				.append($('#video-volume-btn').children().clone())
+				.append($('#video-refresh-btn').children().clone());
+			const volume = v.parent().find('.dropdown-menu.video.volume');
+			slider = v.parent().find('.slider');
+			if (opts.interview) {
+				v.parent().find('.ui-dialog-titlebar-collapse').hide();
+			}
+			vol = v.parent().find('.ui-dialog-titlebar-volume')
+				.on('mouseenter', function(e) {
+					e.stopImmediatePropagation();
+					volume.toggle();
+				})
+				.click(function(e) {
+					e.stopImmediatePropagation();
+					const muted = $(this).find('.ui-icon').hasClass('ui-icon-volume-off');
+					roomAction('mute', JSON.stringify({uid: c.cuid, mute: !muted}));
+					_mute(!muted);
+					volume.hide();
+					return false;
+				}).dblclick(function(e) {
+					e.stopImmediatePropagation();
+					return false;
+				});
+			v.parent().find('.ui-dialog-titlebar-refresh')
+				.click(function(e) {
+					e.stopImmediatePropagation();
+					_refresh();
+					return false;
+				}).dblclick(function(e) {
+					e.stopImmediatePropagation();
+					return false;
+				});
+			volume.on('mouseleave', function() {
+				$(this).hide();
+			});
+			handle = v.parent().find('.slider .handle');
+			slider.slider({
+				orientation: 'vertical'
+				, range: 'min'
+				, min: 0
+				, max: 100
+				, value: lastVolume
+				, create: function() {
+					handle.text($(this).slider("value"));
+				}
+				, slide: function(event, ui) {
+					_handleVolume(ui.value);
+				}
+			});
+			const hasAudio = VideoUtil.hasAudio(c);
+			_handleMicStatus(hasAudio);
+			if (!hasAudio) {
+				vol.hide();
+			}
+		}
+		vc = v.find('.video');
+		vc.width(_w).height(_h);
+		//broadcast
+		const o = Room.getOptions();
+		if (c.self) {
+			o.cam = c.cam;
+			o.mic = c.mic;
+			o.mode = 'broadcast';
+		} else {
+			o.mode = 'play';
+		}
+		o.av = c.activities.join();
+		o.rights = o.rights.join();
+		o.width = c.width;
+		o.height = c.height;
+		o.sid = c.sid;
+		o.uid = c.uid;
+		o.cuid = c.cuid;
+		o.userId = c.user.id;
+		o.broadcastId = c.broadcastId;
+		o.type = c.type;
+		delete o.keycode;
+		swf = initSwf(vc, 'main.swf', _id + '-swf', o);
+		swf.attr('width', _w).attr('height', _h);
+		v.dialog("widget").css(_pos);
+	}
+	function _update(_c) {
+		const opts = Room.getOptions();
+		c.screenActivities = _c.screenActivities;
+		c.activities = _c.activities;
+		c.user.firstName = _c.user.firstName;
+		c.user.lastName = _c.user.lastName;
+		const hasAudio = VideoUtil.hasAudio(c);
+		_handleMicStatus(hasAudio);
+		if (hasAudio) {
+			vol.show();
+		} else {
+			vol.hide();
+			v.parent().find('.dropdown-menu.video.volume').hide();
+		}
+		if (opts.interview && c.pod !== _c.pod) {
+			c.pod = _c.pod;
+			v.dialog('option', 'appendTo', '.pod.pod-' + c.pod);
+		}
+		const name = _getName();
+		v.dialog('option', 'title', name).parent().find('.ui-dialog-titlebar').attr('title', name);
+		if (typeof(swf[0].update) === 'function') {
+			c.self ? swf[0].update() : swf[0].update(c);
+		}
+	}
+	function _refresh(_opts) {
+		if (typeof(swf[0].refresh) === 'function') {
+			const opts = _opts || {};
+			if (!Room.getOptions().interview && !isNaN(opts.width)) {
+				_resizeDlg(opts.width, opts.height);
+			}
+			try {
+				swf[0].refresh(opts);
+			} catch (e) {
+				//swf might throw
+			}
+		}
+	}
+	function _setRights(_r) {
+		if (typeof(swf[0].setRights) === 'function') {
+			swf[0].setRights(_r);
+		}
+	}
+	function _cleanup() {
+		if (typeof(swf[0].cleanup) === 'function') {
+			swf[0].cleanup();
+		}
+	}
+
+	self.update = _update;
+	self.refresh = _refresh;
+	self.mute = _mute;
+	self.isMuted = function() { return 0 === slider.slider("option", "value"); };
+	self.init = _init;
+	self.securityMode = _securityMode;
+	self.client = function() { return c; };
+	self.setRights = _setRights;
+	self.cleanup = _cleanup;
+	return self;
+});
diff --git a/openmeetings-web/src/main/webapp/css/wb.css b/openmeetings-web/src/main/webapp/css/wb.css
index 2f80575..fff1226 100644
--- a/openmeetings-web/src/main/webapp/css/wb.css
+++ b/openmeetings-web/src/main/webapp/css/wb.css
@@ -291,3 +291,29 @@
 .wb-area .wb-zoom button.up {
 	background-image: url(images/page_up.png);
 }
+#quick-vote {
+	position: absolute;
+	right: 40px;
+	bottom: 40px;
+	padding: 5px;
+	background-color: aquamarine;
+}
+#quick-vote .control {
+	display: inline-block;
+	width: 40px;
+	height: 40px;
+	background-repeat: no-repeat;
+	background-size: 35px;
+	position: relative;
+}
+#quick-vote .control.pro {
+	background-image: url(images/add.png);
+}
+#quick-vote .control.con {
+	background-image: url(images/cancel.png);
+}
+#quick-vote .control .badge {
+	position: absolute;
+	right: 0;
+	bottom: 0;
+}

-- 
To stop receiving notification emails like this one, please contact
solomax@apache.org.