Package org.bigbluebutton.api

Source Code of org.bigbluebutton.api.MeetingService

/**
* 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 3.0 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.api;

import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.*;
import org.bigbluebutton.api.domain.Meeting;
import org.bigbluebutton.api.domain.Playback;
import org.bigbluebutton.api.domain.Recording;
import org.bigbluebutton.api.domain.User;
import org.bigbluebutton.api.domain.UserSession;
import org.bigbluebutton.api.messaging.MessageListener;
import org.bigbluebutton.api.messaging.MessagingConstants;
import org.bigbluebutton.api.messaging.MessagingService;
import org.bigbluebutton.api.messaging.ReceivedMessage;
import org.bigbluebutton.api.messaging.messages.CreateMeeting;
import org.bigbluebutton.api.messaging.messages.EndMeeting;
import org.bigbluebutton.api.messaging.messages.IMessage;
import org.bigbluebutton.api.messaging.messages.MeetingDestroyed;
import org.bigbluebutton.api.messaging.messages.MeetingEnded;
import org.bigbluebutton.api.messaging.messages.MeetingStarted;
import org.bigbluebutton.api.messaging.messages.RegisterUser;
import org.bigbluebutton.api.messaging.messages.RemoveExpiredMeetings;
import org.bigbluebutton.api.messaging.messages.UserJoined;
import org.bigbluebutton.api.messaging.messages.UserLeft;
import org.bigbluebutton.api.messaging.messages.UserStatusChanged;
import org.bigbluebutton.web.services.ExpiredMeetingCleanupTimerTask;
import org.bigbluebutton.web.services.KeepAliveService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;

public class MeetingService implements MessageListener {
  private static Logger log = LoggerFactory.getLogger(MeetingService.class);

  private BlockingQueue<IMessage> receivedMessages = new LinkedBlockingQueue<IMessage>()
  private volatile boolean processMessage = false;
 
  private final Executor msgProcessorExec = Executors.newSingleThreadExecutor();
  private final Executor runExec = Executors.newSingleThreadExecutor();
 
  /**
   * http://ria101.wordpress.com/2011/12/12/concurrenthashmap-avoid-a-common-misuse/
   */
  private final ConcurrentMap<String, Meeting> meetings; 
  private final ConcurrentMap<String, UserSession> sessions;
   
  private int defaultMeetingExpireDuration = 1
  private int defaultMeetingCreateJoinDuration = 5;
  private RecordingService recordingService;
  private MessagingService messagingService;
  private ExpiredMeetingCleanupTimerTask cleaner;
  private boolean removeMeetingWhenEnded = false;

  public MeetingService() {
    meetings = new ConcurrentHashMap<String, Meeting>(8, 0.9f, 1)
    sessions = new ConcurrentHashMap<String, UserSession>(8, 0.9f, 1);   
  }
 
  public void addUserSession(String token, UserSession user) {
    log.debug("Adding user [" + user.fullname + "] token=[" + token + "] to meeting [" + user.meetingID + "]");
    sessions.put(token, user);
  }
 
  public void registerUser(String meetingID, String internalUserId, String fullname, String role, String externUserID, String authToken) {
    handle(new RegisterUser(meetingID, internalUserId, fullname, role, externUserID, authToken));
  }
 
  public UserSession getUserSession(String token) {
    return sessions.get(token);
  }
 
  public UserSession removeUserSession(String token) {
    log.debug("Removing user token [" + token + "]");
    UserSession user = sessions.remove(token);
    if (user != null) {
      log.debug("Found user [" + user.fullname + "] token=[" + token + "] to meeting [" + user.meetingID + "]");
    }
    return user;
  }
   
  /**
   * Remove the meetings that have ended from the list of
   * running meetings.
   */
  public void removeExpiredMeetings() {
    log.debug("Trigger cleaning up expired meetings");
    handle(new RemoveExpiredMeetings());
  }
 
  private void kickOffProcessingOfRecording(Meeting m) {
    if (m.isRecord() && m.getNumUsers() == 0) {
      log.info("Kick-off processing of recording for meeting [id={} , name={}]", m.getInternalId(), m.getName());   
     
      Map<String, Object> logData = new HashMap<String, Object>();
      logData.put("meetingId", m.getInternalId());
      logData.put("externalMeetingId", m.getExternalId());
      logData.put("name", m.getName());
      logData.put("event", "kick_off_ingest_and_processing");
      logData.put("description", "Start processing of recording.");
     
      Gson gson = new Gson();
      String logStr =  gson.toJson(logData);
     
      log.info("Initiate recording processing: data={}", logStr);
     
      processRecording(m.getInternalId());
    }        
  }
 
  private void processMeetingForRemoval(Meeting m) {
    kickOffProcessingOfRecording(m);       
    destroyMeeting(m.getInternalId());         
    meetings.remove(m.getInternalId());   
    removeUserSessions(m.getInternalId());
  }
 
  private void removeUserSessions(String meetingId) {
    log.debug("Cleaning up user sessions for meeting [" + meetingId + "]");
    Iterator<Map.Entry<String, UserSession>> iterator = sessions.entrySet().iterator();
    while(iterator.hasNext()){
       Map.Entry<String, UserSession> entry = iterator.next();      
       UserSession userSession = entry.getValue();
       log.debug("Got user [" + userSession.fullname + "] from meeting [" + userSession.conferencename + "]");
       if (userSession.meetingID.equals(meetingId)) {
         log.debug("Removing user [" + userSession.fullname + "] from meeting [" + userSession.conferencename + "]");
         iterator.remove();
       } else {
         log.debug("Not Removing user [" + userSession.fullname + "] from meeting [" + userSession.conferencename + "]");
       }
    }
  }
 
  private void checkAndRemoveExpiredMeetings() {
    log.debug("Cleaning up expired meetings");
    for (Meeting m : meetings.values()) {
      if (m.hasExpired(defaultMeetingExpireDuration) ) {
        log.info("Meeting [id={} , name={}] has expired.", m.getInternalId(), m.getName());
       
        Map<String, Object> logData = new HashMap<String, Object>();
        logData.put("meetingId", m.getInternalId());
        logData.put("externalMeetingId", m.getExternalId());
        logData.put("name", m.getName());
        logData.put("event", "removing_meeting");
        logData.put("description", "Meeting has expired.");
       
        Gson gson = new Gson();
        String logStr =  gson.toJson(logData);
       
        log.info("Removing meeting: data={}", logStr);
       
        processMeetingForRemoval(m);
        continue;
      } else {
        log.debug("Meeting [id={} , name={}] has not expired yet.", m.getInternalId(), m.getName());
      }
     
      if (m.isForciblyEnded()) {
        log.info("Meeting [id={} , name={}] has been forcefully ended.", m.getInternalId(), m.getName());
       
        Map<String, Object> logData = new HashMap<String, Object>();
        logData.put("meetingId", m.getInternalId());
        logData.put("externalMeetingId", m.getExternalId());
        logData.put("name", m.getName());
        logData.put("event", "removing_meeting");
        logData.put("description", "Meeting forcefully ended.");
       
        Gson gson = new Gson();
        String logStr =  gson.toJson(logData);
       
        log.info("Removing meeting: data={}", logStr);
        processMeetingForRemoval(m);     
        continue;
      }
     
      if (m.wasNeverJoined(defaultMeetingCreateJoinDuration)) {
        log.info("No user has joined the meeting [id={} , name={}]. Removing it.", m.getInternalId(), m.getName());
       
        Map<String, Object> logData = new HashMap<String, Object>();
        logData.put("meetingId", m.getInternalId());
        logData.put("externalMeetingId", m.getExternalId());
        logData.put("name", m.getName());
        logData.put("event", "removing_meeting");
        logData.put("description", "Meeting has not been joined.");
       
        Gson gson = new Gson();
        String logStr =  gson.toJson(logData);
       
        log.info("Removing meeting: data={}", logStr);
       
        destroyMeeting(m.getInternalId());     
        meetings.remove(m.getInternalId());
        continue;
      }
     
      if (m.hasExceededDuration()) {
        log.info("Meeting [id={} , name={}] has ran past duration. Ending it.", m.getInternalId(), m.getName());
       
        Map<String, Object> logData = new HashMap<String, Object>();
        logData.put("meetingId", m.getInternalId());
        logData.put("externalMeetingId", m.getExternalId());
        logData.put("name", m.getName());
        logData.put("event", "removing_meeting");
        logData.put("description", "Meeting exceeded duration.");
       
        Gson gson = new Gson();
        String logStr =  gson.toJson(logData);
       
        log.info("Removing meeting: data={}", logStr);
       
        endMeeting(m.getInternalId());
      }     
    }   
  }
 
  private void destroyMeeting(String meetingID) {
    messagingService.destroyMeeting(meetingID);
  }
 
  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 createMeeting(Meeting m) {
    handle(new CreateMeeting(m));
//    handleCreateMeeting(m);
  }

  private void handleCreateMeeting(Meeting m) {
    log.info("Storing Meeting with internalId=[" + m.getInternalId() + "], externalId=["
              + m.getExternalId() + "], name=[" + m.getName() + "], duration=["
              + m.getDuration() + "], record=[" + m.isRecord() + "]");

    meetings.put(m.getInternalId(), m);
    if (m.isRecord()) {
      Map<String,String> metadata = new LinkedHashMap<String,String>();
      metadata.putAll(m.getMetadata());
      //TODO: Need a better way to store these values for recordings
      metadata.put("meetingId", m.getExternalId());
      metadata.put("meetingName", m.getName());
     
      messagingService.recordMeetingInfo(m.getInternalId(), metadata);
    }

    Map<String, Object> logData = new HashMap<String, Object>();
    logData.put("meetingId", m.getInternalId());
    logData.put("externalMeetingId", m.getExternalId());
    logData.put("name", m.getName());
    logData.put("duration", m.getDuration());
    logData.put("record", m.isRecord());
    logData.put("event", "create_meeting");
    logData.put("description", "Create meeting.");
   
    Gson gson = new Gson();
    String logStr =  gson.toJson(logData);
   
    log.info("Create meeting: data={}", logStr);
   
    messagingService.createMeeting(m.getInternalId(), m.getName(), m.isRecord(),
         m.getTelVoice(), m.getDuration(), m.getAutoStartRecording(), m.getAllowStartStopRecording());     
  }
 
  private void processCreateMeeting(CreateMeeting message) {
    handleCreateMeeting(message.meeting);
  }
 
  private void processRegisterUser(RegisterUser message) {
    messagingService.registerUser(message.meetingID, message.internalUserId, message.fullname, message.role, message.externUserID, message.authToken);
  }
 
  public String addSubscription(String meetingId, String event, String callbackURL){
    log.debug("Add a new subscriber");
    String sid = messagingService.storeSubscription(meetingId, event, callbackURL);
    return sid;
  }

  public boolean removeSubscription(String meetingId, String subscriptionId){
    return messagingService.removeSubscription(meetingId, subscriptionId);
  }

  public List<Map<String,String>> listSubscriptions(String meetingId){
    return messagingService.listSubscriptions(meetingId);
  }

  public Meeting getMeeting(String meetingId) {
    if (meetingId == null)
      return null;
    for (String key : meetings.keySet()) {
      if (key.startsWith(meetingId))
        return (Meeting) meetings.get(key);
    }
   
    return null;
  }

  public Collection<Meeting> getMeetingsWithId(String meetingId) {
    if (meetingId == null) return Collections.<Meeting>emptySet();
   
    Collection<Meeting> m = new HashSet<Meeting>();
   
    for (String key : meetings.keySet()) {
      if (key.startsWith(meetingId))
        m.add(meetings.get(key));
    }   
   
    return m;
  }
 
  public Meeting getNotEndedMeetingWithId(String meetingId) {
    if (meetingId == null)
      return null;
    for (String key : meetings.keySet()) {
      if (key.startsWith(meetingId)) {
        Meeting m = (Meeting) meetings.get(key);
        if (! m.isForciblyEnded()) return m;
      }
    }
   
    return null;
  }
 
  public HashMap<String,Recording> getRecordings(ArrayList<String> idList) {
    //TODO: this method shouldn't be used
    HashMap<String,Recording> recs= reorderRecordings(recordingService.getRecordings(idList));
    return recs;
  }
 
  public HashMap<String,Recording> reorderRecordings(ArrayList<Recording> olds){
    HashMap<String,Recording> map= new HashMap<String, Recording>();
    for (Recording r:olds) {
      if (!map.containsKey(r.getId())) {
        Map<String,String> meta= r.getMetadata();
        String mid = meta.remove("meetingId");
        String name = meta.remove("meetingName");
       
        r.setMeetingID(mid);
        r.setName(name);

        ArrayList<Playback> plays = new ArrayList<Playback>();
       
        plays.add(new Playback(r.getPlaybackFormat(), r.getPlaybackLink(),
            getDurationRecording(r.getPlaybackDuration(),
                r.getEndTime(), r.getStartTime()),
            r.getPlaybackExtensions()));
        r.setPlaybacks(plays);
        map.put(r.getId(), r);
      } else {
        Recording rec = map.get(r.getId());
        rec.getPlaybacks().add(new Playback(r.getPlaybackFormat(), r.getPlaybackLink(),
            getDurationRecording(r.getPlaybackDuration(),
                r.getEndTime(), r.getStartTime()),
            r.getPlaybackExtensions()));
      }
    }
   
    return map;
  }
 
  private int getDurationRecording(String playbackDuration, String end, String start) {
    int duration;
    try {
      if (!playbackDuration.equals("")) {
        duration = (int)Math.ceil((Long.parseLong(playbackDuration))/60000.0);
      } else {
        duration = (int)Math.ceil((Long.parseLong(end) - Long.parseLong(start))/60000.0);
      }
    } catch(Exception e){
      log.debug(e.getMessage());
      duration = 0;
    }
   
    return duration;
  }
 
  public boolean existsAnyRecording(ArrayList<String> idList){
    return recordingService.existAnyRecording(idList);
  }
 
  public void setPublishRecording(ArrayList<String> idList,boolean publish){
    for(String id:idList){
      recordingService.publish(id,publish);
    }
  }
 
  public void deleteRecordings(ArrayList<String> idList){
    for(String id:idList){
      recordingService.delete(id);
    }
  }
 
  public void processRecording(String meetingId) {
    log.debug("Process recording for [{}]", meetingId);
    recordingService.startIngestAndProcessing(meetingId);
  }
   
  public boolean isMeetingWithVoiceBridgeExist(String voiceBridge) {
/*    Collection<Meeting> confs = meetings.values();
    for (Meeting c : confs) {
          if (voiceBridge == c.getVoiceBridge()) {
            return true;
          }
    }
*/    return false;
  }
 
  public void send(String channel, String message) {
    messagingService.send(channel, message);
  }

  public void createdPolls(String meetingId, String title, String question, String questionType, ArrayList<String> answers){
    messagingService.sendPolls(meetingId, title, question, questionType, answers);
  }
 
  public void endMeeting(String meetingId) {   
    log.info("Received request to end meeting=[{}]", meetingId);
    handle(new EndMeeting(meetingId));
  }
 
  private void processEndMeeting(EndMeeting message) {
    log.info("Received EndMeeting request from the API for meeting=[{}]", message.meetingId);
    messagingService.endMeeting(message.meetingId);
   
    Meeting m = getMeeting(message.meetingId);
    if (m != null) {
      m.setForciblyEnded(true);
      if (removeMeetingWhenEnded) {
              processRecording(m.getInternalId());
        destroyMeeting(m.getInternalId());         
              meetings.remove(m.getInternalId());   
              removeUserSessions(m.getInternalId());
      }
    } else {
      log.debug("endMeeting - meeting doesn't exist: " + message.meetingId);
    }   
  }
 
  public void addUserCustomData(String meetingId, String userID, Map<String,String> userCustomData){
    Meeting m = getMeeting(meetingId);
    if (m != null){
      m.addUserCustomData(userID, userCustomData);
    }
  }

  private void meetingStarted(MeetingStarted message) {
    log.debug("Meeting [{}] has started.", message.meetingId);
    Meeting m = getMeeting(message.meetingId);
    if (m != null) {
      if (m.getStartTime() == 0) {
        long now = System.currentTimeMillis();
        log.info("Meeting [{}] has started on [{}]", message.meetingId, now);
        m.setStartTime(now);
       
        Map<String, Object> logData = new HashMap<String, Object>();
        logData.put("meetingId", m.getInternalId());
        logData.put("externalMeetingId", m.getExternalId());
        logData.put("name", m.getName());
        logData.put("duration", m.getDuration());
        logData.put("record", m.isRecord());
        logData.put("event", "meeting_started");
        logData.put("description", "Meeting has started.");
       
        Gson gson = new Gson();
        String logStr =  gson.toJson(logData);
       
        log.info("Meeting started: data={}", logStr);
       
      } else {
        log.debug("The meeting [{}] has been started again...", message.meetingId);
       
        Map<String, Object> logData = new HashMap<String, Object>();
        logData.put("meetingId", m.getInternalId());
        logData.put("externalMeetingId", m.getExternalId());
        logData.put("name", m.getName());
        logData.put("duration", m.getDuration());
        logData.put("record", m.isRecord());
        logData.put("event", "meeting_restarted");
        logData.put("description", "Meeting has restarted.");
       
        Gson gson = new Gson();
        String logStr =  gson.toJson(logData);
       
        log.info("Meeting restarted: data={}", logStr);
      }
      return;
    }
    log.warn("The meeting [{}] doesn't exist", message.meetingId);
  }

  private void meetingEnded(MeetingEnded message) {
    log.debug("Meeting [{}] has ended.", message.meetingId);
    Meeting m = getMeeting(message.meetingId);
    if (m != null) {
      long now = System.currentTimeMillis();
      log.debug("Meeting [{}] end time [{}].", message.meetingId, now);
      m.setEndTime(now);
     
      Map<String, Object> logData = new HashMap<String, Object>();
      logData.put("meetingId", m.getInternalId());
      logData.put("externalMeetingId", m.getExternalId());
      logData.put("name", m.getName());
      logData.put("duration", m.getDuration());
      logData.put("record", m.isRecord());
      logData.put("event", "meeting_ended");
      logData.put("description", "Meeting has ended.");
     
      Gson gson = new Gson();
      String logStr =  gson.toJson(logData);
     
      log.info("Meeting ended: data={}", logStr);
     
      return;
    }
    log.warn("The meeting " + message.meetingId + " doesn't exist");
  }

  private void userJoined(UserJoined message) {
    log.debug("User joined in meeting[{}]", message.meetingId);
    Meeting m = getMeeting(message.meetingId);
    if (m != null) {
      User user = new User(message.userId, message.externalUserId, message.name, message.role);
      m.userJoined(user);
      log.info("New user in meeting [" + message.meetingId + "] user [" + user.getFullname() + "]");
     
      Map<String, Object> logData = new HashMap<String, Object>();
      logData.put("meetingId", m.getInternalId());
      logData.put("externalMeetingId", m.getExternalId());
      logData.put("name", m.getName());
      logData.put("userId", message.userId);
      logData.put("externalUserId", user.getExternalUserId());
      logData.put("username", user.getFullname());
      logData.put("role", user.getRole());     
      logData.put("event", "user_joined_meeting");
      logData.put("description", "User had joined the meeting.");
     
      Gson gson = new Gson();
      String logStr =  gson.toJson(logData);
     
      log.info("User joined meeting: data={}", logStr);
     
      return;
    }
    log.warn("The meeting " + message.meetingId + " doesn't exist");
  }

  private void userLeft(UserLeft message) {
    log.debug("User left from meeting[{}]", message.meetingId);
    Meeting m = getMeeting(message.meetingId);
    if (m != null) {
      User user = m.userLeft(message.userId);
      if(user != null){
        log.info("User removed from meeting [" + message.meetingId + "] user [" + user.getFullname() + "]");
       
        Map<String, Object> logData = new HashMap<String, Object>();
        logData.put("meetingId", m.getInternalId());
        logData.put("externalMeetingId", m.getExternalId());
        logData.put("name", m.getName());
        logData.put("userId", message.userId);
        logData.put("externalUserId", user.getExternalUserId());
        logData.put("username", user.getFullname());
        logData.put("role", user.getRole());     
        logData.put("event", "user_joined_meeting");
        logData.put("description", "User had joined the meeting.");
       
        Gson gson = new Gson();
        String logStr =  gson.toJson(logData);
       
        log.info("User left meeting: data={}", logStr);
       
        return;
      }
      log.warn("The participant " + message.userId + " doesn't exist in the meeting " + message.meetingId);
      return;
    }
    log.warn("The meeting " + message.meetingId + " doesn't exist");
  }
   
  private void updatedStatus(UserStatusChanged message) {
    Meeting m = getMeeting(message.meetingId);
    if (m != null) {
      User user = m.getUserById(message.userId);
      if(user != null){
        user.setStatus(message.status, message.value);
        log.info("Setting new status value in meeting " + message.meetingId + " for participant:" + user.getFullname());
        return;
      }
      log.warn("The participant " + message.userId + " doesn't exist in the meeting " + message.meetingId);
      return;
    }
    log.warn("The meeting " + message.meetingId + " doesn't exist");
  }

  private void processMessage(final IMessage message) {
    Runnable task = new Runnable() {
      public void run() {
        if (message instanceof MeetingDestroyed) {
         
        } else if (message instanceof MeetingStarted) {
          meetingStarted((MeetingStarted)message);
        } else if (message instanceof MeetingEnded) {
          log.info("Processing meeting ended request.");
          meetingEnded((MeetingEnded)message);
        } else if (message instanceof UserJoined) {
          log.info("Processing user joined message.");
          userJoined((UserJoined)message);
        } else if (message instanceof UserLeft) {
          log.info("Processing user left message.");
          userLeft((UserLeft)message);
        } else if (message instanceof UserStatusChanged) {
          updatedStatus((UserStatusChanged)message);
        } else if (message instanceof RemoveExpiredMeetings) {
          checkAndRemoveExpiredMeetings();
        } else if (message instanceof CreateMeeting) {
          processCreateMeeting((CreateMeeting)message);
        } else if (message instanceof EndMeeting) {
          log.info("Processing end meeting request.");
          processEndMeeting((EndMeeting)message);
        } else if (message instanceof RegisterUser) {
          processRegisterUser((RegisterUser) message);
       
      }
    };
   
    runExec.execute(task);
  }

  @Override
  public void handle(IMessage message) {
      receivedMessages.add(message);   
  }
 
  public void start() {
    log.info("Starting Meeting Service.");
    try {
      processMessage = true;
      Runnable messageReceiver = new Runnable() {
          public void run() {
            while (processMessage) {
              try {
                IMessage msg = receivedMessages.take();
                processMessage(msg);                
              } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
              } catch (Exception e) {
                log.error("Handling unexpected exception [{}]", e.toString());
              }
            }
          }
      };
     
      msgProcessorExec.execute(messageReceiver);
    } catch (Exception e) {
      log.error("Error PRocessing Message");
    }
  }
 
  public void stop() {
    processMessage = false;
    cleaner.stop();
  }
 
  public void setDefaultMeetingCreateJoinDuration(int expiration) {
    this.defaultMeetingCreateJoinDuration = expiration;
  }
 
  public void setDefaultMeetingExpireDuration(int meetingExpiration) {
    this.defaultMeetingExpireDuration = meetingExpiration;
  }

  public void setRecordingService(RecordingService s) {
    recordingService = s;
  }
 
  public void setMessagingService(MessagingService mess) {
    messagingService = mess;
  }
 
  public void setExpiredMeetingCleanupTimerTask(ExpiredMeetingCleanupTimerTask c) {
    cleaner = c;
    cleaner.setMeetingService(this);
    cleaner.start();
  }
 
  public void setRemoveMeetingWhenEnded(boolean s) {
    removeMeetingWhenEnded = s;
  }
}
TOP

Related Classes of org.bigbluebutton.api.MeetingService

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.