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