package org.red5.server;
/*
* RED5 Open Source Flash Server - http://www.osflash.org/red5
*
* Copyright (c) 2006-2009 by respective authors (see below). All rights reserved.
*
* This library 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.
*
* This library 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 this library; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
import java.util.Collection;
import java.util.Set;
import javax.servlet.ServletContext;
import org.red5.server.api.IApplicationContext;
import org.red5.server.api.IApplicationLoader;
import org.red5.server.api.IConnection;
import org.red5.server.api.IGlobalScope;
import org.red5.server.api.IServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.ServletContextAware;
/**
* Web scope is special scope that is aware of servlet context and represents
* scope of Red5 application in servlet container (or application server) like
* Tomcat, Jetty or JBoss.
*
* Web scope is aware of virtual hosts configuration for Red5 application and is
* the first scope that instantiated after Red5 application gets started.
*
* Then it loads virtual hosts configuration, adds mappings of paths to global
* scope that is injected thru Spring IoC context file and runs initialization
* process.
*
* Red5 server implementation instance and ServletContext are injected as well.
*/
public class WebScope extends Scope implements ServletContextAware {
/**
* Logger
*/
protected static Logger log = LoggerFactory.getLogger(WebScope.class);
/**
* Server instance
*/
protected IServer server;
/**
* Servlet context
*/
protected ServletContext servletContext;
/**
* Context path
*/
protected String contextPath;
/**
* Virtual hosts list as string
*/
protected String virtualHosts;
/**
* Hostnames
*/
protected String[] hostnames;
/**
* Has the web scope been registered?
*/
protected boolean registered;
/**
* The application context this webscope is running in.
*/
protected IApplicationContext appContext;
/**
* Loader for new applications.
*/
protected IApplicationLoader appLoader;
/**
* Is the scope currently shutting down?
*/
protected boolean shuttingDown;
/**
* Setter for global scope. Sets persistence class.
*
* @param globalScope Red5 global scope
*/
public void setGlobalScope(IGlobalScope globalScope) {
// XXX: this is called from nowhere, remove?
super.setParent(globalScope);
try {
setPersistenceClass(globalScope.getStore().getClass().getName());
} catch (Exception error) {
log.error("Could not set persistence class.", error);
}
}
/**
* Web scope has no name
*/
public void setName() {
throw new RuntimeException("Cannot set name, you must set context path");
}
/**
* Can't set parent to Web scope. Web scope is top level.
*/
public void setParent() {
throw new RuntimeException("Cannot set parent, you must set global scope");
}
/**
* Setter for server
*
* @param server Server instance
*/
public void setServer(IServer server) {
log.info("Set server {}", server);
this.server = server;
}
/**
* Servlet context
*
* @param servletContext Servlet context
*/
public void setServletContext(ServletContext servletContext) {
this.servletContext = servletContext;
}
/**
* Setter for context path
*
* @param contextPath Context path
*/
public void setContextPath(String contextPath) {
this.contextPath = contextPath;
super.setName(contextPath.substring(1));
}
/**
* Setter for virtual hosts. Creates array of hostnames.
*
* @param virtualHosts Virtual hosts list as string
*/
public void setVirtualHosts(String virtualHosts) {
this.virtualHosts = virtualHosts;
// Split string into array of vhosts
hostnames = virtualHosts.split(",");
for (int i = 0; i < hostnames.length; i++) {
hostnames[i] = hostnames[i].trim();
if (hostnames[i].equals("*")) {
hostnames[i] = "";
}
}
}
/**
* Map all vhosts to global scope then initialize
*/
public synchronized void register() {
if (registered) {
log.info("Webscope already registered");
return;
}
log.debug("Webscope registering: {}", contextPath);
appContext = LoaderBase.getRed5ApplicationContext(contextPath);
appLoader = LoaderBase.getApplicationLoader();
// Release references
LoaderBase.setRed5ApplicationContext(contextPath, null);
if (hostnames != null && hostnames.length > 0) {
for (String element : hostnames) {
server.addMapping(element, getName(), getParent().getName());
}
}
init();
// We don't want to have configured scopes to get freed when a client
// disconnects.
keepOnDisconnect = true;
registered = true;
}
/**
* Uninitialize and remove all vhosts from the global scope.
*/
public synchronized void unregister() {
if (!registered) {
log.info("Webscope not registered");
return;
}
log.debug("Webscope un-registering: {}", contextPath);
shuttingDown = true;
keepOnDisconnect = false;
uninit();
// We need to disconnect all clients before unregistering
Collection<Set<IConnection>> conns = getConnections();
for (Set<IConnection> set : conns) {
for (IConnection conn : set) {
conn.close();
}
//should we clear the set?
set.clear();
}
//
conns.clear();
//
if (hostnames != null && hostnames.length > 0) {
for (String element : hostnames) {
server.removeMapping(element, getName());
}
}
//check for null
if (appContext == null) {
log.debug("Application context is null, trying retrieve from loader");
appContext = LoaderBase.getRed5ApplicationContext(contextPath);
}
//try to stop the app context
if (appContext != null) {
log.debug("Stopping app context");
appContext.stop();
} else {
log.debug("Application context is null, could not be stopped");
}
// Various cleanup tasks
setStore(null);
setServletContext(null);
setServer(null);
setName(null);
appContext = null;
registered = false;
shuttingDown = false;
//is this needed?
//super.setParent(null);
}
/** {@inheritDoc} */
@Override
public IServer getServer() {
return server;
}
/**
* Return object that can be used to load new applications.
*
* @return the application loader
*/
public IApplicationLoader getApplicationLoader() {
return appLoader;
}
/**
* Is the scope currently shutting down?
*
* @return is shutting down
*/
public boolean isShuttingDown() {
return shuttingDown;
}
}