1 /* 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 22 package javax.imageio.spi; 23 24 import java.util.*; 25 import 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 */ 37 public 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 } 553