blob: 1a18b021e4bb059c742fce04a57d882014c87fb2 [file] [log] [blame]
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -07001/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17/**
18 * @author Rustem V. Rafikov
19 * @version $Revision: 1.3 $
20 */
21package javax.imageio.spi;
22
23import java.util.*;
24import java.util.Map.Entry;
25
26/**
27 * The ServiceRegistry class provides ability to register,
28 * deregister, look up and obtain service provider instances (SPIs).
29 * A service means a set of interfaces and classes, and a service
30 * provider is an implementation of a service. Service providers can
31 * be associated with one or more categories. Each category is defined
32 * by a class or interface. Only a single instance of a each class is
33 * allowed to be registered as a category.
34 */
35public class ServiceRegistry {
36
37 /** The categories. */
38 CategoriesMap categories = new CategoriesMap(this);
39
40 /**
41 * Instantiates a new ServiceRegistry with the specified categories.
42 *
43 * @param categoriesIterator an Iterator of Class objects
44 * for defining of categories.
45 */
46 public ServiceRegistry(Iterator<Class<?>> categoriesIterator) {
47 if (null == categoriesIterator) {
48 throw new IllegalArgumentException("categories iterator should not be NULL");
49 }
50 while(categoriesIterator.hasNext()) {
51 Class<?> c = categoriesIterator.next();
52 categories.addCategory(c);
53 }
54 }
55
56 /**
57 * Looks up and instantiates the available providers of this service using
58 * the specified class loader.
59 *
60 * @param providerClass the Class object of the provider to be looked up.
61 * @param loader the class loader to be used.
62 *
63 * @return the iterator of providers objects for this service.
64 */
65 public static <T> Iterator<T> lookupProviders(Class<T> providerClass, ClassLoader loader) {
66 throw new UnsupportedOperationException("Not supported yet");
67 }
68
69 /**
70 * Looks up and instantiates the available providers of this service using
71 * the context class loader.
72 *
73 * @param providerClass the Class object of the provider to be looked up.
74 *
75 * @return the iterator of providers objects for this service.
76 */
77 public static <T> Iterator<T> lookupProviders(Class<T> providerClass) {
78 return lookupProviders(providerClass, Thread.currentThread().getContextClassLoader());
79 }
80
81 /**
82 * Registers the specified service provider object in the
83 * specified categories.
84 *
85 * @param provider the specified provider to be registered.
86 * @param category the category.
87 *
88 * @return true if no provider of the same class is registered
89 * in this category, false otherwise.
90 */
91 public <T> boolean registerServiceProvider(T provider, Class<T> category) {
92 return categories.addProvider(provider, category);
93 }
94
95 /**
96 * Registers a list of service providers.
97 *
98 * @param providers the list of service providers.
99 */
100 public void registerServiceProviders(Iterator<?> providers) {
101 for (Iterator<?> iterator = providers; iterator.hasNext();) {
102 categories.addProvider(iterator.next(), null);
103 }
104 }
105
106 /**
107 * Registers the specified service provider object in all
108 * categories.
109 *
110 * @param provider the service provider.
111 */
112 public void registerServiceProvider(Object provider) {
113 categories.addProvider(provider, null);
114 }
115
116 /**
117 * Deregisters the specifies service provider from the
118 * specified category.
119 *
120 * @param provider the service provider to be deregistered.
121 * @param category the specified category.
122 *
123 * @return true if the provider was already registered
124 * in the specified category, false otherwise.
125 */
126 public <T> boolean deregisterServiceProvider(T provider, Class<T> category) {
127 throw new UnsupportedOperationException("Not supported yet");
128 }
129
130 /**
131 * Deregisters the specified service provider from all
132 * categories.
133 *
134 * @param provider the specified service provider.
135 */
136 public void deregisterServiceProvider(Object provider) {
137 throw new UnsupportedOperationException("Not supported yet");
138 }
139
140 /**
141 * Gets an Iterator of registered service providers
142 * in the specified category which satisfy the specified Filter.
143 * The useOrdering parameter indicates whether the iterator will
144 * return all of the server provider objects in a set order.
145 *
146 * @param category the specified category.
147 * @param filter the specified filter.
148 * @param useOrdering the flag indicating that providers are ordered
149 * in the returned Iterator.
150 *
151 * @return the iterator of registered service providers.
152 */
153 @SuppressWarnings("unchecked")
154 public <T> Iterator<T> getServiceProviders(Class<T> category, Filter filter, boolean useOrdering) {
155 return new FilteredIterator<T>(filter, (Iterator<T>)categories.getProviders(category, useOrdering));
156 }
157
158 /**
159 * Gets an Iterator of all registered service providers
160 * in the specified category. The useOrdering parameter
161 * indicates whether the iterator will return all of the server
162 * provider objects in a set order.
163 *
164 * @param category the specified category.
165 * @param useOrdering the flag indicating that providers are ordered
166 * in the returned Iterator.
167 *
168 * @return the Iterator of service providers.
169 */
170 @SuppressWarnings("unchecked")
171 public <T> Iterator<T> getServiceProviders(Class<T> category, boolean useOrdering) {
172 return (Iterator<T>)categories.getProviders(category, useOrdering);
173 }
174
175 /**
176 * Gets the registered service provider object that has the
177 * specified class type.
178 *
179 * @param providerClass the specified provider class.
180 *
181 * @return the service provider object.
182 */
183 public <T> T getServiceProviderByClass(Class<T> providerClass) {
184 throw new UnsupportedOperationException("Not supported yet");
185 }
186
187 /**
188 * Sets an ordering between two service provider objects
189 * within the specified category.
190 *
191 * @param category the specified category.
192 * @param firstProvider the first provider.
193 * @param secondProvider the second provider.
194 *
195 * @return true if a previously unset order was set.
196 */
197 public <T> boolean setOrdering(Class<T> category, T firstProvider, T secondProvider) {
198 throw new UnsupportedOperationException("Not supported yet");
199 }
200
201 /**
202 * Unsets an ordering between two service provider objects
203 * within the specified category.
204 *
205 * @param category the specified category.
206 * @param firstProvider the first provider.
207 * @param secondProvider the second provider.
208 *
209 * @return true if a previously unset order was removed.
210 */
211 public <T> boolean unsetOrdering(Class<T> category, T firstProvider, T secondProvider) {
212 throw new UnsupportedOperationException("Not supported yet");
213 }
214
215 /**
216 * Deregisters all providers from the specified category.
217 *
218 * @param category the specified category.
219 */
220 public void deregisterAll(Class<?> category) {
221 throw new UnsupportedOperationException("Not supported yet");
222 }
223
224 /**
225 * Deregister all providers from all categories.
226 */
227 public void deregisterAll() {
228 throw new UnsupportedOperationException("Not supported yet");
229 }
230
231 /**
232 * Finalizes this object.
233 *
234 * @throws Throwable throws if an error occurs during
235 * finalization.
236 */
237 @Override
238 public void finalize() throws Throwable {
239 //TODO uncomment when deregisterAll is implemented
240 //deregisterAll();
241 }
242
243 /**
244 * Checks whether the specified provider has been already registered.
245 *
246 * @param provider the provider to be checked.
247 *
248 * @return true, if the specified provider has been already registered,
249 * false otherwise.
250 */
251 public boolean contains(Object provider) {
252 throw new UnsupportedOperationException("Not supported yet");
253 }
254
255 /**
256 * Gets an iterator of Class objects representing the current
257 * categories.
258 *
259 * @return the Iterator of Class objects.
260 */
261 public Iterator<Class<?>> getCategories() {
262 return categories.list();
263 }
264
265 /**
266 * The ServiceRegistry.Filter interface is used by
267 * ServiceRegistry.getServiceProviders to filter providers according
268 * to the specified criterion.
269 */
270 public static interface Filter {
271
272 /**
273 * Returns true if the specified provider satisfies the
274 * criterion of this Filter.
275 *
276 * @param provider the provider.
277 *
278 * @return true if the specified provider satisfies the
279 * criterion of this Filter, false otherwise.
280 */
281 boolean filter(Object provider);
282 }
283
284 /**
285 * The Class CategoriesMap.
286 */
287 private static class CategoriesMap {
288
289 /** The categories. */
290 Map<Class<?>, ProvidersMap> categories = new HashMap<Class<?>, ProvidersMap>();
291
292 /** The registry. */
293 ServiceRegistry registry;
294
295 /**
296 * Instantiates a new categories map.
297 *
298 * @param registry the registry
299 */
300 public CategoriesMap(ServiceRegistry registry) {
301 this.registry = registry;
302 }
303
304 //-- TODO: useOrdering
305 /**
306 * Gets the providers.
307 *
308 * @param category the category
309 * @param useOrdering the use ordering
310 *
311 * @return the providers
312 */
313 Iterator<?> getProviders(Class<?> category, boolean useOrdering) {
314 ProvidersMap providers = categories.get(category);
315 if (null == providers) {
316 throw new IllegalArgumentException("Unknown category: " + category);
317 }
318 return providers.getProviders(useOrdering);
319 }
320
321 /**
322 * List.
323 *
324 * @return the iterator< class<?>>
325 */
326 Iterator<Class<?>> list() {
327 return categories.keySet().iterator();
328 }
329
330 /**
331 * Adds the category.
332 *
333 * @param category the category
334 */
335 void addCategory(Class<?> category) {
336 categories.put(category, new ProvidersMap());
337 }
338
339 /**
340 * Adds a provider to the category. If <code>category</code> is
341 * <code>null</code> then the provider will be added to all categories
342 * which the provider is assignable from.
343 *
344 * @param provider provider to add
345 * @param category category to add provider to
346 *
347 * @return if there were such provider in some category
348 */
349 boolean addProvider(Object provider, Class<?> category) {
350 if (provider == null) {
351 throw new IllegalArgumentException("provider should be != NULL");
352 }
353
354 boolean rt;
355 if (category == null) {
356 rt = findAndAdd(provider);
357 } else {
358 rt = addToNamed(provider, category);
359 }
360
361 if (provider instanceof RegisterableService) {
362 ((RegisterableService) provider).onRegistration(registry, category);
363 }
364
365 return rt;
366 }
367
368 /**
369 * Adds the to named.
370 *
371 * @param provider the provider
372 * @param category the category
373 *
374 * @return true, if successful
375 */
376 private boolean addToNamed(Object provider, Class<?> category) {
377 Object obj = categories.get(category);
378
379 if (null == obj) {
380 throw new IllegalArgumentException("Unknown category: " + category);
381 }
382
383 return ((ProvidersMap) obj).addProvider(provider);
384 }
385
386 /**
387 * Find and add.
388 *
389 * @param provider the provider
390 *
391 * @return true, if successful
392 */
393 private boolean findAndAdd(Object provider) {
394 boolean rt = false;
395 for (Entry<Class<?>, ProvidersMap> e : categories.entrySet()) {
396 if (e.getKey().isAssignableFrom(provider.getClass())) {
397 rt |= e.getValue().addProvider(provider);
398 }
399 }
400 return rt;
401 }
402 }
403
404 /**
405 * The Class ProvidersMap.
406 */
407 private static class ProvidersMap {
408 //-- TODO: providers ordering support
409
410 /** The providers. */
411 Map<Class<?>, Object> providers = new HashMap<Class<?>, Object>();
412
413 /**
414 * Adds the provider.
415 *
416 * @param provider the provider
417 *
418 * @return true, if successful
419 */
420 boolean addProvider(Object provider) {
421 return providers.put(provider.getClass(), provider) != null;
422 }
423
424 /**
425 * Gets the provider classes.
426 *
427 * @return the provider classes
428 */
429 Iterator<Class<?>> getProviderClasses() {
430 return providers.keySet().iterator();
431 }
432
433 //-- TODO ordering
434 /**
435 * Gets the providers.
436 *
437 * @param userOrdering the user ordering
438 *
439 * @return the providers
440 */
441 Iterator<?> getProviders(boolean userOrdering) {
442 return providers.values().iterator();
443 }
444 }
445
446 /**
447 * The Class FilteredIterator.
448 */
449 private static class FilteredIterator<E> implements Iterator<E> {
450
451 /** The filter. */
452 private Filter filter;
453
454 /** The backend. */
455 private Iterator<E> backend;
456
457 /** The next obj. */
458 private E nextObj;
459
460 /**
461 * Instantiates a new filtered iterator.
462 *
463 * @param filter the filter
464 * @param backend the backend
465 */
466 public FilteredIterator(Filter filter, Iterator<E> backend) {
467 this.filter = filter;
468 this.backend = backend;
469 findNext();
470 }
471
472 /**
473 * Next.
474 *
475 * @return the e
476 */
477 public E next() {
478 if (nextObj == null) {
479 throw new NoSuchElementException();
480 }
481 E tmp = nextObj;
482 findNext();
483 return tmp;
484 }
485
486 /**
487 * Checks for next.
488 *
489 * @return true, if successful
490 */
491 public boolean hasNext() {
492 return nextObj != null;
493 }
494
495 /**
496 * Removes the.
497 */
498 public void remove() {
499 throw new UnsupportedOperationException();
500 }
501
502 /**
503 * Sets nextObj to a next provider matching the criterion given by the filter.
504 */
505 private void findNext() {
506 nextObj = null;
507 while (backend.hasNext()) {
508 E o = backend.next();
509 if (filter.filter(o)) {
510 nextObj = o;
511 return;
512 }
513 }
514 }
515 }
516}