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.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.red5.server.api.IBasicScope;
import org.red5.server.api.IScope;
import org.red5.server.api.ScopeUtils;
import org.red5.server.api.event.IEvent;
import org.red5.server.api.event.IEventListener;
import org.red5.server.api.scheduling.IScheduledJob;
import org.red5.server.api.scheduling.ISchedulingService;
/**
* Generalizations of one of main Red5 object types, Scope.
* Basic scope is a persistable attribute store with event handling functionality
*
* @see org.red5.server.api.IScope
* @see org.red5.server.Scope
*/
public abstract class BasicScope extends PersistableAttributeStore implements
IBasicScope {
/**
* Parent scope. Scopes can be nested.
*
* @see org.red5.server.api.IScope
*/
protected IScope parent;
/**
* List of event listeners
*/
protected Set<IEventListener> listeners;
/**
* Scope persistence storage type
*/
protected String persistenceClass;
/**
* Set to true to prevent the scope from being freed upon disconnect.
*/
protected boolean keepOnDisconnect = false;
/**
* Set to amount of time (in seconds) the scope will be kept before being freed,
* after the last disconnect.
*/
protected int keepDelay = 0;
/**
* Constructor for basic scope
*
* @param parent Parent scope
* @param type Scope type
* @param name Scope name. Used to identify scopes in application, must be unique among scopes of one level
* @param persistent Whether scope is persistent
*/
public BasicScope(IScope parent, String type, String name,
boolean persistent) {
super(type, name, null, persistent);
this.parent = parent;
this.listeners = new HashSet<IEventListener>();
}
/**
* {@inheritDoc}
*/
public boolean hasParent() {
return true;
}
/**
*{@inheritDoc}
*/
public IScope getParent() {
return parent;
}
/**
*{@inheritDoc}
*/
public int getDepth() {
return parent.getDepth() + 1;
}
/**
*{@inheritDoc}
*/
@Override
public String getPath() {
return parent.getPath() + '/' + parent.getName();
}
/**
* Sets the amount of time to keep the scope available after the
* last disconnect.
*
* @param keepDelay delay
*/
public void setKeepDelay(int keepDelay) {
this.keepDelay = keepDelay;
}
/**
* Add event listener to list of notified objects
* @param listener Listening object
*/
public void addEventListener(IEventListener listener) {
listeners.add(listener);
}
/**
* Remove event listener from list of listeners
* @param listener Listener to remove
*/
public void removeEventListener(IEventListener listener) {
listeners.remove(listener);
if (ScopeUtils.isRoom(this) && listeners.isEmpty()) {
if (!keepOnDisconnect && keepDelay > 0) {
// create a job to keep alive for n seconds
ISchedulingService schedulingService = (ISchedulingService) parent.getContext().getBean(
ISchedulingService.BEAN_NAME);
schedulingService.addScheduledOnceJob(keepDelay * 1000, new KeepAliveJob(this));
} else if (!keepOnDisconnect) {
// delete empty rooms
parent.removeChildScope(this);
}
}
}
/**
* Return listeners list iterator
*
* @return Listeners list iterator
*/
public Iterator<IEventListener> getEventListeners() {
return listeners.iterator();
}
/**
* Handles event. To be implemented in subclass realization
*
* @param event Event context
* @return Event handling result
*/
public boolean handleEvent(IEvent event) {
// do nothing.
return false;
}
/**
* Notifies listeners on event. Current implementation is empty. To be implemented in subclass realization
* @param event Event to broadcast
*/
public void notifyEvent(IEvent event) {
}
/**
* Dispatches event (notifies all listeners)
*
* @param event Event to dispatch
*/
public void dispatchEvent(IEvent event) {
for (IEventListener listener : listeners) {
if (event.getSource() == null || event.getSource() != listener) {
listener.notifyEvent(event);
}
}
}
/**
* Getter for subscopes list iterator. Returns null because this is a base implementation
*
* @return Iterator for subscopes
*/
public Iterator<IBasicScope> iterator() {
return null;
}
/**
* Iterator for basic scope
*/
public class EmptyBasicScopeIterator implements Iterator<IBasicScope> {
/** {@inheritDoc} */
public boolean hasNext() {
return false;
}
/** {@inheritDoc} */
public IBasicScope next() {
return null;
}
/** {@inheritDoc} */
public void remove() {
// nothing
}
}
/**
* Keeps the scope alive for a set number of seconds. This should
* fulfill the APPSERVER-165 improvement.
*/
private class KeepAliveJob implements IScheduledJob {
private IBasicScope scope = null;
KeepAliveJob(IBasicScope scope) {
this.scope = scope;
}
public void execute(ISchedulingService service) {
if (listeners.isEmpty()) {
// delete empty rooms
parent.removeChildScope(scope);
}
}
}
}