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