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 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 services = new HashMap<>(serializable + 1); 133 bcsListeners = new ArrayList<>(1); 134 } 135 136 /** 137 * Gets the <tt>BeanContextServices</tt> associated with this 138 * <tt>BeanContextServicesSupport</tt>. 139 * 140 * @return the instance of <tt>BeanContext</tt> 141 * this object is providing the implementation for. 142 */ 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 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 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 195 void removeRequestor(Object requestor) { 196 requestors.remove(requestor); 197 } 198 199 // check a requestors listener 200 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 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 233 Iterator<Map.Entry<Object, BeanContextServiceRevokedListener>> cloneOfEntries() { 234 return ((HashMap<Object, BeanContextServiceRevokedListener>)requestors.clone()).entrySet().iterator(); 235 } 236 237 Iterator<Map.Entry<Object, BeanContextServiceRevokedListener>> entries() { 238 return requestors.entrySet().iterator(); 239 } 240 241 boolean isEmpty() { return requestors.isEmpty(); } 242 243 Class<?> getServiceClass() { return serviceClass; } 244 245 BeanContextServiceProvider getServiceProvider() { 246 return serviceProvider; 247 } 248 249 BeanContextServiceProvider getDelegateProvider() { 250 return delegateProvider; 251 } 252 253 boolean isDelegated() { return delegateProvider != null; } 254 255 void addRef(boolean delegated) { 256 if (delegated) { 257 delegateRefs++; 258 } else { 259 serviceRefs++; 260 } 261 } 262 263 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 276 int getRefs() { return serviceRefs + delegateRefs; } 277 278 int getDelegateRefs() { return delegateRefs; } 279 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 { 302 BCSSCServiceRef(BCSSCServiceClassRef scref, boolean isDelegated) { 303 serviceClassRef = scref; 304 delegated = isDelegated; 305 } 306 307 void addRef() { refCnt++; } 308 int release() { return --refCnt; } 309 310 BCSSCServiceClassRef getServiceClassRef() { return serviceClassRef; } 311 312 boolean isDelegated() { return delegated; } 313 314 /* 315 * fields 316 */ 317 318 BCSSCServiceClassRef serviceClassRef; 319 int refCnt = 1; 320 boolean delegated = false; 321 } 322 323 BCSSChild(Object bcc, Object peer) { super(bcc, peer); } 324 325 // note usage of service per requestor, per service 326 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 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 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 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 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 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 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 */ 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 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 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 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 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 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 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 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 790 BCSSProxyServiceProvider(BeanContextServices bcs) { 791 super(); 792 793 nestingCtxt = bcs; 794 } 795 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 808 public void releaseService(BeanContextServices bcs, Object requestor, Object service) { 809 nestingCtxt.releaseService(bcs, requestor, service); 810 } 811 812 public Iterator<?> getCurrentServiceSelectors(BeanContextServices bcs, Class<?> serviceClass) { 813 return nestingCtxt.getCurrentServiceSelectors(serviceClass); 814 } 815 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 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 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 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 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 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 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 <tt>BeanContextServicesListener</tt> (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 */ 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 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 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 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 <tt>BeanContextServiceEvent</tt> notifying of a new service. 1088 * @param serviceClass the service class 1089 */ 1090 protected final void fireServiceAdded(Class<?> serviceClass) { 1091 BeanContextServiceAvailableEvent bcssae = new BeanContextServiceAvailableEvent(getBeanContextServicesPeer(), serviceClass); 1092 1093 fireServiceAdded(bcssae); 1094 } 1095 1096 /** 1097 * Fires a <tt>BeanContextServiceAvailableEvent</tt> indicating that a new 1098 * service has become available. 1099 * 1100 * @param bcssae the <tt>BeanContextServiceAvailableEvent</tt> 1101 */ 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 <tt>BeanContextServiceEvent</tt> notifying of a service being revoked. 1114 * 1115 * @param bcsre the <tt>BeanContextServiceRevokedEvent</tt> 1116 */ 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 <tt>BeanContextServiceRevokedEvent</tt> 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 */ 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 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 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 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 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 </code> 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 <tt>BeanContextServceProvider</tt>. 1245 */ 1246 protected transient int serializable = 0; 1247 1248 1249 /** 1250 * Delegate for the <tt>BeanContextServiceProvider</tt>. 1251 */ 1252 protected transient BCSSProxyServiceProvider proxy; 1253 1254 1255 /** 1256 * List of <tt>BeanContextServicesListener</tt> objects. 1257 */ 1258 protected transient ArrayList<BeanContextServicesListener> bcsListeners; 1259 }