#3771: Make PluginManager methods thread safe

This commit is contained in:
BoomEaro 2025-01-29 20:38:20 +11:00 committed by md_5
parent 80bb237289
commit b5ae0196fc
No known key found for this signature in database
GPG Key ID: E8E901AC7C617C11

View File

@ -23,6 +23,10 @@ import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.Stack; import java.util.Stack;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.jar.JarEntry; import java.util.jar.JarEntry;
import java.util.jar.JarFile; import java.util.jar.JarFile;
import java.util.logging.Level; import java.util.logging.Level;
@ -59,6 +63,9 @@ public final class PluginManager
private final Multimap<Plugin, Command> commandsByPlugin = ArrayListMultimap.create(); private final Multimap<Plugin, Command> commandsByPlugin = ArrayListMultimap.create();
private final Multimap<Plugin, Listener> listenersByPlugin = ArrayListMultimap.create(); private final Multimap<Plugin, Listener> listenersByPlugin = ArrayListMultimap.create();
private final ReadWriteLock commandsLock = new ReentrantReadWriteLock();
private final Lock listenersLock = new ReentrantLock();
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public PluginManager(ProxyServer proxy) public PluginManager(ProxyServer proxy)
{ {
@ -92,6 +99,9 @@ public final class PluginManager
* @param command the command to register * @param command the command to register
*/ */
public void registerCommand(Plugin plugin, Command command) public void registerCommand(Plugin plugin, Command command)
{
commandsLock.writeLock().lock();
try
{ {
commandMap.put( command.getName().toLowerCase( Locale.ROOT ), command ); commandMap.put( command.getName().toLowerCase( Locale.ROOT ), command );
for ( String alias : command.getAliases() ) for ( String alias : command.getAliases() )
@ -99,6 +109,10 @@ public final class PluginManager
commandMap.put( alias.toLowerCase( Locale.ROOT ), command ); commandMap.put( alias.toLowerCase( Locale.ROOT ), command );
} }
commandsByPlugin.put( plugin, command ); commandsByPlugin.put( plugin, command );
} finally
{
commandsLock.writeLock().unlock();
}
} }
/** /**
@ -107,9 +121,16 @@ public final class PluginManager
* @param command the command to unregister * @param command the command to unregister
*/ */
public void unregisterCommand(Command command) public void unregisterCommand(Command command)
{
commandsLock.writeLock().lock();
try
{ {
while ( commandMap.values().remove( command ) ); while ( commandMap.values().remove( command ) );
commandsByPlugin.values().remove( command ); commandsByPlugin.values().remove( command );
} finally
{
commandsLock.writeLock().unlock();
}
} }
/** /**
@ -118,6 +139,9 @@ public final class PluginManager
* @param plugin the plugin to register the commands of * @param plugin the plugin to register the commands of
*/ */
public void unregisterCommands(Plugin plugin) public void unregisterCommands(Plugin plugin)
{
commandsLock.writeLock().lock();
try
{ {
for ( Iterator<Command> it = commandsByPlugin.get( plugin ).iterator(); it.hasNext(); ) for ( Iterator<Command> it = commandsByPlugin.get( plugin ).iterator(); it.hasNext(); )
{ {
@ -125,6 +149,10 @@ public final class PluginManager
while ( commandMap.values().remove( command ) ); while ( commandMap.values().remove( command ) );
it.remove(); it.remove();
} }
} finally
{
commandsLock.writeLock().unlock();
}
} }
private Command getCommandIfEnabled(String commandName, CommandSender sender) private Command getCommandIfEnabled(String commandName, CommandSender sender)
@ -137,7 +165,14 @@ public final class PluginManager
return null; return null;
} }
commandsLock.readLock().lock();
try
{
return commandMap.get( commandLower ); return commandMap.get( commandLower );
} finally
{
commandsLock.readLock().unlock();
}
} }
/** /**
@ -433,6 +468,9 @@ public final class PluginManager
* @param listener the listener to register events for * @param listener the listener to register events for
*/ */
public void registerListener(Plugin plugin, Listener listener) public void registerListener(Plugin plugin, Listener listener)
{
listenersLock.lock();
try
{ {
for ( Method method : listener.getClass().getDeclaredMethods() ) for ( Method method : listener.getClass().getDeclaredMethods() )
{ {
@ -441,6 +479,10 @@ public final class PluginManager
} }
eventBus.register( listener ); eventBus.register( listener );
listenersByPlugin.put( plugin, listener ); listenersByPlugin.put( plugin, listener );
} finally
{
listenersLock.unlock();
}
} }
/** /**
@ -449,9 +491,16 @@ public final class PluginManager
* @param listener the listener to unregister * @param listener the listener to unregister
*/ */
public void unregisterListener(Listener listener) public void unregisterListener(Listener listener)
{
listenersLock.lock();
try
{ {
eventBus.unregister( listener ); eventBus.unregister( listener );
listenersByPlugin.values().remove( listener ); listenersByPlugin.values().remove( listener );
} finally
{
listenersLock.unlock();
}
} }
/** /**
@ -460,12 +509,19 @@ public final class PluginManager
* @param plugin target plugin * @param plugin target plugin
*/ */
public void unregisterListeners(Plugin plugin) public void unregisterListeners(Plugin plugin)
{
listenersLock.lock();
try
{ {
for ( Iterator<Listener> it = listenersByPlugin.get( plugin ).iterator(); it.hasNext(); ) for ( Iterator<Listener> it = listenersByPlugin.get( plugin ).iterator(); it.hasNext(); )
{ {
eventBus.unregister( it.next() ); eventBus.unregister( it.next() );
it.remove(); it.remove();
} }
} finally
{
listenersLock.unlock();
}
} }
/** /**
@ -474,8 +530,15 @@ public final class PluginManager
* @return commands * @return commands
*/ */
public Collection<Map.Entry<String, Command>> getCommands() public Collection<Map.Entry<String, Command>> getCommands()
{
commandsLock.readLock().lock();
try
{ {
return Collections.unmodifiableCollection( commandMap.entrySet() ); return Collections.unmodifiableCollection( commandMap.entrySet() );
} finally
{
commandsLock.readLock().unlock();
}
} }
boolean isTransitiveDepend(PluginDescription plugin, PluginDescription depend) boolean isTransitiveDepend(PluginDescription plugin, PluginDescription depend)