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); } } } }