001 package org.bukkit.plugin; 002 003 import org.bukkit.Bukkit; 004 import org.bukkit.event.server.ServiceRegisterEvent; 005 import org.bukkit.event.server.ServiceUnregisterEvent; 006 007 import com.google.common.collect.ImmutableList; 008 import com.google.common.collect.ImmutableSet; 009 010 import java.util.ArrayList; 011 import java.util.Collections; 012 import java.util.HashMap; 013 import java.util.Iterator; 014 import java.util.Map; 015 import java.util.List; 016 import java.util.NoSuchElementException; 017 import java.util.Set; 018 019 /** 020 * A simple services manager. 021 */ 022 public class SimpleServicesManager implements ServicesManager { 023 024 /** 025 * Map of providers. 026 */ 027 private final Map<Class<?>, List<RegisteredServiceProvider<?>>> providers = new HashMap<Class<?>, List<RegisteredServiceProvider<?>>>(); 028 029 /** 030 * Register a provider of a service. 031 * 032 * @param <T> Provider 033 * @param service service class 034 * @param provider provider to register 035 * @param plugin plugin with the provider 036 * @param priority priority of the provider 037 */ 038 public <T> void register(Class<T> service, T provider, Plugin plugin, ServicePriority priority) { 039 RegisteredServiceProvider<T> registeredProvider = null; 040 synchronized (providers) { 041 List<RegisteredServiceProvider<?>> registered = providers.get(service); 042 if (registered == null) { 043 registered = new ArrayList<RegisteredServiceProvider<?>>(); 044 providers.put(service, registered); 045 } 046 047 registeredProvider = new RegisteredServiceProvider<T>(service, provider, priority, plugin); 048 049 // Insert the provider into the collection, much more efficient big O than sort 050 int position = Collections.binarySearch(registered, registeredProvider); 051 if (position < 0) { 052 registered.add(-(position + 1), registeredProvider); 053 } else { 054 registered.add(position, registeredProvider); 055 } 056 057 } 058 Bukkit.getServer().getPluginManager().callEvent(new ServiceRegisterEvent(registeredProvider)); 059 } 060 061 /** 062 * Unregister all the providers registered by a particular plugin. 063 * 064 * @param plugin The plugin 065 */ 066 public void unregisterAll(Plugin plugin) { 067 ArrayList<ServiceUnregisterEvent> unregisteredEvents = new ArrayList<ServiceUnregisterEvent>(); 068 synchronized (providers) { 069 Iterator<Map.Entry<Class<?>, List<RegisteredServiceProvider<?>>>> it = providers.entrySet().iterator(); 070 071 try { 072 while (it.hasNext()) { 073 Map.Entry<Class<?>, List<RegisteredServiceProvider<?>>> entry = it.next(); 074 Iterator<RegisteredServiceProvider<?>> it2 = entry.getValue().iterator(); 075 076 try { 077 // Removed entries that are from this plugin 078 079 while (it2.hasNext()) { 080 RegisteredServiceProvider<?> registered = it2.next(); 081 082 if (registered.getPlugin().equals(plugin)) { 083 it2.remove(); 084 unregisteredEvents.add(new ServiceUnregisterEvent(registered)); 085 } 086 } 087 } catch (NoSuchElementException e) { // Why does Java suck 088 } 089 090 // Get rid of the empty list 091 if (entry.getValue().size() == 0) { 092 it.remove(); 093 } 094 } 095 } catch (NoSuchElementException e) {} 096 } 097 for (ServiceUnregisterEvent event : unregisteredEvents) { 098 Bukkit.getServer().getPluginManager().callEvent(event); 099 } 100 } 101 102 /** 103 * Unregister a particular provider for a particular service. 104 * 105 * @param service The service interface 106 * @param provider The service provider implementation 107 */ 108 public void unregister(Class<?> service, Object provider) { 109 ArrayList<ServiceUnregisterEvent> unregisteredEvents = new ArrayList<ServiceUnregisterEvent>(); 110 synchronized (providers) { 111 Iterator<Map.Entry<Class<?>, List<RegisteredServiceProvider<?>>>> it = providers.entrySet().iterator(); 112 113 try { 114 while (it.hasNext()) { 115 Map.Entry<Class<?>, List<RegisteredServiceProvider<?>>> entry = it.next(); 116 117 // We want a particular service 118 if (entry.getKey() != service) { 119 continue; 120 } 121 122 Iterator<RegisteredServiceProvider<?>> it2 = entry.getValue().iterator(); 123 124 try { 125 // Removed entries that are from this plugin 126 127 while (it2.hasNext()) { 128 RegisteredServiceProvider<?> registered = it2.next(); 129 130 if (registered.getProvider() == provider) { 131 it2.remove(); 132 unregisteredEvents.add(new ServiceUnregisterEvent(registered)); 133 } 134 } 135 } catch (NoSuchElementException e) { // Why does Java suck 136 } 137 138 // Get rid of the empty list 139 if (entry.getValue().size() == 0) { 140 it.remove(); 141 } 142 } 143 } catch (NoSuchElementException e) {} 144 } 145 for (ServiceUnregisterEvent event : unregisteredEvents) { 146 Bukkit.getServer().getPluginManager().callEvent(event); 147 } 148 } 149 150 /** 151 * Unregister a particular provider. 152 * 153 * @param provider The service provider implementation 154 */ 155 public void unregister(Object provider) { 156 ArrayList<ServiceUnregisterEvent> unregisteredEvents = new ArrayList<ServiceUnregisterEvent>(); 157 synchronized (providers) { 158 Iterator<Map.Entry<Class<?>, List<RegisteredServiceProvider<?>>>> it = providers.entrySet().iterator(); 159 160 try { 161 while (it.hasNext()) { 162 Map.Entry<Class<?>, List<RegisteredServiceProvider<?>>> entry = it.next(); 163 Iterator<RegisteredServiceProvider<?>> it2 = entry.getValue().iterator(); 164 165 try { 166 // Removed entries that are from this plugin 167 168 while (it2.hasNext()) { 169 RegisteredServiceProvider<?> registered = it2.next(); 170 171 if (registered.getProvider().equals(provider)) { 172 it2.remove(); 173 unregisteredEvents.add(new ServiceUnregisterEvent(registered)); 174 } 175 } 176 } catch (NoSuchElementException e) { // Why does Java suck 177 } 178 179 // Get rid of the empty list 180 if (entry.getValue().size() == 0) { 181 it.remove(); 182 } 183 } 184 } catch (NoSuchElementException e) {} 185 } 186 for (ServiceUnregisterEvent event : unregisteredEvents) { 187 Bukkit.getServer().getPluginManager().callEvent(event); 188 } 189 } 190 191 /** 192 * Queries for a provider. This may return if no provider has been 193 * registered for a service. The highest priority provider is returned. 194 * 195 * @param <T> The service interface 196 * @param service The service interface 197 * @return provider or null 198 */ 199 public <T> T load(Class<T> service) { 200 synchronized (providers) { 201 List<RegisteredServiceProvider<?>> registered = providers.get(service); 202 203 if (registered == null) { 204 return null; 205 } 206 207 // This should not be null! 208 return service.cast(registered.get(0).getProvider()); 209 } 210 } 211 212 /** 213 * Queries for a provider registration. This may return if no provider 214 * has been registered for a service. 215 * 216 * @param <T> The service interface 217 * @param service The service interface 218 * @return provider registration or null 219 */ 220 @SuppressWarnings("unchecked") 221 public <T> RegisteredServiceProvider<T> getRegistration(Class<T> service) { 222 synchronized (providers) { 223 List<RegisteredServiceProvider<?>> registered = providers.get(service); 224 225 if (registered == null) { 226 return null; 227 } 228 229 // This should not be null! 230 return (RegisteredServiceProvider<T>) registered.get(0); 231 } 232 } 233 234 /** 235 * Get registrations of providers for a plugin. 236 * 237 * @param plugin The plugin 238 * @return provider registration or null 239 */ 240 public List<RegisteredServiceProvider<?>> getRegistrations(Plugin plugin) { 241 ImmutableList.Builder<RegisteredServiceProvider<?>> ret = ImmutableList.<RegisteredServiceProvider<?>>builder(); 242 synchronized (providers) { 243 for (List<RegisteredServiceProvider<?>> registered : providers.values()) { 244 for (RegisteredServiceProvider<?> provider : registered) { 245 if (provider.getPlugin().equals(plugin)) { 246 ret.add(provider); 247 } 248 } 249 } 250 } 251 return ret.build(); 252 } 253 254 /** 255 * Get registrations of providers for a service. The returned list is 256 * an unmodifiable copy. 257 * 258 * @param <T> The service interface 259 * @param service The service interface 260 * @return a copy of the list of registrations 261 */ 262 @SuppressWarnings("unchecked") 263 public <T> List<RegisteredServiceProvider<T>> getRegistrations(Class<T> service) { 264 ImmutableList.Builder<RegisteredServiceProvider<T>> ret; 265 synchronized (providers) { 266 List<RegisteredServiceProvider<?>> registered = providers.get(service); 267 268 if (registered == null) { 269 return ImmutableList.<RegisteredServiceProvider<T>>of(); 270 } 271 272 ret = ImmutableList.<RegisteredServiceProvider<T>>builder(); 273 274 for (RegisteredServiceProvider<?> provider : registered) { 275 ret.add((RegisteredServiceProvider<T>) provider); 276 } 277 278 } 279 return ret.build(); 280 } 281 282 /** 283 * Get a list of known services. A service is known if it has registered 284 * providers for it. 285 * 286 * @return a copy of the set of known services 287 */ 288 public Set<Class<?>> getKnownServices() { 289 synchronized (providers) { 290 return ImmutableSet.<Class<?>>copyOf(providers.keySet()); 291 } 292 } 293 294 /** 295 * Returns whether a provider has been registered for a service. 296 * 297 * @param <T> service 298 * @param service service to check 299 * @return true if and only if there are registered providers 300 */ 301 public <T> boolean isProvidedFor(Class<T> service) { 302 synchronized (providers) { 303 return providers.containsKey(service); 304 } 305 } 306 }