diff --git a/client/pom.xml b/client/pom.xml
index 2def3a12b..1f2ad3bc9 100644
--- a/client/pom.xml
+++ b/client/pom.xml
@@ -3,7 +3,7 @@
org.red5
red5-parent
- 1.3.30
+ 1.3.31
4.0.0
red5-client
diff --git a/client/src/main/java/org/red5/client/Red5Client.java b/client/src/main/java/org/red5/client/Red5Client.java
index 2c9f61801..985592904 100644
--- a/client/src/main/java/org/red5/client/Red5Client.java
+++ b/client/src/main/java/org/red5/client/Red5Client.java
@@ -18,7 +18,7 @@ public final class Red5Client {
/**
* Current server version with revision
*/
- public static final String VERSION = "Red5 Client 1.3.30";
+ public static final String VERSION = "Red5 Client 1.3.31";
/**
* Create a new Red5Client object using the connection local to the current thread A bit of magic that lets you access the red5 scope
diff --git a/client/src/main/java/org/red5/client/net/rtmp/BaseRTMPClientHandler.java b/client/src/main/java/org/red5/client/net/rtmp/BaseRTMPClientHandler.java
index a3e7867f0..bcad639ed 100644
--- a/client/src/main/java/org/red5/client/net/rtmp/BaseRTMPClientHandler.java
+++ b/client/src/main/java/org/red5/client/net/rtmp/BaseRTMPClientHandler.java
@@ -541,7 +541,7 @@ public void invoke(String method, Object[] params, IPendingServiceCallback callb
*/
@Override
public void disconnect() {
- log.debug("disconnect: {}", conn);
+ log.debug("disconnect - connection: {}", conn);
if (conn != null) {
streamDataList.clear();
conn.close();
diff --git a/common/pom.xml b/common/pom.xml
index 1ea3a1e97..3e8a8962f 100644
--- a/common/pom.xml
+++ b/common/pom.xml
@@ -3,7 +3,7 @@
org.red5
red5-parent
- 1.3.30
+ 1.3.31
4.0.0
red5-server-common
@@ -113,7 +113,7 @@
net.engio
mbassador
- 1.3.30
+ 1.3.31
-->
junit
diff --git a/common/src/main/java/org/red5/server/api/Red5.java b/common/src/main/java/org/red5/server/api/Red5.java
index a7da45f8a..b9db2c797 100644
--- a/common/src/main/java/org/red5/server/api/Red5.java
+++ b/common/src/main/java/org/red5/server/api/Red5.java
@@ -57,12 +57,12 @@ public final class Red5 {
/**
* Server version with revision
*/
- public static final String VERSION = "Red5 Server 1.3.30";
+ public static final String VERSION = "Red5 Server 1.3.31";
/**
* Server version for fmsVer requests
*/
- public static final String FMS_VERSION = "RED5/1,3,30,0";
+ public static final String FMS_VERSION = "RED5/1,3,31,0";
/**
* Server capabilities
diff --git a/io/pom.xml b/io/pom.xml
index 85f9c267d..005d9bdff 100644
--- a/io/pom.xml
+++ b/io/pom.xml
@@ -3,7 +3,7 @@
org.red5
red5-parent
- 1.3.30
+ 1.3.31
4.0.0
red5-io
diff --git a/pom.xml b/pom.xml
index ad51276ad..16b3ea918 100644
--- a/pom.xml
+++ b/pom.xml
@@ -24,7 +24,7 @@
Red5
The Red5 server
org.red5
- 1.3.30
+ 1.3.31
https://github.com/Red5/red5-server
2005
@@ -105,7 +105,7 @@
1.62
2.0.23
- 5.3.32
+ 5.3.33
8.5.95
[4.13.1,)
1.9.39
@@ -514,7 +514,7 @@
org.sonatype.plugins
nexus-staging-maven-plugin
- 1.6.8
+ 1.6.13
true
ossrh
@@ -524,7 +524,7 @@
maven-gpg-plugin
- 1.6
+ 3.2.1
sign-artifacts
diff --git a/server/pom.xml b/server/pom.xml
index 77edd3e8d..2fd86ca87 100644
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -3,7 +3,7 @@
org.red5
red5-parent
- 1.3.30
+ 1.3.31
4.0.0
red5-server
diff --git a/server/src/main/java/org/red5/net/websocket/WebSocketPlugin.java b/server/src/main/java/org/red5/net/websocket/WebSocketPlugin.java
index 95d2b90dc..771d47d27 100644
--- a/server/src/main/java/org/red5/net/websocket/WebSocketPlugin.java
+++ b/server/src/main/java/org/red5/net/websocket/WebSocketPlugin.java
@@ -82,7 +82,6 @@ public WebSocketPlugin() {
/** {@inheritDoc} */
@Override
public void doStart() throws Exception {
- super.doStart();
log.trace("WebSocketPlugin start");
// add scope listener to allow creation of websocket scopes
scopeListener = new ScopeListenerAdapter() {
@@ -136,7 +135,6 @@ public void doStop() throws Exception {
});
managerMap.clear();
executor.shutdownNow();
- super.doStop();
}
/**
diff --git a/server/src/main/java/org/red5/server/plugin/PluginRegistry.java b/server/src/main/java/org/red5/server/plugin/PluginRegistry.java
index f565cab04..1bd5ee0e5 100644
--- a/server/src/main/java/org/red5/server/plugin/PluginRegistry.java
+++ b/server/src/main/java/org/red5/server/plugin/PluginRegistry.java
@@ -10,9 +10,6 @@
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.red5.logging.Red5LoggerFactory;
import org.red5.server.api.plugin.IRed5Plugin;
@@ -30,16 +27,27 @@ public class PluginRegistry {
// keeps track of plug-ins, keyed by plug-in name
private static volatile ConcurrentMap plugins = new ConcurrentHashMap<>(3, 0.9f, 1);
- // locks for guarding plug-ins
- private final static ReadWriteLock pluginLock = new ReentrantReadWriteLock();
-
- private final static Lock pluginReadLock;
-
- private final static Lock pluginWriteLock;
+ /**
+ * Returns true if the plug-in is registered.
+ *
+ * @param plugin
+ * plugin
+ * @return true if the plug-in is registered
+ */
+ public static boolean isRegistered(IRed5Plugin plugin) {
+ String pluginName = plugin.getName();
+ return plugins.containsKey(pluginName);
+ }
- static {
- pluginReadLock = pluginLock.readLock();
- pluginWriteLock = pluginLock.writeLock();
+ /**
+ * Returns true if the plug-in is registered.
+ *
+ * @param pluginName
+ * plugin name
+ * @return true if the plug-in is registered
+ */
+ public static boolean isRegistered(String pluginName) {
+ return plugins.containsKey(pluginName);
}
/**
@@ -51,27 +59,21 @@ public class PluginRegistry {
public static void register(IRed5Plugin plugin) {
log.debug("Register plugin: {}", plugin);
String pluginName = plugin.getName();
- //get a write lock
- pluginWriteLock.lock();
- try {
- if (plugins.containsKey(pluginName)) {
- //get old plugin
- IRed5Plugin oldPlugin = plugins.get(pluginName);
- //if they are not the same shutdown the older one
- if (!plugin.equals(oldPlugin)) {
- try {
- oldPlugin.doStop();
- } catch (Exception e) {
- log.warn("Exception caused when stopping old plugin", e);
- }
- //replace old one
- plugins.replace(pluginName, plugin);
+ if (plugins.containsKey(pluginName)) {
+ //get old plugin
+ IRed5Plugin oldPlugin = plugins.get(pluginName);
+ //if they are not the same shutdown the older one
+ if (!plugin.equals(oldPlugin)) {
+ try {
+ oldPlugin.doStop();
+ } catch (Exception e) {
+ log.warn("Exception caused when stopping old plugin", e);
}
- } else {
- plugins.put(pluginName, plugin);
+ //replace old one
+ plugins.replace(pluginName, plugin);
}
- } finally {
- pluginWriteLock.unlock();
+ } else {
+ plugins.put(pluginName, plugin);
}
}
@@ -83,30 +85,24 @@ public static void register(IRed5Plugin plugin) {
*/
public static void unregister(IRed5Plugin plugin) {
log.debug("Unregister plugin: {}", plugin);
- //get a write lock
- pluginWriteLock.lock();
- try {
- if (plugins.containsValue(plugin)) {
- boolean removed = false;
- for (Entry f : plugins.entrySet()) {
- if (plugin.equals(f.getValue())) {
- log.debug("Removing {}", plugin);
- plugins.remove(f.getKey());
- removed = true;
- break;
- } else {
- log.debug("Not equal - {} {}", plugin, f.getValue());
- }
- }
- if (!removed) {
- log.debug("Last try to remove the plugin");
- plugins.remove(plugin.getName());
+ if (plugins.containsValue(plugin)) {
+ boolean removed = false;
+ for (Entry f : plugins.entrySet()) {
+ if (plugin.equals(f.getValue())) {
+ log.debug("Removing {}", plugin);
+ plugins.remove(f.getKey());
+ removed = true;
+ break;
+ } else {
+ log.debug("Not equal - {} {}", plugin, f.getValue());
}
- } else {
- log.warn("Plugin is not registered {}", plugin);
}
- } finally {
- pluginWriteLock.unlock();
+ if (!removed) {
+ log.debug("Last try to remove the plugin");
+ plugins.remove(plugin.getName());
+ }
+ } else {
+ log.warn("Plugin is not registered {}", plugin);
}
}
@@ -118,13 +114,7 @@ public static void unregister(IRed5Plugin plugin) {
* @return requested plug-in matching the name given or null if not found
*/
public static IRed5Plugin getPlugin(String pluginName) {
- IRed5Plugin plugin = null;
- pluginReadLock.lock();
- try {
- plugin = plugins.get(pluginName);
- } finally {
- pluginReadLock.unlock();
- }
+ IRed5Plugin plugin = plugins.get(pluginName);
return plugin;
}
@@ -136,23 +126,18 @@ public static IRed5Plugin getPlugin(String pluginName) {
*/
public static void shutdown() throws Exception {
log.info("Destroying and cleaning up {} plugins", plugins.size());
- //loop through the plugins and stop them
- pluginReadLock.lock();
- try {
- for (Entry pluginEntry : plugins.entrySet()) {
- IRed5Plugin plugin = pluginEntry.getValue();
- try {
- plugin.doStop();
- } catch (Exception ex) {
- if (plugin != null) {
- log.warn("Plugin stop failed for: {}", plugin.getName(), ex);
- } else {
- log.warn("Plugin stop failed", ex);
- }
+ // loop through the plugins and stop them
+ for (Entry pluginEntry : plugins.entrySet()) {
+ IRed5Plugin plugin = pluginEntry.getValue();
+ try {
+ plugin.doStop();
+ } catch (Exception ex) {
+ if (plugin != null) {
+ log.warn("Plugin stop failed for: {}", plugin.getName(), ex);
+ } else {
+ log.warn("Plugin stop failed", ex);
}
}
- } finally {
- pluginReadLock.unlock();
}
plugins.clear();
}
diff --git a/server/src/main/java/org/red5/server/service/ShutdownServer.java b/server/src/main/java/org/red5/server/service/ShutdownServer.java
index 66bfd4d23..6f7e1f03a 100644
--- a/server/src/main/java/org/red5/server/service/ShutdownServer.java
+++ b/server/src/main/java/org/red5/server/service/ShutdownServer.java
@@ -89,8 +89,12 @@ public class ShutdownServer implements ApplicationContextAware, InitializingBean
// whether the server is shutdown
private AtomicBoolean shutdown = new AtomicBoolean(false);
- // single thread executor for the internal startup / server
- private ExecutorService executor = Executors.newSingleThreadExecutor();
+ // thread executor for the internal startup and shutdown
+ private ExecutorService executor = Executors.newFixedThreadPool(2, r -> {
+ Thread t = new Thread(r, "ShutdownServer-" + r.hashCode());
+ t.setDaemon(true);
+ return t;
+ });
// reference to the runnable
private Future> future;
@@ -110,10 +114,8 @@ public void afterPropertiesSet() throws Exception {
} catch (Exception e) {
}
// start blocks, so it must be on its own thread
- future = executor.submit(new Runnable() {
- public void run() {
- start();
- }
+ future = executor.submit(() -> {
+ start();
});
}
@@ -196,30 +198,30 @@ public void start() {
private void shutdownOrderly() {
// shutdown internal listener
- shutdown.compareAndSet(false, true);
- // shutdown the plug-in launcher
- try {
- log.debug("Attempting to shutdown plugin registry");
- PluginRegistry.shutdown();
- } catch (Exception e) {
- log.warn("Exception shutting down plugin registry", e);
- }
- // shutdown the context loader
- if (contextLoader != null) {
- log.debug("Attempting to shutdown context loader");
- contextLoader.shutdown();
- contextLoader = null;
- }
- // shutdown the jee server
- if (jeeServer != null) {
- // destroy is a DisposibleBean method not LoaderBase
- // jeeServer.destroy();
- jeeServer = null;
- }
- // attempt to kill the contexts
- final CountDownLatch latch = new CountDownLatch(3);
- new Thread(new Runnable() {
- public void run() {
+ if (shutdown.compareAndSet(false, true)) {
+ log.info("Shutdown server shutdown");
+ // shutdown the plug-in launcher
+ try {
+ log.debug("Attempting to shutdown plugin registry");
+ PluginRegistry.shutdown();
+ } catch (Exception e) {
+ log.warn("Exception shutting down plugin registry", e);
+ }
+ // shutdown the context loader
+ if (contextLoader != null) {
+ log.debug("Attempting to shutdown context loader");
+ contextLoader.shutdown();
+ contextLoader = null;
+ }
+ // shutdown the jee server
+ if (jeeServer != null) {
+ // destroy is a DisposibleBean method not LoaderBase
+ // jeeServer.destroy();
+ jeeServer = null;
+ }
+ // attempt to kill the contexts
+ final CountDownLatch latch = new CountDownLatch(3);
+ executor.submit(() -> {
try {
log.debug("Attempting to close core context");
((ConfigurableApplicationContext) coreContext).close();
@@ -227,10 +229,8 @@ public void run() {
} catch (Exception e) {
e.printStackTrace();
}
- }
- }).start();
- new Thread(new Runnable() {
- public void run() {
+ });
+ executor.submit(() -> {
try {
log.debug("Attempting to close common context");
((ConfigurableApplicationContext) commonContext).close();
@@ -238,10 +238,8 @@ public void run() {
} catch (Exception e) {
e.printStackTrace();
}
- }
- }).start();
- new Thread(new Runnable() {
- public void run() {
+ });
+ executor.submit(() -> {
try {
log.debug("Attempting to close app context");
((ConfigurableApplicationContext) applicationContext).close();
@@ -249,19 +247,22 @@ public void run() {
} catch (Exception e) {
e.printStackTrace();
}
+ });
+ try {
+ if (latch.await(shutdownDelay, TimeUnit.SECONDS)) {
+ log.info("Application contexts are closed");
+ } else {
+ log.info("One or more contexts didn't close in the allotted time");
+ }
+ } catch (InterruptedException e) {
+ log.error("Exception attempting to close app contexts", e);
+ } finally {
+ // shutdown the executor
+ executor.shutdown();
}
- }).start();
- try {
- if (latch.await(shutdownDelay, TimeUnit.SECONDS)) {
- log.info("Application contexts are closed");
- } else {
- log.info("One or more contexts didn't close in the allotted time");
- }
- } catch (InterruptedException e) {
- log.error("Exception attempting to close app contexts", e);
+ // exit
+ System.exit(0);
}
- // exit
- System.exit(0);
}
public void setPort(int port) {
diff --git a/server/src/main/java/org/red5/server/tomcat/TomcatLoader.java b/server/src/main/java/org/red5/server/tomcat/TomcatLoader.java
index fb76908cf..b573a6391 100644
--- a/server/src/main/java/org/red5/server/tomcat/TomcatLoader.java
+++ b/server/src/main/java/org/red5/server/tomcat/TomcatLoader.java
@@ -181,9 +181,10 @@ public void afterPropertiesSet() throws Exception {
WebSocketPlugin plugin = new WebSocketPlugin();
plugin.setApplicationContext(applicationContext);
plugin.setServer(server);
- // start it up and register it
- plugin.doStart();
+ // register it
PluginRegistry.register(plugin);
+ // start it
+ plugin.doStart();
}
start();
}
@@ -866,14 +867,17 @@ public void destroy() throws Exception {
} else {
log.error("Error getting Spring bean factory for shutdown");
}
- try {
+ // no need to stop the websocket plugin if it is not registered
+ if (PluginRegistry.isRegistered(WebSocketPlugin.NAME)) {
// stop websocket
- WebSocketPlugin plugin = (WebSocketPlugin) PluginRegistry.getPlugin(WebSocketPlugin.NAME);
- if (plugin != null) {
- plugin.doStop();
+ try {
+ WebSocketPlugin plugin = (WebSocketPlugin) PluginRegistry.getPlugin(WebSocketPlugin.NAME);
+ if (plugin != null) {
+ plugin.doStop();
+ }
+ } catch (Exception e) {
+ log.warn("WebSocket plugin stop, failed", e);
}
- } catch (Exception e) {
- log.warn("WebSocket plugin stop, failed", e);
}
try {
// stop tomcat
diff --git a/service/pom.xml b/service/pom.xml
index 9cbef4099..bb77afb1b 100644
--- a/service/pom.xml
+++ b/service/pom.xml
@@ -3,7 +3,7 @@
org.red5
red5-parent
- 1.3.30
+ 1.3.31
4.0.0
red5-service
diff --git a/servlet/pom.xml b/servlet/pom.xml
index d6868eda3..4a8dbc5c0 100644
--- a/servlet/pom.xml
+++ b/servlet/pom.xml
@@ -3,7 +3,7 @@
org.red5
red5-parent
- 1.3.30
+ 1.3.31
4.0.0
red5-servlet