blob: 79b02a36644dd5803bcb2fa21acfb696e16a4b2e [file] [log] [blame]
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001/*
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 */
21
22package javax.imageio.spi;
23
24import java.util.*;
25import java.util.Map.Entry;
26
27/**
28 * 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
36 */
37public class ServiceRegistry {
38
39 /**
40 * The categories.
41 */
42 CategoriesMap categories = new CategoriesMap(this);
43
44 /**
45 * Instantiates a new ServiceRegistry with the specified categories.
46 *
47 * @param categoriesIterator
48 * an Iterator of Class objects for defining of categories.
49 */
50 public ServiceRegistry(Iterator<Class<?>> categoriesIterator) {
51 if (null == categoriesIterator) {
52 throw new IllegalArgumentException("categories iterator should not be NULL");
53 }
54 while (categoriesIterator.hasNext()) {
55 Class<?> c = categoriesIterator.next();
56 categories.addCategory(c);
57 }
58 }
59
60 /**
61 * Looks up and instantiates the available providers of this service using
62 * the specified class loader.
63 *
64 * @param providerClass
65 * the Class object of the provider to be looked up.
66 * @param loader
67 * the class loader to be used.
68 * @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 /**
75 * Looks up and instantiates the available providers of this service using
76 * the context class loader.
77 *
78 * @param providerClass
79 * the Class object of the provider to be looked up.
80 * @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 /**
87 * Registers the specified service provider object in the specified
88 * categories.
89 *
90 * @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.
96 */
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 *
104 * @param providers
105 * the list of service providers.
106 */
107 public void registerServiceProviders(Iterator<?> providers) {
108 for (Iterator<?> iterator = providers; iterator.hasNext();) {
109 categories.addProvider(iterator.next(), null);
110 }
111 }
112
113 /**
114 * Registers the specified service provider object in all categories.
115 *
116 * @param provider
117 * the service provider.
118 */
119 public void registerServiceProvider(Object provider) {
120 categories.addProvider(provider, null);
121 }
122
123 /**
124 * Deregisters the specifies service provider from the specified category.
125 *
126 * @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.
132 */
133 public <T> boolean deregisterServiceProvider(T provider, Class<T> category) {
134 throw new UnsupportedOperationException("Not supported yet");
135 }
136
137 /**
138 * Deregisters the specified service provider from all categories.
139 *
140 * @param provider
141 * the specified service provider.
142 */
143 public void deregisterServiceProvider(Object provider) {
144 throw new UnsupportedOperationException("Not supported yet");
145 }
146
147 /**
148 * 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.
152 *
153 * @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.
160 * @return the iterator of registered service providers.
161 */
162 @SuppressWarnings("unchecked")
163 public <T> Iterator<T> getServiceProviders(Class<T> category, Filter filter, boolean useOrdering) {
164 return new FilteredIterator<T>(filter, (Iterator<T>)categories.getProviders(category,
165 useOrdering));
166 }
167
168 /**
169 * 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.
172 *
173 * @param category
174 * the specified category.
175 * @param useOrdering
176 * the flag indicating that providers are ordered in the returned
177 * Iterator.
178 * @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 /**
186 * Gets the registered service provider object that has the specified class
187 * type.
188 *
189 * @param providerClass
190 * the specified provider class.
191 * @return the service provider object.
192 */
193 public <T> T getServiceProviderByClass(Class<T> providerClass) {
194 throw new UnsupportedOperationException("Not supported yet");
195 }
196
197 /**
198 * Sets an ordering between two service provider objects within the
199 * specified category.
200 *
201 * @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.
208 */
209 public <T> boolean setOrdering(Class<T> category, T firstProvider, T secondProvider) {
210 throw new UnsupportedOperationException("Not supported yet");
211 }
212
213 /**
214 * Unsets an ordering between two service provider objects within the
215 * specified category.
216 *
217 * @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.
224 */
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 *
232 * @param category
233 * the specified category.
234 */
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 /**
247 * Finalizes this object.
248 *
249 * @throws Throwable
250 * if an error occurs during finalization.
251 */
252 @Override
253 public void finalize() throws Throwable {
254 // TODO uncomment when deregisterAll is implemented
255 // deregisterAll();
256 }
257
258 /**
259 * Checks whether the specified provider has been already registered.
260 *
261 * @param provider
262 * the provider to be checked.
263 * @return true, if the specified provider has been already registered,
264 * false otherwise.
265 */
266 public boolean contains(Object provider) {
267 throw new UnsupportedOperationException("Not supported yet");
268 }
269
270 /**
271 * Gets an iterator of Class objects representing the current categories.
272 *
273 * @return the Iterator of Class objects.
274 */
275 public Iterator<Class<?>> getCategories() {
276 return categories.list();
277 }
278
279 /**
280 * 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
285 */
286 public static interface Filter {
287
288 /**
289 * Returns true if the specified provider satisfies the criterion of
290 * this Filter.
291 *
292 * @param provider
293 * the provider.
294 * @return true, if the specified provider satisfies the criterion of
295 * this Filter, false otherwise.
296 */
297 boolean filter(Object provider);
298 }
299
300 /**
301 * The Class CategoriesMap.
302 */
303 private static class CategoriesMap {
304
305 /**
306 * The categories.
307 */
308 Map<Class<?>, ProvidersMap> categories = new HashMap<Class<?>, ProvidersMap>();
309
310 /**
311 * The registry.
312 */
313 ServiceRegistry registry;
314
315 /**
316 * Instantiates a new categories map.
317 *
318 * @param registry
319 * the registry.
320 */
321 public CategoriesMap(ServiceRegistry registry) {
322 this.registry = registry;
323 }
324
325 // -- TODO: useOrdering
326 /**
327 * Gets the providers.
328 *
329 * @param category
330 * the category.
331 * @param useOrdering
332 * the use ordering.
333 * @return the providers.
334 */
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 *
346 * @return the iterator< class<?>>.
347 */
348 Iterator<Class<?>> list() {
349 return categories.keySet().iterator();
350 }
351
352 /**
353 * Adds the category.
354 *
355 * @param category
356 * the category.
357 */
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 *
367 * @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.
372 */
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 {
382 rt = addToNamed(provider, category);
383 }
384
385 if (provider instanceof RegisterableService) {
386 ((RegisterableService)provider).onRegistration(registry, category);
387 }
388
389 return rt;
390 }
391
392 /**
393 * Adds the to named.
394 *
395 * @param provider
396 * the provider.
397 * @param category
398 * the category.
399 * @return true, if successful.
400 */
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
408 return ((ProvidersMap)obj).addProvider(provider);
409 }
410
411 /**
412 * Find and add.
413 *
414 * @param provider
415 * the provider.
416 * @return true, if successful.
417 */
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 {
433 // -- TODO: providers ordering support
434
435 /**
436 * The providers.
437 */
438 Map<Class<?>, Object> providers = new HashMap<Class<?>, Object>();
439
440 /**
441 * Adds the provider.
442 *
443 * @param provider
444 * the provider.
445 * @return true, if successful.
446 */
447 boolean addProvider(Object provider) {
448 return providers.put(provider.getClass(), provider) != null;
449 }
450
451 /**
452 * Gets the provider classes.
453 *
454 * @return the provider classes.
455 */
456 Iterator<Class<?>> getProviderClasses() {
457 return providers.keySet().iterator();
458 }
459
460 // -- TODO ordering
461 /**
462 * Gets the providers.
463 *
464 * @param userOrdering
465 * the user ordering.
466 * @return the providers.
467 */
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
478 /**
479 * The filter.
480 */
481 private Filter filter;
482
483 /**
484 * The backend.
485 */
486 private Iterator<E> backend;
487
488 /**
489 * The next obj.
490 */
491 private E nextObj;
492
493 /**
494 * Instantiates a new filtered iterator.
495 *
496 * @param filter
497 * the filter.
498 * @param backend
499 * the backend.
500 */
501 public FilteredIterator(Filter filter, Iterator<E> backend) {
502 this.filter = filter;
503 this.backend = backend;
504 findNext();
505 }
506
507 /**
508 * Next.
509 *
510 * @return the e.
511 */
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 *
524 * @return true, if successful.
525 */
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 /**
538 * Sets nextObj to a next provider matching the criterion given by the
539 * filter.
540 */
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}