/**
* 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.web.services;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import org.bigbluebutton.api.messaging.MessageListener;
import org.bigbluebutton.api.messaging.MessagingService;
import org.bigbluebutton.api.messaging.messages.IMessage;
import org.bigbluebutton.api.messaging.messages.KeepAliveReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class KeepAliveService implements MessageListener {
private static Logger log = LoggerFactory.getLogger(KeepAliveService.class);
private final String KEEP_ALIVE_REQUEST = "KEEP_ALIVE_REQUEST";
private MessagingService service;
private long runEvery = 10000;
private int maxLives = 5;
private KeepAliveTask task = new KeepAliveTask();
private volatile boolean processMessages = false;
volatile boolean available = false;
private static final Executor msgSenderExec = Executors.newFixedThreadPool(1);
private static final Executor runExec = Executors.newFixedThreadPool(1);
private ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(1);
private BlockingQueue<KeepAliveMessage> messages = new LinkedBlockingQueue<KeepAliveMessage>();
private Long lastKeepAliveMessage = 0L;
private final String SYSTEM = "BbbWeb";
public void start() {
scheduledThreadPool.scheduleWithFixedDelay(task, 5000, runEvery, TimeUnit.MILLISECONDS);
processKeepAliveMessage();
}
public void stop() {
processMessages = false;
scheduledThreadPool.shutdownNow();
}
public void setRunEvery(long v) {
runEvery = v * 1000;
}
public void setMessagingService(MessagingService service){
this.service = service;
}
class KeepAliveTask implements Runnable {
public void run() {
KeepAlivePing ping = new KeepAlivePing();
queueMessage(ping);
}
}
public boolean isDown(){
return !available;
}
private void queueMessage(KeepAliveMessage msg) {
messages.add(msg);
}
private void processKeepAliveMessage() {
processMessages = true;
Runnable sender = new Runnable() {
public void run() {
while (processMessages) {
KeepAliveMessage message;
try {
message = messages.take();
processMessage(message);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
log.error("Catching exception [{}]", e.toString());
}
}
}
};
msgSenderExec.execute(sender);
}
private void processMessage(final KeepAliveMessage msg) {
Runnable task = new Runnable() {
public void run() {
if (msg instanceof KeepAlivePing) {
processPing((KeepAlivePing) msg);
} else if (msg instanceof KeepAlivePong) {
processPong((KeepAlivePong) msg);
}
}
};
runExec.execute(task);
}
private void processPing(KeepAlivePing msg) {
service.sendKeepAlive(SYSTEM, System.currentTimeMillis());
Boolean akkaAppsIsAvailable = available;
if (lastKeepAliveMessage != 0 && (System.currentTimeMillis() - lastKeepAliveMessage > 30000)) {
if (akkaAppsIsAvailable) {
log.error("BBB Web pubsub error!");
// BBB-Apps has gone down. Mark it as unavailable. (ralam - april 29, 2014)
available = false;
}
}
}
private void processPong(KeepAlivePong msg) {
if (lastKeepAliveMessage != 0 && !available) {
log.error("BBB Web pubsub recovered!");
}
lastKeepAliveMessage = System.currentTimeMillis();
available = true;
}
private void handleKeepAliveReply(String system, Long timestamp) {
if (system.equals("BbbWeb")) {
KeepAlivePong pong = new KeepAlivePong(system, timestamp);
queueMessage(pong);
}
}
@Override
public void handle(IMessage message) {
if (message instanceof KeepAliveReply) {
KeepAliveReply msg = (KeepAliveReply) message;
handleKeepAliveReply(msg.system, msg.timestamp);
}
}
}