/*
* Jitsi Videobridge, OpenSource video conferencing.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jitsi.jicofo.openfire;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.impl.protocol.jabber.extensions.colibri.*;
import net.java.sip.communicator.util.*;
import org.slf4j.*;
import org.slf4j.Logger;
import org.jitsi.jicofo.*;
import org.jitsi.jicofo.osgi.*;
import org.jitsi.jicofo.xmpp.ConferenceIq;
import org.jitsi.jicofo.xmpp.ConferenceIqProvider;
import org.jitsi.jicofo.xmpp.IQUtils;
import org.jitsi.util.*;
import org.jivesoftware.smack.packet.*;
import org.osgi.framework.*;
import org.xmpp.component.*;
import org.xmpp.packet.IQ;
public class FocusComponent extends AbstractComponent
{
private static final Logger Log = LoggerFactory.getLogger(FocusComponent.class);
/**
* Indicates if the focus is anonymous user or authenticated system admin.
*/
private final boolean isFocusAnonymous;
/**
* Optional password for focus user authentication. If authenticated login
* is used we expect focus user to have admin privileges, so that it has
* explicit moderator rights. Also in this case focus component will always
* return 'ready=true' status, so that users don't have to wait for
* the focus to create the room. If focus is authenticated and is not
* an admin then will refuse to join MUC room.
*/
/**
* The manager object that creates and expires
* {@link org.jitsi.jicofo.JitsiMeetConference}s.
*/
private FocusManager focusManager;
/**
* Creates new instance of <tt>FocusComponent</tt>.
* @param anonymousFocus indicates if the focus user is anonymous.
*/
public FocusComponent(boolean anonymousFocus)
{
this.isFocusAnonymous = anonymousFocus;
new ConferenceIqProvider();
new ColibriIQProvider();
}
/**
* Initializes this component.
*/
public void init()
{
Log.info("Focus Manager init");
this.focusManager = ServiceUtils.getService(FocusBundleActivator.bundleContext, FocusManager.class);
focusManager.start();
}
/**
* Releases resources used by this instance.
*/
public void dispose()
{
focusManager.stop();
}
/**
* Called as part of the execution of {@link AbstractComponent#shutdown()}
* to enable this <tt>Component</tt> to finish cleaning resources up after
* it gets completely shutdown.
*
* @see AbstractComponent#postComponentShutdown()
*/
@Override
public void postComponentShutdown()
{
super.postComponentShutdown();
OSGi.stop();
dispose();
}
/**
* Called as part of the execution of {@link AbstractComponent#start()} to
* enable this <tt>Component</tt> to finish initializing resources after it
* gets completely started.
*
* @see AbstractComponent#postComponentStart()
*/
@Override
public void postComponentStart()
{
super.postComponentStart();
FocusBundleActivator activator = new FocusBundleActivator()
{
@Override
public void start(BundleContext bundleContext) throws Exception
{
}
@Override
public void stop(BundleContext bundleContext) throws Exception
{
// TODO Auto-generated method stub
}
};
OSGi.start(activator);
init();
}
@Override
public String getDescription()
{
return "Manages Jitsi Meet conferences";
}
@Override
public String getName()
{
return "Jitsi Meet Focus";
}
/**
* {@inheritDoc}
*/
@Override
protected String[] discoInfoFeatureNamespaces()
{
return
new String[]
{
ConferenceIq.NAMESPACE
};
}
@Override
protected IQ handleIQGet(IQ iq) throws Exception
{
Log.info("handleIQGet\n" + iq);
try
{
org.jivesoftware.smack.packet.IQ smackIq = IQUtils.convert(iq);
if (smackIq instanceof ColibriStatsIQ)
{
Log.info("handleIQGet ColibriStatsIQ " + smackIq);
// Supports only empty colibri queries
ColibriStatsIQ colibriStatsQuery
= (ColibriStatsIQ) smackIq;
// Reply with stats
ColibriStatsIQ statsReply = new ColibriStatsIQ();
statsReply.setType(
org.jivesoftware.smack.packet.IQ.Type.RESULT);
statsReply.setPacketID(iq.getID());
statsReply.setTo(iq.getFrom().toString());
int conferenceCount = focusManager.getConferenceCount();
// Return conference count
statsReply.addStat(
new ColibriStatsExtension.Stat(
"conferences",
Integer.toString(conferenceCount)));
statsReply.addStat(
new ColibriStatsExtension.Stat(
"graceful_shutdown",
focusManager.isShutdownInProgress()
? "true" : "false"));
return IQUtils.convert(statsReply);
}
else
{
return super.handleIQGet(iq);
}
}
catch (Exception e)
{
Log.error("handleIQGet", e);
throw e;
}
}
/**
* Handles an <tt>org.xmpp.packet.IQ</tt> stanza of type <tt>set</tt> which
* represents a request.
*
* @param iq the <tt>org.xmpp.packet.IQ</tt> stanza of type <tt>set</tt>
* which represents the request to handle
* @return an <tt>org.xmpp.packet.IQ</tt> stanza which represents the
* response to the specified request or <tt>null</tt> to reply with
* <tt>feature-not-implemented</tt>
* @throws Exception to reply with <tt>internal-server-error</tt> to the
* specified request
* @see AbstractComponent#handleIQSet(IQ)
*/
@Override
public IQ handleIQSet(IQ iq) throws Exception
{
Log.info("handleIQSet\n" + iq);
try
{
org.jivesoftware.smack.packet.IQ smackIq = IQUtils.convert(iq);
if (focusManager != null && smackIq instanceof ConferenceIq)
{
ConferenceIq query = (ConferenceIq) smackIq;
ConferenceIq response = new ConferenceIq();
String room = query.getRoom();
Log.info("Focus request for room: " + room);
if (focusManager.isShutdownInProgress() && focusManager.getConference(room) == null)
{
// Service unavailable
org.jivesoftware.smack.packet.IQ smackReply = ColibriConferenceIQ.createGracefulShutdownErrorResponse(query);
// Fix error responses
return IQUtils.convert(smackReply);
}
boolean ready = focusManager.conferenceRequest(room, query.getPropertiesMap());
if (!isFocusAnonymous)
{
// Focus is authenticated system admin, so we let
// them in immediately. Focus will get OWNER anyway.
ready = true;
}
response.setType(org.jivesoftware.smack.packet.IQ.Type.RESULT);
response.setPacketID(query.getPacketID());
response.setFrom(query.getTo());
response.setTo(query.getFrom());
response.setRoom(query.getRoom());
response.setReady(ready);
return IQUtils.convert(response);
}
else
{
return super.handleIQSet(iq);
}
}
catch (Exception e)
{
Log.error("handleIQSet", e);
throw e;
}
}
}