Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/share/classes/java/beans/beancontext/BeanContextServicesSupport.java
41159 views
1
/*
2
* Copyright (c) 1998, 2021, 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 java.beans.beancontext;
27
28
import java.io.IOException;
29
import java.io.ObjectInputStream;
30
import java.io.ObjectOutputStream;
31
import java.io.Serial;
32
import java.io.Serializable;
33
import java.util.ArrayList;
34
import java.util.Collection;
35
import java.util.HashMap;
36
import java.util.HashSet;
37
import java.util.Iterator;
38
import java.util.Locale;
39
import java.util.Map;
40
import java.util.TooManyListenersException;
41
42
/**
43
* <p>
44
* This helper class provides a utility implementation of the
45
* java.beans.beancontext.BeanContextServices interface.
46
* </p>
47
* <p>
48
* Since this class directly implements the BeanContextServices interface,
49
* the class can, and is intended to be used either by subclassing this
50
* implementation, or via delegation of an instance of this class
51
* from another through the BeanContextProxy interface.
52
* </p>
53
*
54
* @author Laurence P. G. Cable
55
* @since 1.2
56
*/
57
58
public class BeanContextServicesSupport extends BeanContextSupport
59
implements BeanContextServices {
60
61
/**
62
* Use serialVersionUID from JDK 1.7 for interoperability.
63
*/
64
@Serial
65
private static final long serialVersionUID = -8494482757288719206L;
66
67
/**
68
* <p>
69
* Construct a BeanContextServicesSupport instance
70
* </p>
71
*
72
* @param peer The peer BeanContext we are supplying an implementation for, if null the this object is its own peer
73
* @param lcle The current Locale for this BeanContext.
74
* @param dTime The initial state, true if in design mode, false if runtime.
75
* @param visible The initial visibility.
76
*
77
*/
78
79
public BeanContextServicesSupport(BeanContextServices peer, Locale lcle, boolean dTime, boolean visible) {
80
super(peer, lcle, dTime, visible);
81
}
82
83
/**
84
* Create an instance using the specified Locale and design mode.
85
*
86
* @param peer The peer BeanContext we are supplying an implementation for, if null the this object is its own peer
87
* @param lcle The current Locale for this BeanContext.
88
* @param dtime The initial state, true if in design mode, false if runtime.
89
*/
90
91
public BeanContextServicesSupport(BeanContextServices peer, Locale lcle, boolean dtime) {
92
this (peer, lcle, dtime, true);
93
}
94
95
/**
96
* Create an instance using the specified locale
97
*
98
* @param peer The peer BeanContext we are supplying an implementation for, if null the this object is its own peer
99
* @param lcle The current Locale for this BeanContext.
100
*/
101
102
public BeanContextServicesSupport(BeanContextServices peer, Locale lcle) {
103
this (peer, lcle, false, true);
104
}
105
106
/**
107
* Create an instance with a peer
108
*
109
* @param peer The peer BeanContext we are supplying an implementation for, if null the this object is its own peer
110
*/
111
112
public BeanContextServicesSupport(BeanContextServices peer) {
113
this (peer, null, false, true);
114
}
115
116
/**
117
* Create an instance that is not a delegate of another object
118
*/
119
120
public BeanContextServicesSupport() {
121
this (null, null, false, true);
122
}
123
124
/**
125
* called by BeanContextSupport superclass during construction and
126
* deserialization to initialize subclass transient state.
127
*
128
* subclasses may envelope this method, but should not override it or
129
* call it directly.
130
*/
131
132
public void initialize() {
133
super.initialize();
134
services = new HashMap<>(serializable + 1);
135
bcsListeners = new ArrayList<>(1);
136
}
137
138
/**
139
* Gets the {@code BeanContextServices} associated with this
140
* {@code BeanContextServicesSupport}.
141
*
142
* @return the instance of {@code BeanContext}
143
* this object is providing the implementation for.
144
*/
145
public BeanContextServices getBeanContextServicesPeer() {
146
return (BeanContextServices)getBeanContextChildPeer();
147
}
148
149
/************************************************************************/
150
151
/*
152
* protected nested class containing per child information, an instance
153
* of which is associated with each child in the "children" hashtable.
154
* subclasses can extend this class to include their own per-child state.
155
*
156
* Note that this 'value' is serialized with the corresponding child 'key'
157
* when the BeanContextSupport is serialized.
158
*/
159
160
protected class BCSSChild extends BeanContextSupport.BCSChild {
161
162
/**
163
* Use serialVersionUID from JDK 1.7 for interoperability.
164
*/
165
@Serial
166
private static final long serialVersionUID = -3263851306889194873L;
167
168
/*
169
* private nested class to map serviceClass to Provider and requestors
170
* listeners.
171
*/
172
173
class BCSSCServiceClassRef {
174
175
// create an instance of a service ref
176
177
BCSSCServiceClassRef(Class<?> sc, BeanContextServiceProvider bcsp, boolean delegated) {
178
super();
179
180
serviceClass = sc;
181
182
if (delegated)
183
delegateProvider = bcsp;
184
else
185
serviceProvider = bcsp;
186
}
187
188
// add a requestor and assoc listener
189
190
void addRequestor(Object requestor, BeanContextServiceRevokedListener bcsrl) throws TooManyListenersException {
191
BeanContextServiceRevokedListener cbcsrl = requestors.get(requestor);
192
193
if (cbcsrl != null && !cbcsrl.equals(bcsrl))
194
throw new TooManyListenersException();
195
196
requestors.put(requestor, bcsrl);
197
}
198
199
// remove a requestor
200
201
void removeRequestor(Object requestor) {
202
requestors.remove(requestor);
203
}
204
205
// check a requestors listener
206
207
void verifyRequestor(Object requestor, BeanContextServiceRevokedListener bcsrl) throws TooManyListenersException {
208
BeanContextServiceRevokedListener cbcsrl = requestors.get(requestor);
209
210
if (cbcsrl != null && !cbcsrl.equals(bcsrl))
211
throw new TooManyListenersException();
212
}
213
214
void verifyAndMaybeSetProvider(BeanContextServiceProvider bcsp, boolean isDelegated) {
215
BeanContextServiceProvider current;
216
217
if (isDelegated) { // the provider is delegated
218
current = delegateProvider;
219
220
if (current == null || bcsp == null) {
221
delegateProvider = bcsp;
222
return;
223
}
224
} else { // the provider is registered with this BCS
225
current = serviceProvider;
226
227
if (current == null || bcsp == null) {
228
serviceProvider = bcsp;
229
return;
230
}
231
}
232
233
if (!current.equals(bcsp))
234
throw new UnsupportedOperationException("existing service reference obtained from different BeanContextServiceProvider not supported");
235
236
}
237
238
@SuppressWarnings("unchecked") // Cast from clone
239
Iterator<Map.Entry<Object, BeanContextServiceRevokedListener>> cloneOfEntries() {
240
return ((HashMap<Object, BeanContextServiceRevokedListener>)requestors.clone()).entrySet().iterator();
241
}
242
243
Iterator<Map.Entry<Object, BeanContextServiceRevokedListener>> entries() {
244
return requestors.entrySet().iterator();
245
}
246
247
boolean isEmpty() { return requestors.isEmpty(); }
248
249
Class<?> getServiceClass() { return serviceClass; }
250
251
BeanContextServiceProvider getServiceProvider() {
252
return serviceProvider;
253
}
254
255
BeanContextServiceProvider getDelegateProvider() {
256
return delegateProvider;
257
}
258
259
boolean isDelegated() { return delegateProvider != null; }
260
261
void addRef(boolean delegated) {
262
if (delegated) {
263
delegateRefs++;
264
} else {
265
serviceRefs++;
266
}
267
}
268
269
270
void releaseRef(boolean delegated) {
271
if (delegated) {
272
if (--delegateRefs == 0) {
273
delegateProvider = null;
274
}
275
} else {
276
if (--serviceRefs <= 0) {
277
serviceProvider = null;
278
}
279
}
280
}
281
282
int getRefs() { return serviceRefs + delegateRefs; }
283
284
int getDelegateRefs() { return delegateRefs; }
285
286
int getServiceRefs() { return serviceRefs; }
287
288
/*
289
* fields
290
*/
291
292
Class<?> serviceClass;
293
294
BeanContextServiceProvider serviceProvider;
295
int serviceRefs;
296
297
BeanContextServiceProvider delegateProvider; // proxy
298
int delegateRefs;
299
300
HashMap<Object, BeanContextServiceRevokedListener> requestors = new HashMap<>(1);
301
}
302
303
/*
304
* per service reference info ...
305
*/
306
307
class BCSSCServiceRef {
308
BCSSCServiceRef(BCSSCServiceClassRef scref, boolean isDelegated) {
309
serviceClassRef = scref;
310
delegated = isDelegated;
311
}
312
313
void addRef() { refCnt++; }
314
int release() { return --refCnt; }
315
316
BCSSCServiceClassRef getServiceClassRef() { return serviceClassRef; }
317
318
boolean isDelegated() { return delegated; }
319
320
/*
321
* fields
322
*/
323
324
BCSSCServiceClassRef serviceClassRef;
325
int refCnt = 1;
326
boolean delegated = false;
327
}
328
329
BCSSChild(Object bcc, Object peer) { super(bcc, peer); }
330
331
// note usage of service per requestor, per service
332
333
synchronized void usingService(Object requestor, Object service, Class<?> serviceClass, BeanContextServiceProvider bcsp, boolean isDelegated, BeanContextServiceRevokedListener bcsrl) throws TooManyListenersException, UnsupportedOperationException {
334
335
// first, process mapping from serviceClass to requestor(s)
336
337
BCSSCServiceClassRef serviceClassRef = null;
338
339
if (serviceClasses == null)
340
serviceClasses = new HashMap<>(1);
341
else
342
serviceClassRef = serviceClasses.get(serviceClass);
343
344
if (serviceClassRef == null) { // new service being used ...
345
serviceClassRef = new BCSSCServiceClassRef(serviceClass, bcsp, isDelegated);
346
serviceClasses.put(serviceClass, serviceClassRef);
347
348
} else { // existing service ...
349
serviceClassRef.verifyAndMaybeSetProvider(bcsp, isDelegated); // throws
350
serviceClassRef.verifyRequestor(requestor, bcsrl); // throws
351
}
352
353
serviceClassRef.addRequestor(requestor, bcsrl);
354
serviceClassRef.addRef(isDelegated);
355
356
// now handle mapping from requestor to service(s)
357
358
BCSSCServiceRef serviceRef = null;
359
Map<Object , BCSSCServiceRef> services = null;
360
361
if (serviceRequestors == null) {
362
serviceRequestors = new HashMap<>(1);
363
} else {
364
services = serviceRequestors.get(requestor);
365
}
366
367
if (services == null) {
368
services = new HashMap<>(1);
369
370
serviceRequestors.put(requestor, services);
371
} else
372
serviceRef = services.get(service);
373
374
if (serviceRef == null) {
375
serviceRef = new BCSSCServiceRef(serviceClassRef, isDelegated);
376
377
services.put(service, serviceRef);
378
} else {
379
serviceRef.addRef();
380
}
381
}
382
383
// release a service reference
384
385
synchronized void releaseService(Object requestor, Object service) {
386
if (serviceRequestors == null) return;
387
388
Map<Object, BCSSCServiceRef> services = serviceRequestors.get(requestor);
389
390
if (services == null) return; // oops its not there anymore!
391
392
BCSSCServiceRef serviceRef = services.get(service);
393
394
if (serviceRef == null) return; // oops its not there anymore!
395
396
BCSSCServiceClassRef serviceClassRef = serviceRef.getServiceClassRef();
397
boolean isDelegated = serviceRef.isDelegated();
398
BeanContextServiceProvider bcsp = isDelegated ? serviceClassRef.getDelegateProvider() : serviceClassRef.getServiceProvider();
399
400
bcsp.releaseService(BeanContextServicesSupport.this.getBeanContextServicesPeer(), requestor, service);
401
402
serviceClassRef.releaseRef(isDelegated);
403
serviceClassRef.removeRequestor(requestor);
404
405
if (serviceRef.release() == 0) {
406
407
services.remove(service);
408
409
if (services.isEmpty()) {
410
serviceRequestors.remove(requestor);
411
serviceClassRef.removeRequestor(requestor);
412
}
413
414
if (serviceRequestors.isEmpty()) {
415
serviceRequestors = null;
416
}
417
418
if (serviceClassRef.isEmpty()) {
419
serviceClasses.remove(serviceClassRef.getServiceClass());
420
}
421
422
if (serviceClasses.isEmpty())
423
serviceClasses = null;
424
}
425
}
426
427
// revoke a service
428
429
synchronized void revokeService(Class<?> serviceClass, boolean isDelegated, boolean revokeNow) {
430
if (serviceClasses == null) return;
431
432
BCSSCServiceClassRef serviceClassRef = serviceClasses.get(serviceClass);
433
434
if (serviceClassRef == null) return;
435
436
Iterator<Map.Entry<Object, BeanContextServiceRevokedListener>> i = serviceClassRef.cloneOfEntries();
437
438
BeanContextServiceRevokedEvent bcsre = new BeanContextServiceRevokedEvent(BeanContextServicesSupport.this.getBeanContextServicesPeer(), serviceClass, revokeNow);
439
boolean noMoreRefs = false;
440
441
while (i.hasNext() && serviceRequestors != null) {
442
Map.Entry<Object,BeanContextServiceRevokedListener> entry = i.next();
443
BeanContextServiceRevokedListener listener = entry.getValue();
444
445
if (revokeNow) {
446
Object requestor = entry.getKey();
447
Map<Object, BCSSCServiceRef> services = serviceRequestors.get(requestor);
448
449
if (services != null) {
450
Iterator<Map.Entry<Object, BCSSCServiceRef>> i1 = services.entrySet().iterator();
451
452
while (i1.hasNext()) {
453
Map.Entry<Object, BCSSCServiceRef> tmp = i1.next();
454
455
BCSSCServiceRef serviceRef = tmp.getValue();
456
if (serviceRef.getServiceClassRef().equals(serviceClassRef) && isDelegated == serviceRef.isDelegated()) {
457
i1.remove();
458
}
459
}
460
461
if (noMoreRefs = services.isEmpty()) {
462
serviceRequestors.remove(requestor);
463
}
464
}
465
466
if (noMoreRefs) serviceClassRef.removeRequestor(requestor);
467
}
468
469
listener.serviceRevoked(bcsre);
470
}
471
472
if (revokeNow && serviceClasses != null) {
473
if (serviceClassRef.isEmpty())
474
serviceClasses.remove(serviceClass);
475
476
if (serviceClasses.isEmpty())
477
serviceClasses = null;
478
}
479
480
if (serviceRequestors != null && serviceRequestors.isEmpty())
481
serviceRequestors = null;
482
}
483
484
// release all references for this child since it has been unnested.
485
486
void cleanupReferences() {
487
488
if (serviceRequestors == null) return;
489
490
Iterator<Map.Entry<Object, Map<Object, BCSSCServiceRef>>> requestors = serviceRequestors.entrySet().iterator();
491
492
while(requestors.hasNext()) {
493
Map.Entry<Object, Map<Object, BCSSCServiceRef>> tmp = requestors.next();
494
Object requestor = tmp.getKey();
495
Iterator<Map.Entry<Object, BCSSCServiceRef>> services = tmp.getValue().entrySet().iterator();
496
497
requestors.remove();
498
499
while (services.hasNext()) {
500
Map.Entry<Object, BCSSCServiceRef> entry = services.next();
501
Object service = entry.getKey();
502
BCSSCServiceRef sref = entry.getValue();
503
504
BCSSCServiceClassRef scref = sref.getServiceClassRef();
505
506
BeanContextServiceProvider bcsp = sref.isDelegated() ? scref.getDelegateProvider() : scref.getServiceProvider();
507
508
scref.removeRequestor(requestor);
509
services.remove();
510
511
while (sref.release() >= 0) {
512
bcsp.releaseService(BeanContextServicesSupport.this.getBeanContextServicesPeer(), requestor, service);
513
}
514
}
515
}
516
517
serviceRequestors = null;
518
serviceClasses = null;
519
}
520
521
void revokeAllDelegatedServicesNow() {
522
if (serviceClasses == null) return;
523
524
for (BCSSCServiceClassRef serviceClassRef : new HashSet<>(serviceClasses.values())) {
525
if (!serviceClassRef.isDelegated()) continue;
526
527
Iterator<Map.Entry<Object, BeanContextServiceRevokedListener>> i = serviceClassRef.cloneOfEntries();
528
BeanContextServiceRevokedEvent bcsre = new BeanContextServiceRevokedEvent(BeanContextServicesSupport.this.getBeanContextServicesPeer(), serviceClassRef.getServiceClass(), true);
529
boolean noMoreRefs = false;
530
531
while (i.hasNext()) {
532
Map.Entry<Object, BeanContextServiceRevokedListener> entry = i.next();
533
BeanContextServiceRevokedListener listener = entry.getValue();
534
535
Object requestor = entry.getKey();
536
Map<Object, BCSSCServiceRef> services = serviceRequestors.get(requestor);
537
538
if (services != null) {
539
Iterator<Map.Entry<Object, BCSSCServiceRef>> i1 = services.entrySet().iterator();
540
541
while (i1.hasNext()) {
542
Map.Entry<Object, BCSSCServiceRef> tmp = i1.next();
543
544
BCSSCServiceRef serviceRef = tmp.getValue();
545
if (serviceRef.getServiceClassRef().equals(serviceClassRef) && serviceRef.isDelegated()) {
546
i1.remove();
547
}
548
}
549
550
if (noMoreRefs = services.isEmpty()) {
551
serviceRequestors.remove(requestor);
552
}
553
}
554
555
if (noMoreRefs) serviceClassRef.removeRequestor(requestor);
556
557
listener.serviceRevoked(bcsre);
558
559
if (serviceClassRef.isEmpty())
560
serviceClasses.remove(serviceClassRef.getServiceClass());
561
}
562
}
563
564
if (serviceClasses.isEmpty()) serviceClasses = null;
565
566
if (serviceRequestors != null && serviceRequestors.isEmpty())
567
serviceRequestors = null;
568
}
569
570
/*
571
* fields
572
*/
573
574
private transient HashMap<Class<?>, BCSSCServiceClassRef> serviceClasses;
575
private transient HashMap<Object, Map<Object, BeanContextServicesSupport.BCSSChild.BCSSCServiceRef>> serviceRequestors;
576
}
577
578
/**
579
* <p>
580
* Subclasses can override this method to insert their own subclass
581
* of Child without having to override add() or the other Collection
582
* methods that add children to the set.
583
* </p>
584
*
585
* @param targetChild the child to create the Child on behalf of
586
* @param peer the peer if the targetChild and peer are related by BeanContextProxy
587
*/
588
589
protected BCSChild createBCSChild(Object targetChild, Object peer) {
590
return new BCSSChild(targetChild, peer);
591
}
592
593
/************************************************************************/
594
595
/**
596
* subclasses may subclass this nested class to add behaviors for
597
* each BeanContextServicesProvider.
598
*/
599
600
protected static class BCSSServiceProvider implements Serializable {
601
602
/**
603
* Use serialVersionUID from JDK 1.7 for interoperability.
604
*/
605
@Serial
606
private static final long serialVersionUID = 861278251667444782L;
607
608
BCSSServiceProvider(Class<?> sc, BeanContextServiceProvider bcsp) {
609
super();
610
611
serviceProvider = bcsp;
612
}
613
614
/**
615
* Returns the service provider.
616
* @return the service provider
617
*/
618
protected BeanContextServiceProvider getServiceProvider() {
619
return serviceProvider;
620
}
621
622
/**
623
* The service provider.
624
*/
625
@SuppressWarnings("serial") // Not statically typed as Serializable
626
protected BeanContextServiceProvider serviceProvider;
627
}
628
629
/**
630
* subclasses can override this method to create new subclasses of
631
* BCSSServiceProvider without having to override addService() in
632
* order to instantiate.
633
* @param sc the class
634
* @param bcsp the service provider
635
* @return a service provider without overriding addService()
636
*/
637
638
protected BCSSServiceProvider createBCSSServiceProvider(Class<?> sc, BeanContextServiceProvider bcsp) {
639
return new BCSSServiceProvider(sc, bcsp);
640
}
641
642
/************************************************************************/
643
644
/**
645
* add a BeanContextServicesListener
646
*
647
* @throws NullPointerException if the argument is null
648
*/
649
650
public void addBeanContextServicesListener(BeanContextServicesListener bcsl) {
651
if (bcsl == null) throw new NullPointerException("bcsl");
652
653
synchronized(bcsListeners) {
654
if (bcsListeners.contains(bcsl))
655
return;
656
else
657
bcsListeners.add(bcsl);
658
}
659
}
660
661
/**
662
* remove a BeanContextServicesListener
663
*/
664
665
public void removeBeanContextServicesListener(BeanContextServicesListener bcsl) {
666
if (bcsl == null) throw new NullPointerException("bcsl");
667
668
synchronized(bcsListeners) {
669
if (!bcsListeners.contains(bcsl))
670
return;
671
else
672
bcsListeners.remove(bcsl);
673
}
674
}
675
676
/**
677
* add a service
678
* @param serviceClass the service class
679
* @param bcsp the service provider
680
*/
681
682
public boolean addService(Class<?> serviceClass, BeanContextServiceProvider bcsp) {
683
return addService(serviceClass, bcsp, true);
684
}
685
686
/**
687
* add a service
688
* @param serviceClass the service class
689
* @param bcsp the service provider
690
* @param fireEvent whether or not an event should be fired
691
* @return true if the service was successfully added
692
*/
693
694
protected boolean addService(Class<?> serviceClass, BeanContextServiceProvider bcsp, boolean fireEvent) {
695
696
if (serviceClass == null) throw new NullPointerException("serviceClass");
697
if (bcsp == null) throw new NullPointerException("bcsp");
698
699
synchronized(BeanContext.globalHierarchyLock) {
700
if (services.containsKey(serviceClass))
701
return false;
702
else {
703
services.put(serviceClass, createBCSSServiceProvider(serviceClass, bcsp));
704
705
if (bcsp instanceof Serializable) serializable++;
706
707
if (!fireEvent) return true;
708
709
710
BeanContextServiceAvailableEvent bcssae = new BeanContextServiceAvailableEvent(getBeanContextServicesPeer(), serviceClass);
711
712
fireServiceAdded(bcssae);
713
714
synchronized(children) {
715
for (Object c : children.keySet()) {
716
if (c instanceof BeanContextServices) {
717
((BeanContextServicesListener)c).serviceAvailable(bcssae);
718
}
719
}
720
}
721
722
return true;
723
}
724
}
725
}
726
727
/**
728
* remove a service
729
* @param serviceClass the service class
730
* @param bcsp the service provider
731
* @param revokeCurrentServicesNow whether or not to revoke the service
732
*/
733
734
public void revokeService(Class<?> serviceClass, BeanContextServiceProvider bcsp, boolean revokeCurrentServicesNow) {
735
736
if (serviceClass == null) throw new NullPointerException("serviceClass");
737
if (bcsp == null) throw new NullPointerException("bcsp");
738
739
synchronized(BeanContext.globalHierarchyLock) {
740
if (!services.containsKey(serviceClass)) return;
741
742
BCSSServiceProvider bcsssp = services.get(serviceClass);
743
744
if (!bcsssp.getServiceProvider().equals(bcsp))
745
throw new IllegalArgumentException("service provider mismatch");
746
747
services.remove(serviceClass);
748
749
if (bcsp instanceof Serializable) serializable--;
750
751
Iterator<BeanContextSupport.BCSChild> i = bcsChildren(); // get the BCSChild values.
752
753
while (i.hasNext()) {
754
((BCSSChild)i.next()).revokeService(serviceClass, false, revokeCurrentServicesNow);
755
}
756
757
fireServiceRevoked(serviceClass, revokeCurrentServicesNow);
758
}
759
}
760
761
/**
762
* has a service, which may be delegated
763
*/
764
765
public synchronized boolean hasService(Class<?> serviceClass) {
766
if (serviceClass == null) throw new NullPointerException("serviceClass");
767
768
synchronized(BeanContext.globalHierarchyLock) {
769
if (services.containsKey(serviceClass)) return true;
770
771
BeanContextServices bcs = null;
772
773
try {
774
bcs = (BeanContextServices)getBeanContext();
775
} catch (ClassCastException cce) {
776
return false;
777
}
778
779
return bcs == null ? false : bcs.hasService(serviceClass);
780
}
781
}
782
783
/************************************************************************/
784
785
/*
786
* a nested subclass used to represent a proxy for serviceClasses delegated
787
* to an enclosing BeanContext.
788
*/
789
790
protected class BCSSProxyServiceProvider implements BeanContextServiceProvider, BeanContextServiceRevokedListener {
791
792
BCSSProxyServiceProvider(BeanContextServices bcs) {
793
super();
794
795
nestingCtxt = bcs;
796
}
797
798
public Object getService(BeanContextServices bcs, Object requestor, Class<?> serviceClass, Object serviceSelector) {
799
Object service = null;
800
801
try {
802
service = nestingCtxt.getService(bcs, requestor, serviceClass, serviceSelector, this);
803
} catch (TooManyListenersException tmle) {
804
return null;
805
}
806
807
return service;
808
}
809
810
public void releaseService(BeanContextServices bcs, Object requestor, Object service) {
811
nestingCtxt.releaseService(bcs, requestor, service);
812
}
813
814
public Iterator<?> getCurrentServiceSelectors(BeanContextServices bcs, Class<?> serviceClass) {
815
return nestingCtxt.getCurrentServiceSelectors(serviceClass);
816
}
817
818
public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) {
819
Iterator<BeanContextSupport.BCSChild> i = bcsChildren(); // get the BCSChild values.
820
821
while (i.hasNext()) {
822
((BCSSChild)i.next()).revokeService(bcsre.getServiceClass(), true, bcsre.isCurrentServiceInvalidNow());
823
}
824
}
825
826
/*
827
* fields
828
*/
829
830
private BeanContextServices nestingCtxt;
831
}
832
833
/************************************************************************/
834
835
/**
836
* obtain a service which may be delegated
837
*/
838
839
public Object getService(BeanContextChild child, Object requestor, Class<?> serviceClass, Object serviceSelector, BeanContextServiceRevokedListener bcsrl) throws TooManyListenersException {
840
if (child == null) throw new NullPointerException("child");
841
if (serviceClass == null) throw new NullPointerException("serviceClass");
842
if (requestor == null) throw new NullPointerException("requestor");
843
if (bcsrl == null) throw new NullPointerException("bcsrl");
844
845
Object service = null;
846
BCSSChild bcsc;
847
BeanContextServices bcssp = getBeanContextServicesPeer();
848
849
synchronized(BeanContext.globalHierarchyLock) {
850
synchronized(children) { bcsc = (BCSSChild)children.get(child); }
851
852
if (bcsc == null) throw new IllegalArgumentException("not a child of this context"); // not a child ...
853
854
BCSSServiceProvider bcsssp = services.get(serviceClass);
855
856
if (bcsssp != null) {
857
BeanContextServiceProvider bcsp = bcsssp.getServiceProvider();
858
service = bcsp.getService(bcssp, requestor, serviceClass, serviceSelector);
859
if (service != null) { // do bookkeeping ...
860
try {
861
bcsc.usingService(requestor, service, serviceClass, bcsp, false, bcsrl);
862
} catch (TooManyListenersException tmle) {
863
bcsp.releaseService(bcssp, requestor, service);
864
throw tmle;
865
} catch (UnsupportedOperationException uope) {
866
bcsp.releaseService(bcssp, requestor, service);
867
throw uope; // unchecked rt exception
868
}
869
870
return service;
871
}
872
}
873
874
875
if (proxy != null) {
876
877
// try to delegate ...
878
879
service = proxy.getService(bcssp, requestor, serviceClass, serviceSelector);
880
881
if (service != null) { // do bookkeeping ...
882
try {
883
bcsc.usingService(requestor, service, serviceClass, proxy, true, bcsrl);
884
} catch (TooManyListenersException tmle) {
885
proxy.releaseService(bcssp, requestor, service);
886
throw tmle;
887
} catch (UnsupportedOperationException uope) {
888
proxy.releaseService(bcssp, requestor, service);
889
throw uope; // unchecked rt exception
890
}
891
892
return service;
893
}
894
}
895
}
896
897
return null;
898
}
899
900
/**
901
* release a service
902
*/
903
904
public void releaseService(BeanContextChild child, Object requestor, Object service) {
905
if (child == null) throw new NullPointerException("child");
906
if (requestor == null) throw new NullPointerException("requestor");
907
if (service == null) throw new NullPointerException("service");
908
909
BCSSChild bcsc;
910
911
synchronized(BeanContext.globalHierarchyLock) {
912
synchronized(children) { bcsc = (BCSSChild)children.get(child); }
913
914
if (bcsc != null)
915
bcsc.releaseService(requestor, service);
916
else
917
throw new IllegalArgumentException("child actual is not a child of this BeanContext");
918
}
919
}
920
921
/**
922
* @return an iterator for all the currently registered service classes.
923
*/
924
925
public Iterator<Object> getCurrentServiceClasses() {
926
return new BCSIterator(services.keySet().iterator());
927
}
928
929
/**
930
* @return an iterator for all the currently available service selectors
931
* (if any) available for the specified service.
932
*/
933
934
public Iterator<?> getCurrentServiceSelectors(Class<?> serviceClass) {
935
936
BCSSServiceProvider bcsssp = services.get(serviceClass);
937
938
return bcsssp != null ? new BCSIterator(bcsssp.getServiceProvider().getCurrentServiceSelectors(getBeanContextServicesPeer(), serviceClass)) : null;
939
}
940
941
/**
942
* BeanContextServicesListener callback, propagates event to all
943
* currently registered listeners and BeanContextServices children,
944
* if this BeanContextService does not already implement this service
945
* itself.
946
*
947
* subclasses may override or envelope this method to implement their
948
* own propagation semantics.
949
*/
950
951
public void serviceAvailable(BeanContextServiceAvailableEvent bcssae) {
952
synchronized(BeanContext.globalHierarchyLock) {
953
if (services.containsKey(bcssae.getServiceClass())) return;
954
955
fireServiceAdded(bcssae);
956
957
Iterator<Object> i;
958
959
synchronized(children) {
960
i = children.keySet().iterator();
961
}
962
963
while (i.hasNext()) {
964
Object c = i.next();
965
966
if (c instanceof BeanContextServices) {
967
((BeanContextServicesListener)c).serviceAvailable(bcssae);
968
}
969
}
970
}
971
}
972
973
/**
974
* BeanContextServicesListener callback, propagates event to all
975
* currently registered listeners and BeanContextServices children,
976
* if this BeanContextService does not already implement this service
977
* itself.
978
*
979
* subclasses may override or envelope this method to implement their
980
* own propagation semantics.
981
*/
982
983
public void serviceRevoked(BeanContextServiceRevokedEvent bcssre) {
984
synchronized(BeanContext.globalHierarchyLock) {
985
if (services.containsKey(bcssre.getServiceClass())) return;
986
987
fireServiceRevoked(bcssre);
988
989
Iterator<Object> i;
990
991
synchronized(children) {
992
i = children.keySet().iterator();
993
}
994
995
while (i.hasNext()) {
996
Object c = i.next();
997
998
if (c instanceof BeanContextServices) {
999
((BeanContextServicesListener)c).serviceRevoked(bcssre);
1000
}
1001
}
1002
}
1003
}
1004
1005
/**
1006
* Gets the {@code BeanContextServicesListener} (if any) of the specified
1007
* child.
1008
*
1009
* @param child the specified child
1010
* @return the BeanContextServicesListener (if any) of the specified child
1011
*/
1012
protected static final BeanContextServicesListener getChildBeanContextServicesListener(Object child) {
1013
try {
1014
return (BeanContextServicesListener)child;
1015
} catch (ClassCastException cce) {
1016
return null;
1017
}
1018
}
1019
1020
/**
1021
* called from superclass child removal operations after a child
1022
* has been successfully removed. called with child synchronized.
1023
*
1024
* This subclass uses this hook to immediately revoke any services
1025
* being used by this child if it is a BeanContextChild.
1026
*
1027
* subclasses may envelope this method in order to implement their
1028
* own child removal side-effects.
1029
*/
1030
1031
protected void childJustRemovedHook(Object child, BCSChild bcsc) {
1032
BCSSChild bcssc = (BCSSChild)bcsc;
1033
1034
bcssc.cleanupReferences();
1035
}
1036
1037
/**
1038
* called from setBeanContext to notify a BeanContextChild
1039
* to release resources obtained from the nesting BeanContext.
1040
*
1041
* This method revokes any services obtained from its parent.
1042
*
1043
* subclasses may envelope this method to implement their own semantics.
1044
*/
1045
1046
protected synchronized void releaseBeanContextResources() {
1047
Object[] bcssc;
1048
1049
super.releaseBeanContextResources();
1050
1051
synchronized(children) {
1052
if (children.isEmpty()) return;
1053
1054
bcssc = children.values().toArray();
1055
}
1056
1057
1058
for (int i = 0; i < bcssc.length; i++) {
1059
((BCSSChild)bcssc[i]).revokeAllDelegatedServicesNow();
1060
}
1061
1062
proxy = null;
1063
}
1064
1065
/**
1066
* called from setBeanContext to notify a BeanContextChild
1067
* to allocate resources obtained from the nesting BeanContext.
1068
*
1069
* subclasses may envelope this method to implement their own semantics.
1070
*/
1071
1072
protected synchronized void initializeBeanContextResources() {
1073
super.initializeBeanContextResources();
1074
1075
BeanContext nbc = getBeanContext();
1076
1077
if (nbc == null) return;
1078
1079
try {
1080
BeanContextServices bcs = (BeanContextServices)nbc;
1081
1082
proxy = new BCSSProxyServiceProvider(bcs);
1083
} catch (ClassCastException cce) {
1084
// do nothing ...
1085
}
1086
}
1087
1088
/**
1089
* Fires a {@code BeanContextServiceEvent} notifying of a new service.
1090
* @param serviceClass the service class
1091
*/
1092
protected final void fireServiceAdded(Class<?> serviceClass) {
1093
BeanContextServiceAvailableEvent bcssae = new BeanContextServiceAvailableEvent(getBeanContextServicesPeer(), serviceClass);
1094
1095
fireServiceAdded(bcssae);
1096
}
1097
1098
/**
1099
* Fires a {@code BeanContextServiceAvailableEvent} indicating that a new
1100
* service has become available.
1101
*
1102
* @param bcssae the {@code BeanContextServiceAvailableEvent}
1103
*/
1104
protected final void fireServiceAdded(BeanContextServiceAvailableEvent bcssae) {
1105
Object[] copy;
1106
1107
synchronized (bcsListeners) { copy = bcsListeners.toArray(); }
1108
1109
for (int i = 0; i < copy.length; i++) {
1110
((BeanContextServicesListener)copy[i]).serviceAvailable(bcssae);
1111
}
1112
}
1113
1114
/**
1115
* Fires a {@code BeanContextServiceEvent} notifying of a service being revoked.
1116
*
1117
* @param bcsre the {@code BeanContextServiceRevokedEvent}
1118
*/
1119
protected final void fireServiceRevoked(BeanContextServiceRevokedEvent bcsre) {
1120
Object[] copy;
1121
1122
synchronized (bcsListeners) { copy = bcsListeners.toArray(); }
1123
1124
for (int i = 0; i < copy.length; i++) {
1125
((BeanContextServiceRevokedListener)copy[i]).serviceRevoked(bcsre);
1126
}
1127
}
1128
1129
/**
1130
* Fires a {@code BeanContextServiceRevokedEvent}
1131
* indicating that a particular service is
1132
* no longer available.
1133
* @param serviceClass the service class
1134
* @param revokeNow whether or not the event should be revoked now
1135
*/
1136
protected final void fireServiceRevoked(Class<?> serviceClass, boolean revokeNow) {
1137
Object[] copy;
1138
BeanContextServiceRevokedEvent bcsre = new BeanContextServiceRevokedEvent(getBeanContextServicesPeer(), serviceClass, revokeNow);
1139
1140
synchronized (bcsListeners) { copy = bcsListeners.toArray(); }
1141
1142
for (int i = 0; i < copy.length; i++) {
1143
((BeanContextServicesListener)copy[i]).serviceRevoked(bcsre);
1144
}
1145
}
1146
1147
/**
1148
* called from BeanContextSupport writeObject before it serializes the
1149
* children ...
1150
*
1151
* This class will serialize any Serializable BeanContextServiceProviders
1152
* herein.
1153
*
1154
* subclasses may envelope this method to insert their own serialization
1155
* processing that has to occur prior to serialization of the children
1156
*/
1157
1158
protected synchronized void bcsPreSerializationHook(ObjectOutputStream oos) throws IOException {
1159
1160
oos.writeInt(serializable);
1161
1162
if (serializable <= 0) return;
1163
1164
int count = 0;
1165
1166
Iterator<Map.Entry<Object, BCSSServiceProvider>> i = services.entrySet().iterator();
1167
1168
while (i.hasNext() && count < serializable) {
1169
Map.Entry<Object, BCSSServiceProvider> entry = i.next();
1170
BCSSServiceProvider bcsp = null;
1171
1172
try {
1173
bcsp = entry.getValue();
1174
} catch (ClassCastException cce) {
1175
continue;
1176
}
1177
1178
if (bcsp.getServiceProvider() instanceof Serializable) {
1179
oos.writeObject(entry.getKey());
1180
oos.writeObject(bcsp);
1181
count++;
1182
}
1183
}
1184
1185
if (count != serializable)
1186
throw new IOException("wrote different number of service providers than expected");
1187
}
1188
1189
/**
1190
* called from BeanContextSupport readObject before it deserializes the
1191
* children ...
1192
*
1193
* This class will deserialize any Serializable BeanContextServiceProviders
1194
* serialized earlier thus making them available to the children when they
1195
* deserialized.
1196
*
1197
* subclasses may envelope this method to insert their own serialization
1198
* processing that has to occur prior to serialization of the children
1199
*/
1200
1201
protected synchronized void bcsPreDeserializationHook(ObjectInputStream ois) throws IOException, ClassNotFoundException {
1202
1203
serializable = ois.readInt();
1204
1205
int count = serializable;
1206
1207
while (count > 0) {
1208
services.put(ois.readObject(), (BCSSServiceProvider)ois.readObject());
1209
count--;
1210
}
1211
}
1212
1213
/**
1214
* Serialize the instance.
1215
*
1216
* @param oos the {@code ObjectOutputStream} to write
1217
* @throws IOException if an I/O error occurs
1218
*/
1219
@Serial
1220
private synchronized void writeObject(ObjectOutputStream oos) throws IOException {
1221
oos.defaultWriteObject();
1222
1223
serialize(oos, (Collection)bcsListeners);
1224
}
1225
1226
/**
1227
* Deserialize the instance.
1228
*
1229
* @param ois the {@code ObjectInputStream} to read
1230
* @throws ClassNotFoundException if the class of a serialized object could
1231
* not be found
1232
* @throws IOException if an I/O error occurs
1233
*/
1234
@Serial
1235
private synchronized void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
1236
1237
ois.defaultReadObject();
1238
1239
deserialize(ois, (Collection)bcsListeners);
1240
}
1241
1242
1243
/*
1244
* fields
1245
*/
1246
1247
/**
1248
* all accesses to the {@code protected transient HashMap services}
1249
* field should be synchronized on that object
1250
*/
1251
protected transient HashMap<Object, BCSSServiceProvider> services;
1252
1253
/**
1254
* The number of instances of a serializable {@code BeanContextServceProvider}.
1255
*/
1256
protected transient int serializable = 0;
1257
1258
1259
/**
1260
* Delegate for the {@code BeanContextServiceProvider}.
1261
*/
1262
protected transient BCSSProxyServiceProvider proxy;
1263
1264
1265
/**
1266
* List of {@code BeanContextServicesListener} objects.
1267
*/
1268
protected transient ArrayList<BeanContextServicesListener> bcsListeners;
1269
}
1270
1271