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/BeanContextSupport.java
41159 views
1
/*
2
* Copyright (c) 1997, 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.awt.Component;
29
import java.awt.Container;
30
import java.beans.Beans;
31
import java.beans.PropertyChangeEvent;
32
import java.beans.PropertyChangeListener;
33
import java.beans.PropertyVetoException;
34
import java.beans.VetoableChangeListener;
35
import java.beans.Visibility;
36
import java.io.IOException;
37
import java.io.InputStream;
38
import java.io.ObjectInputStream;
39
import java.io.ObjectOutputStream;
40
import java.io.Serial;
41
import java.io.Serializable;
42
import java.net.URL;
43
import java.util.ArrayList;
44
import java.util.Collection;
45
import java.util.HashMap;
46
import java.util.Iterator;
47
import java.util.Locale;
48
import java.util.Map;
49
50
/**
51
* This helper class provides a utility implementation of the
52
* java.beans.beancontext.BeanContext interface.
53
* <p>
54
* Since this class directly implements the BeanContext interface, the class
55
* can, and is intended to be used either by subclassing this implementation,
56
* or via ad-hoc delegation of an instance of this class from another.
57
* </p>
58
*
59
* @author Laurence P. G. Cable
60
* @since 1.2
61
*/
62
public class BeanContextSupport extends BeanContextChildSupport
63
implements BeanContext,
64
Serializable,
65
PropertyChangeListener,
66
VetoableChangeListener {
67
68
/**
69
* Use serialVersionUID from JDK 1.3 for interoperability.
70
*/
71
@Serial
72
private static final long serialVersionUID = -4879613978649577204L;
73
74
/**
75
*
76
* Construct a BeanContextSupport instance
77
*
78
*
79
* @param peer The peer {@code BeanContext} we are
80
* supplying an implementation for,
81
* or {@code null}
82
* if this object is its own peer
83
* @param lcle The current Locale for this BeanContext. If
84
* {@code lcle} is {@code null}, the default locale
85
* is assigned to the {@code BeanContext} instance.
86
* @param dTime The initial state,
87
* {@code true} if in design mode,
88
* {@code false} if runtime.
89
* @param visible The initial visibility.
90
* @see java.util.Locale#getDefault()
91
* @see java.util.Locale#setDefault(java.util.Locale)
92
*/
93
public BeanContextSupport(BeanContext peer, Locale lcle, boolean dTime, boolean visible) {
94
super(peer);
95
96
locale = lcle != null ? lcle : Locale.getDefault();
97
designTime = dTime;
98
okToUseGui = visible;
99
100
initialize();
101
}
102
103
/**
104
* Create an instance using the specified Locale and design mode.
105
*
106
* @param peer The peer {@code BeanContext} we
107
* are supplying an implementation for,
108
* or {@code null} if this object is its own peer
109
* @param lcle The current Locale for this {@code BeanContext}. If
110
* {@code lcle} is {@code null}, the default locale
111
* is assigned to the {@code BeanContext} instance.
112
* @param dtime The initial state, {@code true}
113
* if in design mode,
114
* {@code false} if runtime.
115
* @see java.util.Locale#getDefault()
116
* @see java.util.Locale#setDefault(java.util.Locale)
117
*/
118
public BeanContextSupport(BeanContext peer, Locale lcle, boolean dtime) {
119
this (peer, lcle, dtime, true);
120
}
121
122
/**
123
* Create an instance using the specified locale
124
*
125
* @param peer The peer BeanContext we are
126
* supplying an implementation for,
127
* or {@code null} if this object
128
* is its own peer
129
* @param lcle The current Locale for this
130
* {@code BeanContext}. If
131
* {@code lcle} is {@code null},
132
* the default locale
133
* is assigned to the {@code BeanContext}
134
* instance.
135
* @see java.util.Locale#getDefault()
136
* @see java.util.Locale#setDefault(java.util.Locale)
137
*/
138
public BeanContextSupport(BeanContext peer, Locale lcle) {
139
this (peer, lcle, false, true);
140
}
141
142
/**
143
* Create an instance using with a default locale
144
*
145
* @param peer The peer {@code BeanContext} we are
146
* supplying an implementation for,
147
* or {@code null} if this object
148
* is its own peer
149
*/
150
public BeanContextSupport(BeanContext peer) {
151
this (peer, null, false, true);
152
}
153
154
/**
155
* Create an instance that is not a delegate of another object
156
*/
157
158
public BeanContextSupport() {
159
this (null, null, false, true);
160
}
161
162
/**
163
* Gets the instance of {@code BeanContext} that
164
* this object is providing the implementation for.
165
* @return the BeanContext instance
166
*/
167
public BeanContext getBeanContextPeer() { return (BeanContext)getBeanContextChildPeer(); }
168
169
/**
170
* <p>
171
* The instantiateChild method is a convenience hook
172
* in BeanContext to simplify
173
* the task of instantiating a Bean, nested,
174
* into a {@code BeanContext}.
175
* </p>
176
* <p>
177
* The semantics of the beanName parameter are defined by java.beans.Beans.instantiate.
178
* </p>
179
*
180
* @param beanName the name of the Bean to instantiate within this BeanContext
181
* @throws IOException if there is an I/O error when the bean is being deserialized
182
* @throws ClassNotFoundException if the class
183
* identified by the beanName parameter is not found
184
* @return the new object
185
*/
186
public Object instantiateChild(String beanName)
187
throws IOException, ClassNotFoundException {
188
BeanContext bc = getBeanContextPeer();
189
190
return Beans.instantiate(bc.getClass().getClassLoader(), beanName, bc);
191
}
192
193
/**
194
* Gets the number of children currently nested in
195
* this BeanContext.
196
*
197
* @return number of children
198
*/
199
public int size() {
200
synchronized(children) {
201
return children.size();
202
}
203
}
204
205
/**
206
* Reports whether or not this
207
* {@code BeanContext} is empty.
208
* A {@code BeanContext} is considered
209
* empty when it contains zero
210
* nested children.
211
* @return if there are not children
212
*/
213
public boolean isEmpty() {
214
synchronized(children) {
215
return children.isEmpty();
216
}
217
}
218
219
/**
220
* Determines whether or not the specified object
221
* is currently a child of this {@code BeanContext}.
222
* @param o the Object in question
223
* @return if this object is a child
224
*/
225
public boolean contains(Object o) {
226
synchronized(children) {
227
return children.containsKey(o);
228
}
229
}
230
231
/**
232
* Determines whether or not the specified object
233
* is currently a child of this {@code BeanContext}.
234
* @param o the Object in question
235
* @return if this object is a child
236
*/
237
public boolean containsKey(Object o) {
238
synchronized(children) {
239
return children.containsKey(o);
240
}
241
}
242
243
/**
244
* Gets all JavaBean or {@code BeanContext} instances
245
* currently nested in this {@code BeanContext}.
246
* @return an {@code Iterator} of the nested children
247
*/
248
public Iterator<Object> iterator() {
249
synchronized(children) {
250
return new BCSIterator(children.keySet().iterator());
251
}
252
}
253
254
/**
255
* Gets all JavaBean or {@code BeanContext}
256
* instances currently nested in this BeanContext.
257
*/
258
public Object[] toArray() {
259
synchronized(children) {
260
return children.keySet().toArray();
261
}
262
}
263
264
/**
265
* Gets an array containing all children of
266
* this {@code BeanContext} that match
267
* the types contained in arry.
268
* @param arry The array of object
269
* types that are of interest.
270
* @return an array of children
271
*/
272
public Object[] toArray(Object[] arry) {
273
synchronized(children) {
274
return children.keySet().toArray(arry);
275
}
276
}
277
278
279
/************************************************************************/
280
281
/**
282
* protected final subclass that encapsulates an iterator but implements
283
* a noop remove() method.
284
*/
285
286
protected static final class BCSIterator implements Iterator<Object> {
287
BCSIterator(Iterator<?> i) { super(); src = i; }
288
289
public boolean hasNext() { return src.hasNext(); }
290
public Object next() { return src.next(); }
291
public void remove() { /* do nothing */ }
292
293
private Iterator<?> src;
294
}
295
296
/************************************************************************/
297
298
/*
299
* protected nested class containing per child information, an instance
300
* of which is associated with each child in the "children" hashtable.
301
* subclasses can extend this class to include their own per-child state.
302
*
303
* Note that this 'value' is serialized with the corresponding child 'key'
304
* when the BeanContextSupport is serialized.
305
*/
306
307
protected class BCSChild implements Serializable {
308
309
/**
310
* Use serialVersionUID from JDK 1.7 for interoperability.
311
*/
312
@Serial
313
private static final long serialVersionUID = -5815286101609939109L;
314
315
BCSChild(Object bcc, Object peer) {
316
super();
317
318
child = bcc;
319
proxyPeer = peer;
320
}
321
322
Object getChild() { return child; }
323
324
void setRemovePending(boolean v) { removePending = v; }
325
326
boolean isRemovePending() { return removePending; }
327
328
boolean isProxyPeer() { return proxyPeer != null; }
329
330
Object getProxyPeer() { return proxyPeer; }
331
/*
332
* fields
333
*/
334
335
336
/**
337
* The child.
338
*/
339
@SuppressWarnings("serial") // Not statically typed as Serializable
340
private Object child;
341
342
/**
343
* The peer if the child and the peer are related by an implementation
344
* of BeanContextProxy
345
*/
346
@SuppressWarnings("serial") // Not statically typed as Serializable
347
private Object proxyPeer;
348
349
private transient boolean removePending;
350
}
351
352
/**
353
* <p>
354
* Subclasses can override this method to insert their own subclass
355
* of Child without having to override add() or the other Collection
356
* methods that add children to the set.
357
* </p>
358
* @param targetChild the child to create the Child on behalf of
359
* @param peer the peer if the tragetChild and the peer are related by an implementation of BeanContextProxy
360
* @return Subtype-specific subclass of Child without overriding collection methods
361
*/
362
363
protected BCSChild createBCSChild(Object targetChild, Object peer) {
364
return new BCSChild(targetChild, peer);
365
}
366
367
/************************************************************************/
368
369
/**
370
* Adds/nests a child within this {@code BeanContext}.
371
* <p>
372
* Invoked as a side effect of java.beans.Beans.instantiate().
373
* If the child object is not valid for adding then this method
374
* throws an IllegalStateException.
375
* </p>
376
*
377
*
378
* @param targetChild The child objects to nest
379
* within this {@code BeanContext}
380
* @return true if the child was added successfully.
381
* @see #validatePendingAdd
382
*/
383
public boolean add(Object targetChild) {
384
385
if (targetChild == null) throw new IllegalArgumentException();
386
387
// The specification requires that we do nothing if the child
388
// is already nested herein.
389
390
if (children.containsKey(targetChild)) return false; // test before locking
391
392
synchronized(BeanContext.globalHierarchyLock) {
393
if (children.containsKey(targetChild)) return false; // check again
394
395
if (!validatePendingAdd(targetChild)) {
396
throw new IllegalStateException();
397
}
398
399
400
// The specification requires that we invoke setBeanContext() on the
401
// newly added child if it implements the java.beans.beancontext.BeanContextChild interface
402
403
BeanContextChild cbcc = getChildBeanContextChild(targetChild);
404
BeanContextChild bccp = null;
405
406
synchronized(targetChild) {
407
408
if (targetChild instanceof BeanContextProxy) {
409
bccp = ((BeanContextProxy)targetChild).getBeanContextProxy();
410
411
if (bccp == null) throw new NullPointerException("BeanContextPeer.getBeanContextProxy()");
412
}
413
414
BCSChild bcsc = createBCSChild(targetChild, bccp);
415
BCSChild pbcsc = null;
416
417
synchronized (children) {
418
children.put(targetChild, bcsc);
419
420
if (bccp != null) children.put(bccp, pbcsc = createBCSChild(bccp, targetChild));
421
}
422
423
if (cbcc != null) synchronized(cbcc) {
424
try {
425
cbcc.setBeanContext(getBeanContextPeer());
426
} catch (PropertyVetoException pve) {
427
428
synchronized (children) {
429
children.remove(targetChild);
430
431
if (bccp != null) children.remove(bccp);
432
}
433
434
throw new IllegalStateException();
435
}
436
437
cbcc.addPropertyChangeListener("beanContext", childPCL);
438
cbcc.addVetoableChangeListener("beanContext", childVCL);
439
}
440
441
Visibility v = getChildVisibility(targetChild);
442
443
if (v != null) {
444
if (okToUseGui)
445
v.okToUseGui();
446
else
447
v.dontUseGui();
448
}
449
450
if (getChildSerializable(targetChild) != null) serializable++;
451
452
childJustAddedHook(targetChild, bcsc);
453
454
if (bccp != null) {
455
v = getChildVisibility(bccp);
456
457
if (v != null) {
458
if (okToUseGui)
459
v.okToUseGui();
460
else
461
v.dontUseGui();
462
}
463
464
if (getChildSerializable(bccp) != null) serializable++;
465
466
childJustAddedHook(bccp, pbcsc);
467
}
468
469
470
}
471
472
// The specification requires that we fire a notification of the change
473
474
fireChildrenAdded(new BeanContextMembershipEvent(getBeanContextPeer(), bccp == null ? new Object[] { targetChild } : new Object[] { targetChild, bccp } ));
475
476
}
477
478
return true;
479
}
480
481
/**
482
* Removes a child from this BeanContext. If the child object is not
483
* for adding then this method throws an IllegalStateException.
484
* @param targetChild The child objects to remove
485
* @see #validatePendingRemove
486
*/
487
public boolean remove(Object targetChild) {
488
return remove(targetChild, true);
489
}
490
491
/**
492
* internal remove used when removal caused by
493
* unexpected {@code setBeanContext} or
494
* by {@code remove()} invocation.
495
* @param targetChild the JavaBean, BeanContext, or Object to be removed
496
* @param callChildSetBC used to indicate that
497
* the child should be notified that it is no
498
* longer nested in this {@code BeanContext}.
499
* @return whether or not was present before being removed
500
*/
501
protected boolean remove(Object targetChild, boolean callChildSetBC) {
502
503
if (targetChild == null) throw new IllegalArgumentException();
504
505
synchronized(BeanContext.globalHierarchyLock) {
506
if (!containsKey(targetChild)) return false;
507
508
if (!validatePendingRemove(targetChild)) {
509
throw new IllegalStateException();
510
}
511
512
BCSChild bcsc = children.get(targetChild);
513
BCSChild pbcsc = null;
514
Object peer = null;
515
516
// we are required to notify the child that it is no longer nested here if
517
// it implements java.beans.beancontext.BeanContextChild
518
519
synchronized(targetChild) {
520
if (callChildSetBC) {
521
BeanContextChild cbcc = getChildBeanContextChild(targetChild);
522
if (cbcc != null) synchronized(cbcc) {
523
cbcc.removePropertyChangeListener("beanContext", childPCL);
524
cbcc.removeVetoableChangeListener("beanContext", childVCL);
525
526
try {
527
cbcc.setBeanContext(null);
528
} catch (PropertyVetoException pve1) {
529
cbcc.addPropertyChangeListener("beanContext", childPCL);
530
cbcc.addVetoableChangeListener("beanContext", childVCL);
531
throw new IllegalStateException();
532
}
533
534
}
535
}
536
537
synchronized (children) {
538
children.remove(targetChild);
539
540
if (bcsc.isProxyPeer()) {
541
pbcsc = children.get(peer = bcsc.getProxyPeer());
542
children.remove(peer);
543
}
544
}
545
546
if (getChildSerializable(targetChild) != null) serializable--;
547
548
childJustRemovedHook(targetChild, bcsc);
549
550
if (peer != null) {
551
if (getChildSerializable(peer) != null) serializable--;
552
553
childJustRemovedHook(peer, pbcsc);
554
}
555
}
556
557
fireChildrenRemoved(new BeanContextMembershipEvent(getBeanContextPeer(), peer == null ? new Object[] { targetChild } : new Object[] { targetChild, peer } ));
558
559
}
560
561
return true;
562
}
563
564
/**
565
* Tests to see if all objects in the
566
* specified {@code Collection} are children of
567
* this {@code BeanContext}.
568
* @param c the specified {@code Collection}
569
*
570
* @return {@code true} if all objects
571
* in the collection are children of
572
* this {@code BeanContext}, false if not.
573
*/
574
@SuppressWarnings("rawtypes")
575
public boolean containsAll(Collection c) {
576
synchronized(children) {
577
for (Object o : c)
578
if(!contains(o))
579
return false;
580
581
return true;
582
}
583
}
584
585
/**
586
* add Collection to set of Children (Unsupported)
587
* implementations must synchronized on the hierarchy lock and "children" protected field
588
* @throws UnsupportedOperationException thrown unconditionally by this implementation
589
* @return this implementation unconditionally throws {@code UnsupportedOperationException}
590
*/
591
@SuppressWarnings("rawtypes")
592
public boolean addAll(Collection c) {
593
throw new UnsupportedOperationException();
594
}
595
596
/**
597
* remove all specified children (Unsupported)
598
* implementations must synchronized on the hierarchy lock and "children" protected field
599
* @throws UnsupportedOperationException thrown unconditionally by this implementation
600
* @return this implementation unconditionally throws {@code UnsupportedOperationException}
601
602
*/
603
@SuppressWarnings("rawtypes")
604
public boolean removeAll(Collection c) {
605
throw new UnsupportedOperationException();
606
}
607
608
609
/**
610
* retain only specified children (Unsupported)
611
* implementations must synchronized on the hierarchy lock and "children" protected field
612
* @throws UnsupportedOperationException thrown unconditionally by this implementation
613
* @return this implementation unconditionally throws {@code UnsupportedOperationException}
614
*/
615
@SuppressWarnings("rawtypes")
616
public boolean retainAll(Collection c) {
617
throw new UnsupportedOperationException();
618
}
619
620
/**
621
* clear the children (Unsupported)
622
* implementations must synchronized on the hierarchy lock and "children" protected field
623
* @throws UnsupportedOperationException thrown unconditionally by this implementation
624
*/
625
public void clear() {
626
throw new UnsupportedOperationException();
627
}
628
629
/**
630
* Adds a BeanContextMembershipListener
631
*
632
* @param bcml the BeanContextMembershipListener to add
633
* @throws NullPointerException if the argument is null
634
*/
635
636
public void addBeanContextMembershipListener(BeanContextMembershipListener bcml) {
637
if (bcml == null) throw new NullPointerException("listener");
638
639
synchronized(bcmListeners) {
640
if (bcmListeners.contains(bcml))
641
return;
642
else
643
bcmListeners.add(bcml);
644
}
645
}
646
647
/**
648
* Removes a BeanContextMembershipListener
649
*
650
* @param bcml the BeanContextMembershipListener to remove
651
* @throws NullPointerException if the argument is null
652
*/
653
654
public void removeBeanContextMembershipListener(BeanContextMembershipListener bcml) {
655
if (bcml == null) throw new NullPointerException("listener");
656
657
synchronized(bcmListeners) {
658
if (!bcmListeners.contains(bcml))
659
return;
660
else
661
bcmListeners.remove(bcml);
662
}
663
}
664
665
/**
666
* @param name the name of the resource requested.
667
* @param bcc the child object making the request.
668
*
669
* @return the requested resource as an InputStream
670
* @throws NullPointerException if the argument is null
671
*/
672
673
public InputStream getResourceAsStream(String name, BeanContextChild bcc) {
674
if (name == null) throw new NullPointerException("name");
675
if (bcc == null) throw new NullPointerException("bcc");
676
677
if (containsKey(bcc)) {
678
ClassLoader cl = bcc.getClass().getClassLoader();
679
680
return cl != null ? cl.getResourceAsStream(name)
681
: ClassLoader.getSystemResourceAsStream(name);
682
} else throw new IllegalArgumentException("Not a valid child");
683
}
684
685
/**
686
* @param name the name of the resource requested.
687
* @param bcc the child object making the request.
688
*
689
* @return the requested resource as an InputStream
690
*/
691
692
public URL getResource(String name, BeanContextChild bcc) {
693
if (name == null) throw new NullPointerException("name");
694
if (bcc == null) throw new NullPointerException("bcc");
695
696
if (containsKey(bcc)) {
697
ClassLoader cl = bcc.getClass().getClassLoader();
698
699
return cl != null ? cl.getResource(name)
700
: ClassLoader.getSystemResource(name);
701
} else throw new IllegalArgumentException("Not a valid child");
702
}
703
704
/**
705
* Sets the new design time value for this {@code BeanContext}.
706
* @param dTime the new designTime value
707
*/
708
public synchronized void setDesignTime(boolean dTime) {
709
if (designTime != dTime) {
710
designTime = dTime;
711
712
firePropertyChange("designMode", Boolean.valueOf(!dTime), Boolean.valueOf(dTime));
713
}
714
}
715
716
717
/**
718
* Reports whether or not this object is in
719
* currently in design time mode.
720
* @return {@code true} if in design time mode,
721
* {@code false} if not
722
*/
723
public synchronized boolean isDesignTime() { return designTime; }
724
725
/**
726
* Sets the locale of this BeanContext.
727
* @param newLocale the new locale. This method call will have
728
* no effect if newLocale is {@code null}.
729
* @throws PropertyVetoException if the new value is rejected
730
*/
731
public synchronized void setLocale(Locale newLocale) throws PropertyVetoException {
732
733
if ((locale != null && !locale.equals(newLocale)) && newLocale != null) {
734
Locale old = locale;
735
736
fireVetoableChange("locale", old, newLocale); // throws
737
738
locale = newLocale;
739
740
firePropertyChange("locale", old, newLocale);
741
}
742
}
743
744
/**
745
* Gets the locale for this {@code BeanContext}.
746
*
747
* @return the current Locale of the {@code BeanContext}
748
*/
749
public synchronized Locale getLocale() { return locale; }
750
751
/**
752
* <p>
753
* This method is typically called from the environment in order to determine
754
* if the implementor "needs" a GUI.
755
* </p>
756
* <p>
757
* The algorithm used herein tests the BeanContextPeer, and its current children
758
* to determine if they are either Containers, Components, or if they implement
759
* Visibility and return needsGui() == true.
760
* </p>
761
* @return {@code true} if the implementor needs a GUI
762
*/
763
public synchronized boolean needsGui() {
764
BeanContext bc = getBeanContextPeer();
765
766
if (bc != this) {
767
if (bc instanceof Visibility) return ((Visibility)bc).needsGui();
768
769
if (bc instanceof Container || bc instanceof Component)
770
return true;
771
}
772
773
synchronized(children) {
774
for (Iterator<Object> i = children.keySet().iterator(); i.hasNext();) {
775
Object c = i.next();
776
777
try {
778
return ((Visibility)c).needsGui();
779
} catch (ClassCastException cce) {
780
// do nothing ...
781
}
782
783
if (c instanceof Container || c instanceof Component)
784
return true;
785
}
786
}
787
788
return false;
789
}
790
791
/**
792
* notify this instance that it may no longer render a GUI.
793
*/
794
795
public synchronized void dontUseGui() {
796
if (okToUseGui) {
797
okToUseGui = false;
798
799
// lets also tell the Children that can that they may not use their GUI's
800
synchronized(children) {
801
for (Iterator<Object> i = children.keySet().iterator(); i.hasNext();) {
802
Visibility v = getChildVisibility(i.next());
803
804
if (v != null) v.dontUseGui();
805
}
806
}
807
}
808
}
809
810
/**
811
* Notify this instance that it may now render a GUI
812
*/
813
814
public synchronized void okToUseGui() {
815
if (!okToUseGui) {
816
okToUseGui = true;
817
818
// lets also tell the Children that can that they may use their GUI's
819
synchronized(children) {
820
for (Iterator<Object> i = children.keySet().iterator(); i.hasNext();) {
821
Visibility v = getChildVisibility(i.next());
822
823
if (v != null) v.okToUseGui();
824
}
825
}
826
}
827
}
828
829
/**
830
* Used to determine if the {@code BeanContext}
831
* child is avoiding using its GUI.
832
* @return is this instance avoiding using its GUI?
833
* @see Visibility
834
*/
835
public boolean avoidingGui() {
836
return !okToUseGui && needsGui();
837
}
838
839
/**
840
* Is this {@code BeanContext} in the
841
* process of being serialized?
842
* @return if this {@code BeanContext} is
843
* currently being serialized
844
*/
845
public boolean isSerializing() { return serializing; }
846
847
/**
848
* Returns an iterator of all children
849
* of this {@code BeanContext}.
850
* @return an iterator for all the current BCSChild values
851
*/
852
protected Iterator<BCSChild> bcsChildren() { synchronized(children) { return children.values().iterator(); } }
853
854
/**
855
* called by writeObject after defaultWriteObject() but prior to
856
* serialization of currently serializable children.
857
*
858
* This method may be overridden by subclasses to perform custom
859
* serialization of their state prior to this superclass serializing
860
* the children.
861
*
862
* This method should not however be used by subclasses to replace their
863
* own implementation (if any) of writeObject().
864
* @param oos the {@code ObjectOutputStream} to use during serialization
865
* @throws IOException if serialization failed
866
*/
867
868
protected void bcsPreSerializationHook(ObjectOutputStream oos) throws IOException {
869
}
870
871
/**
872
* called by readObject after defaultReadObject() but prior to
873
* deserialization of any children.
874
*
875
* This method may be overridden by subclasses to perform custom
876
* deserialization of their state prior to this superclass deserializing
877
* the children.
878
*
879
* This method should not however be used by subclasses to replace their
880
* own implementation (if any) of readObject().
881
* @param ois the {@code ObjectInputStream} to use during deserialization
882
* @throws IOException if deserialization failed
883
* @throws ClassNotFoundException if needed classes are not found
884
*/
885
886
protected void bcsPreDeserializationHook(ObjectInputStream ois) throws IOException, ClassNotFoundException {
887
}
888
889
/**
890
* Called by readObject with the newly deserialized child and BCSChild.
891
* @param child the newly deserialized child
892
* @param bcsc the newly deserialized BCSChild
893
*/
894
protected void childDeserializedHook(Object child, BCSChild bcsc) {
895
synchronized(children) {
896
children.put(child, bcsc);
897
}
898
}
899
900
/**
901
* Used by writeObject to serialize a Collection.
902
* @param oos the {@code ObjectOutputStream}
903
* to use during serialization
904
* @param coll the {@code Collection} to serialize
905
* @throws IOException if serialization failed
906
*/
907
protected final void serialize(ObjectOutputStream oos, Collection<?> coll) throws IOException {
908
int count = 0;
909
Object[] objects = coll.toArray();
910
911
for (int i = 0; i < objects.length; i++) {
912
if (objects[i] instanceof Serializable)
913
count++;
914
else
915
objects[i] = null;
916
}
917
918
oos.writeInt(count); // number of subsequent objects
919
920
for (int i = 0; count > 0; i++) {
921
Object o = objects[i];
922
923
if (o != null) {
924
oos.writeObject(o);
925
count--;
926
}
927
}
928
}
929
930
/**
931
* used by readObject to deserialize a collection.
932
* @param ois the ObjectInputStream to use
933
* @param coll the Collection
934
* @throws IOException if deserialization failed
935
* @throws ClassNotFoundException if needed classes are not found
936
*/
937
@SuppressWarnings({"rawtypes", "unchecked"})
938
protected final void deserialize(ObjectInputStream ois, Collection coll) throws IOException, ClassNotFoundException {
939
int count = 0;
940
941
count = ois.readInt();
942
943
while (count-- > 0) {
944
coll.add(ois.readObject());
945
}
946
}
947
948
/**
949
* Used to serialize all children of
950
* this {@code BeanContext}.
951
* @param oos the {@code ObjectOutputStream}
952
* to use during serialization
953
* @throws IOException if serialization failed
954
*/
955
public final void writeChildren(ObjectOutputStream oos) throws IOException {
956
if (serializable <= 0) return;
957
958
boolean prev = serializing;
959
960
serializing = true;
961
962
int count = 0;
963
964
synchronized(children) {
965
Iterator<Map.Entry<Object, BCSChild>> i = children.entrySet().iterator();
966
967
while (i.hasNext() && count < serializable) {
968
Map.Entry<Object, BCSChild> entry = i.next();
969
970
if (entry.getKey() instanceof Serializable) {
971
try {
972
oos.writeObject(entry.getKey()); // child
973
oos.writeObject(entry.getValue()); // BCSChild
974
} catch (IOException ioe) {
975
serializing = prev;
976
throw ioe;
977
}
978
count++;
979
}
980
}
981
}
982
983
serializing = prev;
984
985
if (count != serializable) {
986
throw new IOException("wrote different number of children than expected");
987
}
988
989
}
990
991
/**
992
* Serialize the BeanContextSupport, if this instance has a distinct
993
* peer (that is this object is acting as a delegate for another) then
994
* the children of this instance are not serialized here due to a
995
* 'chicken and egg' problem that occurs on deserialization of the
996
* children at the same time as this instance.
997
*
998
* Therefore in situations where there is a distinct peer to this instance
999
* it should always call writeObject() followed by writeChildren() and
1000
* readObject() followed by readChildren().
1001
*
1002
* @param oos the {@code ObjectOutputStream} to write
1003
* @throws IOException if an I/O error occurs
1004
*/
1005
@Serial
1006
private synchronized void writeObject(ObjectOutputStream oos) throws IOException {
1007
serializing = true;
1008
1009
synchronized (BeanContext.globalHierarchyLock) {
1010
try {
1011
oos.defaultWriteObject(); // serialize the BeanContextSupport object
1012
1013
bcsPreSerializationHook(oos);
1014
1015
if (serializable > 0 && this.equals(getBeanContextPeer()))
1016
writeChildren(oos);
1017
1018
serialize(oos, (Collection)bcmListeners);
1019
} finally {
1020
serializing = false;
1021
}
1022
}
1023
}
1024
1025
/**
1026
* When an instance of this class is used as a delegate for the
1027
* implementation of the BeanContext protocols (and its subprotocols)
1028
* there exists a 'chicken and egg' problem during deserialization
1029
* @param ois the ObjectInputStream to use
1030
* @throws IOException if deserialization failed
1031
* @throws ClassNotFoundException if needed classes are not found
1032
*/
1033
1034
public final void readChildren(ObjectInputStream ois) throws IOException, ClassNotFoundException {
1035
int count = serializable;
1036
1037
while (count-- > 0) {
1038
Object child = ois.readObject();
1039
BCSChild bscc = (BCSChild) ois.readObject();
1040
1041
synchronized(child) {
1042
BeanContextChild bcc = null;
1043
1044
try {
1045
bcc = (BeanContextChild)child;
1046
} catch (ClassCastException cce) {
1047
// do nothing;
1048
}
1049
1050
if (bcc != null) {
1051
try {
1052
bcc.setBeanContext(getBeanContextPeer());
1053
1054
bcc.addPropertyChangeListener("beanContext", childPCL);
1055
bcc.addVetoableChangeListener("beanContext", childVCL);
1056
1057
} catch (PropertyVetoException pve) {
1058
continue;
1059
}
1060
}
1061
1062
childDeserializedHook(child, bscc);
1063
}
1064
}
1065
}
1066
1067
/**
1068
* deserialize contents ... if this instance has a distinct peer the
1069
* children are *not* serialized here, the peer's readObject() must call
1070
* readChildren() after deserializing this instance.
1071
*
1072
* @param ois the {@code ObjectInputStream} to read
1073
* @throws ClassNotFoundException if the class of a serialized object could
1074
* not be found
1075
* @throws IOException if an I/O error occurs
1076
*/
1077
@Serial
1078
private synchronized void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
1079
1080
synchronized(BeanContext.globalHierarchyLock) {
1081
ois.defaultReadObject();
1082
1083
initialize();
1084
1085
bcsPreDeserializationHook(ois);
1086
1087
if (serializable > 0 && this.equals(getBeanContextPeer()))
1088
readChildren(ois);
1089
1090
deserialize(ois, bcmListeners = new ArrayList<>(1));
1091
}
1092
}
1093
1094
/**
1095
* subclasses may envelope to monitor veto child property changes.
1096
*/
1097
1098
public void vetoableChange(PropertyChangeEvent pce) throws PropertyVetoException {
1099
String propertyName = pce.getPropertyName();
1100
Object source = pce.getSource();
1101
1102
synchronized(children) {
1103
if ("beanContext".equals(propertyName) &&
1104
containsKey(source) &&
1105
!getBeanContextPeer().equals(pce.getNewValue())
1106
) {
1107
if (!validatePendingRemove(source)) {
1108
throw new PropertyVetoException("current BeanContext vetoes setBeanContext()", pce);
1109
} else children.get(source).setRemovePending(true);
1110
}
1111
}
1112
}
1113
1114
/**
1115
* subclasses may envelope to monitor child property changes.
1116
*/
1117
1118
public void propertyChange(PropertyChangeEvent pce) {
1119
String propertyName = pce.getPropertyName();
1120
Object source = pce.getSource();
1121
1122
synchronized(children) {
1123
if ("beanContext".equals(propertyName) &&
1124
containsKey(source) &&
1125
children.get(source).isRemovePending()) {
1126
BeanContext bc = getBeanContextPeer();
1127
1128
if (bc.equals(pce.getOldValue()) && !bc.equals(pce.getNewValue())) {
1129
remove(source, false);
1130
} else {
1131
children.get(source).setRemovePending(false);
1132
}
1133
}
1134
}
1135
}
1136
1137
/**
1138
* <p>
1139
* Subclasses of this class may override, or envelope, this method to
1140
* add validation behavior for the BeanContext to examine child objects
1141
* immediately prior to their being added to the BeanContext.
1142
* </p>
1143
*
1144
* @param targetChild the child to create the Child on behalf of
1145
* @return true iff the child may be added to this BeanContext, otherwise false.
1146
*/
1147
1148
protected boolean validatePendingAdd(Object targetChild) {
1149
return true;
1150
}
1151
1152
/**
1153
* <p>
1154
* Subclasses of this class may override, or envelope, this method to
1155
* add validation behavior for the BeanContext to examine child objects
1156
* immediately prior to their being removed from the BeanContext.
1157
* </p>
1158
*
1159
* @param targetChild the child to create the Child on behalf of
1160
* @return true iff the child may be removed from this BeanContext, otherwise false.
1161
*/
1162
1163
protected boolean validatePendingRemove(Object targetChild) {
1164
return true;
1165
}
1166
1167
/**
1168
* subclasses may override this method to simply extend add() semantics
1169
* after the child has been added and before the event notification has
1170
* occurred. The method is called with the child synchronized.
1171
* @param child the child
1172
* @param bcsc the BCSChild
1173
*/
1174
1175
protected void childJustAddedHook(Object child, BCSChild bcsc) {
1176
}
1177
1178
/**
1179
* subclasses may override this method to simply extend remove() semantics
1180
* after the child has been removed and before the event notification has
1181
* occurred. The method is called with the child synchronized.
1182
* @param child the child
1183
* @param bcsc the BCSChild
1184
*/
1185
1186
protected void childJustRemovedHook(Object child, BCSChild bcsc) {
1187
}
1188
1189
/**
1190
* Gets the Component (if any) associated with the specified child.
1191
* @param child the specified child
1192
* @return the Component (if any) associated with the specified child.
1193
*/
1194
protected static final Visibility getChildVisibility(Object child) {
1195
try {
1196
return (Visibility)child;
1197
} catch (ClassCastException cce) {
1198
return null;
1199
}
1200
}
1201
1202
/**
1203
* Gets the Serializable (if any) associated with the specified Child
1204
* @param child the specified child
1205
* @return the Serializable (if any) associated with the specified Child
1206
*/
1207
protected static final Serializable getChildSerializable(Object child) {
1208
try {
1209
return (Serializable)child;
1210
} catch (ClassCastException cce) {
1211
return null;
1212
}
1213
}
1214
1215
/**
1216
* Gets the PropertyChangeListener
1217
* (if any) of the specified child
1218
* @param child the specified child
1219
* @return the PropertyChangeListener (if any) of the specified child
1220
*/
1221
protected static final PropertyChangeListener getChildPropertyChangeListener(Object child) {
1222
try {
1223
return (PropertyChangeListener)child;
1224
} catch (ClassCastException cce) {
1225
return null;
1226
}
1227
}
1228
1229
/**
1230
* Gets the VetoableChangeListener
1231
* (if any) of the specified child
1232
* @param child the specified child
1233
* @return the VetoableChangeListener (if any) of the specified child
1234
*/
1235
protected static final VetoableChangeListener getChildVetoableChangeListener(Object child) {
1236
try {
1237
return (VetoableChangeListener)child;
1238
} catch (ClassCastException cce) {
1239
return null;
1240
}
1241
}
1242
1243
/**
1244
* Gets the BeanContextMembershipListener
1245
* (if any) of the specified child
1246
* @param child the specified child
1247
* @return the BeanContextMembershipListener (if any) of the specified child
1248
*/
1249
protected static final BeanContextMembershipListener getChildBeanContextMembershipListener(Object child) {
1250
try {
1251
return (BeanContextMembershipListener)child;
1252
} catch (ClassCastException cce) {
1253
return null;
1254
}
1255
}
1256
1257
/**
1258
* Gets the BeanContextChild (if any) of the specified child
1259
* @param child the specified child
1260
* @return the BeanContextChild (if any) of the specified child
1261
* @throws IllegalArgumentException if child implements both BeanContextChild and BeanContextProxy
1262
*/
1263
protected static final BeanContextChild getChildBeanContextChild(Object child) {
1264
try {
1265
BeanContextChild bcc = (BeanContextChild)child;
1266
1267
if (child instanceof BeanContextChild && child instanceof BeanContextProxy)
1268
throw new IllegalArgumentException("child cannot implement both BeanContextChild and BeanContextProxy");
1269
else
1270
return bcc;
1271
} catch (ClassCastException cce) {
1272
try {
1273
return ((BeanContextProxy)child).getBeanContextProxy();
1274
} catch (ClassCastException cce1) {
1275
return null;
1276
}
1277
}
1278
}
1279
1280
/**
1281
* Fire a BeanContextshipEvent on the BeanContextMembershipListener interface
1282
* @param bcme the event to fire
1283
*/
1284
1285
protected final void fireChildrenAdded(BeanContextMembershipEvent bcme) {
1286
Object[] copy;
1287
1288
synchronized(bcmListeners) { copy = bcmListeners.toArray(); }
1289
1290
for (int i = 0; i < copy.length; i++)
1291
((BeanContextMembershipListener)copy[i]).childrenAdded(bcme);
1292
}
1293
1294
/**
1295
* Fire a BeanContextshipEvent on the BeanContextMembershipListener interface
1296
* @param bcme the event to fire
1297
*/
1298
1299
protected final void fireChildrenRemoved(BeanContextMembershipEvent bcme) {
1300
Object[] copy;
1301
1302
synchronized(bcmListeners) { copy = bcmListeners.toArray(); }
1303
1304
for (int i = 0; i < copy.length; i++)
1305
((BeanContextMembershipListener)copy[i]).childrenRemoved(bcme);
1306
}
1307
1308
/**
1309
* protected method called from constructor and readObject to initialize
1310
* transient state of BeanContextSupport instance.
1311
*
1312
* This class uses this method to instantiate inner class listeners used
1313
* to monitor PropertyChange and VetoableChange events on children.
1314
*
1315
* subclasses may envelope this method to add their own initialization
1316
* behavior
1317
*/
1318
1319
protected synchronized void initialize() {
1320
children = new HashMap<>(serializable + 1);
1321
bcmListeners = new ArrayList<>(1);
1322
1323
childPCL = new PropertyChangeListener() {
1324
1325
/*
1326
* this adaptor is used by the BeanContextSupport class to forward
1327
* property changes from a child to the BeanContext, avoiding
1328
* accidential serialization of the BeanContext by a badly
1329
* behaved Serializable child.
1330
*/
1331
1332
public void propertyChange(PropertyChangeEvent pce) {
1333
BeanContextSupport.this.propertyChange(pce);
1334
}
1335
};
1336
1337
childVCL = new VetoableChangeListener() {
1338
1339
/*
1340
* this adaptor is used by the BeanContextSupport class to forward
1341
* vetoable changes from a child to the BeanContext, avoiding
1342
* accidential serialization of the BeanContext by a badly
1343
* behaved Serializable child.
1344
*/
1345
1346
public void vetoableChange(PropertyChangeEvent pce) throws PropertyVetoException {
1347
BeanContextSupport.this.vetoableChange(pce);
1348
}
1349
};
1350
}
1351
1352
/**
1353
* Gets a copy of the this BeanContext's children.
1354
* @return a copy of the current nested children
1355
*/
1356
protected final Object[] copyChildren() {
1357
synchronized(children) { return children.keySet().toArray(); }
1358
}
1359
1360
/**
1361
* Tests to see if two class objects,
1362
* or their names are equal.
1363
* @param first the first object
1364
* @param second the second object
1365
* @return true if equal, false if not
1366
*/
1367
protected static final boolean classEquals(Class<?> first, Class<?> second) {
1368
return first.equals(second) || first.getName().equals(second.getName());
1369
}
1370
1371
1372
/*
1373
* fields
1374
*/
1375
1376
1377
/**
1378
* all accesses to the {@code protected HashMap children} field
1379
* shall be synchronized on that object.
1380
*/
1381
protected transient HashMap<Object, BCSChild> children;
1382
1383
/**
1384
* Currently serializable children.
1385
*/
1386
private int serializable = 0; // children serializable
1387
1388
/**
1389
* all accesses to the {@code protected ArrayList bcmListeners} field
1390
* shall be synchronized on that object.
1391
*/
1392
protected transient ArrayList<BeanContextMembershipListener> bcmListeners;
1393
1394
//
1395
1396
/**
1397
* The current locale of this BeanContext.
1398
*/
1399
protected Locale locale;
1400
1401
/**
1402
* A {@code boolean} indicating if this
1403
* instance may now render a GUI.
1404
*/
1405
protected boolean okToUseGui;
1406
1407
1408
/**
1409
* A {@code boolean} indicating whether or not
1410
* this object is currently in design time mode.
1411
*/
1412
protected boolean designTime;
1413
1414
/*
1415
* transient
1416
*/
1417
1418
private transient PropertyChangeListener childPCL;
1419
1420
private transient VetoableChangeListener childVCL;
1421
1422
private transient boolean serializing;
1423
}
1424
1425