package org.bukkit.plugin; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import org.bukkit.Bukkit; import org.bukkit.event.server.ServiceRegisterEvent; import org.bukkit.event.server.ServiceUnregisterEvent; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; /** * A simple services manager. */ public class SimpleServicesManager implements ServicesManager { /** * Map of providers. */ private final Map<Class<?>, List<RegisteredServiceProvider<?>>> providers = new HashMap<Class<?>, List<RegisteredServiceProvider<?>>>(); /** * Register a provider of a service. * * @param <T> Provider * @param service service class * @param provider provider to register * @param plugin plugin with the provider * @param priority priority of the provider */ public <T> void register(Class<T> service, T provider, Plugin plugin, ServicePriority priority) { RegisteredServiceProvider<T> registeredProvider = null; synchronized(providers) { List<RegisteredServiceProvider<?>> registered = providers.get(service); if(registered == null) { registered = new ArrayList<RegisteredServiceProvider<?>>(); providers.put(service, registered); } registeredProvider = new RegisteredServiceProvider<T>(service, provider, priority, plugin); // Insert the provider into the collection, much more efficient big O than sort int position = Collections.binarySearch(registered, registeredProvider); if(position < 0) { registered.add(-(position + 1), registeredProvider); } else { registered.add(position, registeredProvider); } } Bukkit.getServer().getPluginManager().callEvent(new ServiceRegisterEvent(registeredProvider)); } /** * Unregister all the providers registered by a particular plugin. * * @param plugin The plugin */ public void unregisterAll(Plugin plugin) { ArrayList<ServiceUnregisterEvent> unregisteredEvents = new ArrayList<ServiceUnregisterEvent>(); synchronized(providers) { Iterator<Map.Entry<Class<?>, List<RegisteredServiceProvider<?>>>> it = providers.entrySet().iterator(); try { while(it.hasNext()) { Map.Entry<Class<?>, List<RegisteredServiceProvider<?>>> entry = it.next(); Iterator<RegisteredServiceProvider<?>> it2 = entry.getValue().iterator(); try { // Removed entries that are from this plugin while(it2.hasNext()) { RegisteredServiceProvider<?> registered = it2.next(); Plugin oPlugin = registered.getPlugin(); if(oPlugin != null ? oPlugin.equals(plugin) : plugin == null) { it2.remove(); unregisteredEvents.add(new ServiceUnregisterEvent(registered)); } } } catch(NoSuchElementException e) { // Why does Java suck } // Get rid of the empty list if(entry.getValue().size() == 0) { it.remove(); } } } catch(NoSuchElementException e) { } } for(ServiceUnregisterEvent event : unregisteredEvents) { Bukkit.getServer().getPluginManager().callEvent(event); } } /** * Unregister a particular provider for a particular service. * * @param service The service interface * @param provider The service provider implementation */ public void unregister(Class<?> service, Object provider) { ArrayList<ServiceUnregisterEvent> unregisteredEvents = new ArrayList<ServiceUnregisterEvent>(); synchronized(providers) { Iterator<Map.Entry<Class<?>, List<RegisteredServiceProvider<?>>>> it = providers.entrySet().iterator(); try { while(it.hasNext()) { Map.Entry<Class<?>, List<RegisteredServiceProvider<?>>> entry = it.next(); // We want a particular service if(entry.getKey() != service) { continue; } Iterator<RegisteredServiceProvider<?>> it2 = entry.getValue().iterator(); try { // Removed entries that are from this plugin while(it2.hasNext()) { RegisteredServiceProvider<?> registered = it2.next(); if(registered.getProvider() == provider) { it2.remove(); unregisteredEvents.add(new ServiceUnregisterEvent(registered)); } } } catch(NoSuchElementException e) { // Why does Java suck } // Get rid of the empty list if(entry.getValue().size() == 0) { it.remove(); } } } catch(NoSuchElementException e) { } } for(ServiceUnregisterEvent event : unregisteredEvents) { Bukkit.getServer().getPluginManager().callEvent(event); } } /** * Unregister a particular provider. * * @param provider The service provider implementation */ public void unregister(Object provider) { ArrayList<ServiceUnregisterEvent> unregisteredEvents = new ArrayList<ServiceUnregisterEvent>(); synchronized(providers) { Iterator<Map.Entry<Class<?>, List<RegisteredServiceProvider<?>>>> it = providers.entrySet().iterator(); try { while(it.hasNext()) { Map.Entry<Class<?>, List<RegisteredServiceProvider<?>>> entry = it.next(); Iterator<RegisteredServiceProvider<?>> it2 = entry.getValue().iterator(); try { // Removed entries that are from this plugin while(it2.hasNext()) { RegisteredServiceProvider<?> registered = it2.next(); if(registered.getProvider().equals(provider)) { it2.remove(); unregisteredEvents.add(new ServiceUnregisterEvent(registered)); } } } catch(NoSuchElementException e) { // Why does Java suck } // Get rid of the empty list if(entry.getValue().size() == 0) { it.remove(); } } } catch(NoSuchElementException e) { } } for(ServiceUnregisterEvent event : unregisteredEvents) { Bukkit.getServer().getPluginManager().callEvent(event); } } /** * Queries for a provider. This may return if no provider has been * registered for a service. The highest priority provider is returned. * * @param <T> The service interface * @param service The service interface * @return provider or null */ public <T> T load(Class<T> service) { synchronized(providers) { List<RegisteredServiceProvider<?>> registered = providers.get(service); if(registered == null) { return null; } // This should not be null! return service.cast(registered.get(0).getProvider()); } } /** * Queries for a provider registration. This may return if no provider * has been registered for a service. * * @param <T> The service interface * @param service The service interface * @return provider registration or null */ @SuppressWarnings("unchecked") public <T> RegisteredServiceProvider<T> getRegistration(Class<T> service) { synchronized(providers) { List<RegisteredServiceProvider<?>> registered = providers.get(service); if(registered == null) { return null; } // This should not be null! return (RegisteredServiceProvider<T>) registered.get(0); } } /** * Get registrations of providers for a plugin. * * @param plugin The plugin * @return provider registration or null */ public List<RegisteredServiceProvider<?>> getRegistrations(Plugin plugin) { ImmutableList.Builder<RegisteredServiceProvider<?>> ret = ImmutableList.<RegisteredServiceProvider<?>>builder(); synchronized(providers) { for(List<RegisteredServiceProvider<?>> registered : providers.values()) { for(RegisteredServiceProvider<?> provider : registered) { if(provider.getPlugin().equals(plugin)) { ret.add(provider); } } } } return ret.build(); } /** * Get registrations of providers for a service. The returned list is * an unmodifiable copy. * * @param <T> The service interface * @param service The service interface * @return a copy of the list of registrations */ @SuppressWarnings("unchecked") public <T> List<RegisteredServiceProvider<T>> getRegistrations(Class<T> service) { ImmutableList.Builder<RegisteredServiceProvider<T>> ret; synchronized(providers) { List<RegisteredServiceProvider<?>> registered = providers.get(service); if(registered == null) { return ImmutableList.<RegisteredServiceProvider<T>>of(); } ret = ImmutableList.<RegisteredServiceProvider<T>>builder(); for(RegisteredServiceProvider<?> provider : registered) { ret.add((RegisteredServiceProvider<T>) provider); } } return ret.build(); } /** * Get a list of known services. A service is known if it has registered * providers for it. * * @return a copy of the set of known services */ public Set<Class<?>> getKnownServices() { synchronized(providers) { return ImmutableSet.<Class<?>>copyOf(providers.keySet()); } } /** * Returns whether a provider has been registered for a service. * * @param <T> service * @param service service to check * @return true if and only if there are registered providers */ public <T> boolean isProvidedFor(Class<T> service) { synchronized(providers) { return providers.containsKey(service); } } }