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