Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/javax/imageio/spi/ServiceRegistry.java
38830 views
1
/*
2
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package javax.imageio.spi;
27
28
import java.io.File;
29
import java.security.AccessControlContext;
30
import java.security.AccessController;
31
import java.security.PrivilegedAction;
32
import java.util.ArrayList;
33
import java.util.HashMap;
34
import java.util.Iterator;
35
import java.util.List;
36
import java.util.Map;
37
import java.util.NoSuchElementException;
38
import java.util.Set;
39
import java.util.ServiceLoader;
40
41
/**
42
* A registry for service provider instances.
43
*
44
* <p> A <i>service</i> is a well-known set of interfaces and (usually
45
* abstract) classes. A <i>service provider</i> is a specific
46
* implementation of a service. The classes in a provider typically
47
* implement the interface or subclass the class defined by the
48
* service itself.
49
*
50
* <p> Service providers are stored in one or more <i>categories</i>,
51
* each of which is defined by a class of interface (described by a
52
* <code>Class</code> object) that all of its members must implement.
53
* The set of categories may be changed dynamically.
54
*
55
* <p> Only a single instance of a given leaf class (that is, the
56
* actual class returned by <code>getClass()</code>, as opposed to any
57
* inherited classes or interfaces) may be registered. That is,
58
* suppose that the
59
* <code>com.mycompany.mypkg.GreenServiceProvider</code> class
60
* implements the <code>com.mycompany.mypkg.MyService</code>
61
* interface. If a <code>GreenServiceProvider</code> instance is
62
* registered, it will be stored in the category defined by the
63
* <code>MyService</code> class. If a new instance of
64
* <code>GreenServiceProvider</code> is registered, it will replace
65
* the previous instance. In practice, service provider objects are
66
* usually singletons so this behavior is appropriate.
67
*
68
* <p> To declare a service provider, a <code>services</code>
69
* subdirectory is placed within the <code>META-INF</code> directory
70
* that is present in every JAR file. This directory contains a file
71
* for each service provider interface that has one or more
72
* implementation classes present in the JAR file. For example, if
73
* the JAR file contained a class named
74
* <code>com.mycompany.mypkg.MyServiceImpl</code> which implements the
75
* <code>javax.someapi.SomeService</code> interface, the JAR file
76
* would contain a file named: <pre>
77
* META-INF/services/javax.someapi.SomeService </pre>
78
*
79
* containing the line:
80
*
81
* <pre>
82
* com.mycompany.mypkg.MyService
83
* </pre>
84
*
85
* <p> The service provider classes should be to be lightweight and
86
* quick to load. Implementations of these interfaces should avoid
87
* complex dependencies on other classes and on native code. The usual
88
* pattern for more complex services is to register a lightweight
89
* proxy for the heavyweight service.
90
*
91
* <p> An application may customize the contents of a registry as it
92
* sees fit, so long as it has the appropriate runtime permission.
93
*
94
* <p> For more details on declaring service providers, and the JAR
95
* format in general, see the <a
96
* href="../../../../technotes/guides/jar/jar.html">
97
* JAR File Specification</a>.
98
*
99
* @see RegisterableService
100
*
101
*/
102
public class ServiceRegistry {
103
104
// Class -> Registry
105
private Map categoryMap = new HashMap();
106
107
/**
108
* Constructs a <code>ServiceRegistry</code> instance with a
109
* set of categories taken from the <code>categories</code>
110
* argument.
111
*
112
* @param categories an <code>Iterator</code> containing
113
* <code>Class</code> objects to be used to define categories.
114
*
115
* @exception IllegalArgumentException if
116
* <code>categories</code> is <code>null</code>.
117
*/
118
public ServiceRegistry(Iterator<Class<?>> categories) {
119
if (categories == null) {
120
throw new IllegalArgumentException("categories == null!");
121
}
122
while (categories.hasNext()) {
123
Class category = (Class)categories.next();
124
SubRegistry reg = new SubRegistry(this, category);
125
categoryMap.put(category, reg);
126
}
127
}
128
129
// The following two methods expose functionality from
130
// sun.misc.Service. If that class is made public, they may be
131
// removed.
132
//
133
// The sun.misc.ServiceConfigurationError class may also be
134
// exposed, in which case the references to 'an
135
// <code>Error</code>' below should be changed to 'a
136
// <code>ServiceConfigurationError</code>'.
137
138
/**
139
* Searches for implementations of a particular service class
140
* using the given class loader.
141
*
142
* <p> This method transforms the name of the given service class
143
* into a provider-configuration filename as described in the
144
* class comment and then uses the <code>getResources</code>
145
* method of the given class loader to find all available files
146
* with that name. These files are then read and parsed to
147
* produce a list of provider-class names. The iterator that is
148
* returned uses the given class loader to look up and then
149
* instantiate each element of the list.
150
*
151
* <p> Because it is possible for extensions to be installed into
152
* a running Java virtual machine, this method may return
153
* different results each time it is invoked.
154
*
155
* @param providerClass a <code>Class</code>object indicating the
156
* class or interface of the service providers being detected.
157
*
158
* @param loader the class loader to be used to load
159
* provider-configuration files and instantiate provider classes,
160
* or <code>null</code> if the system class loader (or, failing that
161
* the bootstrap class loader) is to be used.
162
*
163
* @param <T> the type of the providerClass.
164
*
165
* @return An <code>Iterator</code> that yields provider objects
166
* for the given service, in some arbitrary order. The iterator
167
* will throw an <code>Error</code> if a provider-configuration
168
* file violates the specified format or if a provider class
169
* cannot be found and instantiated.
170
*
171
* @exception IllegalArgumentException if
172
* <code>providerClass</code> is <code>null</code>.
173
*/
174
public static <T> Iterator<T> lookupProviders(Class<T> providerClass,
175
ClassLoader loader)
176
{
177
if (providerClass == null) {
178
throw new IllegalArgumentException("providerClass == null!");
179
}
180
return ServiceLoader.load(providerClass, loader).iterator();
181
}
182
183
/**
184
* Locates and incrementally instantiates the available providers
185
* of a given service using the context class loader. This
186
* convenience method is equivalent to:
187
*
188
* <pre>
189
* ClassLoader cl = Thread.currentThread().getContextClassLoader();
190
* return Service.providers(service, cl);
191
* </pre>
192
*
193
* @param providerClass a <code>Class</code>object indicating the
194
* class or interface of the service providers being detected.
195
*
196
* @param <T> the type of the providerClass.
197
*
198
* @return An <code>Iterator</code> that yields provider objects
199
* for the given service, in some arbitrary order. The iterator
200
* will throw an <code>Error</code> if a provider-configuration
201
* file violates the specified format or if a provider class
202
* cannot be found and instantiated.
203
*
204
* @exception IllegalArgumentException if
205
* <code>providerClass</code> is <code>null</code>.
206
*/
207
public static <T> Iterator<T> lookupProviders(Class<T> providerClass) {
208
if (providerClass == null) {
209
throw new IllegalArgumentException("providerClass == null!");
210
}
211
return ServiceLoader.load(providerClass).iterator();
212
}
213
214
/**
215
* Returns an <code>Iterator</code> of <code>Class</code> objects
216
* indicating the current set of categories. The iterator will be
217
* empty if no categories exist.
218
*
219
* @return an <code>Iterator</code> containing
220
* <code>Class</code>objects.
221
*/
222
public Iterator<Class<?>> getCategories() {
223
Set keySet = categoryMap.keySet();
224
return keySet.iterator();
225
}
226
227
/**
228
* Returns an Iterator containing the subregistries to which the
229
* provider belongs.
230
*/
231
private Iterator getSubRegistries(Object provider) {
232
List l = new ArrayList();
233
Iterator iter = categoryMap.keySet().iterator();
234
while (iter.hasNext()) {
235
Class c = (Class)iter.next();
236
if (c.isAssignableFrom(provider.getClass())) {
237
l.add((SubRegistry)categoryMap.get(c));
238
}
239
}
240
return l.iterator();
241
}
242
243
/**
244
* Adds a service provider object to the registry. The provider
245
* is associated with the given category.
246
*
247
* <p> If <code>provider</code> implements the
248
* <code>RegisterableService</code> interface, its
249
* <code>onRegistration</code> method will be called. Its
250
* <code>onDeregistration</code> method will be called each time
251
* it is deregistered from a category, for example if a
252
* category is removed or the registry is garbage collected.
253
*
254
* @param provider the service provide object to be registered.
255
* @param category the category under which to register the
256
* provider.
257
* @param <T> the type of the provider.
258
*
259
* @return true if no provider of the same class was previously
260
* registered in the same category category.
261
*
262
* @exception IllegalArgumentException if <code>provider</code> is
263
* <code>null</code>.
264
* @exception IllegalArgumentException if there is no category
265
* corresponding to <code>category</code>.
266
* @exception ClassCastException if provider does not implement
267
* the <code>Class</code> defined by <code>category</code>.
268
*/
269
public <T> boolean registerServiceProvider(T provider,
270
Class<T> category) {
271
if (provider == null) {
272
throw new IllegalArgumentException("provider == null!");
273
}
274
SubRegistry reg = (SubRegistry)categoryMap.get(category);
275
if (reg == null) {
276
throw new IllegalArgumentException("category unknown!");
277
}
278
if (!category.isAssignableFrom(provider.getClass())) {
279
throw new ClassCastException();
280
}
281
282
return reg.registerServiceProvider(provider);
283
}
284
285
/**
286
* Adds a service provider object to the registry. The provider
287
* is associated within each category present in the registry
288
* whose <code>Class</code> it implements.
289
*
290
* <p> If <code>provider</code> implements the
291
* <code>RegisterableService</code> interface, its
292
* <code>onRegistration</code> method will be called once for each
293
* category it is registered under. Its
294
* <code>onDeregistration</code> method will be called each time
295
* it is deregistered from a category or when the registry is
296
* finalized.
297
*
298
* @param provider the service provider object to be registered.
299
*
300
* @exception IllegalArgumentException if
301
* <code>provider</code> is <code>null</code>.
302
*/
303
public void registerServiceProvider(Object provider) {
304
if (provider == null) {
305
throw new IllegalArgumentException("provider == null!");
306
}
307
Iterator regs = getSubRegistries(provider);
308
while (regs.hasNext()) {
309
SubRegistry reg = (SubRegistry)regs.next();
310
reg.registerServiceProvider(provider);
311
}
312
}
313
314
/**
315
* Adds a set of service provider objects, taken from an
316
* <code>Iterator</code> to the registry. Each provider is
317
* associated within each category present in the registry whose
318
* <code>Class</code> it implements.
319
*
320
* <p> For each entry of <code>providers</code> that implements
321
* the <code>RegisterableService</code> interface, its
322
* <code>onRegistration</code> method will be called once for each
323
* category it is registered under. Its
324
* <code>onDeregistration</code> method will be called each time
325
* it is deregistered from a category or when the registry is
326
* finalized.
327
*
328
* @param providers an Iterator containing service provider
329
* objects to be registered.
330
*
331
* @exception IllegalArgumentException if <code>providers</code>
332
* is <code>null</code> or contains a <code>null</code> entry.
333
*/
334
public void registerServiceProviders(Iterator<?> providers) {
335
if (providers == null) {
336
throw new IllegalArgumentException("provider == null!");
337
}
338
while (providers.hasNext()) {
339
registerServiceProvider(providers.next());
340
}
341
}
342
343
/**
344
* Removes a service provider object from the given category. If
345
* the provider was not previously registered, nothing happens and
346
* <code>false</code> is returned. Otherwise, <code>true</code>
347
* is returned. If an object of the same class as
348
* <code>provider</code> but not equal (using <code>==</code>) to
349
* <code>provider</code> is registered, it will not be
350
* deregistered.
351
*
352
* <p> If <code>provider</code> implements the
353
* <code>RegisterableService</code> interface, its
354
* <code>onDeregistration</code> method will be called.
355
*
356
* @param provider the service provider object to be deregistered.
357
* @param category the category from which to deregister the
358
* provider.
359
* @param <T> the type of the provider.
360
*
361
* @return <code>true</code> if the provider was previously
362
* registered in the same category category,
363
* <code>false</code> otherwise.
364
*
365
* @exception IllegalArgumentException if <code>provider</code> is
366
* <code>null</code>.
367
* @exception IllegalArgumentException if there is no category
368
* corresponding to <code>category</code>.
369
* @exception ClassCastException if provider does not implement
370
* the class defined by <code>category</code>.
371
*/
372
public <T> boolean deregisterServiceProvider(T provider,
373
Class<T> category) {
374
if (provider == null) {
375
throw new IllegalArgumentException("provider == null!");
376
}
377
SubRegistry reg = (SubRegistry)categoryMap.get(category);
378
if (reg == null) {
379
throw new IllegalArgumentException("category unknown!");
380
}
381
if (!category.isAssignableFrom(provider.getClass())) {
382
throw new ClassCastException();
383
}
384
return reg.deregisterServiceProvider(provider);
385
}
386
387
/**
388
* Removes a service provider object from all categories that
389
* contain it.
390
*
391
* @param provider the service provider object to be deregistered.
392
*
393
* @exception IllegalArgumentException if <code>provider</code> is
394
* <code>null</code>.
395
*/
396
public void deregisterServiceProvider(Object provider) {
397
if (provider == null) {
398
throw new IllegalArgumentException("provider == null!");
399
}
400
Iterator regs = getSubRegistries(provider);
401
while (regs.hasNext()) {
402
SubRegistry reg = (SubRegistry)regs.next();
403
reg.deregisterServiceProvider(provider);
404
}
405
}
406
407
/**
408
* Returns <code>true</code> if <code>provider</code> is currently
409
* registered.
410
*
411
* @param provider the service provider object to be queried.
412
*
413
* @return <code>true</code> if the given provider has been
414
* registered.
415
*
416
* @exception IllegalArgumentException if <code>provider</code> is
417
* <code>null</code>.
418
*/
419
public boolean contains(Object provider) {
420
if (provider == null) {
421
throw new IllegalArgumentException("provider == null!");
422
}
423
Iterator regs = getSubRegistries(provider);
424
while (regs.hasNext()) {
425
SubRegistry reg = (SubRegistry)regs.next();
426
if (reg.contains(provider)) {
427
return true;
428
}
429
}
430
431
return false;
432
}
433
434
/**
435
* Returns an <code>Iterator</code> containing all registered
436
* service providers in the given category. If
437
* <code>useOrdering</code> is <code>false</code>, the iterator
438
* will return all of the server provider objects in an arbitrary
439
* order. Otherwise, the ordering will respect any pairwise
440
* orderings that have been set. If the graph of pairwise
441
* orderings contains cycles, any providers that belong to a cycle
442
* will not be returned.
443
*
444
* @param category the category to be retrieved from.
445
* @param useOrdering <code>true</code> if pairwise orderings
446
* should be taken account in ordering the returned objects.
447
* @param <T> the type of the category.
448
*
449
* @return an <code>Iterator</code> containing service provider
450
* objects from the given category, possibly in order.
451
*
452
* @exception IllegalArgumentException if there is no category
453
* corresponding to <code>category</code>.
454
*/
455
public <T> Iterator<T> getServiceProviders(Class<T> category,
456
boolean useOrdering) {
457
SubRegistry reg = (SubRegistry)categoryMap.get(category);
458
if (reg == null) {
459
throw new IllegalArgumentException("category unknown!");
460
}
461
return reg.getServiceProviders(useOrdering);
462
}
463
464
/**
465
* A simple filter interface used by
466
* <code>ServiceRegistry.getServiceProviders</code> to select
467
* providers matching an arbitrary criterion. Classes that
468
* implement this interface should be defined in order to make use
469
* of the <code>getServiceProviders</code> method of
470
* <code>ServiceRegistry</code> that takes a <code>Filter</code>.
471
*
472
* @see ServiceRegistry#getServiceProviders(Class, ServiceRegistry.Filter, boolean)
473
*/
474
public interface Filter {
475
476
/**
477
* Returns <code>true</code> if the given
478
* <code>provider</code> object matches the criterion defined
479
* by this <code>Filter</code>.
480
*
481
* @param provider a service provider <code>Object</code>.
482
*
483
* @return true if the provider matches the criterion.
484
*/
485
boolean filter(Object provider);
486
}
487
488
/**
489
* Returns an <code>Iterator</code> containing service provider
490
* objects within a given category that satisfy a criterion
491
* imposed by the supplied <code>ServiceRegistry.Filter</code>
492
* object's <code>filter</code> method.
493
*
494
* <p> The <code>useOrdering</code> argument controls the
495
* ordering of the results using the same rules as
496
* <code>getServiceProviders(Class, boolean)</code>.
497
*
498
* @param category the category to be retrieved from.
499
* @param filter an instance of <code>ServiceRegistry.Filter</code>
500
* whose <code>filter</code> method will be invoked.
501
* @param useOrdering <code>true</code> if pairwise orderings
502
* should be taken account in ordering the returned objects.
503
* @param <T> the type of the category.
504
*
505
* @return an <code>Iterator</code> containing service provider
506
* objects from the given category, possibly in order.
507
*
508
* @exception IllegalArgumentException if there is no category
509
* corresponding to <code>category</code>.
510
*/
511
public <T> Iterator<T> getServiceProviders(Class<T> category,
512
Filter filter,
513
boolean useOrdering) {
514
SubRegistry reg = (SubRegistry)categoryMap.get(category);
515
if (reg == null) {
516
throw new IllegalArgumentException("category unknown!");
517
}
518
Iterator iter = getServiceProviders(category, useOrdering);
519
return new FilterIterator(iter, filter);
520
}
521
522
/**
523
* Returns the currently registered service provider object that
524
* is of the given class type. At most one object of a given
525
* class is allowed to be registered at any given time. If no
526
* registered object has the desired class type, <code>null</code>
527
* is returned.
528
*
529
* @param providerClass the <code>Class</code> of the desired
530
* service provider object.
531
* @param <T> the type of the provider.
532
*
533
* @return a currently registered service provider object with the
534
* desired <code>Class</code>type, or <code>null</code> is none is
535
* present.
536
*
537
* @exception IllegalArgumentException if <code>providerClass</code> is
538
* <code>null</code>.
539
*/
540
public <T> T getServiceProviderByClass(Class<T> providerClass) {
541
if (providerClass == null) {
542
throw new IllegalArgumentException("providerClass == null!");
543
}
544
Iterator iter = categoryMap.keySet().iterator();
545
while (iter.hasNext()) {
546
Class c = (Class)iter.next();
547
if (c.isAssignableFrom(providerClass)) {
548
SubRegistry reg = (SubRegistry)categoryMap.get(c);
549
T provider = reg.getServiceProviderByClass(providerClass);
550
if (provider != null) {
551
return provider;
552
}
553
}
554
}
555
return null;
556
}
557
558
/**
559
* Sets a pairwise ordering between two service provider objects
560
* within a given category. If one or both objects are not
561
* currently registered within the given category, or if the
562
* desired ordering is already set, nothing happens and
563
* <code>false</code> is returned. If the providers previously
564
* were ordered in the reverse direction, that ordering is
565
* removed.
566
*
567
* <p> The ordering will be used by the
568
* <code>getServiceProviders</code> methods when their
569
* <code>useOrdering</code> argument is <code>true</code>.
570
*
571
* @param category a <code>Class</code> object indicating the
572
* category under which the preference is to be established.
573
* @param firstProvider the preferred provider.
574
* @param secondProvider the provider to which
575
* <code>firstProvider</code> is preferred.
576
* @param <T> the type of the category.
577
*
578
* @return <code>true</code> if a previously unset ordering
579
* was established.
580
*
581
* @exception IllegalArgumentException if either provider is
582
* <code>null</code> or they are the same object.
583
* @exception IllegalArgumentException if there is no category
584
* corresponding to <code>category</code>.
585
*/
586
public <T> boolean setOrdering(Class<T> category,
587
T firstProvider,
588
T secondProvider) {
589
if (firstProvider == null || secondProvider == null) {
590
throw new IllegalArgumentException("provider is null!");
591
}
592
if (firstProvider == secondProvider) {
593
throw new IllegalArgumentException("providers are the same!");
594
}
595
SubRegistry reg = (SubRegistry)categoryMap.get(category);
596
if (reg == null) {
597
throw new IllegalArgumentException("category unknown!");
598
}
599
if (reg.contains(firstProvider) &&
600
reg.contains(secondProvider)) {
601
return reg.setOrdering(firstProvider, secondProvider);
602
}
603
return false;
604
}
605
606
/**
607
* Sets a pairwise ordering between two service provider objects
608
* within a given category. If one or both objects are not
609
* currently registered within the given category, or if no
610
* ordering is currently set between them, nothing happens
611
* and <code>false</code> is returned.
612
*
613
* <p> The ordering will be used by the
614
* <code>getServiceProviders</code> methods when their
615
* <code>useOrdering</code> argument is <code>true</code>.
616
*
617
* @param category a <code>Class</code> object indicating the
618
* category under which the preference is to be disestablished.
619
* @param firstProvider the formerly preferred provider.
620
* @param secondProvider the provider to which
621
* <code>firstProvider</code> was formerly preferred.
622
* @param <T> the type of the category.
623
*
624
* @return <code>true</code> if a previously set ordering was
625
* disestablished.
626
*
627
* @exception IllegalArgumentException if either provider is
628
* <code>null</code> or they are the same object.
629
* @exception IllegalArgumentException if there is no category
630
* corresponding to <code>category</code>.
631
*/
632
public <T> boolean unsetOrdering(Class<T> category,
633
T firstProvider,
634
T secondProvider) {
635
if (firstProvider == null || secondProvider == null) {
636
throw new IllegalArgumentException("provider is null!");
637
}
638
if (firstProvider == secondProvider) {
639
throw new IllegalArgumentException("providers are the same!");
640
}
641
SubRegistry reg = (SubRegistry)categoryMap.get(category);
642
if (reg == null) {
643
throw new IllegalArgumentException("category unknown!");
644
}
645
if (reg.contains(firstProvider) &&
646
reg.contains(secondProvider)) {
647
return reg.unsetOrdering(firstProvider, secondProvider);
648
}
649
return false;
650
}
651
652
/**
653
* Deregisters all service provider object currently registered
654
* under the given category.
655
*
656
* @param category the category to be emptied.
657
*
658
* @exception IllegalArgumentException if there is no category
659
* corresponding to <code>category</code>.
660
*/
661
public void deregisterAll(Class<?> category) {
662
SubRegistry reg = (SubRegistry)categoryMap.get(category);
663
if (reg == null) {
664
throw new IllegalArgumentException("category unknown!");
665
}
666
reg.clear();
667
}
668
669
/**
670
* Deregisters all currently registered service providers from all
671
* categories.
672
*/
673
public void deregisterAll() {
674
Iterator iter = categoryMap.values().iterator();
675
while (iter.hasNext()) {
676
SubRegistry reg = (SubRegistry)iter.next();
677
reg.clear();
678
}
679
}
680
681
/**
682
* Finalizes this object prior to garbage collection. The
683
* <code>deregisterAll</code> method is called to deregister all
684
* currently registered service providers. This method should not
685
* be called from application code.
686
*
687
* @exception Throwable if an error occurs during superclass
688
* finalization.
689
*/
690
public void finalize() throws Throwable {
691
deregisterAll();
692
super.finalize();
693
}
694
}
695
696
697
/**
698
* A portion of a registry dealing with a single superclass or
699
* interface.
700
*/
701
class SubRegistry {
702
703
ServiceRegistry registry;
704
705
Class category;
706
707
// Provider Objects organized by partial ordering
708
final PartiallyOrderedSet poset = new PartiallyOrderedSet();
709
710
// Class -> Provider Object of that class
711
final Map<Class<?>,Object> map = new HashMap();
712
final Map<Class<?>,AccessControlContext> accMap = new HashMap<>();
713
714
public SubRegistry(ServiceRegistry registry, Class category) {
715
this.registry = registry;
716
this.category = category;
717
}
718
719
public boolean registerServiceProvider(Object provider) {
720
Object oprovider = map.get(provider.getClass());
721
boolean present = oprovider != null;
722
723
if (present) {
724
deregisterServiceProvider(oprovider);
725
}
726
map.put(provider.getClass(), provider);
727
accMap.put(provider.getClass(), AccessController.getContext());
728
poset.add(provider);
729
if (provider instanceof RegisterableService) {
730
RegisterableService rs = (RegisterableService)provider;
731
rs.onRegistration(registry, category);
732
}
733
734
return !present;
735
}
736
737
/**
738
* If the provider was not previously registered, do nothing.
739
*
740
* @return true if the provider was previously registered.
741
*/
742
public boolean deregisterServiceProvider(Object provider) {
743
Object oprovider = map.get(provider.getClass());
744
745
if (provider == oprovider) {
746
map.remove(provider.getClass());
747
accMap.remove(provider.getClass());
748
poset.remove(provider);
749
if (provider instanceof RegisterableService) {
750
RegisterableService rs = (RegisterableService)provider;
751
rs.onDeregistration(registry, category);
752
}
753
754
return true;
755
}
756
return false;
757
}
758
759
public boolean contains(Object provider) {
760
Object oprovider = map.get(provider.getClass());
761
return oprovider == provider;
762
}
763
764
public boolean setOrdering(Object firstProvider,
765
Object secondProvider) {
766
return poset.setOrdering(firstProvider, secondProvider);
767
}
768
769
public boolean unsetOrdering(Object firstProvider,
770
Object secondProvider) {
771
return poset.unsetOrdering(firstProvider, secondProvider);
772
}
773
774
public Iterator getServiceProviders(boolean useOrdering) {
775
if (useOrdering) {
776
return poset.iterator();
777
} else {
778
return map.values().iterator();
779
}
780
}
781
782
public <T> T getServiceProviderByClass(Class<T> providerClass) {
783
return (T)map.get(providerClass);
784
}
785
786
public void clear() {
787
Iterator iter = map.values().iterator();
788
while (iter.hasNext()) {
789
Object provider = iter.next();
790
iter.remove();
791
792
if (provider instanceof RegisterableService) {
793
RegisterableService rs = (RegisterableService)provider;
794
AccessControlContext acc = accMap.get(provider.getClass());
795
if (acc != null || System.getSecurityManager() == null) {
796
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
797
rs.onDeregistration(registry, category);
798
return null;
799
}, acc);
800
}
801
}
802
}
803
poset.clear();
804
accMap.clear();
805
}
806
807
public void finalize() {
808
clear();
809
}
810
}
811
812
813
/**
814
* A class for wrapping <code>Iterators</code> with a filter function.
815
* This provides an iterator for a subset without duplication.
816
*/
817
class FilterIterator<T> implements Iterator<T> {
818
819
private Iterator<T> iter;
820
private ServiceRegistry.Filter filter;
821
822
private T next = null;
823
824
public FilterIterator(Iterator<T> iter,
825
ServiceRegistry.Filter filter) {
826
this.iter = iter;
827
this.filter = filter;
828
advance();
829
}
830
831
private void advance() {
832
while (iter.hasNext()) {
833
T elt = iter.next();
834
if (filter.filter(elt)) {
835
next = elt;
836
return;
837
}
838
}
839
840
next = null;
841
}
842
843
public boolean hasNext() {
844
return next != null;
845
}
846
847
public T next() {
848
if (next == null) {
849
throw new NoSuchElementException();
850
}
851
T o = next;
852
advance();
853
return o;
854
}
855
856
public void remove() {
857
throw new UnsupportedOperationException();
858
}
859
}
860
861