/* * RED5 Open Source Flash Server - https://github.com/red5 * * Copyright 2006-2015 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.net.websocket; import java.util.Collection; import java.util.Collections; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; import org.red5.net.websocket.listener.IWebSocketDataListener; import org.red5.net.websocket.model.WSMessage; import org.red5.server.api.scope.IScope; import org.red5.server.plugin.PluginRegistry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; /** * WebSocketScope contains an IScope and keeps track of WebSocketConnection and IWebSocketDataListener instances. * * @author Paul Gregoire (mondain@gmail.com) */ public class WebSocketScope implements InitializingBean, DisposableBean { private static Logger log = LoggerFactory.getLogger(WebSocketScope.class); protected CopyOnWriteArraySet<WebSocketConnection> conns = new CopyOnWriteArraySet<>(); protected CopyOnWriteArraySet<IWebSocketDataListener> listeners = new CopyOnWriteArraySet<>(); protected IScope scope; protected String path = "default"; public WebSocketScope() { } public WebSocketScope(IScope scope) { log.debug("Creating WebSocket scope for: {}", scope); setScope(scope); setPath(String.format("/%s", scope.getName())); } @Override public void afterPropertiesSet() throws Exception { register(); } @Override public void destroy() throws Exception { unregister(); } /** * Registers with the WebSocketScopeManager. */ public void register() { log.info("Application scope: {}", scope); // set the logger to the app scope //log = Red5LoggerFactory.getLogger(WebSocketScope.class, scope.getName()); WebSocketScopeManager manager = ((WebSocketPlugin) PluginRegistry.getPlugin("WebSocketPlugin")).getManager(scope); manager.setApplication(scope); log.info("WebSocket app added: {}", scope.getName()); manager.addWebSocketScope(this); log.info("WebSocket scope added"); } /** * Un-registers from the WebSocketScopeManager. */ public void unregister() { // clean up the connections by first closing them for (WebSocketConnection conn : conns) { conn.close(); } conns.clear(); // clean up the listeners by first stopping them for (IWebSocketDataListener listener : listeners) { listener.stop(); } listeners.clear(); } /** * Returns the set of connections. * * @return conns */ public Set<WebSocketConnection> getConns() { return conns; } /** * Returns the associated scope. * * @return scope */ public IScope getScope() { return scope; } /** * Sets the associated scope. * * @param scope */ public void setScope(IScope scope) { this.scope = scope; // set this ws scope as an attribute for ez lookup this.scope.setAttribute(Constants.SCOPE, this); } /** * Sets the path. * * @param path */ public void setPath(String path) { this.path = path; // /room/name } /** * Returns the path of the scope. * * @return path */ public String getPath() { return path; } /** * Add new connection on scope. * * @param conn * WebSocketConnection */ public void addConnection(WebSocketConnection conn) { conns.add(conn); for (IWebSocketDataListener listener : listeners) { listener.onWSConnect(conn); } } /** * Remove connection from scope. * * @param conn * WebSocketConnection */ public void removeConnection(WebSocketConnection conn) { conns.remove(conn); for (IWebSocketDataListener listener : listeners) { listener.onWSDisconnect(conn); } } /** * Add new listener on scope. * * @param listener * IWebSocketDataListener */ public void addListener(IWebSocketDataListener listener) { log.info("addListener: {}", listener); listeners.add(listener); } /** * Remove listener from scope. * * @param listener * IWebSocketDataListener */ public void removeListener(IWebSocketDataListener listener) { log.info("removeListener: {}", listener); listeners.remove(listener); } /** * Add new listeners on scope. * * @param listeners * list of IWebSocketDataListener */ public void setListeners(Collection<IWebSocketDataListener> listeners) { log.trace("setListeners: {}", listeners); this.listeners.addAll(listeners); } /** * Returns the listeners in an unmodifiable set. * * @return listeners */ public Set<IWebSocketDataListener> getListeners() { return Collections.unmodifiableSet(listeners); } /** * Check the scope state. * * @return true:still have relation */ public boolean isValid() { return (conns.size() + listeners.size()) > 0; } /** * Message received from client and passed on to the listeners. * * @param message */ public void onMessage(WSMessage message) { log.trace("Listeners: {}", listeners.size()); for (IWebSocketDataListener listener : listeners) { try { listener.onWSMessage(message); } catch (Exception e) { log.warn("onMessage exception", e); } } } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((path == null) ? 0 : path.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; WebSocketScope other = (WebSocketScope) obj; if (path == null) { if (other.path != null) return false; } else if (!path.equals(other.path)) return false; return true; } @Override public String toString() { return "WebSocketScope [path=" + path + ", listeners=" + listeners.size() + ", connections=" + conns.size() + "]"; } }