Package org.red5.server.scope

Source Code of org.red5.server.scope.BasicScope$KeepAliveJob

/*
* RED5 Open Source Flash Server - http://code.google.com/p/red5/
*
* Copyright 2006-2014 by respective authors (see below). All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.red5.server.scope;

import java.beans.ConstructorProperties;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;

import org.red5.server.api.event.IEvent;
import org.red5.server.api.event.IEventListener;
import org.red5.server.api.persistence.IPersistenceStore;
import org.red5.server.api.scheduling.IScheduledJob;
import org.red5.server.api.scheduling.ISchedulingService;
import org.red5.server.api.scope.IBasicScope;
import org.red5.server.api.scope.IScope;
import org.red5.server.api.scope.ScopeType;
import org.red5.server.util.ScopeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Generalizations of one of main Red5 object types, Scope.
*
* @see org.red5.server.api.scope.IScope
* @see org.red5.server.scope.Scope
*/
public abstract class BasicScope implements IBasicScope, Comparable<BasicScope> {

  protected static Logger log = LoggerFactory.getLogger(BasicScope.class);

  /**
   * Parent scope. Scopes can be nested.
   *
   * @see org.red5.server.api.scope.IScope
   */
  protected IScope parent;

  /**
   * Scope type.
   *
   * @see org.red5.server.api.scope.ScopeType
   */
  protected ScopeType type = ScopeType.UNDEFINED;

  /**
   * String identifier for this scope
   */
  protected String name;

  /**
   * Creation timestamp
   */
  protected long creation;

  /**
   * Whether or not to persist attributes
   */
  protected boolean persistent;

  /**
   * Storage for persistable attributes
   */
  protected IPersistenceStore store;

  /**
   * Scope persistence storage type
   */
  protected String persistenceClass;

  /**
   * Set to true to prevent the scope from being freed upon disconnect.
   */
  protected boolean keepOnDisconnect;

  /**
   * Set to amount of time (in seconds) the scope will be kept before being freed, after the last disconnect.
   */
  protected int keepDelay = 0;

  /**
   * List of event listeners
   */
  protected CopyOnWriteArraySet<IEventListener> listeners;

  /**
   * Scheduled job name for keep alive check
   */
  private String keepAliveJobName;

  /**
   * Creates unnamed scope
   */
  @ConstructorProperties(value = { "" })
  public BasicScope() {
    this.creation = System.nanoTime();
  }

  /**
   * 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
   */
  @ConstructorProperties({ "parent", "type", "name", "persistent" })
  public BasicScope(IScope parent, ScopeType type, String name, boolean persistent) {
    this.parent = parent;
    this.type = type;
    this.name = name;
    this.persistent = persistent;
    this.listeners = new CopyOnWriteArraySet<IEventListener>();
    this.creation = System.nanoTime();
  }

  /**
   * {@inheritDoc}
   */
  public boolean hasParent() {
    return true;
  }

  /**
   *{@inheritDoc}
   */
  public IScope getParent() {
    return parent;
  }

  /**
   * @return the type
   */
  public ScopeType getType() {
    return type;
  }

  /**
   * @return the name
   */
  public String getName() {
    return name;
  }

  /**
   * @return the store
   */
  public IPersistenceStore getStore() {
    return store;
  }

  /**
   *{@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;
  }

  /**
   * Validates a scope based on its name and type
   *
   * @return true if both name and type are valid, false otherwise
   */
  public boolean isValid() {
    // to be valid a scope must have a type set other than undefined and its name will be set
    return (type != null && !type.equals(ScopeType.UNDEFINED) && (name != null && !("").equals(name)));
  }

  /**
   * Add event listener to list of notified objects
   * @param listener        Listening object
   * @return true if listener is added and false otherwise
   */
  public boolean addEventListener(IEventListener listener) {
    log.debug("addEventListener - scope: {} {}", getName(), listener);
    return listeners.add(listener);
  }

  /**
   * Remove event listener from list of listeners
   * @param listener            Listener to remove
   * @return true if listener is removed and false otherwise
   */
  public boolean removeEventListener(IEventListener listener) {
    log.debug("removeEventListener - scope: {} {}", getName(), listener);
    if (log.isTraceEnabled()) {
      log.trace("Listeners - check #1: {}", listeners);
    }
    boolean removed = listeners.remove(listener);
    if (!keepOnDisconnect) {
      if (removed && keepAliveJobName == null) {
        if (ScopeUtils.isRoom(this) && listeners.isEmpty()) {
          // create job to kill the scope off if no listeners join within the delay
          ISchedulingService schedulingService = (ISchedulingService) parent.getContext().getBean(ISchedulingService.BEAN_NAME);
          // by default keep a scope around for a fraction of a second
          keepAliveJobName = schedulingService.addScheduledOnceJob((keepDelay > 0 ? keepDelay * 1000 : 100), new KeepAliveJob(this));
        }
      }
    } else {
      log.trace("Scope: {} is exempt from removal when empty", getName());
    }
    if (log.isTraceEnabled()) {
      log.trace("Listeners - check #2: {}", listeners);
    }   
    return removed;
  }

  /**
   * Return listeners list iterator
   *
   * @return  Listeners list iterator
   */
  public Set<IEventListener> getEventListeners() {
    return Collections.unmodifiableSet(listeners);
  }

  /**
   * Returns true if there are event listeners attached to
   * this scope.
   *
   * @return true if it has listeners; else false.
   */
  public boolean hasEventListeners() {
    return !listeners.isEmpty();
  }

  /**
   * Handles event. To be implemented in subclass realization
   *
   * @param event          Event context
   * @return               Event handling result
   */
  public boolean handleEvent(IEvent event) {
    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);
      }
    }
  }

  /**
   * Hash code is based on the scope's name and type
   *
   * @return hash code
   */
  public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((name == null) ? 0 : name.hashCode());
    result = prime * result + ((type == null) ? 0 : type.hashCode());
    return result;
  }

  /**
   * Equality is based on the scope's name and type
   *
   * @param obj
   */
  public boolean equals(Object obj) {
    if (this == obj) {
      return true;
    }
    if (obj == null) {
      return false;
    }
    if (getClass() != obj.getClass()) {
      return false;
    }
    BasicScope other = (BasicScope) obj;
    if (hashCode() != other.hashCode()) {
      return false;
    }
    return true;
  }

  public int compareTo(BasicScope that) {
    if (this.equals(that)) {
      return 0;
    }
    return name.compareTo(that.getName());
  }

  /**
   * Keeps the scope alive for a set number of seconds.
   */
  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
        log.trace("Removing {} from {}", scope.getName(), parent.getName());
        parent.removeChildScope(scope);
      }
      keepAliveJobName = null;
    }

  }

}
TOP

Related Classes of org.red5.server.scope.BasicScope$KeepAliveJob

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.