OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [javax/] [imageio/] [spi/] [ServiceRegistry.java] - Blame information for rev 781

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 772 jeremybenn
/* ServiceRegistry.java -- A simple registry for service providers.
2
   Copyright (C) 2004, 2005  Free Software Foundation, Inc.
3
 
4
This file is part of GNU Classpath.
5
 
6
GNU Classpath is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2, or (at your option)
9
any later version.
10
 
11
GNU Classpath is distributed in the hope that it will be useful, but
12
WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
General Public License for more details.
15
 
16
You should have received a copy of the GNU General Public License
17
along with GNU Classpath; see the file COPYING.  If not, write to the
18
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
02110-1301 USA.
20
 
21
Linking this library statically or dynamically with other modules is
22
making a combined work based on this library.  Thus, the terms and
23
conditions of the GNU General Public License cover the whole
24
combination.
25
 
26
As a special exception, the copyright holders of this library give you
27
permission to link this library with independent modules to produce an
28
executable, regardless of the license terms of these independent
29
modules, and to copy and distribute the resulting executable under
30
terms of your choice, provided that you also meet, for each linked
31
independent module, the terms and conditions of the license of that
32
module.  An independent module is a module which is not derived from
33
or based on this library.  If you modify this library, you may extend
34
this exception to your version of the library, but you are not
35
obligated to do so.  If you do not wish to do so, delete this
36
exception statement from your version. */
37
 
38
 
39
package javax.imageio.spi;
40
 
41
import gnu.classpath.ServiceFactory;
42
 
43
import java.util.ArrayList;
44
import java.util.Collection;
45
import java.util.Collections;
46
import java.util.Comparator;
47
import java.util.HashSet;
48
import java.util.IdentityHashMap;
49
import java.util.Iterator;
50
import java.util.LinkedList;
51
import java.util.Map;
52
import java.util.NoSuchElementException;
53
import java.util.Set;
54
 
55
/**
56
 * A registry for service providers.
57
 *
58
 * @since 1.4
59
 *
60
 * @author Michael Koch (konqueror@gmx.de)
61
 * @author Sascha Brawer (brawer@dandelis.ch)
62
 */
63
public class ServiceRegistry
64
{
65
  // Package-private to avoid a trampoline.
66
  /**
67
   * The service categories of this registry.
68
   *
69
   * <p>Note that we expect that only very few categories will
70
   * typically be used with a registry. The most common case will be
71
   * one, it seems unlikely that any registry would contain more than
72
   * five or six categories. Therefore, we intentionally avoid the
73
   * overhead of a HashMap.
74
   *
75
   * @see #providers
76
   */
77
  final Class[] categories;
78
 
79
 
80
  /**
81
   * The registered providers for each service category, indexed by
82
   * the same index as the {@link #categories} array. If no provider
83
   * is registered for a category, the array entry will be
84
   * <code>null</code>.
85
   *
86
   * <p>Note that we expect that only very few providers will
87
   * typically be registered for a category. The most common case will
88
   * be one or two. Therefore, we intentionally avoid the overhead of
89
   * a HashMap.
90
   */
91
  private final LinkedList[] providers;
92
 
93
 
94
  /**
95
   * The ordring constaints for each service category, indexed by the
96
   * same index as the {@link #categories} array. The constraints for
97
   * a service category are stored as a <code>Map&lt;Object,
98
   * Set&lt;Object&gt;&gt;</code>, where the Map&#x2019;s values are
99
   * those providers that need to come after the key.  If no
100
   * constraints are imposed on the providers of a category, the array
101
   * entry will be <code>null</code>. If no constraints have been set
102
   * whatsoever, <code>constraints</code> will be <code>null</code>.
103
   *
104
   * <p>Note that we expect that only very few constraints will
105
   * typically be imposed on a category. The most common case will
106
   * be zero.
107
   */
108
  private IdentityHashMap[] constraints;
109
 
110
 
111
  /**
112
   * Constructs a <code>ServiceRegistry</code> for the specified
113
   * service categories.
114
   *
115
   * @param categories the categories to support
116
   *
117
   * @throws IllegalArgumentException if <code>categories</code> is
118
   * <code>null</code>, or if its {@link Iterator#next()} method
119
   * returns <code>null</code>.
120
   *
121
   * @throws ClassCastException if <code>categories</code> does not
122
   * iterate over instances of {@link java.lang.Class}.
123
   */
124
  public ServiceRegistry(Iterator<Class<?>> categories)
125
  {
126
    ArrayList cats = new ArrayList(/* expected size */ 10);
127
 
128
    if (categories == null)
129
      throw new IllegalArgumentException();
130
 
131
    while (categories.hasNext())
132
      {
133
        Class cat = (Class) categories.next();
134
        if (cat == null)
135
          throw new IllegalArgumentException();
136
        cats.add(cat);
137
      }
138
 
139
    int numCats = cats.size();
140
    this.categories = (Class[]) cats.toArray(new Class[numCats]);
141
    this.providers = new LinkedList[numCats];
142
  }
143
 
144
 
145
  /**
146
   * Finds service providers that are implementing the specified
147
   * Service Provider Interface.
148
   *
149
   * <p><b>On-demand loading:</b> Loading and initializing service
150
   * providers is delayed as much as possible. The rationale is that
151
   * typical clients will iterate through the set of installed service
152
   * providers until one is found that matches some criteria (like
153
   * supported formats, or quality of service). In such scenarios, it
154
   * might make sense to install only the frequently needed service
155
   * providers on the local machine. More exotic providers can be put
156
   * onto a server; the server will only be contacted when no suitable
157
   * service could be found locally.</p>
158
   *
159
   * <p><b>Security considerations:</b> Any loaded service providers
160
   * are loaded through the specified ClassLoader, or the system
161
   * ClassLoader if <code>classLoader</code> is
162
   * <code>null</code>. When <code>lookupProviders</code> is called,
163
   * the current {@link java.security.AccessControlContext} gets
164
   * recorded. This captured security context will determine the
165
   * permissions when services get loaded via the <code>next()</code>
166
   * method of the returned <code>Iterator</code>.</p>
167
   *
168
   * @param spi the service provider interface which must be
169
   * implemented by any loaded service providers.
170
   *
171
   * @param loader the class loader that will be used to load the
172
   * service providers, or <code>null</code> for the system class
173
   * loader. For using the context class loader, see {@link
174
   * #lookupProviders(Class)}.
175
   *
176
   * @return an iterator over instances of <code>spi</code>.
177
   *
178
   * @throws IllegalArgumentException if <code>spi</code> is
179
   * <code>null</code>.
180
   */
181
  public static <T> Iterator<T> lookupProviders(Class<T> spi,
182
                                                ClassLoader loader)
183
  {
184
    return ServiceFactory.lookupProviders(spi, loader);
185
  }
186
 
187
 
188
  /**
189
   * Finds service providers that are implementing the specified
190
   * Service Provider Interface, using the context class loader
191
   * for loading providers.
192
   *
193
   * @param spi the service provider interface which must be
194
   * implemented by any loaded service providers.
195
   *
196
   * @return an iterator over instances of <code>spi</code>.
197
   *
198
   * @throws IllegalArgumentException if <code>spi</code> is
199
   * <code>null</code>.
200
   *
201
   * @see #lookupProviders(Class, ClassLoader)
202
   */
203
  public static <T> Iterator<T> lookupProviders(Class<T> spi)
204
  {
205
    return ServiceFactory.lookupProviders(spi);
206
  }
207
 
208
 
209
  /**
210
   * Returns an iterator over all service categories.
211
   *
212
   * @return an unmodifiable {@link
213
   * java.util.Iterator}&lt;{@link java.lang.Class}&gt;.
214
   */
215
  public Iterator<Class<?>> getCategories()
216
  {
217
    return new Iterator()
218
      {
219
        int index = -1;
220
 
221
        public boolean hasNext()
222
        {
223
          return index < categories.length - 1;
224
        }
225
 
226
        public Object next()
227
        {
228
          if (!hasNext())
229
            throw new NoSuchElementException();
230
 
231
          return categories[++index];
232
        }
233
 
234
        public void remove()
235
        {
236
          throw new UnsupportedOperationException();
237
        }
238
      };
239
  }
240
 
241
 
242
  /**
243
   * Registers a provider for a service category which is specified by
244
   * the class-internal category ID.
245
   *
246
   * @param provider the service provider to be registered.
247
   *
248
   * @param cat the service category, which is identified by an index
249
   * into the {@link #categories} array.
250
   *
251
   * @return <code>true</code> if <code>provider</code> is the first
252
   * provider that gets registered for the specified service category;
253
   * <code>false</code> if other providers have already been
254
   * registered for the same servide category.
255
   *
256
   * @throws IllegalArgumentException if <code>provider</code> is
257
   * <code>null</code>.
258
   *
259
   * @throws ClassCastException if <code>provider</code> does not
260
   * implement the specified service provider interface.
261
   */
262
  private synchronized boolean registerServiceProvider(Object provider,
263
                                                       int cat)
264
  {
265
    LinkedList provs;
266
    boolean result;
267
    Class category;
268
 
269
    if (provider == null)
270
      throw new IllegalArgumentException();
271
 
272
    category = categories[cat];
273
    if (!category.isInstance(provider))
274
      throw new ClassCastException(category.getName());
275
 
276
    provs = providers[cat];
277
    if (provs == null)
278
    {
279
      result = true;
280
      provs = providers[cat] = new LinkedList();
281
    }
282
    else
283
      result = false;
284
 
285
    provs.add(provider);
286
    if (provider instanceof RegisterableService)
287
      ((RegisterableService) provider).onRegistration(this, category);
288
 
289
    return result;
290
  }
291
 
292
 
293
  /**
294
   * Registers a provider for the specified service category.
295
   *
296
   * <p>If <code>provider</code> implements the {@link
297
   * RegisterableService} interface, its {@link
298
   * RegisterableService#onRegistration onRegistration} method is
299
   * invoked in order to inform the provider about the addition to
300
   * this registry.
301
   *
302
   * @param provider the service provider to be registered.
303
   *
304
   * @param category the service category under which
305
   * <code>provider</code> shall be registered.
306
   *
307
   * @return <code>true</code> if <code>provider</code> is the first
308
   * provider that gets registered for the specified service category;
309
   * <code>false</code> if other providers have already been
310
   * registered for the same servide category.
311
   *
312
   * @throws IllegalArgumentException if <code>provider</code> is
313
   * <code>null</code>, or if <code>category</code> is not among the
314
   * categories passed to the {@linkplain #ServiceRegistry(Iterator)
315
   * constructor} of this ServiceRegistry.
316
   *
317
   * @throws ClassCastException if <code>provider</code> does not
318
   * implement <code>category</code>.
319
   */
320
  public synchronized <T> boolean registerServiceProvider(T provider,
321
                                                          Class<T> category)
322
  {
323
    for (int i = 0; i < categories.length; i++)
324
      if (categories[i] == category)
325
        return registerServiceProvider(provider, i);
326
    throw new IllegalArgumentException();
327
  }
328
 
329
 
330
  /**
331
   * Registers a provider under all service categories it
332
   * implements.
333
   *
334
   * <p>If <code>provider</code> implements the {@link
335
   * RegisterableService} interface, its {@link
336
   * RegisterableService#onRegistration onRegistration} method is
337
   * invoked in order to inform the provider about the addition to
338
   * this registry. If <code>provider</code> implements several
339
   * service categories, <code>onRegistration</code> gets called
340
   * multiple times.
341
   *
342
   * @param provider the service provider to be registered.
343
   *
344
   * @throws IllegalArgumentException if <code>provider</code> is
345
   * <code>null</code>, or if <code>provider</code> does not implement
346
   * any of the service categories passed to the {@linkplain
347
   * #ServiceRegistry(Iterator) constructor} of this ServiceRegistry.
348
   */
349
  public synchronized void registerServiceProvider(Object provider)
350
  {
351
    boolean ok = false;
352
 
353
    if (provider == null)
354
      throw new IllegalArgumentException();
355
 
356
    for (int i = 0; i < categories.length; i++)
357
      if (categories[i].isInstance(provider))
358
        {
359
          ok = true;
360
          registerServiceProvider(provider, i);
361
        }
362
 
363
    if (!ok)
364
      throw new IllegalArgumentException();
365
  }
366
 
367
 
368
  /**
369
   * Registers a number of providers under all service categories they
370
   * implement.
371
   *
372
   * <p>If a provider implements the {@link RegisterableService}
373
   * interface, its {@link RegisterableService#onRegistration
374
   * onRegistration} method is invoked in order to inform the provider
375
   * about the addition to this registry. If <code>provider</code>
376
   * implements several service categories,
377
   * <code>onRegistration</code> gets called multiple times.
378
   *
379
   * @throws IllegalArgumentException if <code>providers</code> is
380
   * <code>null</code>, if any iterated provider is <code>null</code>,
381
   * or if some iterated provider does not implement any of the
382
   * service categories passed to the {@linkplain
383
   * #ServiceRegistry(Iterator) constructor} of this
384
   * <code>ServiceRegistry</code>.
385
   */
386
  public synchronized void registerServiceProviders(Iterator<?> providers)
387
  {
388
    if (providers == null)
389
      throw new IllegalArgumentException();
390
 
391
    while (providers.hasNext())
392
      registerServiceProvider(providers.next());
393
  }
394
 
395
 
396
  /**
397
   * De-registers a provider for a service category which is specified
398
   * by the class-internal category ID.
399
   *
400
   * @param provider the service provider to be registered.
401
   *
402
   * @param cat the service category, which is identified by an index
403
   * into the {@link #categories} array.
404
   *
405
   * @return <code>true</code> if <code>provider</code> was previously
406
   * registered for the specified service category; <code>false</code>
407
   * if if the provider had not been registered.
408
   *
409
   * @throws IllegalArgumentException if <code>provider</code> is
410
   * <code>null</code>.
411
   *
412
   * @throws ClassCastException if <code>provider</code> does not
413
   * implement the specified service provider interface.
414
   */
415
  private synchronized boolean deregisterServiceProvider(Object provider,
416
                                                         int cat)
417
  {
418
    LinkedList provs;
419
    boolean result;
420
    Class category;
421
 
422
    if (provider == null)
423
      throw new IllegalArgumentException();
424
 
425
    category = categories[cat];
426
    if (!category.isInstance(provider))
427
      throw new ClassCastException(category.getName());
428
 
429
    provs = providers[cat];
430
    if (provs == null)
431
      return false;
432
 
433
    result = provs.remove(provider);
434
    if (provs.isEmpty())
435
      providers[cat] = null;
436
 
437
    if (result && (provider instanceof RegisterableService))
438
      ((RegisterableService) provider).onDeregistration(this, category);
439
 
440
    return result;
441
  }
442
 
443
 
444
  /**
445
   * De-registers a provider for the specified service category.
446
   *
447
   * <p>If <code>provider</code> implements the {@link
448
   * RegisterableService} interface, its {@link
449
   * RegisterableService#onDeregistration onDeregistration} method is
450
   * invoked in order to inform the provider about the removal from
451
   * this registry.
452
   *
453
   * @param provider the service provider to be de-registered.
454
   *
455
   * @param category the service category from which
456
   * <code>provider</code> shall be de-registered.
457
   *
458
   * @return <code>true</code> if <code>provider</code> was previously
459
   * registered for the specified service category; <code>false</code>
460
   * if if the provider had not been registered.
461
   *
462
   * @throws IllegalArgumentException if <code>provider</code> is
463
   * <code>null</code>, or if <code>category</code> is not among the
464
   * categories passed to the {@linkplain #ServiceRegistry(Iterator)
465
   * constructor} of this ServiceRegistry.
466
   *
467
   * @throws ClassCastException if <code>provider</code> does not
468
   * implement <code>category</code>.
469
   */
470
  public synchronized <T> boolean deregisterServiceProvider(T provider,
471
                                                            Class<T> category)
472
  {
473
    for (int i = 0; i < categories.length; i++)
474
      if (categories[i] == category)
475
        return deregisterServiceProvider(provider, i);
476
    throw new IllegalArgumentException();
477
  }
478
 
479
 
480
  /**
481
   * De-registers a provider from all service categories it
482
   * implements.
483
   *
484
   * <p>If <code>provider</code> implements the {@link
485
   * RegisterableService} interface, its {@link
486
   * RegisterableService#onDeregistration onDeregistration} method is
487
   * invoked in order to inform the provider about the removal from
488
   * this registry. If <code>provider</code> implements several
489
   * service categories, <code>onDeregistration</code> gets called
490
   * multiple times.</p>
491
   *
492
   * @param provider the service provider to be de-registered.
493
   *
494
   * @throws IllegalArgumentException if <code>provider</code> is
495
   * <code>null</code>, or if <code>provider</code> does not implement
496
   * any of the service categories passed to the {@linkplain
497
   * #ServiceRegistry(Iterator) constructor} of this
498
   * <code>ServiceRegistry</code>.
499
   */
500
  public synchronized void deregisterServiceProvider(Object provider)
501
  {
502
    boolean ok = false;
503
 
504
    if (provider == null)
505
      throw new IllegalArgumentException();
506
 
507
    for (int i = 0; i < categories.length; i++)
508
      if (categories[i].isInstance(provider))
509
        {
510
          ok = true;
511
          deregisterServiceProvider(provider, i);
512
        }
513
 
514
    if (!ok)
515
      throw new IllegalArgumentException();
516
  }
517
 
518
 
519
  /**
520
   * De-registers all providers which have been registered for the
521
   * specified service category.
522
   *
523
   * <p>If a provider implements the {@link RegisterableService}
524
   * interface, its {@link RegisterableService#onDeregistration
525
   * onDeregistration} method is invoked in order to inform the
526
   * provider about the removal from this registry. If the provider
527
   * implements several service categories,
528
   * <code>onDeregistration</code> gets called multiple times.
529
   *
530
   * @param category the category whose registered providers will be
531
   * de-registered.
532
   *
533
   * @throws IllegalArgumentException if <code>category</code> is not
534
   * among the categories passed to the {@linkplain
535
   * #ServiceRegistry(Iterator) constructor} of this
536
   * <code>ServiceRegistry</code>.
537
   */
538
  public synchronized void deregisterAll(Class<?> category)
539
  {
540
    boolean ok = false;
541
 
542
    for (int i = 0; i < categories.length; i++)
543
      {
544
        if (categories[i] != category)
545
          continue;
546
 
547
        ok = true;
548
        while (providers[i] != null)
549
          deregisterServiceProvider(providers[i].get(0), i);
550
      }
551
 
552
    if (!ok)
553
      throw new IllegalArgumentException();
554
  }
555
 
556
 
557
  /**
558
   * De-registers all service providers.
559
   *
560
   * <p>If a provider implements the {@link RegisterableService}
561
   * interface, its {@link RegisterableService#onDeregistration
562
   * onDeregistration} method is invoked in order to inform the
563
   * provider about the removal from this registry. If the provider
564
   * implements several service categories,
565
   * <code>onDeregistration</code> gets called multiple times.
566
   */
567
  public synchronized void deregisterAll()
568
  {
569
    for (int i = 0; i < categories.length; i++)
570
      while (providers[i] != null)
571
        deregisterServiceProvider(providers[i].get(0), i);
572
  }
573
 
574
 
575
  /**
576
   * Called by the Virtual Machine when it detects that this
577
   * <code>ServiceRegistry</code> has become garbage. De-registers all
578
   * service providers, which will cause those that implement {@link
579
   * RegisterableService} to receive a {@link
580
   * RegisterableService#onDeregistration onDeregistration}
581
   * notification.
582
   */
583
  public void finalize()
584
    throws Throwable
585
  {
586
    super.finalize();
587
    deregisterAll();
588
  }
589
 
590
 
591
  /**
592
   * Determines whether a provider has been registered with this
593
   * registry.
594
   *
595
   * @return <code>true</code> if <code>provider</code> has been
596
   * registered under any service category; <code>false</code> if
597
   * it is not registered.
598
   *
599
   * @throws IllegalArgumentException if <code>provider</code> is
600
   * <code>null</code>.
601
   */
602
  public synchronized boolean contains(Object provider)
603
  {
604
    if (provider == null)
605
      throw new IllegalArgumentException();
606
 
607
    // Note that contains is rather unlikely to be ever called,
608
    // so it would be wasteful to keep a special data structure
609
    // (such as a HashSet) for making it a fast operation.
610
    for (int i = 0; i < providers.length; i++)
611
      {
612
        // If provider does not implement categories[i],
613
        // it would not have been possible to register it there.
614
        // In that case, it would be pointless to look there.
615
        if (!categories[i].isInstance(provider))
616
          continue;
617
 
618
        // But if the list of registered providers contains provider,
619
        // we have found it.
620
        LinkedList p = providers[i];
621
        if (p != null && p.contains(provider))
622
          return true;
623
      }
624
 
625
    return false;
626
  }
627
 
628
 
629
  /**
630
   * Returns the index in {@link #categories} occupied by the
631
   * specified service category.
632
   *
633
   * @throws IllegalArgumentException if <code>category</code> is not
634
   * among the categories passed to the {@linkplain
635
   * #ServiceRegistry(Iterator) constructor} of this ServiceRegistry.
636
   */
637
  private int getCategoryID(Class category)
638
  {
639
    for (int i = 0; i < categories.length; i++)
640
      if (categories[i] == category)
641
        return i;
642
 
643
    throw new IllegalArgumentException();
644
  }
645
 
646
 
647
  /**
648
   * Retrieves all providers that have been registered for the
649
   * specified service category.
650
   *
651
   * @param category the service category whose providers are
652
   * to be retrieved.
653
   *
654
   * @param useOrdering <code>true</code> in order to retrieve the
655
   * providers in an order imposed by the {@linkplain #setOrdering
656
   * ordering constraints}; <code>false</code> in order to retrieve
657
   * the providers in any order.
658
   *
659
   * @throws IllegalArgumentException if <code>category</code> is not
660
   * among the categories passed to the {@linkplain
661
   * #ServiceRegistry(Iterator) constructor} of this
662
   * <code>ServiceRegistry</code>.
663
   *
664
   * @see #getServiceProviders(Class, Filter, boolean)
665
   */
666
  public <T> Iterator<T> getServiceProviders(Class<T> category,
667
                                             boolean useOrdering)
668
  {
669
    return getServiceProviders(category, null, useOrdering);
670
  }
671
 
672
 
673
  /**
674
   * Retrieves all providers that have been registered for the
675
   * specified service category and that satisfy the criteria
676
   * of a custom filter.
677
   *
678
   * @param category the service category whose providers are
679
   * to be retrieved.
680
   *
681
   * @param filter a custom filter, or <code>null</code> to
682
   * retrieve all registered providers for the specified
683
   * category.
684
   *
685
   * @param useOrdering <code>true</code> in order to retrieve the
686
   * providers in an order imposed by the {@linkplain #setOrdering
687
   * ordering constraints}; <code>false</code> in order to retrieve
688
   * the providers in any order.
689
   *
690
   * @throws IllegalArgumentException if <code>category</code> is not
691
   * among the categories passed to the {@linkplain
692
   * #ServiceRegistry(Iterator) constructor} of this
693
   * <code>ServiceRegistry</code>.
694
   */
695
  public synchronized <T> Iterator<T> getServiceProviders(Class<T> category,
696
                                                          Filter filter,
697
                                                          boolean useOrdering)
698
  {
699
    int catid;
700
    LinkedList provs;
701
    ArrayList result;
702
 
703
    catid = getCategoryID(category);
704
    provs = providers[catid];
705
    if (provs == null)
706
      return Collections.EMPTY_LIST.iterator();
707
 
708
    result = new ArrayList(provs.size());
709
    for (Iterator iter = provs.iterator(); iter.hasNext();)
710
      {
711
        Object provider = iter.next();
712
        if (filter == null || filter.filter(provider))
713
          result.add(provider);
714
      }
715
 
716
    // If we are supposed to obey ordering constraints, and
717
    // if any constraints have been imposed on the specified
718
    // service category, sort the result.
719
    if (useOrdering && constraints != null)
720
      {
721
        final Map cons = constraints[catid];
722
        if (cons != null)
723
          Collections.sort(result, new Comparator()
724
            {
725
              public int compare(Object o1, Object o2)
726
              {
727
                Set s;
728
 
729
                if (o1 == o2)
730
                  return 0;
731
 
732
                s = (Set) cons.get(o1);
733
                if (s != null && s.contains(o2))
734
                  return -1;  // o1 < o2
735
 
736
                s = (Set) cons.get(o2);
737
                if (s != null && s.contains(o1))
738
                  return 1;  // o1 > o2
739
 
740
                return 0; // o1 == o2
741
              }
742
            });
743
      }
744
 
745
    return result.iterator();
746
  }
747
 
748
 
749
  /**
750
   * Returns one of the service providers that is a subclass of the
751
   * specified class.
752
   *
753
   * @param providerClass a class to search for.
754
   */
755
  public synchronized <T> T getServiceProviderByClass(Class<T> providerClass)
756
  {
757
    if (providerClass == null)
758
      throw new IllegalArgumentException();
759
 
760
    // Note that the method getServiceProviderByClass is rather
761
    // unlikely to be ever called, so it would be wasteful to keep a
762
    // special data structure for making it a fast operation.
763
    for (int cat = 0; cat < categories.length; cat++)
764
      {
765
        if (!categories[cat].isAssignableFrom(providerClass))
766
          continue;
767
 
768
        LinkedList provs = providers[cat];
769
        if (provs == null)
770
          continue;
771
 
772
        for (Iterator iter = provs.iterator(); iter.hasNext();)
773
          {
774
            Object provider = iter.next();
775
            if (providerClass.isInstance(provider))
776
              return (T) provider;
777
          }
778
      }
779
 
780
    return null;
781
  }
782
 
783
 
784
  /**
785
   * Adds an ordering constraint on service providers.
786
   *
787
   * @param category the service category to which an ordering
788
   * constraint is to be added.
789
   *
790
   * @param firstProvider the provider which is supposed to come before
791
   * <code>second</code>.
792
   *
793
   * @param secondProvider the provider which is supposed to come after
794
   * <code>first</code>.
795
   *
796
   * @throws IllegalArgumentException if <code>first</code> and
797
   * <code>second</code> are referring to the same object, or if one
798
   * of them is <code>null</code>.
799
   *
800
   * @see #unsetOrdering
801
   * @see #getServiceProviders(Class, Filter, boolean)
802
   */
803
  public synchronized <T> boolean setOrdering(Class<T> category,
804
                                              T firstProvider,
805
                                              T secondProvider)
806
  {
807
    return addConstraint(getCategoryID(category), firstProvider,
808
                         secondProvider);
809
  }
810
 
811
 
812
  /**
813
   * Removes an ordering constraint on service providers.
814
   *
815
   * @param category the service category from which an ordering
816
   * constraint is to be removed.
817
   *
818
   * @param firstProvider the provider which is supposed to come before
819
   * <code>second</code>.
820
   *
821
   * @param secondProvider the provider which is supposed to come after
822
   * <code>first</code>.
823
   *
824
   * @throws IllegalArgumentException if <code>first</code> and
825
   * <code>second</code> are referring to the same object, or if one
826
   * of them is <code>null</code>.
827
   *
828
   * @see #setOrdering
829
   */
830
  public synchronized <T> boolean unsetOrdering(Class<T> category,
831
                                                T firstProvider,
832
                                                T secondProvider)
833
  {
834
    return removeConstraint(getCategoryID(category),
835
                            firstProvider, secondProvider);
836
  }
837
 
838
 
839
  /**
840
   * Adds an ordering constraint on service providers.
841
   *
842
   * @param catid the service category ID, which is the
843
   * category&#x2019;s index into the {@link #categories} array.
844
   *
845
   * @param first the provider which is supposed to come before
846
   * <code>second</code>.
847
   *
848
   * @param second the provider which is supposed to come after
849
   * <code>first</code>.
850
   *
851
   * @throws IllegalArgumentException if <code>first</code> and
852
   * <code>second</code> are referring to the same object, or if one
853
   * of them is <code>null</code>.
854
   */
855
  private boolean addConstraint(int catid, Object first, Object second)
856
  {
857
    Set s;
858
    IdentityHashMap cons;
859
 
860
    // Also checks argument validity.
861
    removeConstraint(catid, second, first);
862
 
863
    if (constraints == null)
864
      constraints = new IdentityHashMap[categories.length];
865
    cons = constraints[catid];
866
    if (cons == null)
867
      cons = constraints[catid] = new IdentityHashMap();
868
 
869
    s = (Set) cons.get(first);
870
    if (s == null)
871
      cons.put(first, s = new HashSet());
872
    return s.add(second);
873
  }
874
 
875
 
876
  /**
877
   * Removes an ordering constraint on service providers.
878
   *
879
   * @param catid the service category ID, which is the
880
   * category&#x2019;s index into the {@link #categories} array.
881
   *
882
   * @param first the provider which is supposed to come before
883
   * <code>second</code>.
884
   *
885
   * @param second the provider which is supposed to come after
886
   * <code>first</code>.
887
   *
888
   * @throws IllegalArgumentException if <code>first</code> and
889
   * <code>second</code> are referring to the same object, or if one
890
   * of them is <code>null</code>.
891
   */
892
  private boolean removeConstraint(int catid, Object first, Object second)
893
  {
894
    Collection s;
895
    IdentityHashMap cons;
896
 
897
    if (first == null || second == null || first == second)
898
      throw new IllegalArgumentException();
899
 
900
    if (constraints == null)
901
      return false;
902
 
903
    cons = constraints[catid];
904
    if (cons == null)
905
      return false;
906
 
907
    s = (Collection) cons.get(first);
908
    if (s == null)
909
      return false;
910
 
911
    if (!s.remove(second))
912
      return false;
913
 
914
    // If we removed the last constraint for a service category,
915
    // we can get free some memory.
916
    if (cons.isEmpty())
917
      {
918
        constraints[catid] = null;
919
        boolean anyConstraints = false;
920
        for (int i = 0; i < constraints.length; i++)
921
          {
922
            if (constraints[i] != null)
923
              {
924
                anyConstraints = true;
925
                break;
926
              }
927
          }
928
        if (!anyConstraints)
929
          constraints = null;
930
      }
931
 
932
    return true;
933
  }
934
 
935
 
936
  /**
937
   * A filter for selecting service providers that match custom
938
   * criteria.
939
   *
940
   * @see ServiceRegistry#getServiceProviders(Class, Filter,
941
   * boolean)
942
   *
943
   * @since 1.4
944
   *
945
   * @author Michael Koch (konqueror@gmx.de)
946
   * @author Sascha Brawer (brawer@dandelis.ch)
947
   */
948
  public static interface Filter
949
  {
950
    /**
951
     * Checks whether the specified service provider matches the
952
     * constraints of this Filter.
953
     *
954
     * @param provider the service provider in question.
955
     *
956
     * @return <code>true</code> if <code>provider</code> matches the
957
     * criteria; <code>false</code> if it does not match.
958
     */
959
    boolean filter(Object provider);
960
  }
961
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.