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