merge remove-bbb-commons, working prototype, need to add status method to listener

This commit is contained in:
Marco Calderon 2011-06-09 01:35:24 +00:00
commit 2ac6aaa09a
31 changed files with 1066 additions and 588 deletions

View File

@ -1 +1,4 @@
bin
build
dist
lib

View File

@ -57,7 +57,7 @@ repositories {
}
}
mavenRepo urls: 'http://scala-tools.org/repo-releases/'
flatDir name: 'fileRepo', dirs: System.getenv()['FLAT_REPO']
//flatDir name: 'fileRepo', dirs: System.getenv()['FLAT_REPO']
}
dependencies {
@ -113,7 +113,7 @@ dependencies {
compile 'redis.clients:jedis:1.5.1'
compile 'commons-pool:commons-pool:1.5.5'
compile 'org/bigbluebutton/common:bbb-common-message:0.8@jar'
//compile 'org/bigbluebutton/common:bbb-common-message:0.8@jar'
// Freeswitch ESL Client
compile 'org/freeswitch:fs-esl-client:0.8.1@jar'

View File

@ -16,23 +16,14 @@
* with BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
*
*/
package org.bigbluebutton.conference;
import org.springframework.integration.annotation.Gateway;
public interface IRoomListener {
public String getName();
public void participantStatusChange(Long userid, String status, Object value);
public void participantJoined(Participant participant);
public void participantLeft(Long userid);
/*
* TODO: perhaps this should actually be merged with IRoomListener
* in some way, but for now I am using it to test the Spring Integration / JMS
* stuff. (JRT - 09/26/2009)
*/
public interface IConferenceEventListener {
@Gateway(requestChannel="conferenceStarted")
void started(Room room);
@Gateway(requestChannel="conferenceEnded")
void ended(Room room);
@Gateway(requestChannel="participantsUpdated")
void participantsUpdated(Room room);
public void endAndKickAll();
}

View File

@ -0,0 +1,118 @@
/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
* Copyright (c) 2010 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/>.
*
*/
package org.bigbluebutton.conference;
import net.jcip.annotations.ThreadSafe;
import java.util.concurrent.ConcurrentHashMap;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.io.Serializable;
import java.lang.Long;
/**
* Contains information for a Participant. Encapsulates status and the
* only way to change/add status is through setStatus;
*/
@ThreadSafe
public class Participant implements Serializable {
private Long userid;
private String name;
private String role = "VIEWER";
private String externUserID;
private final Map status;
private Map<String, Object> unmodifiableStatus;
public Participant(Long userid, String name, String role, String externUserID, Map<String, Object> status) {
this.userid = userid;
this.name = name;
this.role = role;
this.externUserID = externUserID;
this.status = new ConcurrentHashMap<String, Object>(status);
unmodifiableStatus = Collections.unmodifiableMap(status);
}
public boolean isModerator() {
return "MODERATOR".equals(role);
}
public String getName() {
return name;
}
public Long getUserid() {
return userid;
}
public String getRole() {
return role;
}
public String getExternUserID() {
return externUserID;
}
/**
* Returns that status for this participant. However, the status cannot
* be modified. To do that, setStatus(...) must be used.
*/
public Map getStatus() {
return unmodifiableStatus;
}
public void setStatus(String statusName, Object value) {
// Should we sychronize?
synchronized (this) {
status.put(statusName, value);
/**
* Update unmodifiableStatus as it does not get synched with status.
* Not sure it it should auto-syc, so just sync it.
* Not sure if this is the right way to do it (ralam 2/26/2009).
*/
unmodifiableStatus = Collections.unmodifiableMap(status);
}
}
public void removeStatus(String statusName) {
// Should we sychronize?
synchronized (this) {
status.remove(statusName);
/**
* Update unmodifiableStatus as it does not get synched with status.
* Not sure it it should auto-syc, so just sync it.
* Not sure if this is the right way to do it (ralam 2/26/2009).
*/
unmodifiableStatus = Collections.unmodifiableMap(status);
}
}
public Map toMap() {
Map m = new HashMap();
m.put("userid", userid);
m.put("name", name);
m.put("role", role);
/**
* Create a copy of the status instead of returning the
* unmodifiableMap. This way callers can still manipulate it
* for their own purpose but our copy still remains unmodified.
*/
m.put("status", new HashMap(unmodifiableStatus));
return m;
}
}

View File

@ -19,48 +19,57 @@
package org.bigbluebutton.conference;
import org.bigbluebutton.conference.service.recorder.pubsub.RedisPublisher;
import org.bigbluebutton.conference.service.messaging.RedisPublisher;
import org.red5.logging.Red5LoggerFactory;
import org.slf4j.Logger;
public class ParticipantUpdatingRoomListener implements IRoomListener{
RedisPublisher publisher;
private IConferenceEventListener conferenceEventListener;
private Room room;
private static Logger log = Red5LoggerFactory.getLogger(ParticipantUpdatingRoomListener.class, "bigbluebutton");
public ParticipantUpdatingRoomListener(IConferenceEventListener lstnr, Room room, RedisPublisher publisher) {
this.conferenceEventListener = lstnr;
RedisPublisher publisher;
//private IConferenceEventListener conferenceEventListener;
private Room room;
private final String pubsub_pattern;
public ParticipantUpdatingRoomListener(Room room, RedisPublisher publisher) {
//this.conferenceEventListener = lstnr;
this.room = room;
this.publisher=publisher;
this.pubsub_pattern="bigbluebutton:meeting:participants";
}
public String getName() {
return "TEMPNAME";
return "PARTICIPANT:UPDATE:ROOM";
}
public void participantStatusChange(Long userid, String status, Object value){
if (conferenceEventListener != null) {
conferenceEventListener.participantsUpdated(room);
if (publisher != null) {
//conferenceEventListener.participantsUpdated(room);
//redis pubsub
publisher.publish(this.pubsub_pattern, this.room.getName()+":status:"+userid+":"+status+":"+value);
log.debug("Publishing message to {} action status change",this.pubsub_pattern);
}
}
public void participantJoined(Participant p) {
if (conferenceEventListener != null) {
conferenceEventListener.participantsUpdated(room);
if (publisher != null) {
//conferenceEventListener.participantsUpdated(room);
//redis pubsub
//redis pubsub test
publisher.publish("bigbluebutton:conference:join", room.getName()+":"+p.getUserid()+":"+p.getName()+":"+p.getRole());
publisher.publish(this.pubsub_pattern,this.room.getName()+":join:"+p.getUserid()+":"+p.getName()+":"+p.getRole());
log.debug("Publishing message to {} action join",this.pubsub_pattern);
}
}
public void participantLeft(Long userid) {
if (conferenceEventListener != null) {
conferenceEventListener.participantsUpdated(room);
if (publisher != null) {
//conferenceEventListener.participantsUpdated(room);
//redis pubsub
//redis pubsub test
publisher.publish("bigbluebutton:conference:remove", room.getName()+":"+userid);
publisher.publish(this.pubsub_pattern, this.room.getName()+":left:"+userid);
log.debug("Publishing message to {} action left",this.pubsub_pattern);
}
}

View File

@ -0,0 +1,158 @@
/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
* Copyright (c) 2010 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/>.
*
*/
package org.bigbluebutton.conference;
import org.slf4j.Logger;
import org.red5.logging.Red5LoggerFactory;
import net.jcip.annotations.ThreadSafe;
import java.io.Serializable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
/**
* Contains information about a Room and it's Participants.
* Encapsulates Participants and RoomListeners.
*/
@ThreadSafe
public class Room implements Serializable {
private static Logger log = Red5LoggerFactory.getLogger( Room.class, "bigbluebutton" );
private String name;
private Map <Long, Participant> participants;
// these should stay transient so they're not serialized in ActiveMQ messages:
//private transient Map <Long, Participant> unmodifiableMap;
private transient final Map<String, IRoomListener> listeners;
public Room(String name) {
this.name = name;
participants = new ConcurrentHashMap<Long, Participant>();
//unmodifiableMap = Collections.unmodifiableMap(participants);
listeners = new ConcurrentHashMap<String, IRoomListener>();
}
public String getName() {
return name;
}
public void addRoomListener(IRoomListener listener) {
if (! listeners.containsKey(listener.getName())) {
log.debug("adding room listener");
listeners.put(listener.getName(), listener);
}
}
public void removeRoomListener(IRoomListener listener) {
log.debug("removing room listener");
listeners.remove(listener);
}
public void addParticipant(Participant participant) {
synchronized (this) {
log.debug("adding participant {}",participant.getUserid());
participants.put(participant.getUserid(), participant);
// unmodifiableMap = Collections.unmodifiableMap(participants)
}
log.debug("addparticipant - informing roomlisteners {}",listeners.size());
for (Iterator it = listeners.values().iterator(); it.hasNext();) {
//for (IRoomListener listener : listeners) {
log.debug("calling participantJoined on listener");
IRoomListener listener = (IRoomListener) it.next();
log.debug("calling participantJoined on listener {}",listener.getName());
listener.participantJoined(participant);
}
}
public void removeParticipant(Long userid) {
boolean present = false;
synchronized (this) {
present = participants.containsKey(userid);
if (present) {
log.debug("removing participant");
participants.remove(userid);
}
}
if (present) {
for (Iterator it = listeners.values().iterator(); it.hasNext();) {
log.debug("calling participantLeft on listener");
IRoomListener listener = (IRoomListener) it.next();
log.debug("calling participantLeft on listener {}",listener.getName());
listener.participantLeft(userid);
}
}
}
public void changeParticipantStatus(Long userid, String status, Object value) {
boolean present = false;
synchronized (this) {
present = participants.containsKey(userid);
if (present) {
log.debug("change participant status");
Participant p = participants.get(userid);
p.setStatus(status, value);
//participants.put(userid, p);
//unmodifiableMap = Collections.unmodifiableMap(participants);
}
}
if (present) {
for (Iterator it = listeners.values().iterator(); it.hasNext();) {
log.debug("calling participantStatusChange on listener");
IRoomListener listener = (IRoomListener) it.next();
log.debug("calling participantStatusChange on listener {}",listener.getName());
listener.participantStatusChange(userid, status, value);
}
}
}
public void endAndKickAll() {
for (Iterator it = listeners.values().iterator(); it.hasNext();) {
IRoomListener listener = (IRoomListener) it.next();
log.debug("calling endAndKickAll on listener {}",listener.getName());
listener.endAndKickAll();
}
}
public Map getParticipants() {
return participants;//unmodifiableMap;
}
public Collection<Participant> getParticipantCollection() {
return participants.values();
}
public int getNumberOfParticipants() {
log.debug("Returning number of participants: " + participants.size());
return participants.size();
}
public int getNumberOfModerators() {
int sum = 0;
for (Iterator<Participant> it = participants.values().iterator(); it.hasNext(); ) {
Participant part = it.next();
if (part.isModerator()) {
sum++;
}
}
log.debug("Returning number of moderators: " + sum);
return sum;
}
}

View File

@ -19,8 +19,8 @@
package org.bigbluebutton.conference;
import org.slf4j.Logger;
import org.bigbluebutton.conference.service.messaging.RedisPublisher;
import org.bigbluebutton.conference.service.recorder.RedisDispatcher;
import org.bigbluebutton.conference.service.recorder.pubsub.RedisPublisher;
import org.red5.logging.Red5LoggerFactory;
import net.jcip.annotations.ThreadSafe;
import java.util.Map;
@ -35,11 +35,9 @@ public class RoomsManager {
private final Map <String, Room> rooms;
private IConferenceEventListener conferenceEventListener;
//replaced with redis publisher
//private IConferenceEventListener conferenceEventListener;
/*redis pubsub*/
RedisPublisher publisher;
public RoomsManager() {
@ -47,14 +45,14 @@ public class RoomsManager {
}
public void addRoom(final Room room) {
public void addRoom(Room room) {
log.debug("Adding room {}", room.getName());
room.addRoomListener(new ParticipantUpdatingRoomListener(conferenceEventListener, room,publisher));
room.addRoomListener(new ParticipantUpdatingRoomListener(room,publisher));
if (checkEvtListener()) {
conferenceEventListener.started(room);
if (checkPublisher()) {
//conferenceEventListener.started(room);
//redis pubsub test
publisher.publish("bigbluebutton:conference:status", room.getName()+":started");
publisher.publish("bigbluebutton:meeting:state", room.getName()+":started");
log.debug("Notified event listener of conference start");
}
@ -64,12 +62,12 @@ public class RoomsManager {
public void removeRoom(String name) {
log.debug("Remove room {}", name);
Room room = rooms.remove(name);
if (checkEvtListener() && room != null) {
if (checkPublisher() && room != null) {
room.endAndKickAll();
conferenceEventListener.ended(room);
//conferenceEventListener.ended(room);
//redis pubsub test
publisher.publish("bigbluebutton:conference:status", room.getName()+":ended");
publisher.publish("bigbluebutton:meeting:state",room.getName()+":ended");
log.debug("Notified event listener of conference end");
}
@ -82,8 +80,8 @@ public class RoomsManager {
}
}
private boolean checkEvtListener() {
return conferenceEventListener != null;
private boolean checkPublisher() {
return publisher != null;
}
@ -96,8 +94,8 @@ public class RoomsManager {
}
// this method is called by incoming JMS requests (Spring integration)
public void endMeetingRequest(Room room) {
room = getRoom(room.getName()); // must do this because the room coming in is serialized (no transient values are present)
public void endMeetingRequest(String roomname) {
Room room = getRoom(roomname); // must do this because the room coming in is serialized (no transient values are present)
log.debug("End meeting request for room: {} ", room.getName());
room.endAndKickAll();
}
@ -144,19 +142,20 @@ public class RoomsManager {
log.debug("Add participant {}", participant.getName());
Room r = getRoom(roomName);
if (r != null) {
if (checkEvtListener()) {
conferenceEventListener.participantsUpdated(r);
if (checkPublisher()) {
//conferenceEventListener.participantsUpdated(r);
//missing_method()
if (r.getNumberOfParticipants() == 0) {
conferenceEventListener.started(r);
//conferenceEventListener.started(r);
log.debug("Notified event listener of conference start");
//redis pubsub test
publisher.publish("bigbluebutton:conference:status", r.getName()+":started");
publisher.publish("bigbluebutton:meeting:state", roomName+":started");
}
}
r.addParticipant(participant);
//redis pubsub test
publisher.publish("bigbluebutton:conference:join", r.getName()+":"+participant.getUserid()+":"+participant.getName()+":"+participant.getRole());
//publisher.publish("bigbluebutton:conference:join", r.getName()+":"+participant.getUserid()+":"+participant.getName()+":"+participant.getRole());
return;
}
@ -167,14 +166,11 @@ public class RoomsManager {
log.debug("Remove participant {} from {}", userid, roomName);
Room r = getRoom(roomName);
if (r != null) {
if (checkEvtListener()) {
conferenceEventListener.participantsUpdated(r);
if (checkPublisher()) {
//conferenceEventListener.participantsUpdated(r);
//missing method()?
}
r.removeParticipant(userid);
//redis pubsub test
publisher.publish("bigbluebutton:conference:remove", r.getName()+":"+userid);
return;
}
@ -191,13 +187,13 @@ public class RoomsManager {
log.warn("Changing participant status on a non-existing room {}", roomName);
}
public void setConferenceEventListener(IConferenceEventListener conferenceEventListener) {
this.conferenceEventListener = conferenceEventListener;
}
public IConferenceEventListener getConferenceEventListener() {
return conferenceEventListener;
}
// public void setConferenceEventListener(IConferenceEventListener conferenceEventListener) {
// this.conferenceEventListener = conferenceEventListener;
// }
//
// public IConferenceEventListener getConferenceEventListener() {
// return conferenceEventListener;
// }
public RedisPublisher getPublisher() {
return publisher;

View File

@ -0,0 +1,132 @@
package org.bigbluebutton.conference.service.messaging;
import java.util.HashMap;
import org.bigbluebutton.conference.RoomsManager;
import org.bigbluebutton.conference.service.presentation.ConversionUpdatesMessageListener;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPubSub;
public class RedisListener{
JedisPool redisPool;
RoomsManager roomsManager;
ConversionUpdatesMessageListener messageListener;
public RedisListener() {
super();
}
public void init(){
Jedis jedis = redisPool.getResource();
//subscribe(jedis);
redisPool.returnResource(jedis);
}
public void subscribe(final Jedis jedis){
Thread t= new Thread(new Runnable() {
@Override
public void run() {
jedis.subscribe(new JedisPubSub() {
@Override
public void onUnsubscribe(String arg0, int arg1) {
// TODO Auto-generated method stub
}
@Override
public void onSubscribe(String arg0, int arg1) {
// TODO Auto-generated method stub
}
@Override
public void onPUnsubscribe(String arg0, int arg1) {
// TODO Auto-generated method stub
}
@Override
public void onPSubscribe(String arg0, int arg1) {
}
@Override
public void onPMessage(String pattern, String channel, String message) {
if(channel.equalsIgnoreCase("bigbluebutton:meeting:request")){
String[] args=message.split(":");
String roomname=args[0];
String type=args[1];
if(type.equalsIgnoreCase("end")){
roomsManager.endMeetingRequest(roomname);
}
}
else if(channel.equalsIgnoreCase("bigbluebutton:meeting:presentation")){
String[] args=message.split(":");
HashMap<String,Object> map=new HashMap<String, Object>();
map.put("code",args[0]);
map.put("presentationName",args[1]);
map.put("conference",args[2]);
String messageKey=args[3];
map.put("messageKey",messageKey);
if(messageKey.equalsIgnoreCase(ConversionUpdatesMessageListener.PAGE_COUNT_EXCEEDED_KEY)){
map.put("numberOfPages", args[4]);
map.put("maxNumberPages", args[5]);
}
else if(messageKey.equalsIgnoreCase(ConversionUpdatesMessageListener.GENERATED_SLIDE_KEY)){
map.put("numberOfPages", args[4]);
map.put("pagesCompleted", args[5]);
}
else if(messageKey.equalsIgnoreCase(ConversionUpdatesMessageListener.CONVERSION_COMPLETED_KEY)){
map.put("slidesInfo", args[4]);
}
messageListener.handleReceivedMessage(map);
}
}
@Override
public void onMessage(String channel, String message) {
}
}, "bigbluebutton:meeting:*");
}
});
t.start();
}
public JedisPool getRedisPool() {
return redisPool;
}
public void setRedisPool(JedisPool redisPool) {
this.redisPool = redisPool;
}
public RoomsManager getRoomsManager() {
return roomsManager;
}
public void setRoomsManager(RoomsManager roomsManager) {
this.roomsManager = roomsManager;
}
public ConversionUpdatesMessageListener getMessageListener() {
return messageListener;
}
public void setMessageListener(ConversionUpdatesMessageListener messageListener) {
this.messageListener = messageListener;
}
}

View File

@ -0,0 +1,31 @@
package org.bigbluebutton.conference.service.messaging;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
public class RedisPublisher{
JedisPool redisPool;
public RedisPublisher(){
super();
}
public void publish(String channel, String message){
Jedis jedis = redisPool.getResource();
try {
jedis.publish(channel, message);
} finally {
redisPool.returnResource(jedis);
}
}
public JedisPool getRedisPool() {
return redisPool;
}
public void setRedisPool(JedisPool redisPool) {
this.redisPool = redisPool;
}
}

View File

@ -29,9 +29,12 @@ public class ParticipantsApplication {
private RoomsManager roomsManager;
public boolean createRoom(String name) {
log.info("Creating room {}", name);
roomsManager.addRoom(new Room(name));
return true;
if(!roomsManager.hasRoom(name)){
log.info("Creating room {}", name);
roomsManager.addRoom(new Room(name));
return true;
}
return false;
}
public boolean destroyRoom(String name) {
@ -68,7 +71,7 @@ public class ParticipantsApplication {
public Map getParticipants(String roomName) {
log.debug("getParticipants - " + roomName);
if (! roomsManager.hasRoom(roomName)) {
log.warn("Could not find room "+roomName);
log.warn("Could not find room "+roomName+" Total rooms "+roomsManager.numberOfRooms());
return null;
}

View File

@ -44,8 +44,11 @@ public class ParticipantsService {
Map participants = new HashMap();
if (p == null) {
participants.put("count", 0);
log.debug("partipants of {} is null",roomName);
} else {
participants.put("count", p.size());
log.debug("number of partipants is {}",p.size());
if (p.size() > 0) {
/**
* Somehow we need to convert to Map so the client will be

View File

@ -21,53 +21,49 @@
*/
package org.bigbluebutton.conference.service.presentation;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.MapMessage;
import org.slf4j.Logger;
import org.red5.logging.Red5LoggerFactory;
import java.util.HashMap;
import java.util.Map;
public class ConversionUpdatesMessageListener implements MessageListener{
public class ConversionUpdatesMessageListener {
private static Logger log = Red5LoggerFactory.getLogger(ConversionUpdatesMessageListener.class, "bigbluebutton");
private ConversionUpdatesProcessor conversionUpdatesProcessor;
private static final String OFFICE_DOC_CONVERSION_SUCCESS_KEY = "OFFICE_DOC_CONVERSION_SUCCESS";
private static final String OFFICE_DOC_CONVERSION_FAILED_KEY = "OFFICE_DOC_CONVERSION_FAILED";
private static final String SUPPORTED_DOCUMENT_KEY = "SUPPORTED_DOCUMENT";
private static final String UNSUPPORTED_DOCUMENT_KEY = "UNSUPPORTED_DOCUMENT";
private static final String PAGE_COUNT_FAILED_KEY = "PAGE_COUNT_FAILED";
private static final String PAGE_COUNT_EXCEEDED_KEY = "PAGE_COUNT_EXCEEDED";
private static final String GENERATED_SLIDE_KEY = "GENERATED_SLIDE";
private static final String GENERATING_THUMBNAIL_KEY = "GENERATING_THUMBNAIL";
private static final String GENERATED_THUMBNAIL_KEY = "GENERATED_THUMBNAIL";
private static final String CONVERSION_COMPLETED_KEY = "CONVERSION_COMPLETED";
public static final String OFFICE_DOC_CONVERSION_SUCCESS_KEY = "OFFICE_DOC_CONVERSION_SUCCESS";
public static final String OFFICE_DOC_CONVERSION_FAILED_KEY = "OFFICE_DOC_CONVERSION_FAILED";
public static final String SUPPORTED_DOCUMENT_KEY = "SUPPORTED_DOCUMENT";
public static final String UNSUPPORTED_DOCUMENT_KEY = "UNSUPPORTED_DOCUMENT";
public static final String PAGE_COUNT_FAILED_KEY = "PAGE_COUNT_FAILED";
public static final String PAGE_COUNT_EXCEEDED_KEY = "PAGE_COUNT_EXCEEDED";
public static final String GENERATED_SLIDE_KEY = "GENERATED_SLIDE";
public static final String GENERATING_THUMBNAIL_KEY = "GENERATING_THUMBNAIL";
public static final String GENERATED_THUMBNAIL_KEY = "GENERATED_THUMBNAIL";
public static final String CONVERSION_COMPLETED_KEY = "CONVERSION_COMPLETED";
public void start() {
log.debug("Starting conversion updates receiver.");
conversionUpdatesProcessor.start();
}
@Override
/*@Override
public void onMessage(Message jmsMessage){
if (jmsMessage instanceof MapMessage) {
MapMessage mapMessage = ((MapMessage) jmsMessage);
handleReceivedMessage(mapMessage);
}
}
}*/
@SuppressWarnings("unchecked")
private void handleReceivedMessage(MapMessage mapMessage) {
@SuppressWarnings({ "unchecked", "rawtypes" })
public void handleReceivedMessage(Map mapMessage) {
try{
String code = mapMessage.getString("returnCode");
String room = mapMessage.getString("room");
String presentationName = mapMessage.getString("presentationName");
String conference = mapMessage.getString("conference");
String messageKey = mapMessage.getString("messageKey");
String code = (String) mapMessage.get("returnCode");
String room = (String) mapMessage.get("room");
String presentationName = (String) mapMessage.get("presentationName");
String conference = (String) mapMessage.get("conference");
String messageKey = (String) mapMessage.get("messageKey");
Map message = new HashMap();
message.put("conference", conference);
@ -90,15 +86,15 @@ public class ConversionUpdatesMessageListener implements MessageListener{
}
else if(messageKey.equalsIgnoreCase(PAGE_COUNT_EXCEEDED_KEY)){
log.debug("JMS: {}[{}]",messageKey,presentationName);
int numberOfPages = mapMessage.getInt("numberOfPages");
int maxNumberPages = mapMessage.getInt("maxNumberPages");
int numberOfPages = (Integer) mapMessage.get("numberOfPages");
int maxNumberPages = (Integer) mapMessage.get("maxNumberPages");
message.put("numberOfPages", numberOfPages);
message.put("maxNumberPages", maxNumberPages);
conversionUpdatesProcessor.process(message);
}
else if(messageKey.equalsIgnoreCase(GENERATED_SLIDE_KEY)){
int numberOfPages = mapMessage.getInt("numberOfPages");
int pagesCompleted = mapMessage.getInt("pagesCompleted");
int numberOfPages = (Integer) mapMessage.get("numberOfPages");
int pagesCompleted = (Integer) mapMessage.get("pagesCompleted");
message.put("numberOfPages", numberOfPages);
message.put("pagesCompleted", pagesCompleted);
@ -106,7 +102,7 @@ public class ConversionUpdatesMessageListener implements MessageListener{
conversionUpdatesProcessor.process(message);
}
else if(messageKey.equalsIgnoreCase(CONVERSION_COMPLETED_KEY)){
String slidesInfo = mapMessage.getString("slidesInfo");
String slidesInfo = (String) mapMessage.get("slidesInfo");
message.put("slidesInfo", slidesInfo);
log.debug("JMS: {}[{}]",messageKey,presentationName);
conversionUpdatesProcessor.process(message);
@ -114,7 +110,7 @@ public class ConversionUpdatesMessageListener implements MessageListener{
else{
log.error("Cannot handle recieved message.");
}
}catch(JMSException ex){
}catch(Exception ex){
log.warn(ex.getMessage());
}
}

View File

@ -30,7 +30,7 @@ package org.bigbluebutton.conference.service.recorder;
public interface Recorder {
/**
* Receive the messages from the bigbluebutton modules and send
* them to a JMS queue. These messages are the events generated in a conference.
* them to a queue. These messages are the events generated in a conference.
* @param message a JSON String message with the attributes of an event
*/
public void record(String session, RecordEvent event);

View File

@ -1,94 +0,0 @@
/**
* ===License Header===
*
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
* Copyright (c) 2010 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/>.
*
* ===License Header===
*/
package org.bigbluebutton.conference.service.recorder;
import java.util.HashMap;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import org.bigbluebutton.recorder.EventMessage;
import org.bigbluebutton.recorder.IEventMessage;
import org.red5.logging.Red5LoggerFactory;
import org.slf4j.Logger;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
/**
*
* The RecorderEventDispatcher class creates a object message and implements
* the sender method for sending events to the JMS queue
*
**/
public class RecorderEventDispatcher implements Recorder {
private static Logger log = Red5LoggerFactory.getLogger( RecorderEventDispatcher.class, "bigbluebutton" );
private JmsTemplate jmsTemplate;
/**
* RecorderEventDispatcher constructor.
* @param conference the conference name
* @param room the room name
* @return RecorderEventDispatcher
*/
public RecorderEventDispatcher() {
log.debug("create an instance of RecorderEventDispatcher");
}
/**
* The method creates a object message for sending to the jms queue.
* @param event receive a IEventMessage object from bbb-common-messages
*/
public void sendEvents(final IEventMessage event) {
jmsTemplate.send(new MessageCreator() {
public Message createMessage(Session sn) throws JMSException {
Message msg = sn.createObjectMessage(event);
return msg;
}
});
log.debug("create and send object message");
}
/**
* The method implements recordEvent from IRecoder. It sets the EventMessage
* from bbb-common-messages with the room name, timestamp and message-event.
* @param message this is a event-message sent by the BigBlueButton modules.
* @see Recorder
*/
@Override
public void record(String session, RecordEvent message) {
EventMessage event = new EventMessage();
event.setConferenceID(session);
//event.setMessage(message);
event.setTimeStamp(System.currentTimeMillis());
sendEvents(event);
log.debug("event-message: {}",message);
}
/**
* The method sets a Jms Template.
* @param jmsTemplate a JmsTemplate.
*/
public void setJmsTemplate(JmsTemplate jmsTemplate){
this.jmsTemplate=jmsTemplate;
log.debug("set jms template");
}
}

View File

@ -8,29 +8,25 @@ import redis.clients.jedis.JedisPool;
public class RedisDispatcher implements Recorder {
private static final String COLON=":";
private String host;
private int port;
JedisPool redisPool;
private Jedis jedis;
// Jedis jedis;
JedisPool jpool;
public RedisDispatcher(String host, int port){
this.host = host;
this.port = port;
// jedis = new Jedis(host, port);
// Config poolConfig = new Config();
// jpool = new JedisPool(poolConfig, host, port);
public RedisDispatcher(){
super();
}
@Override
public void record(String session, RecordEvent message) {
Jedis jedis = new Jedis(host, port);
Long msgid = jedis.incr("global:nextRecordedMsgId");
jedis.hmset("recording" + COLON + session + COLON + msgid, message.toMap());
jedis.rpush("meeting" + COLON + session + COLON + "recordings", msgid.toString());
Jedis jedis = redisPool.getResource();
try {
Long msgid = jedis.incr("global:nextRecordedMsgId");
jedis.hmset("recording" + COLON + session + COLON + msgid, message.toMap());
jedis.rpush("meeting" + COLON + session + COLON + "recordings", msgid.toString());
} finally {
redisPool.returnResource(jedis);
}
//pool.destroy();
}
/*
@Override
@ -58,8 +54,13 @@ public class RedisDispatcher implements Recorder {
}
*/
public Jedis getJedis(){
return jedis;
public JedisPool getRedisPool() {
return redisPool;
}
public void setRedisPool(JedisPool redisPool) {
this.redisPool = redisPool;
}
}

View File

@ -1,26 +0,0 @@
package org.bigbluebutton.conference.service.recorder;
import java.io.IOException;
import redis.clients.jedis.Jedis;
public class RedisServer {
protected Jedis jedis;
public RedisServer(String server, int port) {
jedis = new Jedis(server, port,0);
jedis.set("foo", "bar");
}
public Jedis getJedis(){
return jedis;
}
public void closeConnection(){
try {
jedis.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
}
}

View File

@ -1,49 +0,0 @@
package org.bigbluebutton.conference.service.recorder.pubsub;
import redis.clients.jedis.JedisPubSub;
class PubsubListener extends JedisPubSub {
public PubsubListener() {
super();
}
@Override
public void onMessage(String channel, String message) {
System.out.println("pubsub "+channel+":"+message);
}
@Override
public void onPMessage(String pattern, String channel,
String message) {
// TODO Auto-generated method stub
}
@Override
public void onPSubscribe(String pattern, int subscribedChannels) {
// TODO Auto-generated method stub
}
@Override
public void onPUnsubscribe(String pattern, int subscribedChannels) {
// TODO Auto-generated method stub
}
@Override
public void onSubscribe(String channel, int subscribedChannels) {
// TODO Auto-generated method stub
}
@Override
public void onUnsubscribe(String channel, int subscribedChannels) {
// TODO Auto-generated method stub
}
}

View File

@ -1,34 +0,0 @@
package org.bigbluebutton.conference.service.recorder.pubsub;
import org.bigbluebutton.conference.service.recorder.RedisServer;
public class RedisListener extends RedisServer implements Runnable {
private PubsubListener pubsubListener;
public RedisListener(String server, int port) {
super(server, port);
// TODO Auto-generated constructor stub
}
public void subscribe(){
Thread t= new Thread(this);
t.start();
}
@Override
public void run() {
jedis.subscribe(pubsubListener, "bbbConferenceEvents");
}
public PubsubListener getPubsubListener() {
return pubsubListener;
}
public void setPubsubListener(PubsubListener pubsubListener) {
System.out.println("setting pubsub");
this.pubsubListener = pubsubListener;
}
}

View File

@ -1,26 +0,0 @@
package org.bigbluebutton.conference.service.recorder.pubsub;
import java.io.IOException;
import redis.clients.jedis.Jedis;
public class RedisPublisher {
Jedis jedis;
public RedisPublisher(String host, int port){
jedis= new Jedis(host,port);
}
public void publish(String channel, String message){
jedis.publish(channel, message);
}
public void disconnect(){
try {
jedis.disconnect();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

View File

@ -18,15 +18,9 @@
">
<bean id="roomsManager" class="org.bigbluebutton.conference.RoomsManager">
<property name="conferenceEventListener" ref="conferenceEventListener" />
<property name="publisher" ref="redisPublisher"></property>
</bean>
<bean id="redisPublisher" class="org.bigbluebutton.conference.service.recorder.pubsub.RedisPublisher">
<constructor-arg index="0" value="${redis.host}"/>
<constructor-arg index="1" value="${redis.port}"/>
</bean>
<bean id="participantsHandler" class="org.bigbluebutton.conference.service.participants.ParticipantsHandler">
<property name="participantsApplication"> <ref local="participantsApplication"/></property>
<property name="recorderApplication"> <ref local="recorderApplication"/></property>
@ -41,28 +35,6 @@
<property name="participantsApplication"> <ref local="participantsApplication"/></property>
</bean>
<!-- BEGIN JMS EVENTS -->
<bean id="jmsRecorder" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg index="0">
<value>RecorderEventsQueue</value>
</constructor-arg>
</bean>
<bean id="templateEvent" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory"><ref local="connectionFactory" /></property>
<property name="defaultDestination"><ref local="jmsRecorder" /> </property>
</bean>
<bean id="recorderApplication" class="org.bigbluebutton.conference.service.recorder.RecorderApplication">
<property name="recorder"><ref local="redisRecorder" /> </property>
</bean>
<bean id="redisRecorder" class="org.bigbluebutton.conference.service.recorder.RedisDispatcher">
<constructor-arg index="0" value="${redis.host}"/>
<constructor-arg index="1" value="${redis.port}"/>
</bean>
<!-- END JMS EVENTS -->
<!-- BEGIN PRESENTATION -->
<bean id="presentationRoomsManager" class="org.bigbluebutton.conference.service.presentation.PresentationRoomsManager"/>
@ -89,17 +61,17 @@
<property name="presentationApplication"> <ref local="presentationApplication"/></property>
</bean>
<bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<!-- bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL">
<value>tcp://localhost:61616</value>
</property>
</bean>
</bean-->
<bean id="destination" class="org.apache.activemq.command.ActiveMQQueue">
<!-- bean id="destination" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg index="0">
<value>UpdatesQueue</value>
</constructor-arg>
</bean>
</bean-->
<bean id="conversionUpdatesProcessor" class="org.bigbluebutton.conference.service.presentation.ConversionUpdatesProcessor">
<property name="presentationApplication"> <ref local="presentationApplication"/></property>
@ -109,11 +81,11 @@
<property name="conversionUpdatesProcessor" ref="conversionUpdatesProcessor" />
</bean>
<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<!-- bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="destination" ref="destination"/>
<property name="messageListener" ref="messageListener" />
</bean>
</bean-->
<!-- END PRESENTATION -->
<!-- BEGIN CHAT -->
@ -148,43 +120,32 @@
<bean id="whiteboardRoomManager" class="org.bigbluebutton.conference.service.whiteboard.WhiteboardRoomManager"/>
<!-- END WHITEBOARD -->
<!-- Starting the Spring Integration configuration for JMS integration -->
<!-- INCOMING MESSAGES -->
<!-- endMeetingRequest -->
<jms:inbound-channel-adapter id="jmsInEndMeetingRequest"
destination-name="endMeetingRequestEvents"
channel="endMeetingRequest"
extract-payload="true">
<integration:poller>
<integration:interval-trigger interval="5" time-unit="SECONDS"/>
</integration:poller>
</jms:inbound-channel-adapter>
<integration:channel id="endMeetingRequest"/>
<integration:service-activator input-channel="endMeetingRequest" ref="roomsManager" method="endMeetingRequest" />
<!-- RECORDER AND MESSAGING -->
<!-- OUTGOING MESSAGES -->
<integration:gateway id="conferenceEventListener" service-interface="org.bigbluebutton.conference.IConferenceEventListener" />
<!-- conferenceStarted -->
<integration:channel id="conferenceStarted" />
<jms:outbound-channel-adapter id="conferenceStartedJmsOut" destination="conferenceStartedEvents" channel="conferenceStarted" />
<bean id="conferenceStartedEvents" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="conferenceStartedEvents"/>
</bean>
<!-- conferenceEnded -->
<integration:channel id="conferenceEnded" />
<jms:outbound-channel-adapter id="conferenceEndedJmsOut" destination="conferenceEndedEvents" channel="conferenceEnded" />
<bean id="conferenceEndedEvents" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="conferenceEndedEvents"/>
</bean>
<!-- participantsUpdated -->
<integration:channel id="participantsUpdated" />
<jms:outbound-channel-adapter id="participantsUpdatedJmsOut" destination="participantsUpdatedEvents" channel="participantsUpdated" />
<bean id="participantsUpdatedEvents" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="participantsUpdatedEvents"/>
<bean id="recorderApplication" class="org.bigbluebutton.conference.service.recorder.RecorderApplication">
<property name="recorder"><ref local="redisRecorder" /> </property>
</bean>
<bean id="redisRecorder" class="org.bigbluebutton.conference.service.recorder.RedisDispatcher">
<property name="redisPool"><ref local="redisPool" /> </property>
</bean>
<bean id="redisListener" class="org.bigbluebutton.conference.service.messaging.RedisListener" init-method="init">
<property name="redisPool"><ref local="redisPool" /> </property>
<property name="roomsManager"> <ref local="roomsManager"/></property>
<property name="messageListener"> <ref local="messageListener"/></property>
</bean>
<bean id="redisPublisher" class="org.bigbluebutton.conference.service.messaging.RedisPublisher">
<property name="redisPool"><ref local="redisPool" /> </property>
</bean>
<bean id="redisPool" class="redis.clients.jedis.JedisPool">
<constructor-arg index="0" value="${redis.host}"/>
<constructor-arg index="1" value="${redis.port}"/>
</bean>
<!-- END RECORDER AND MESSAGING -->
</beans>

View File

@ -3,3 +3,5 @@
stacktrace.log
lib
web-app/demo/bbb_api_conf.jsp
target
plugins/*

View File

@ -1,8 +1,7 @@
#utf-8
#Tue Apr 12 17:57:12 UTC 2011
#Mon Jun 06 06:53:20 UTC 2011
app.version=0.70dev
app.servlet.version=2.4
app.grails.version=1.1.1
plugins.hibernate=1.1.1
plugins.jsecurity=0.4.1
app.name=bigbluebutton

View File

@ -1,19 +0,0 @@
/*
* BigBlueButton - http://www.bigbluebutton.org
*
* Copyright (c) 2008-2009 by respective authors (see below). All rights reserved.
*
* BigBlueButton 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 3 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, If not, see <http://www.gnu.org/licenses/>.
*
* $Id: $
*/

View File

@ -1,10 +1,10 @@
#
# These are the default properites for BigBlueButton Web application
dataSource.url=jdbc:mysql://localhost/bigbluebutton_dev
dataSource.username=bbb
dataSource.password=secret
dataSource.driverClassName =com.mysql.jdbc.Driver
#dataSource.url=jdbc:mysql://localhost/bigbluebutton_dev
#dataSource.username=bbb
#dataSource.password=secret
#dataSource.driverClassName =com.mysql.jdbc.Driver
#----------------------------------------------------
# Directory where BigBlueButton stores uploaded slides
@ -69,7 +69,7 @@ defaultMaxUsers=20
#----------------------------------------------------
# This URL is where the BBB client is accessible. When a user sucessfully
# enters a name and password, she is redirected here to load the client.
bigbluebutton.web.serverURL=http://192.168.0.166
bigbluebutton.web.serverURL=http://192.168.1.38
#----------------------------------------------------
# Assign URL where the logged-out participant will be redirected after sign-out.
@ -94,7 +94,7 @@ beans.presentationService.testUploadedPresentation=appkonference.txt
# Test voiceBridge number
beans.dynamicConferenceService.testVoiceBridge=99999
redisHost=192.168.0.166
redisHost=localhost
redisPort=6379
# Directory where we drop the <meeting-id-recorded>.done file

View File

@ -32,7 +32,18 @@
<property name="dynamicConferenceService" ref="dynamicConferenceService"></property>
</bean>
-->
<bean id="meetingService" class="org.bigbluebutton.api.MeetingServiceImp">
<property name="messagingService" ref="messagingService"></property>
</bean>
<bean id="messagingService" class="org.bigbluebutton.api.messaging.RedisMessagingService">
<property name="redisPool" ref="redisPool"></property>
</bean>
<bean id="redisPool" class="redis.clients.jedis.JedisPool">
<constructor-arg index="0" value="${redisHost}"/>
<constructor-arg index="1" value="${redisPort}"/>
</bean>
<!-- Spring Integration / JMS gateways -->
<bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
@ -41,56 +52,6 @@
</property>
</bean>
<!-- INCOMING MESSAGES -->
<!-- conferenceStarted -->
<jms:inbound-channel-adapter id="jmsInConferenceStarted"
destination-name="conferenceStartedEvents"
channel="conferenceStarted"
extract-payload="true">
<integration:poller>
<integration:interval-trigger interval="5" time-unit="SECONDS"/>
</integration:poller>
</jms:inbound-channel-adapter>
<integration:channel id="conferenceStarted"/>
<!--integration:service-activator input-channel="conferenceStarted" ref="dynamicConferenceService" method="conferenceStarted" /-->
<!-- conferenceEnded -->
<jms:inbound-channel-adapter id="jmsInConferenceEnded"
destination-name="conferenceEndedEvents"
channel="conferenceEnded"
extract-payload="true">
<integration:poller>
<integration:interval-trigger interval="5" time-unit="SECONDS"/>
</integration:poller>
</jms:inbound-channel-adapter>
<integration:channel id="conferenceEnded"/>
<!--integration:service-activator input-channel="conferenceEnded" ref="dynamicConferenceService" method="conferenceEnded" /-->
<!-- participantsUpdated -->
<jms:inbound-channel-adapter id="jmsInParticipantsUpdated"
destination-name="participantsUpdatedEvents"
channel="participantsUpdated"
extract-payload="true">
<integration:poller>
<integration:interval-trigger interval="5" time-unit="SECONDS"/>
</integration:poller>
</jms:inbound-channel-adapter>
<integration:channel id="participantsUpdated"/>
<!--integration:service-activator input-channel="participantsUpdated" ref="dynamicConferenceService" method="participantsUpdated" /-->
<!-- <stream:stdout-channel-adapter id="stdout" channel="jmsinToStdoutChannel" append-newline="true"/>-->
<!-- OUTGOING MESSAGES -->
<integration:gateway id="conferenceEventListener" service-interface="org.bigbluebutton.api.IApiConferenceEventListener" />
<!-- endMeetingRequest -->
<integration:channel id="endMeetingRequest" />
<jms:outbound-channel-adapter id="endMeetingRequestJmsOut" destination="endMeetingRequestEvents" channel="endMeetingRequest" />
<bean id="endMeetingRequestEvents" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="endMeetingRequestEvents"/>
</bean>
<import resource="doc-conversion.xml" />
</beans>

View File

@ -119,14 +119,15 @@ class ApiController {
String logoutUrl = dynamicConferenceService.processLogoutUrl(params.logoutURL);
boolean record = dynamicConferenceService.processRecordMeeting(params.record);
int maxUsers = dynamicConferenceService.processMaxUser(params.maxParticipants);
String welcomeMessage = dynamicConferenceService.processWelcomeMessage(params.welcome, dialNumber, telVoice, meetingName);
String welcomeMessage = dynamicConferenceService.processWelcomeMessage(params.welcome == null ? "" : params.welcome, dialNumber, telVoice, meetingName);
// Translate the external meeting id into an internal meeting id.
String internalMeetingId = dynamicConferenceService.getInternalMeetingId(externalMeetingId);
Meeting existing = dynamicConferenceService.getMeeting(internalMeetingId);
if (existing != null) {
log.debug "Existing conference found"
if (existing.getAttendeePassword().equals(viewerPass) && existing.getModeratorPassword().equals(modPass)) {
if (existing.getViewerPassword().equals(viewerPass) && existing.getModeratorPassword().equals(modPass)) {
// trying to create a conference a second time
// return success, but give extra info
uploadDocuments(existing);

View File

@ -59,7 +59,8 @@ public class DynamicConferenceService {
}
public void createMeeting(Meeting meeting) {
meetingService.storeMeeting(meeting)
log.debug("Creating New Meeting...");
meetingService.storeMeeting(meeting);
}
public Meeting getMeeting(String meetingId) {
@ -256,6 +257,7 @@ public class DynamicConferenceService {
}
}
}
return welcomeMessage;
}
public void setMeetingService(MeetingService s) {

316
bigbluebutton-web/pom.xml Normal file
View File

@ -0,0 +1,316 @@
<?xml version="1.0" encoding="utf-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.bigbluebutton</groupId>
<artifactId>bigbluebutton</artifactId>
<packaging>war</packaging>
<version>0.70dev</version>
<name>A custom grails project</name>
<description>A custom grails project</description>
<url>http://www.myorganization.org</url>
<properties>
<grails.version>1.3.7</grails.version>
</properties>
<dependencies>
<dependency>
<groupId>org.grails</groupId>
<artifactId>grails-bootstrap</artifactId>
<version>${grails.version}</version>
<exclusions>
<exclusion>
<groupId>org.codehaus.gpars</groupId>
<artifactId>gpars</artifactId>
</exclusion>
<exclusion>
<groupId>org.codehaus.gant</groupId>
<artifactId>gant_groovy1.7</artifactId>
</exclusion>
<exclusion>
<groupId>org.gparallelizer</groupId>
<artifactId>GParallelizer</artifactId>
</exclusion>
<exclusion>
<groupId>org.codehaus.gant</groupId>
<artifactId>gant_groovy1.6</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.ant</groupId>
<artifactId>ant</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.ant</groupId>
<artifactId>ant-launcher</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.ivy</groupId>
<artifactId>ivy</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.grails</groupId>
<artifactId>grails-crud</artifactId>
<version>${grails.version}</version>
<exclusions>
<exclusion>
<groupId>org.grails</groupId>
<artifactId>grails-docs</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.ant</groupId>
<artifactId>ant</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.ant</groupId>
<artifactId>ant-launcher</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</exclusion>
<exclusion>
<groupId>radeox</groupId>
<artifactId>radeox</artifactId>
</exclusion>
<exclusion>
<groupId>commons-digester</groupId>
<artifactId>commons-digester</artifactId>
</exclusion>
<exclusion>
<groupId>javax.persistence</groupId>
<artifactId>persistence-api</artifactId>
</exclusion>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.grails</groupId>
<artifactId>grails-gorm</artifactId>
<version>${grails.version}</version>
<exclusions>
<exclusion>
<groupId>org.apache.ant</groupId>
<artifactId>ant</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.ant</groupId>
<artifactId>ant-launcher</artifactId>
</exclusion>
<exclusion>
<groupId>commons-digester</groupId>
<artifactId>commons-digester</artifactId>
</exclusion>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
<exclusion>
<groupId>org.hibernate</groupId>
<artifactId>hibernate</artifactId>
</exclusion>
<exclusion>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-annotations</artifactId>
</exclusion>
<exclusion>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-commons-annotations</artifactId>
</exclusion>
<exclusion>
<groupId>antlr</groupId>
<artifactId>antlr</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.grails</groupId>
<artifactId>grails-test</artifactId>
<version>${grails.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
<!-- Grails defaults to Ehache for the second-level Hibernate cache. -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>3.3.1.GA</version>
<exclusions>
<!-- See http://www.slf4j.org/faq.html#IllegalAccessError -->
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
<!-- We are pulling in ehcache-core below -->
<exclusion>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
<version>1.7.1</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- For ease of development and testing, we include the HSQLDB database. -->
<dependency>
<groupId>hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>1.8.0.10</version>
</dependency>
<!-- Use Log4J for logging. This artifact also pulls in the Log4J JAR. -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.5.8</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.5.8</version>
<scope>runtime</scope>
</dependency>
<!-- Needed in the case of AOP usage -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.8</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.8</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.3</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
<dependency>
<groupId>commons-pool</groupId>
<artifactId>commons-pool</artifactId>
<version>1.5.3</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.16</version>
<scope>runtime</scope>
</dependency>
</dependencies>
</dependencyManagement>
<repositories>
<!-- Required to get hold of javassist:javassist -->
<repository>
<id>jboss.org</id>
<name>jboss.org</name>
<url>http://repository.jboss.com/maven2/</url>
</repository>
</repositories>
<build>
<pluginManagement />
<plugins>
<plugin>
<groupId>org.grails</groupId>
<artifactId>grails-maven-plugin</artifactId>
<version>${grails.version}</version>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>init</goal>
<goal>maven-clean</goal>
<goal>validate</goal>
<goal>config-directories</goal>
<goal>maven-compile</goal>
<goal>maven-test</goal>
<goal>maven-war</goal>
<goal>maven-functional-test</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>tools</id>
<activation>
<property>
<name>java.vendor</name>
<value>Sun Microsystems Inc.</value>
</property>
</activation>
<dependencies>
<dependency>
<groupId>com.sun</groupId>
<artifactId>tools</artifactId>
<version>${java.version}</version>
<scope>system</scope>
<systemPath>${java.home}/../lib/tools.jar</systemPath>
</dependency>
</dependencies>
</profile>
</profiles>
</project>

View File

@ -61,10 +61,12 @@ public class MeetingServiceImp implements MeetingService {
}
public Collection<Meeting> getMeetings() {
log.debug("The number of meetings are: "+meetings.size());
return meetings.isEmpty() ? Collections.<Meeting>emptySet() : Collections.unmodifiableCollection(meetings.values());
}
public void storeMeeting(Meeting m) {
log.debug("Storing Meeting with internal id:"+m.getInternalId());
meetings.put(m.getInternalId(), m);
}
@ -102,6 +104,7 @@ public class MeetingServiceImp implements MeetingService {
public void setMessagingService(MessagingService mess) {
messagingService = mess;
messagingService.addListener(new MeetingMessageListener());
messagingService.start();
}
public void setExpiredMeetingCleanupTimerTask(ExpiredMeetingCleanupTimerTask c) {
@ -121,6 +124,7 @@ public class MeetingServiceImp implements MeetingService {
Meeting m = getMeeting(meetingId);
if (m != null) {
m.setStartTime(System.currentTimeMillis());
log.debug("Setting meeting started time...");
}
}
@ -129,11 +133,13 @@ public class MeetingServiceImp implements MeetingService {
Meeting m = getMeeting(meetingId);
if (m != null) {
m.setEndTime(System.currentTimeMillis());
log.debug("Setting meeting end time...");
}
}
@Override
public void userJoined(String meetingId, String userId, String name, String role) {
log.debug("Adding new user...");
Meeting m = getMeeting(meetingId);
if (m != null) {
User user = new User(userId, name, role);
@ -146,6 +152,7 @@ public class MeetingServiceImp implements MeetingService {
Meeting m = getMeeting(meetingId);
if (m != null) {
m.userLeft(userId);
log.debug("Removing user...");
}
}
}

View File

@ -1,7 +1,5 @@
package org.bigbluebutton.api.messaging;
import java.io.IOException;
import java.net.UnknownHostException;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@ -11,22 +9,21 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisException;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPubSub;
public class RedisMessagingService implements MessagingService {
private static Logger log = LoggerFactory.getLogger(RedisMessagingService.class);
private Jedis jedis;
private final String host;
private final int port;
private JedisPool redisPool;
private final Set<MessageListener> listeners = new HashSet<MessageListener>();
private final Executor exec = Executors.newSingleThreadExecutor();
private Runnable pubsubListener;
public RedisMessagingService(String host, int port) {
this.host = host;
this.port = port;
public RedisMessagingService() {
}
@Override
@ -41,12 +38,29 @@ public class RedisMessagingService implements MessagingService {
@Override
public void recordMeetingInfo(String meetingId, Map<String, String> info) {
jedis.hmset("meeting.info:" + meetingId, info);
Jedis jedis=redisPool.getResource();
try{
jedis.hmset("meeting.info:" + meetingId, info);
}catch(JedisException e){
log.error("Cannot record the info meeting: %s",meetingId);
}finally{
redisPool.returnResource(jedis);
}
}
@Override
public void recordMeetingMetadata(String meetingId, Map<String, String> metadata) {
jedis.hmset("meeting:metadata:" + meetingId, metadata);
Jedis jedis=redisPool.getResource();
try{
jedis.hmset("meeting:metadata:" + meetingId, metadata);
}catch(JedisException e){
log.error("Cannot record the metadata meeting: %s",meetingId);
}finally{
redisPool.returnResource(jedis);
}
}
@Override
@ -56,37 +70,48 @@ public class RedisMessagingService implements MessagingService {
@Override
public void send(String channel, String message) {
jedis.publish(channel, message);
Jedis jedis=redisPool.getResource();
try{
jedis.publish(channel, message);
}catch(JedisException e){
log.error("Cannot publish the message %s to redis",message);
}finally{
redisPool.returnResource(jedis);
}
}
@Override
public void start() {
jedis = new Jedis(host, port, 0);
log.debug("Starting redis pubsub...");
final Jedis jedis=redisPool.getResource();
try {
jedis.connect();
pubsubListener = new Runnable() {
public void run() {
jedis.psubscribe(new PubSubListener(), "bigbluebutton:conference:*");
jedis.psubscribe(new PubSubListener(), "bigbluebutton:meeting:*");
}
};
exec.execute(pubsubListener);
} catch (UnknownHostException e) {
log.error("Unknown host[" + host + "]");
} catch (IOException e) {
log.error("Cannot connect to [" + host + ":" + port + "]");
} catch (JedisException e) {
log.error("Cannot subscribe to the redis channel");
}finally{
redisPool.returnResource(jedis);
}
}
@Override
public void stop() {
try {
jedis.disconnect();
} catch (IOException e) {
redisPool.destroy();
} catch (Exception e) {
e.printStackTrace();
}
}
public void setRedisPool(JedisPool redisPool){
this.redisPool=redisPool;
}
/*
* Pubsub channels:
@ -98,10 +123,9 @@ public class RedisMessagingService implements MessagingService {
**/
private class PubSubListener extends JedisPubSub {
private final String PATTERN_CONFERENCE="bigbluebutton:conference:*";
private final String CHANNEL_STATUS="bigbluebutton:conference:status";
private final String CHANNEL_JOIN="bigbluebutton:conference:join";
private final String CHANNEL_LEAVE="bigbluebutton:conference:remove";
private final String PATTERN_MEETING="bigbluebutton:meeting:*";
private final String CHANNEL_STATE="bigbluebutton:meeting:state";
private final String CHANNEL_PARTICIPANTS="bigbluebutton:meeting:participants";
private final String COLON=":";
@ -120,39 +144,51 @@ public class RedisMessagingService implements MessagingService {
System.out.println("redis message received. pattern:" + pattern + " channel:" + channel + " message:" + message);
if(pattern.equalsIgnoreCase(PATTERN_CONFERENCE)){
String[] args = message.split(COLON);
String[] args=message.split(COLON);
if(channel.equalsIgnoreCase(CHANNEL_STATUS)){
//params extract
String meetingId = args[0];
String status = args[1];
if(channel.equalsIgnoreCase(CHANNEL_STATE)){
//params extract
String meetingId=args[0];
String status=args[1];
for (MessageListener listener : listeners) {
if(status.equalsIgnoreCase("started")) {
listener.meetingStarted(meetingId);
} else if(status.equalsIgnoreCase("ended")) {
listener.meetingStarted(meetingId);
}
}
} else if(channel.equalsIgnoreCase(CHANNEL_JOIN)){
//params extract
String meetingId = args[0];
String userId = args[1];
String name = args[2];
String role = args[3];
for (MessageListener listener : listeners) {
listener.userJoined(meetingId, userId, name, role);
}
} else if(channel.equalsIgnoreCase(CHANNEL_LEAVE)){
String meetingId = args[0];
String userId = args[1];
for (MessageListener listener : listeners) {
listener.userLeft(meetingId, userId);
for (MessageListener listener : listeners) {
if(status.equalsIgnoreCase("started")) {
listener.meetingStarted(meetingId);
} else if(status.equalsIgnoreCase("ended")) {
listener.meetingStarted(meetingId);
}
}
}
else if(channel.equalsIgnoreCase(CHANNEL_PARTICIPANTS)){
//params extract
String meetingId=args[0];
String action=args[1];
if(action.equalsIgnoreCase("join")){
String userid=args[2];
String fullname=args[3];
String role=args[4];
for (MessageListener listener : listeners) {
listener.userJoined(meetingId, userid, fullname, role);
}
}
else if(action.equalsIgnoreCase("status")){
String userid=args[2];
String status=args[3];
String value=args[4];
//missing method...
//dynamicConferenceService.participantsUpdatedStatus(roomname, userid, status, value);
}
else if(action.equalsIgnoreCase("left")){
String userid=args[2];
for (MessageListener listener : listeners) {
listener.userLeft(meetingId, userid);
}
}
}
}