13
0
geforkt von Mirrors/Paper

[Bleeding] Fixes deadlock issue and generic usage. Fixes BUKKIT-844 and fixes BUKKIT-854

By: Wesley Wolfe <weswolf@aol.com>
Dieser Commit ist enthalten in:
Bukkit/Spigot 2012-02-29 08:29:22 -06:00
Ursprung 2fa5a7033a
Commit 9ebb2f13de
3 geänderte Dateien mit 60 neuen und 37 gelöschten Zeilen

Datei anzeigen

@ -4,7 +4,9 @@ import org.bukkit.event.HandlerList;
import org.bukkit.plugin.RegisteredServiceProvider; import org.bukkit.plugin.RegisteredServiceProvider;
/** /**
* This event is called when a service is registered. * This event is called when a service is registered.<br>
* <b>Warning:</b> The order in which register and unregister
* events are called should not be relied upon.
*/ */
public class ServiceRegisterEvent extends ServiceEvent { public class ServiceRegisterEvent extends ServiceEvent {
private static final HandlerList handlers = new HandlerList(); private static final HandlerList handlers = new HandlerList();
@ -13,6 +15,7 @@ public class ServiceRegisterEvent extends ServiceEvent {
super(registeredProvider); super(registeredProvider);
} }
@Override
public HandlerList getHandlers() { public HandlerList getHandlers() {
return handlers; return handlers;
} }

Datei anzeigen

@ -4,7 +4,9 @@ import org.bukkit.event.HandlerList;
import org.bukkit.plugin.RegisteredServiceProvider; import org.bukkit.plugin.RegisteredServiceProvider;
/** /**
* This event is called when a service is unregistered. * This event is called when a service is unregistered.<br>
* <b>Warning:</b> The order in which register and unregister
* events are called should not be relied upon.
*/ */
public class ServiceUnregisterEvent extends ServiceEvent { public class ServiceUnregisterEvent extends ServiceEvent {
private static final HandlerList handlers = new HandlerList(); private static final HandlerList handlers = new HandlerList();
@ -13,6 +15,7 @@ public class ServiceUnregisterEvent extends ServiceEvent {
super(serviceProvider); super(serviceProvider);
} }
@Override
public HandlerList getHandlers() { public HandlerList getHandlers() {
return handlers; return handlers;
} }

Datei anzeigen

@ -4,14 +4,17 @@ import org.bukkit.Bukkit;
import org.bukkit.event.server.ServiceRegisterEvent; import org.bukkit.event.server.ServiceRegisterEvent;
import org.bukkit.event.server.ServiceUnregisterEvent; import org.bukkit.event.server.ServiceUnregisterEvent;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.List; import java.util.List;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.Set;
/** /**
* A simple services manager. * A simple services manager.
@ -33,24 +36,26 @@ public class SimpleServicesManager implements ServicesManager {
* @param priority priority of the provider * @param priority priority of the provider
*/ */
public <T> void register(Class<T> service, T provider, Plugin plugin, ServicePriority priority) { public <T> void register(Class<T> service, T provider, Plugin plugin, ServicePriority priority) {
RegisteredServiceProvider<T> registeredProvider = null;
synchronized (providers) { synchronized (providers) {
List<RegisteredServiceProvider<?>> registered = providers.get(service); List<RegisteredServiceProvider<?>> registered = providers.get(service);
if (registered == null) { if (registered == null) {
registered = new ArrayList<RegisteredServiceProvider<?>>(); registered = new ArrayList<RegisteredServiceProvider<?>>();
providers.put(service, registered); providers.put(service, registered);
} }
RegisteredServiceProvider<T> registeredProvider = new RegisteredServiceProvider<T>(service, provider, priority, plugin);
registered.add(registeredProvider); registeredProvider = new RegisteredServiceProvider<T>(service, provider, priority, plugin);
// Make sure that providers are in the right order in order // Insert the provider into the collection, much more efficient big O than sort
// for priorities to work correctly int position = Collections.binarySearch(registered, registeredProvider);
Collections.sort(registered); if (position < 0) {
registered.add(-(position + 1), registeredProvider);
Bukkit.getServer().getPluginManager().callEvent(new ServiceRegisterEvent(registeredProvider)); } else {
registered.add(position, registeredProvider);
} }
}
Bukkit.getServer().getPluginManager().callEvent(new ServiceRegisterEvent(registeredProvider));
} }
/** /**
@ -59,6 +64,7 @@ public class SimpleServicesManager implements ServicesManager {
* @param plugin The plugin * @param plugin The plugin
*/ */
public void unregisterAll(Plugin plugin) { public void unregisterAll(Plugin plugin) {
ArrayList<ServiceUnregisterEvent> unregisteredEvents = new ArrayList<ServiceUnregisterEvent>();
synchronized (providers) { synchronized (providers) {
Iterator<Map.Entry<Class<?>, List<RegisteredServiceProvider<?>>>> it = providers.entrySet().iterator(); Iterator<Map.Entry<Class<?>, List<RegisteredServiceProvider<?>>>> it = providers.entrySet().iterator();
@ -73,9 +79,9 @@ public class SimpleServicesManager implements ServicesManager {
while (it2.hasNext()) { while (it2.hasNext()) {
RegisteredServiceProvider<?> registered = it2.next(); RegisteredServiceProvider<?> registered = it2.next();
if (registered.getPlugin() == plugin) { if (registered.getPlugin().equals(plugin)) {
it2.remove(); it2.remove();
Bukkit.getServer().getPluginManager().callEvent(new ServiceUnregisterEvent(registered)); unregisteredEvents.add(new ServiceUnregisterEvent(registered));
} }
} }
} catch (NoSuchElementException e) { // Why does Java suck } catch (NoSuchElementException e) { // Why does Java suck
@ -88,6 +94,9 @@ public class SimpleServicesManager implements ServicesManager {
} }
} catch (NoSuchElementException e) {} } catch (NoSuchElementException e) {}
} }
for (ServiceUnregisterEvent event : unregisteredEvents) {
Bukkit.getServer().getPluginManager().callEvent(event);
}
} }
/** /**
@ -97,6 +106,7 @@ public class SimpleServicesManager implements ServicesManager {
* @param provider The service provider implementation * @param provider The service provider implementation
*/ */
public void unregister(Class<?> service, Object provider) { public void unregister(Class<?> service, Object provider) {
ArrayList<ServiceUnregisterEvent> unregisteredEvents = new ArrayList<ServiceUnregisterEvent>();
synchronized (providers) { synchronized (providers) {
Iterator<Map.Entry<Class<?>, List<RegisteredServiceProvider<?>>>> it = providers.entrySet().iterator(); Iterator<Map.Entry<Class<?>, List<RegisteredServiceProvider<?>>>> it = providers.entrySet().iterator();
@ -119,7 +129,7 @@ public class SimpleServicesManager implements ServicesManager {
if (registered.getProvider() == provider) { if (registered.getProvider() == provider) {
it2.remove(); it2.remove();
Bukkit.getServer().getPluginManager().callEvent(new ServiceUnregisterEvent(registered)); unregisteredEvents.add(new ServiceUnregisterEvent(registered));
} }
} }
} catch (NoSuchElementException e) { // Why does Java suck } catch (NoSuchElementException e) { // Why does Java suck
@ -132,6 +142,9 @@ public class SimpleServicesManager implements ServicesManager {
} }
} catch (NoSuchElementException e) {} } catch (NoSuchElementException e) {}
} }
for (ServiceUnregisterEvent event : unregisteredEvents) {
Bukkit.getServer().getPluginManager().callEvent(event);
}
} }
/** /**
@ -140,6 +153,7 @@ public class SimpleServicesManager implements ServicesManager {
* @param provider The service provider implementation * @param provider The service provider implementation
*/ */
public void unregister(Object provider) { public void unregister(Object provider) {
ArrayList<ServiceUnregisterEvent> unregisteredEvents = new ArrayList<ServiceUnregisterEvent>();
synchronized (providers) { synchronized (providers) {
Iterator<Map.Entry<Class<?>, List<RegisteredServiceProvider<?>>>> it = providers.entrySet().iterator(); Iterator<Map.Entry<Class<?>, List<RegisteredServiceProvider<?>>>> it = providers.entrySet().iterator();
@ -154,9 +168,9 @@ public class SimpleServicesManager implements ServicesManager {
while (it2.hasNext()) { while (it2.hasNext()) {
RegisteredServiceProvider<?> registered = it2.next(); RegisteredServiceProvider<?> registered = it2.next();
if (registered.getProvider() == provider) { if (registered.getProvider().equals(provider)) {
it2.remove(); it2.remove();
Bukkit.getServer().getPluginManager().callEvent(new ServiceUnregisterEvent(registered)); unregisteredEvents.add(new ServiceUnregisterEvent(registered));
} }
} }
} catch (NoSuchElementException e) { // Why does Java suck } catch (NoSuchElementException e) { // Why does Java suck
@ -169,6 +183,9 @@ public class SimpleServicesManager implements ServicesManager {
} }
} catch (NoSuchElementException e) {} } catch (NoSuchElementException e) {}
} }
for (ServiceUnregisterEvent event : unregisteredEvents) {
Bukkit.getServer().getPluginManager().callEvent(event);
}
} }
/** /**
@ -179,7 +196,6 @@ public class SimpleServicesManager implements ServicesManager {
* @param service The service interface * @param service The service interface
* @return provider or null * @return provider or null
*/ */
@SuppressWarnings("unchecked")
public <T> T load(Class<T> service) { public <T> T load(Class<T> service) {
synchronized (providers) { synchronized (providers) {
List<RegisteredServiceProvider<?>> registered = providers.get(service); List<RegisteredServiceProvider<?>> registered = providers.get(service);
@ -189,7 +205,7 @@ public class SimpleServicesManager implements ServicesManager {
} }
// This should not be null! // This should not be null!
return (T) registered.get(0).getProvider(); return service.cast(registered.get(0).getProvider());
} }
} }
@ -222,68 +238,69 @@ public class SimpleServicesManager implements ServicesManager {
* @return provider registration or null * @return provider registration or null
*/ */
public List<RegisteredServiceProvider<?>> getRegistrations(Plugin plugin) { public List<RegisteredServiceProvider<?>> getRegistrations(Plugin plugin) {
ImmutableList.Builder<RegisteredServiceProvider<?>> ret = ImmutableList.<RegisteredServiceProvider<?>>builder();
synchronized (providers) { synchronized (providers) {
List<RegisteredServiceProvider<?>> ret = new ArrayList<RegisteredServiceProvider<?>>();
for (List<RegisteredServiceProvider<?>> registered : providers.values()) { for (List<RegisteredServiceProvider<?>> registered : providers.values()) {
for (RegisteredServiceProvider<?> provider : registered) { for (RegisteredServiceProvider<?> provider : registered) {
if (provider.getPlugin() == plugin) { if (provider.getPlugin().equals(plugin)) {
ret.add(provider); ret.add(provider);
} }
} }
} }
return ret;
} }
return ret.build();
} }
/** /**
* Get registrations of providers for a service. The returned list is * Get registrations of providers for a service. The returned list is
* unmodifiable. * an unmodifiable copy.
* *
* @param <T> The service interface * @param <T> The service interface
* @param service The service interface * @param service The service interface
* @return list of registrations * @return a copy of the list of registrations
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T> Collection<RegisteredServiceProvider<T>> getRegistrations(Class<T> service) { public <T> List<RegisteredServiceProvider<T>> getRegistrations(Class<T> service) {
ImmutableList.Builder<RegisteredServiceProvider<T>> ret;
synchronized (providers) { synchronized (providers) {
List<RegisteredServiceProvider<?>> registered = providers.get(service); List<RegisteredServiceProvider<?>> registered = providers.get(service);
if (registered == null) { if (registered == null) {
return Collections.unmodifiableList(new ArrayList<RegisteredServiceProvider<T>>()); return ImmutableList.<RegisteredServiceProvider<T>>of();
} }
List<RegisteredServiceProvider<T>> ret = new ArrayList<RegisteredServiceProvider<T>>(); ret = ImmutableList.<RegisteredServiceProvider<T>>builder();
for (RegisteredServiceProvider<?> provider : registered) { for (RegisteredServiceProvider<?> provider : registered) {
ret.add((RegisteredServiceProvider<T>) provider); ret.add((RegisteredServiceProvider<T>) provider);
} }
return Collections.unmodifiableList(ret);
} }
return ret.build();
} }
/** /**
* Get a list of known services. A service is known if it has registered * Get a list of known services. A service is known if it has registered
* providers for it. * providers for it.
* *
* @return list of known services * @return a copy of the set of known services
*/ */
public Collection<Class<?>> getKnownServices() { public Set<Class<?>> getKnownServices() {
return Collections.unmodifiableSet(providers.keySet()); synchronized (providers) {
return ImmutableSet.<Class<?>>copyOf(providers.keySet());
}
} }
/** /**
* Returns whether a provider has been registered for a service. Do not * Returns whether a provider has been registered for a service.
* check this first only to call <code>load(service)</code> later, as that
* would be a non-thread safe situation.
* *
* @param <T> service * @param <T> service
* @param service service to check * @param service service to check
* @return whether there has been a registered provider * @return true if and only if there are registered providers
*/ */
public <T> boolean isProvidedFor(Class<T> service) { public <T> boolean isProvidedFor(Class<T> service) {
return getRegistration(service) != null; synchronized (providers) {
return providers.containsKey(service);
}
} }
} }