diff --git a/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/layout/ILayoutRoomListener.java b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/layout/ILayoutRoomListener.java new file mode 100755 index 0000000000000000000000000000000000000000..526c9eb8aad7d4151a2c43d15f220d8c800095e6 --- /dev/null +++ b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/layout/ILayoutRoomListener.java @@ -0,0 +1,29 @@ +/** + * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/ + * + * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below). + * + * This program is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation; either version 2.1 of the License, or (at your option) any later + * version. + * + * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. + * + * Author: Felipe Cecagno <felipe@mconf.org> + */ +package org.bigbluebutton.conference.service.layout; + +import java.util.List; + +public interface ILayoutRoomListener { + public String getName(); + public void updateLayout(List<Object> args); +// public void lockLayout(); +// public void unlockLayout(); +} diff --git a/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/layout/LayoutApplication.java b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/layout/LayoutApplication.java new file mode 100755 index 0000000000000000000000000000000000000000..13fbcbfdfae11ca2134eabc011b55e9cd97e9d2b --- /dev/null +++ b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/layout/LayoutApplication.java @@ -0,0 +1,75 @@ +/** + * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/ + * + * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below). + * + * This program is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation; either version 2.1 of the License, or (at your option) any later + * version. + * + * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. + * + * Author: Felipe Cecagno <felipe@mconf.org> + */ +package org.bigbluebutton.conference.service.layout; + +import java.util.List; + +import org.red5.logging.Red5LoggerFactory; +import org.slf4j.Logger; + +public class LayoutApplication { + + private static Logger log = Red5LoggerFactory.getLogger( LayoutApplication.class, "bigbluebutton" ); + + private LayoutRoomsManager roomsManager; + public LayoutHandler handler; + + public boolean createRoom(String name) { + roomsManager.addRoom(new LayoutRoom(name)); + return true; + } + + public boolean destroyRoom(String name) { + if (roomsManager.hasRoom(name)) { + roomsManager.removeRoom(name); + } + return true; + } + + public boolean hasRoom(String name) { + return roomsManager.hasRoom(name); + } + + public boolean addRoomListener(String room, ILayoutRoomListener listener) { + if (roomsManager.hasRoom(room)){ + roomsManager.addRoomListener(room, listener); + return true; + } + log.warn("Adding listener to a non-existant room " + room); + return false; + } + + public void setRoomsManager(LayoutRoomsManager r) { + log.debug("Setting room manager"); + roomsManager = r; + } + + public void lockLayout(String room, int userId, String layout) { + roomsManager.lockLayout(room, userId, layout); + } + + public void unlockLayout(String room) { + roomsManager.unlockLayout(room); + } + + public List<Object> currentLayout(String roomName) { + return roomsManager.currentLayout(roomName); + } +} diff --git a/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/layout/LayoutHandler.java b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/layout/LayoutHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..14ea32ee214cff33d790b3e6a6858d9aa5cbbb8d --- /dev/null +++ b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/layout/LayoutHandler.java @@ -0,0 +1,130 @@ +/** + * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/ + * + * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below). + * + * This program is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation; either version 2.1 of the License, or (at your option) any later + * version. + * + * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. + * + * Author: Felipe Cecagno <felipe@mconf.org> + */ +package org.bigbluebutton.conference.service.layout; + +import org.red5.logging.Red5LoggerFactory; +import org.red5.server.adapter.ApplicationAdapter; +import org.red5.server.adapter.IApplication; +import org.red5.server.api.IClient; +import org.red5.server.api.IConnection; +import org.red5.server.api.IScope; +import org.red5.server.api.so.ISharedObject; +import org.slf4j.Logger; + +public class LayoutHandler extends ApplicationAdapter implements IApplication { + private static Logger log = Red5LoggerFactory.getLogger( LayoutHandler.class, "bigbluebutton" ); + + private static final String APP = "LAYOUT"; + private static final String LAYOUT_SO = "layoutSO"; + + private LayoutApplication layoutApplication; + + @Override + public boolean appConnect(IConnection conn, Object[] params) { + log.debug(APP + ":appConnect"); + return true; + } + + @Override + public void appDisconnect(IConnection conn) { + log.debug( APP + ":appDisconnect"); + } + + @Override + public boolean appJoin(IClient client, IScope scope) { + log.debug( APP + ":appJoin " + scope.getName()); + return true; + } + + @Override + public void appLeave(IClient client, IScope scope) { + log.debug(APP + ":appLeave " + scope.getName()); + } + + @Override + public boolean appStart(IScope scope) { + log.debug(APP + ":appStart " + scope.getName()); + return true; + } + + @Override + public void appStop(IScope scope) { + log.debug(APP + ":appStop " + scope.getName()); + } + + @Override + public boolean roomConnect(IConnection connection, Object[] params) { + log.debug(APP + ":roomConnect"); + ISharedObject so = getSharedObject(connection.getScope(), LAYOUT_SO); + log.debug("Setting up Listener"); + LayoutSender sender = new LayoutSender(so); + String room = connection.getScope().getName(); + log.debug("Adding event listener to " + room); + log.debug("Adding room listener"); + layoutApplication.addRoomListener(room, sender); + log.debug("Done setting up listener"); + return true; + } + + @Override + public void roomDisconnect(IConnection connection) { + log.debug(APP + ":roomDisconnect"); + } + + @Override + public boolean roomJoin(IClient client, IScope scope) { + log.debug(APP + ":roomJoin " + scope.getName() + " - " + scope.getParent().getName()); + return true; + } + + @Override + public void roomLeave(IClient client, IScope scope) { + log.debug(APP + ":roomLeave " + scope.getName()); + } + + @Override + public boolean roomStart(IScope scope) { + log.debug(APP + ":roomStart " + scope.getName()); + layoutApplication.createRoom(scope.getName()); + if (!hasSharedObject(scope, LAYOUT_SO)) { + if (createSharedObject(scope, LAYOUT_SO, false)) { + return true; + } + } + log.error("Failed to start room " + scope.getName()); + return false; + } + + @Override + public void roomStop(IScope scope) { + log.debug(APP + ":roomStop " + scope.getName()); + layoutApplication.destroyRoom(scope.getName()); + if (!hasSharedObject(scope, LAYOUT_SO)) { + clearSharedObjects(scope, LAYOUT_SO); + } + } + + public void setLayoutApplication(LayoutApplication a) { + log.debug("Setting layout application"); + layoutApplication = a; + layoutApplication.handler = this; + } + +} diff --git a/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/layout/LayoutRoom.java b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/layout/LayoutRoom.java new file mode 100755 index 0000000000000000000000000000000000000000..fe4b7ee1990f097da271496804907ede189a99ab --- /dev/null +++ b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/layout/LayoutRoom.java @@ -0,0 +1,96 @@ +/** + * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/ + * + * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below). + * + * This program is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation; either version 2.1 of the License, or (at your option) any later + * version. + * + * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. + * + * Author: Felipe Cecagno <felipe@mconf.org> + */ +package org.bigbluebutton.conference.service.layout; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import net.jcip.annotations.ThreadSafe; + +import org.red5.logging.Red5LoggerFactory; +import org.slf4j.Logger; +/** + * Contains information about a LayoutRoom. + */ +@ThreadSafe +public class LayoutRoom { + private static Logger log = Red5LoggerFactory.getLogger( LayoutRoom.class, "bigbluebutton" ); + + private final String name; + private final Map<String, ILayoutRoomListener> listeners; + private boolean locked = false; + private int modifierId = -1; + private String currentLayout = ""; + + public LayoutRoom(String name) { + this.name = name; + this.listeners = new ConcurrentHashMap<String, ILayoutRoomListener>(); + } + + public String getName() { + return name; + } + + public void addRoomListener(ILayoutRoomListener listener) { + if (! listeners.containsKey(listener.getName())) { + log.debug("adding room listener"); + listeners.put(listener.getName(), listener); + } + } + + public void removeRoomListener(ILayoutRoomListener listener) { + log.debug("removing room listener"); + listeners.remove(listener); + } + + private void updateLayout() { + for (Iterator<ILayoutRoomListener> iter = listeners.values().iterator(); iter.hasNext();) { + log.debug("calling on listener"); + ILayoutRoomListener listener = (ILayoutRoomListener) iter.next(); + log.debug("calling updateLayout on listener " + listener.getName()); + listener.updateLayout(currentLayout()); + } + } + + public void lockLayout(int userId, String layout) { + locked = true; + modifierId = userId; + currentLayout = layout; + updateLayout(); + } + + public void unlockLayout() { + locked = false; + modifierId = -1; + currentLayout = ""; + updateLayout(); + } + + public List<Object> currentLayout() { + List<Object> args = new ArrayList<Object>(); + args.add(locked); + args.add(modifierId); + args.add(currentLayout); + return args; + } +} diff --git a/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/layout/LayoutRoomsManager.java b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/layout/LayoutRoomsManager.java new file mode 100755 index 0000000000000000000000000000000000000000..89715eb2fc4976a4cb30a77d919b8914926621d9 --- /dev/null +++ b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/layout/LayoutRoomsManager.java @@ -0,0 +1,113 @@ +/** + * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/ + * + * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below). + * + * This program is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation; either version 2.1 of the License, or (at your option) any later + * version. + * + * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. + * + * Author: Felipe Cecagno <felipe@mconf.org> + */ +package org.bigbluebutton.conference.service.layout; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import net.jcip.annotations.ThreadSafe; + +import org.red5.logging.Red5LoggerFactory; +import org.slf4j.Logger; +/** + * This encapsulates access to LayoutRoom and messages. This class must be threadsafe. + */ +@ThreadSafe +public class LayoutRoomsManager { + private static Logger log = Red5LoggerFactory.getLogger( LayoutRoomsManager.class, "bigbluebutton" ); + + private final Map <String, LayoutRoom> rooms; + + public LayoutRoomsManager() { + log.debug("In LayoutRoomsManager constructor"); + rooms = new ConcurrentHashMap<String, LayoutRoom>(); + } + + public void addRoom(LayoutRoom room) { + log.debug("In LayoutRoomsManager adding room " + room.getName()); + rooms.put(room.getName(), room); + } + + public void removeRoom(String name) { + log.debug("In LayoutRoomsManager remove room " + name); + rooms.remove(name); + } + + public boolean hasRoom(String name) { + log.debug("In LayoutRoomsManager has Room " + name); + return rooms.containsKey(name); + } + + + /** + * Keeping getRoom private so that all access to ChatRoom goes through here. + */ + private LayoutRoom getRoom(String name) { + log.debug("In LayoutRoomsManager get room " + name); + return rooms.get(name); + } + + public void addRoomListener(String roomName, ILayoutRoomListener listener) { + LayoutRoom r = getRoom(roomName); + if (r != null) { + r.addRoomListener(listener); + return; + } + log.warn("Adding listener to a non-existing room " + roomName); + } + + public void removeRoomListener(String roomName, ILayoutRoomListener listener) { + LayoutRoom r = getRoom(roomName); + if (r != null) { + r.removeRoomListener(listener); + return; + } + log.warn("Removing listener to a non-existing room " + roomName); + } + + public void lockLayout(String room, int userId, String layout) { + LayoutRoom r = getRoom(room); + if (r != null) { + r.lockLayout(userId, layout); + } else { + log.warn("lockLayout: sending message to a non-existing room " + room); + } + } + + public void unlockLayout(String room) { + LayoutRoom r = getRoom(room); + if (r != null) { + r.unlockLayout(); + } else { + log.warn("unlockLayout: sending message to a non-existing room " + room); + } + } + + public List<Object> currentLayout(String room) { + LayoutRoom r = getRoom(room); + if (r != null) { + return r.currentLayout(); + } else { + log.warn("initLayout: sending message to a non-existing room " + room); + return null; + } + } +} diff --git a/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/layout/LayoutSender.java b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/layout/LayoutSender.java new file mode 100755 index 0000000000000000000000000000000000000000..1f0e7ff50983d1676b9d69f4faf189f210d8cc92 --- /dev/null +++ b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/layout/LayoutSender.java @@ -0,0 +1,59 @@ +/** + * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/ + * + * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below). + * + * This program is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation; either version 2.1 of the License, or (at your option) any later + * version. + * + * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. + * + * Author: Felipe Cecagno <felipe@mconf.org> + */ +package org.bigbluebutton.conference.service.layout; + +import java.util.List; + +import org.red5.logging.Red5LoggerFactory; +import org.red5.server.api.so.ISharedObject; +import org.red5.server.api.statistics.ISharedObjectStatistics; +import org.slf4j.Logger; + +public class LayoutSender implements ILayoutRoomListener { + +private static Logger log = Red5LoggerFactory.getLogger( LayoutSender.class, "bigbluebutton" ); + + private ISharedObject so; + private String name = "LAYOUT"; + + public LayoutSender(ISharedObject so) { + this.so = so; + } + + @Override + public String getName() { + return name; + } + + @Override + public void updateLayout(List<Object> args) { + log.debug("Sending update layout"); + + if (so.isLocked()) log.info("Layout SO is locked"); + if (so.isAcquired()) log.info("Layout SO is acquired"); + ISharedObjectStatistics stats = so.getStatistics(); + log.debug("Before: Layout SO stats [total-sends=" + stats.getTotalSends() + "]"); + so.sendMessage("remoteUpdateLayout", args); + log.debug("After: Layout SO stats [total-sends=" + stats.getTotalSends() + "]"); + if (so.isLocked()) log.info("Layout SO is locked"); + if (so.isAcquired()) log.info("Layout SO is acquired"); + } + +} diff --git a/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/layout/LayoutService.java b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/layout/LayoutService.java new file mode 100755 index 0000000000000000000000000000000000000000..be0348ef68c8116a9e51432a4a5c02695871bff5 --- /dev/null +++ b/bigbluebutton-apps/src/main/java/org/bigbluebutton/conference/service/layout/LayoutService.java @@ -0,0 +1,55 @@ +/** + * BigBlueButton open source conferencing system - http://www.bigbluebutton.org/ + * + * Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below). + * + * This program is free software; you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License as published by the Free Software + * Foundation; either version 2.1 of the License, or (at your option) any later + * version. + * + * BigBlueButton is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with BigBlueButton; if not, see <http://www.gnu.org/licenses/>. + * + * Author: Felipe Cecagno <felipe@mconf.org> + */ +package org.bigbluebutton.conference.service.layout; + import java.util.List; + +import org.red5.logging.Red5LoggerFactory; +import org.red5.server.api.Red5; +import org.slf4j.Logger; + +public class LayoutService { + + private static Logger log = Red5LoggerFactory.getLogger( LayoutService.class, "bigbluebutton" ); + + private LayoutApplication application; + + public List<Object> init() { + log.debug("Initializing layout"); + String roomName = Red5.getConnectionLocal().getScope().getName(); + return application.currentLayout(roomName); + } + + public void lock(int userId, String layout) { + log.debug("Layout locked"); + String roomName = Red5.getConnectionLocal().getScope().getName(); + application.lockLayout(roomName, userId, layout); + } + + public void unlock() { + log.debug("Layout unlocked"); + String roomName = Red5.getConnectionLocal().getScope().getName(); + application.unlockLayout(roomName); + } + + public void setLayoutApplication(LayoutApplication a) { + log.debug("Setting layout application"); + application = a; + } +} diff --git a/bigbluebutton-apps/src/main/webapp/WEB-INF/bbb-apps.xml b/bigbluebutton-apps/src/main/webapp/WEB-INF/bbb-apps.xml index 0b1a7183b8ea70816ab15c5ff4e14e3f7d7c1dd7..e0acad00de434bcf3ecc417f2ed63f04acdb940d 100755 --- a/bigbluebutton-apps/src/main/webapp/WEB-INF/bbb-apps.xml +++ b/bigbluebutton-apps/src/main/webapp/WEB-INF/bbb-apps.xml @@ -27,6 +27,23 @@ <property name="participantsApplication"> <ref local="participantsApplication"/></property> </bean> + + <!-- BEGIN LAYOUT --> + <bean id="layoutRoomsManager" class="org.bigbluebutton.conference.service.layout.LayoutRoomsManager"/> + + <bean id="layoutHandler" class="org.bigbluebutton.conference.service.layout.LayoutHandler"> + <property name="layoutApplication"><ref local="layoutApplication"/></property> + </bean> + + <bean id="layoutApplication" class="org.bigbluebutton.conference.service.layout.LayoutApplication"> + <property name="roomsManager"><ref local="layoutRoomsManager"/></property> + </bean> + + <bean id="layout.service" class="org.bigbluebutton.conference.service.layout.LayoutService"> + <property name="layoutApplication"><ref local="layoutApplication"/></property> + </bean> + <!-- END LAYOUT --> + <!-- BEGIN PRESENTATION --> <bean id="presentationRoomsManager" class="org.bigbluebutton.conference.service.presentation.PresentationRoomsManager"/> diff --git a/bigbluebutton-apps/src/main/webapp/WEB-INF/red5-web.xml b/bigbluebutton-apps/src/main/webapp/WEB-INF/red5-web.xml index 6b55275cf40813b22b9823383189eb6848a7a1d5..fa36b5981ea19f980f26252c8d816cbfc6c1eff1 100755 --- a/bigbluebutton-apps/src/main/webapp/WEB-INF/red5-web.xml +++ b/bigbluebutton-apps/src/main/webapp/WEB-INF/red5-web.xml @@ -32,6 +32,7 @@ <set> <ref bean="participantsHandler" /> <ref bean="chatHandler" /> + <ref bean="layoutHandler" /> <ref bean="presentationHandler" /> <ref bean="voiceHandler" /> <ref bean="whiteboardApplication" />