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 }