blob: 79b02a36644dd5803bcb2fa21acfb696e16a4b2e [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 */
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -080021
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -070022package javax.imageio.spi;
23
24import java.util.*;
25import java.util.Map.Entry;
26
27/**
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -080028 * The ServiceRegistry class provides ability to register, deregister, look up
29 * and obtain service provider instances (SPIs). A service means a set of
30 * interfaces and classes, and a service provider is an implementation of a
31 * service. Service providers can be associated with one or more categories.
32 * Each category is defined by a class or interface. Only a single instance of a
33 * each class is allowed to be registered as a category.
34 *
35 * @since Android 1.0
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -070036 */
37public class ServiceRegistry {
38
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -080039 /**
40 * The categories.
41 */
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -070042 CategoriesMap categories = new CategoriesMap(this);
43
44 /**
45 * Instantiates a new ServiceRegistry with the specified categories.
46 *
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -080047 * @param categoriesIterator
48 * an Iterator of Class objects for defining of categories.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -070049 */
50 public ServiceRegistry(Iterator<Class<?>> categoriesIterator) {
51 if (null == categoriesIterator) {
52 throw new IllegalArgumentException("categories iterator should not be NULL");
53 }
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -080054 while (categoriesIterator.hasNext()) {
55 Class<?> c = categoriesIterator.next();
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -070056 categories.addCategory(c);
57 }
58 }
59
60 /**
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -080061 * Looks up and instantiates the available providers of this service using
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -070062 * the specified class loader.
63 *
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -080064 * @param providerClass
65 * the Class object of the provider to be looked up.
66 * @param loader
67 * the class loader to be used.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -070068 * @return the iterator of providers objects for this service.
69 */
70 public static <T> Iterator<T> lookupProviders(Class<T> providerClass, ClassLoader loader) {
71 throw new UnsupportedOperationException("Not supported yet");
72 }
73
74 /**
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -080075 * Looks up and instantiates the available providers of this service using
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -070076 * the context class loader.
77 *
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -080078 * @param providerClass
79 * the Class object of the provider to be looked up.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -070080 * @return the iterator of providers objects for this service.
81 */
82 public static <T> Iterator<T> lookupProviders(Class<T> providerClass) {
83 return lookupProviders(providerClass, Thread.currentThread().getContextClassLoader());
84 }
85
86 /**
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -080087 * Registers the specified service provider object in the specified
88 * categories.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -070089 *
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -080090 * @param provider
91 * the specified provider to be registered.
92 * @param category
93 * the category.
94 * @return true, if no provider of the same class is registered in this
95 * category, false otherwise.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -070096 */
97 public <T> boolean registerServiceProvider(T provider, Class<T> category) {
98 return categories.addProvider(provider, category);
99 }
100
101 /**
102 * Registers a list of service providers.
103 *
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800104 * @param providers
105 * the list of service providers.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700106 */
107 public void registerServiceProviders(Iterator<?> providers) {
108 for (Iterator<?> iterator = providers; iterator.hasNext();) {
109 categories.addProvider(iterator.next(), null);
110 }
111 }
112
113 /**
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800114 * Registers the specified service provider object in all categories.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700115 *
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800116 * @param provider
117 * the service provider.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700118 */
119 public void registerServiceProvider(Object provider) {
120 categories.addProvider(provider, null);
121 }
122
123 /**
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800124 * Deregisters the specifies service provider from the specified category.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700125 *
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800126 * @param provider
127 * the service provider to be deregistered.
128 * @param category
129 * the specified category.
130 * @return true, if the provider was already registered in the specified
131 * category, false otherwise.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700132 */
133 public <T> boolean deregisterServiceProvider(T provider, Class<T> category) {
134 throw new UnsupportedOperationException("Not supported yet");
135 }
136
137 /**
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800138 * Deregisters the specified service provider from all categories.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700139 *
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800140 * @param provider
141 * the specified service provider.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700142 */
143 public void deregisterServiceProvider(Object provider) {
144 throw new UnsupportedOperationException("Not supported yet");
145 }
146
147 /**
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800148 * Gets an Iterator of registered service providers in the specified
149 * category which satisfy the specified Filter. The useOrdering parameter
150 * indicates whether the iterator will return all of the server provider
151 * objects in a set order.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700152 *
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800153 * @param category
154 * the specified category.
155 * @param filter
156 * the specified filter.
157 * @param useOrdering
158 * the flag indicating that providers are ordered in the returned
159 * Iterator.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700160 * @return the iterator of registered service providers.
161 */
162 @SuppressWarnings("unchecked")
163 public <T> Iterator<T> getServiceProviders(Class<T> category, Filter filter, boolean useOrdering) {
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800164 return new FilteredIterator<T>(filter, (Iterator<T>)categories.getProviders(category,
165 useOrdering));
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700166 }
167
168 /**
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800169 * Gets an Iterator of all registered service providers in the specified
170 * category. The useOrdering parameter indicates whether the iterator will
171 * return all of the server provider objects in a set order.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700172 *
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800173 * @param category
174 * the specified category.
175 * @param useOrdering
176 * the flag indicating that providers are ordered in the returned
177 * Iterator.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700178 * @return the Iterator of service providers.
179 */
180 @SuppressWarnings("unchecked")
181 public <T> Iterator<T> getServiceProviders(Class<T> category, boolean useOrdering) {
182 return (Iterator<T>)categories.getProviders(category, useOrdering);
183 }
184
185 /**
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800186 * Gets the registered service provider object that has the specified class
187 * type.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700188 *
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800189 * @param providerClass
190 * the specified provider class.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700191 * @return the service provider object.
192 */
193 public <T> T getServiceProviderByClass(Class<T> providerClass) {
194 throw new UnsupportedOperationException("Not supported yet");
195 }
196
197 /**
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800198 * Sets an ordering between two service provider objects within the
199 * specified category.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700200 *
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800201 * @param category
202 * the specified category.
203 * @param firstProvider
204 * the first provider.
205 * @param secondProvider
206 * the second provider.
207 * @return true, if a previously unset order was set.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700208 */
209 public <T> boolean setOrdering(Class<T> category, T firstProvider, T secondProvider) {
210 throw new UnsupportedOperationException("Not supported yet");
211 }
212
213 /**
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800214 * Unsets an ordering between two service provider objects within the
215 * specified category.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700216 *
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800217 * @param category
218 * the specified category.
219 * @param firstProvider
220 * the first provider.
221 * @param secondProvider
222 * the second provider.
223 * @return true, if a previously unset order was removed.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700224 */
225 public <T> boolean unsetOrdering(Class<T> category, T firstProvider, T secondProvider) {
226 throw new UnsupportedOperationException("Not supported yet");
227 }
228
229 /**
230 * Deregisters all providers from the specified category.
231 *
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800232 * @param category
233 * the specified category.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700234 */
235 public void deregisterAll(Class<?> category) {
236 throw new UnsupportedOperationException("Not supported yet");
237 }
238
239 /**
240 * Deregister all providers from all categories.
241 */
242 public void deregisterAll() {
243 throw new UnsupportedOperationException("Not supported yet");
244 }
245
246 /**
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800247 * Finalizes this object.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700248 *
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800249 * @throws Throwable
250 * if an error occurs during finalization.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700251 */
252 @Override
253 public void finalize() throws Throwable {
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800254 // TODO uncomment when deregisterAll is implemented
255 // deregisterAll();
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700256 }
257
258 /**
259 * Checks whether the specified provider has been already registered.
260 *
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800261 * @param provider
262 * the provider to be checked.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700263 * @return true, if the specified provider has been already registered,
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800264 * false otherwise.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700265 */
266 public boolean contains(Object provider) {
267 throw new UnsupportedOperationException("Not supported yet");
268 }
269
270 /**
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800271 * Gets an iterator of Class objects representing the current categories.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700272 *
273 * @return the Iterator of Class objects.
274 */
275 public Iterator<Class<?>> getCategories() {
276 return categories.list();
277 }
278
279 /**
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800280 * The ServiceRegistry.Filter interface is used by
281 * ServiceRegistry.getServiceProviders to filter providers according to the
282 * specified criterion.
283 *
284 * @since Android 1.0
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700285 */
286 public static interface Filter {
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800287
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700288 /**
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800289 * Returns true if the specified provider satisfies the criterion of
290 * this Filter.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700291 *
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800292 * @param provider
293 * the provider.
294 * @return true, if the specified provider satisfies the criterion of
295 * this Filter, false otherwise.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700296 */
297 boolean filter(Object provider);
298 }
299
300 /**
301 * The Class CategoriesMap.
302 */
303 private static class CategoriesMap {
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800304
305 /**
306 * The categories.
307 */
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700308 Map<Class<?>, ProvidersMap> categories = new HashMap<Class<?>, ProvidersMap>();
309
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800310 /**
311 * The registry.
312 */
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700313 ServiceRegistry registry;
314
315 /**
316 * Instantiates a new categories map.
317 *
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800318 * @param registry
319 * the registry.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700320 */
321 public CategoriesMap(ServiceRegistry registry) {
322 this.registry = registry;
323 }
324
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800325 // -- TODO: useOrdering
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700326 /**
327 * Gets the providers.
328 *
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800329 * @param category
330 * the category.
331 * @param useOrdering
332 * the use ordering.
333 * @return the providers.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700334 */
335 Iterator<?> getProviders(Class<?> category, boolean useOrdering) {
336 ProvidersMap providers = categories.get(category);
337 if (null == providers) {
338 throw new IllegalArgumentException("Unknown category: " + category);
339 }
340 return providers.getProviders(useOrdering);
341 }
342
343 /**
344 * List.
345 *
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800346 * @return the iterator< class<?>>.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700347 */
348 Iterator<Class<?>> list() {
349 return categories.keySet().iterator();
350 }
351
352 /**
353 * Adds the category.
354 *
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800355 * @param category
356 * the category.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700357 */
358 void addCategory(Class<?> category) {
359 categories.put(category, new ProvidersMap());
360 }
361
362 /**
363 * Adds a provider to the category. If <code>category</code> is
364 * <code>null</code> then the provider will be added to all categories
365 * which the provider is assignable from.
366 *
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800367 * @param provider
368 * provider to add.
369 * @param category
370 * category to add provider to.
371 * @return true, if there were such provider in some category.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700372 */
373 boolean addProvider(Object provider, Class<?> category) {
374 if (provider == null) {
375 throw new IllegalArgumentException("provider should be != NULL");
376 }
377
378 boolean rt;
379 if (category == null) {
380 rt = findAndAdd(provider);
381 } else {
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800382 rt = addToNamed(provider, category);
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700383 }
384
385 if (provider instanceof RegisterableService) {
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800386 ((RegisterableService)provider).onRegistration(registry, category);
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700387 }
388
389 return rt;
390 }
391
392 /**
393 * Adds the to named.
394 *
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800395 * @param provider
396 * the provider.
397 * @param category
398 * the category.
399 * @return true, if successful.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700400 */
401 private boolean addToNamed(Object provider, Class<?> category) {
402 Object obj = categories.get(category);
403
404 if (null == obj) {
405 throw new IllegalArgumentException("Unknown category: " + category);
406 }
407
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800408 return ((ProvidersMap)obj).addProvider(provider);
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700409 }
410
411 /**
412 * Find and add.
413 *
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800414 * @param provider
415 * the provider.
416 * @return true, if successful.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700417 */
418 private boolean findAndAdd(Object provider) {
419 boolean rt = false;
420 for (Entry<Class<?>, ProvidersMap> e : categories.entrySet()) {
421 if (e.getKey().isAssignableFrom(provider.getClass())) {
422 rt |= e.getValue().addProvider(provider);
423 }
424 }
425 return rt;
426 }
427 }
428
429 /**
430 * The Class ProvidersMap.
431 */
432 private static class ProvidersMap {
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800433 // -- TODO: providers ordering support
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700434
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800435 /**
436 * The providers.
437 */
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700438 Map<Class<?>, Object> providers = new HashMap<Class<?>, Object>();
439
440 /**
441 * Adds the provider.
442 *
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800443 * @param provider
444 * the provider.
445 * @return true, if successful.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700446 */
447 boolean addProvider(Object provider) {
448 return providers.put(provider.getClass(), provider) != null;
449 }
450
451 /**
452 * Gets the provider classes.
453 *
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800454 * @return the provider classes.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700455 */
456 Iterator<Class<?>> getProviderClasses() {
457 return providers.keySet().iterator();
458 }
459
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800460 // -- TODO ordering
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700461 /**
462 * Gets the providers.
463 *
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800464 * @param userOrdering
465 * the user ordering.
466 * @return the providers.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700467 */
468 Iterator<?> getProviders(boolean userOrdering) {
469 return providers.values().iterator();
470 }
471 }
472
473 /**
474 * The Class FilteredIterator.
475 */
476 private static class FilteredIterator<E> implements Iterator<E> {
477
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800478 /**
479 * The filter.
480 */
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700481 private Filter filter;
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800482
483 /**
484 * The backend.
485 */
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700486 private Iterator<E> backend;
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800487
488 /**
489 * The next obj.
490 */
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700491 private E nextObj;
492
493 /**
494 * Instantiates a new filtered iterator.
495 *
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800496 * @param filter
497 * the filter.
498 * @param backend
499 * the backend.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700500 */
501 public FilteredIterator(Filter filter, Iterator<E> backend) {
502 this.filter = filter;
503 this.backend = backend;
504 findNext();
505 }
506
507 /**
508 * Next.
509 *
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800510 * @return the e.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700511 */
512 public E next() {
513 if (nextObj == null) {
514 throw new NoSuchElementException();
515 }
516 E tmp = nextObj;
517 findNext();
518 return tmp;
519 }
520
521 /**
522 * Checks for next.
523 *
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800524 * @return true, if successful.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700525 */
526 public boolean hasNext() {
527 return nextObj != null;
528 }
529
530 /**
531 * Removes the.
532 */
533 public void remove() {
534 throw new UnsupportedOperationException();
535 }
536
537 /**
The Android Open Source Projecte09fd9e2008-12-17 18:05:43 -0800538 * Sets nextObj to a next provider matching the criterion given by the
539 * filter.
The Android Open Source Project7c1b96a2008-10-21 07:00:00 -0700540 */
541 private void findNext() {
542 nextObj = null;
543 while (backend.hasNext()) {
544 E o = backend.next();
545 if (filter.filter(o)) {
546 nextObj = o;
547 return;
548 }
549 }
550 }
551 }
552}