001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019 package org.apache.felix.framework.util; 020 021 import java.security.AccessController; 022 import java.security.PrivilegedAction; 023 import java.util.ArrayList; 024 import java.util.Collection; 025 import java.util.Dictionary; 026 import java.util.EventListener; 027 import java.util.EventObject; 028 import java.util.Iterator; 029 import java.util.List; 030 import java.util.NoSuchElementException; 031 032 import org.apache.felix.framework.InvokeHookCallback; 033 import org.apache.felix.framework.Logger; 034 import org.apache.felix.framework.ServiceRegistry; 035 import org.osgi.framework.AllServiceListener; 036 import org.osgi.framework.Bundle; 037 import org.osgi.framework.BundleContext; 038 import org.osgi.framework.BundleEvent; 039 import org.osgi.framework.BundleListener; 040 import org.osgi.framework.Constants; 041 import org.osgi.framework.Filter; 042 import org.osgi.framework.FrameworkEvent; 043 import org.osgi.framework.FrameworkListener; 044 import org.osgi.framework.ServiceEvent; 045 import org.osgi.framework.ServiceListener; 046 import org.osgi.framework.ServicePermission; 047 import org.osgi.framework.ServiceReference; 048 import org.osgi.framework.ServiceRegistration; 049 import org.osgi.framework.SynchronousBundleListener; 050 import org.osgi.framework.hooks.service.EventHook; 051 import org.osgi.framework.hooks.service.ListenerHook; 052 import org.osgi.framework.launch.Framework; 053 054 public class EventDispatcher 055 { 056 static final int LISTENER_BUNDLE_OFFSET = 0; 057 static final int LISTENER_CLASS_OFFSET = 1; 058 static final int LISTENER_OBJECT_OFFSET = 2; 059 static final int LISTENER_FILTER_OFFSET = 3; 060 static final int LISTENER_SECURITY_OFFSET = 4; 061 static final int LISTENER_ARRAY_INCREMENT = 5; 062 063 private Logger m_logger = null; 064 private volatile ServiceRegistry m_serviceRegistry = null; 065 066 // Representation of an empty listener list. 067 private static final Object[] m_emptyList = new Object[0]; 068 069 private Object[] m_frameworkListeners = m_emptyList; 070 private Object[] m_bundleListeners = m_emptyList; 071 private Object[] m_syncBundleListeners = m_emptyList; 072 private Object[] m_serviceListeners = m_emptyList; 073 074 // A single thread is used to deliver events for all dispatchers. 075 private static Thread m_thread = null; 076 private final static String m_threadLock = new String("thread lock"); 077 private static int m_references = 0; 078 private static volatile boolean m_stopping = false; 079 080 // List of requests. 081 private static final ArrayList m_requestList = new ArrayList(); 082 // Pooled requests to avoid memory allocation. 083 private static final ArrayList m_requestPool = new ArrayList(); 084 085 private EventDispatcher(Logger logger) 086 { 087 m_logger = logger; 088 } 089 090 public static EventDispatcher start(Logger logger) 091 { 092 EventDispatcher eventDispatcher = new EventDispatcher(logger); 093 094 synchronized (m_threadLock) 095 { 096 // Start event dispatching thread if necessary. 097 if (m_thread == null || !m_thread.isAlive()) 098 { 099 m_stopping = false; 100 101 m_thread = new Thread(new Runnable() { 102 public void run() 103 { 104 try 105 { 106 EventDispatcher.run(); 107 } 108 finally 109 { 110 // Ensure we update state even if stopped by external cause 111 // e.g. an Applet VM forceably killing threads 112 synchronized (m_threadLock) 113 { 114 m_thread = null; 115 m_stopping = false; 116 m_references = 0; 117 m_threadLock.notifyAll(); 118 } 119 } 120 } 121 }, "FelixDispatchQueue"); 122 m_thread.start(); 123 } 124 125 // reference counting and flags 126 m_references++; 127 } 128 129 return eventDispatcher; 130 } 131 132 public void setServiceRegistry(ServiceRegistry sr) 133 { 134 m_serviceRegistry = sr; 135 } 136 137 public static void shutdown() 138 { 139 synchronized (m_threadLock) 140 { 141 // Return if already dead or stopping. 142 if (m_thread == null || m_stopping) 143 { 144 return; 145 } 146 147 // decrement use counter, don't continue if there are users 148 m_references--; 149 if (m_references > 0) 150 { 151 return; 152 } 153 154 m_stopping = true; 155 } 156 157 // Signal dispatch thread. 158 synchronized (m_requestList) 159 { 160 m_requestList.notify(); 161 } 162 163 // Use separate lock for shutdown to prevent any chance of nested lock deadlock 164 synchronized (m_threadLock) 165 { 166 while (m_thread != null) 167 { 168 try 169 { 170 m_threadLock.wait(); 171 } 172 catch (InterruptedException ex) 173 { 174 } 175 } 176 } 177 } 178 179 public Filter addListener(Bundle bundle, Class clazz, EventListener l, Filter filter) 180 { 181 // Verify the listener. 182 if (l == null) 183 { 184 throw new IllegalArgumentException("Listener is null"); 185 } 186 else if (!clazz.isInstance(l)) 187 { 188 throw new IllegalArgumentException( 189 "Listener not of type " + clazz.getName()); 190 } 191 192 // See if we can simply update the listener, if so then 193 // return immediately. 194 Filter oldFilter = updateListener(bundle, clazz, l, filter); 195 if (oldFilter != null) 196 { 197 return oldFilter; 198 } 199 200 // Lock the object to add the listener. 201 synchronized (this) 202 { 203 Object[] listeners = null; 204 Object acc = null; 205 206 if (clazz == FrameworkListener.class) 207 { 208 listeners = m_frameworkListeners; 209 } 210 else if (clazz == BundleListener.class) 211 { 212 if (SynchronousBundleListener.class.isInstance(l)) 213 { 214 listeners = m_syncBundleListeners; 215 } 216 else 217 { 218 listeners = m_bundleListeners; 219 } 220 } 221 else if (clazz == ServiceListener.class) 222 { 223 // Remember security context for filtering service events. 224 Object sm = System.getSecurityManager(); 225 if (sm != null) 226 { 227 acc = ((SecurityManager) sm).getSecurityContext(); 228 } 229 // We need to create a Set for keeping track of matching service 230 // registrations so we can fire ServiceEvent.MODIFIED_ENDMATCH 231 // events. We need a Set even if filter is null, since the 232 // listener can be updated and have a filter added later. 233 listeners = m_serviceListeners; 234 } 235 else 236 { 237 throw new IllegalArgumentException("Unknown listener: " + l.getClass()); 238 } 239 240 // If we have no listeners, then just add the new listener. 241 if (listeners == m_emptyList) 242 { 243 listeners = new Object[LISTENER_ARRAY_INCREMENT]; 244 listeners[LISTENER_BUNDLE_OFFSET] = bundle; 245 listeners[LISTENER_CLASS_OFFSET] = clazz; 246 listeners[LISTENER_OBJECT_OFFSET] = l; 247 listeners[LISTENER_FILTER_OFFSET] = filter; 248 listeners[LISTENER_SECURITY_OFFSET] = acc; 249 } 250 // Otherwise, we need to do some array copying. 251 // Notice, the old array is always valid, so if 252 // the dispatch thread is in the middle of a dispatch, 253 // then it has a reference to the old listener array 254 // and is not affected by the new value. 255 else 256 { 257 Object[] newList = new Object[listeners.length + LISTENER_ARRAY_INCREMENT]; 258 System.arraycopy(listeners, 0, newList, 0, listeners.length); 259 newList[listeners.length + LISTENER_BUNDLE_OFFSET] = bundle; 260 newList[listeners.length + LISTENER_CLASS_OFFSET] = clazz; 261 newList[listeners.length + LISTENER_OBJECT_OFFSET] = l; 262 newList[listeners.length + LISTENER_FILTER_OFFSET] = filter; 263 newList[listeners.length + LISTENER_SECURITY_OFFSET] = acc; 264 listeners = newList; 265 } 266 267 if (clazz == FrameworkListener.class) 268 { 269 m_frameworkListeners = listeners; 270 } 271 else if (clazz == BundleListener.class) 272 { 273 if (SynchronousBundleListener.class.isInstance(l)) 274 { 275 m_syncBundleListeners = listeners; 276 } 277 else 278 { 279 m_bundleListeners = listeners; 280 } 281 } 282 else if (clazz == ServiceListener.class) 283 { 284 m_serviceListeners = listeners; 285 } 286 } 287 return null; 288 } 289 290 public ListenerHook.ListenerInfo removeListener( 291 Bundle bundle, Class clazz, EventListener l) 292 { 293 ListenerHook.ListenerInfo listenerInfo = null; 294 295 // Verify listener. 296 if (l == null) 297 { 298 throw new IllegalArgumentException("Listener is null"); 299 } 300 else if (!clazz.isInstance(l)) 301 { 302 throw new IllegalArgumentException( 303 "Listener not of type " + clazz.getName()); 304 } 305 306 // Lock the object to remove the listener. 307 synchronized (this) 308 { 309 Object[] listeners = null; 310 311 if (clazz == FrameworkListener.class) 312 { 313 listeners = m_frameworkListeners; 314 } 315 else if (clazz == BundleListener.class) 316 { 317 if (SynchronousBundleListener.class.isInstance(l)) 318 { 319 listeners = m_syncBundleListeners; 320 } 321 else 322 { 323 listeners = m_bundleListeners; 324 } 325 } 326 else if (clazz == ServiceListener.class) 327 { 328 listeners = m_serviceListeners; 329 } 330 else 331 { 332 throw new IllegalArgumentException("Unknown listener: " + l.getClass()); 333 } 334 335 // Try to find the instance in our list. 336 int idx = -1; 337 for (int i = 0; i < listeners.length; i += LISTENER_ARRAY_INCREMENT) 338 { 339 if (listeners[i + LISTENER_BUNDLE_OFFSET].equals(bundle) && 340 (listeners[i + LISTENER_CLASS_OFFSET] == clazz) && 341 (listeners[i + LISTENER_OBJECT_OFFSET] == l)) 342 { 343 // For service listeners, we must return some info about 344 // the listener for the ListenerHook callback. 345 if (ServiceListener.class == clazz) 346 { 347 listenerInfo = wrapListener(listeners, i, true); 348 } 349 idx = i; 350 break; 351 } 352 } 353 354 // If we have the instance, then remove it. 355 if (idx >= 0) 356 { 357 // If this is the last listener, then point to empty list. 358 if ((listeners.length - LISTENER_ARRAY_INCREMENT) == 0) 359 { 360 listeners = m_emptyList; 361 } 362 // Otherwise, we need to do some array copying. 363 // Notice, the old array is always valid, so if 364 // the dispatch thread is in the middle of a dispatch, 365 // then it has a reference to the old listener array 366 // and is not affected by the new value. 367 else 368 { 369 Object[] newList = new Object[listeners.length - LISTENER_ARRAY_INCREMENT]; 370 System.arraycopy(listeners, 0, newList, 0, idx); 371 if (idx < newList.length) 372 { 373 System.arraycopy( 374 listeners, idx + LISTENER_ARRAY_INCREMENT, 375 newList, idx, newList.length - idx); 376 } 377 listeners = newList; 378 } 379 } 380 381 if (clazz == FrameworkListener.class) 382 { 383 m_frameworkListeners = listeners; 384 } 385 else if (clazz == BundleListener.class) 386 { 387 if (SynchronousBundleListener.class.isInstance(l)) 388 { 389 m_syncBundleListeners = listeners; 390 } 391 else 392 { 393 m_bundleListeners = listeners; 394 } 395 } 396 else if (clazz == ServiceListener.class) 397 { 398 m_serviceListeners = listeners; 399 } 400 } 401 402 // Return information about the listener; this is null 403 // for everything but service listeners. 404 return listenerInfo; 405 } 406 407 public void removeListeners(Bundle bundle) 408 { 409 if (bundle == null) 410 { 411 return; 412 } 413 414 synchronized (this) 415 { 416 // Remove all framework listeners associated with the specified bundle. 417 Object[] listeners = m_frameworkListeners; 418 for (int i = listeners.length - LISTENER_ARRAY_INCREMENT; 419 i >= 0; 420 i -= LISTENER_ARRAY_INCREMENT) 421 { 422 // Check if the bundle associated with the current listener 423 // is the same as the specified bundle, if so remove the listener. 424 Bundle registeredBundle = (Bundle) listeners[i + LISTENER_BUNDLE_OFFSET]; 425 if (bundle.equals(registeredBundle)) 426 { 427 Class clazz = (Class) listeners[i + LISTENER_CLASS_OFFSET]; 428 EventListener l = (EventListener) listeners[i + LISTENER_OBJECT_OFFSET]; 429 removeListener(bundle, clazz, l); 430 } 431 } 432 433 // Remove all bundle listeners associated with the specified bundle. 434 listeners = m_bundleListeners; 435 for (int i = listeners.length - LISTENER_ARRAY_INCREMENT; 436 i >= 0; 437 i -= LISTENER_ARRAY_INCREMENT) 438 { 439 // Check if the bundle associated with the current listener 440 // is the same as the specified bundle, if so remove the listener. 441 Bundle registeredBundle = (Bundle) listeners[i + LISTENER_BUNDLE_OFFSET]; 442 if (bundle.equals(registeredBundle)) 443 { 444 Class clazz = (Class) listeners[i + LISTENER_CLASS_OFFSET]; 445 EventListener l = (EventListener) listeners[i + LISTENER_OBJECT_OFFSET]; 446 removeListener(bundle, clazz, l); 447 } 448 } 449 450 // Remove all synchronous bundle listeners associated with 451 // the specified bundle. 452 listeners = m_syncBundleListeners; 453 for (int i = listeners.length - LISTENER_ARRAY_INCREMENT; 454 i >= 0; 455 i -= LISTENER_ARRAY_INCREMENT) 456 { 457 // Check if the bundle associated with the current listener 458 // is the same as the specified bundle, if so remove the listener. 459 Bundle registeredBundle = (Bundle) listeners[i + LISTENER_BUNDLE_OFFSET]; 460 if (bundle.equals(registeredBundle)) 461 { 462 Class clazz = (Class) listeners[i + LISTENER_CLASS_OFFSET]; 463 EventListener l = (EventListener) listeners[i + LISTENER_OBJECT_OFFSET]; 464 removeListener(bundle, clazz, l); 465 } 466 } 467 468 // Remove all service listeners associated with the specified bundle. 469 listeners = m_serviceListeners; 470 for (int i = listeners.length - LISTENER_ARRAY_INCREMENT; 471 i >= 0; 472 i -= LISTENER_ARRAY_INCREMENT) 473 { 474 // Check if the bundle associated with the current listener 475 // is the same as the specified bundle, if so remove the listener. 476 Bundle registeredBundle = (Bundle) listeners[i + LISTENER_BUNDLE_OFFSET]; 477 if (bundle.equals(registeredBundle)) 478 { 479 Class clazz = (Class) listeners[i + LISTENER_CLASS_OFFSET]; 480 EventListener l = (EventListener) listeners[i + LISTENER_OBJECT_OFFSET]; 481 removeListener(bundle, clazz, l); 482 } 483 } 484 } 485 } 486 487 public Filter updateListener(Bundle bundle, Class clazz, EventListener l, Filter filter) 488 { 489 synchronized (this) 490 { 491 Object[] listeners = null; 492 493 if (clazz == FrameworkListener.class) 494 { 495 listeners = m_frameworkListeners; 496 } 497 else if (clazz == BundleListener.class) 498 { 499 if (SynchronousBundleListener.class.isInstance(l)) 500 { 501 listeners = m_syncBundleListeners; 502 } 503 else 504 { 505 listeners = m_bundleListeners; 506 } 507 } 508 else if (clazz == ServiceListener.class) 509 { 510 listeners = m_serviceListeners; 511 } 512 513 // See if the listener is already registered, if so then 514 // handle it according to the spec. 515 for (int i = 0; i < listeners.length; i += LISTENER_ARRAY_INCREMENT) 516 { 517 if (listeners[i + LISTENER_BUNDLE_OFFSET].equals(bundle) && 518 (listeners[i + LISTENER_CLASS_OFFSET] == clazz) && 519 (listeners[i + LISTENER_OBJECT_OFFSET] == l)) 520 { 521 Filter oldFilter = null; 522 if (clazz == FrameworkListener.class) 523 { 524 // The spec says to ignore this case. 525 } 526 else if (clazz == BundleListener.class) 527 { 528 // The spec says to ignore this case. 529 } 530 else if (clazz == ServiceListener.class) 531 { 532 // The spec says to update the filter in this case. 533 oldFilter = (Filter) listeners[i + LISTENER_FILTER_OFFSET]; 534 listeners[i + LISTENER_FILTER_OFFSET] = filter; 535 } 536 return oldFilter; 537 } 538 } 539 } 540 541 return null; 542 } 543 544 /** 545 * Returns all existing service listener information into a collection of 546 * ListenerHook.ListenerInfo objects. This is used the first time a listener 547 * hook is registered to synchronize it with the existing set of listeners. 548 * @return Returns all existing service listener information into a collection of 549 * ListenerHook.ListenerInfo objects 550 **/ 551 public Collection /* <? extends ListenerHook.ListenerInfo> */ wrapAllServiceListeners(boolean removed) 552 { 553 Object[] listeners = null; 554 synchronized (this) 555 { 556 listeners = m_serviceListeners; 557 } 558 559 List existingListeners = new ArrayList(); 560 for (int i = 0, j = 0; i < listeners.length; i += LISTENER_ARRAY_INCREMENT, j++) 561 { 562 existingListeners.add(wrapListener(listeners, i, removed)); 563 } 564 return existingListeners; 565 } 566 567 /** 568 * Wraps the information about a given listener in a ListenerHook.ListenerInfo 569 * object. 570 * @param listeners The array of listeners. 571 * @param offset The offset into the array of the listener to wrap. 572 * @return A ListenerHook.ListenerInfo object for the specified listener. 573 */ 574 private static ListenerHook.ListenerInfo wrapListener(Object[] listeners, int offset, boolean removed) 575 { 576 Filter filter = ((Filter)listeners[offset + LISTENER_FILTER_OFFSET]); 577 578 return new ListenerHookInfoImpl( 579 ((Bundle)listeners[offset + LISTENER_BUNDLE_OFFSET]).getBundleContext(), 580 (ServiceListener) listeners[offset + LISTENER_OBJECT_OFFSET], 581 filter == null ? null : filter.toString(), 582 removed); 583 } 584 585 public void fireFrameworkEvent(FrameworkEvent event) 586 { 587 // Take a snapshot of the listener array. 588 Object[] listeners = null; 589 synchronized (this) 590 { 591 listeners = m_frameworkListeners; 592 } 593 594 // Fire all framework listeners on a separate thread. 595 fireEventAsynchronously(m_logger, Request.FRAMEWORK_EVENT, listeners, event); 596 } 597 598 public void fireBundleEvent(BundleEvent event) 599 { 600 // Take a snapshot of the listener array. 601 Object[] listeners = null; 602 Object[] syncListeners = null; 603 synchronized (this) 604 { 605 listeners = m_bundleListeners; 606 syncListeners = m_syncBundleListeners; 607 } 608 609 // Fire synchronous bundle listeners immediately on the calling thread. 610 fireEventImmediately( 611 m_logger, Request.BUNDLE_EVENT, syncListeners, event, null); 612 613 // The spec says that asynchronous bundle listeners do not get events 614 // of types STARTING, STOPPING, or LAZY_ACTIVATION. 615 if ((event.getType() != BundleEvent.STARTING) && 616 (event.getType() != BundleEvent.STOPPING) && 617 (event.getType() != BundleEvent.LAZY_ACTIVATION)) 618 { 619 // Fire asynchronous bundle listeners on a separate thread. 620 fireEventAsynchronously(m_logger, Request.BUNDLE_EVENT, listeners, event); 621 } 622 } 623 624 public void fireServiceEvent( 625 final ServiceEvent event, final Dictionary oldProps, final Framework felix) 626 { 627 // Take a snapshot of the listener array. 628 Object[] listeners = null; 629 synchronized (this) 630 { 631 listeners = m_serviceListeners; 632 } 633 634 if (m_serviceRegistry != null) 635 { 636 List eventHooks = m_serviceRegistry.getEventHooks(); 637 if ((eventHooks != null) && (eventHooks.size() > 0)) 638 { 639 final ListenerBundleContextCollectionWrapper wrapper = 640 new ListenerBundleContextCollectionWrapper(listeners); 641 InvokeHookCallback callback = new InvokeHookCallback() 642 { 643 public void invokeHook(Object hook) 644 { 645 ((EventHook) hook).event(event, wrapper); 646 } 647 }; 648 for (int i = 0; i < eventHooks.size(); i++) 649 { 650 if (felix != null) 651 { 652 m_serviceRegistry.invokeHook( 653 (ServiceReference) eventHooks.get(i), felix, callback); 654 } 655 } 656 657 listeners = wrapper.getListeners(); 658 } 659 } 660 661 // Fire all service events immediately on the calling thread. 662 fireEventImmediately( 663 m_logger, Request.SERVICE_EVENT, listeners, event, oldProps); 664 } 665 666 private void fireEventAsynchronously( 667 Logger logger, int type, Object[] listeners, EventObject event) 668 { 669 //TODO: should possibly check this within thread lock, seems to be ok though without 670 // If dispatch thread is stopped, then ignore dispatch request. 671 if (m_stopping || m_thread == null) 672 { 673 return; 674 } 675 676 // First get a request from the pool or create one if necessary. 677 Request req = null; 678 synchronized (m_requestPool) 679 { 680 if (m_requestPool.size() > 0) 681 { 682 req = (Request) m_requestPool.remove(0); 683 } 684 else 685 { 686 req = new Request(); 687 } 688 } 689 690 // Initialize dispatch request. 691 req.m_logger = logger; 692 req.m_type = type; 693 req.m_listeners = listeners; 694 req.m_event = event; 695 696 // Lock the request list. 697 synchronized (m_requestList) 698 { 699 // Add our request to the list. 700 m_requestList.add(req); 701 // Notify the dispatch thread that there is work to do. 702 m_requestList.notify(); 703 } 704 } 705 706 private static void fireEventImmediately( 707 Logger logger, int type, Object[] listeners, EventObject event, Dictionary oldProps) 708 { 709 if (listeners.length > 0) 710 { 711 // Notify appropriate listeners. 712 for (int i = listeners.length - LISTENER_ARRAY_INCREMENT; 713 i >= 0; 714 i -= LISTENER_ARRAY_INCREMENT) 715 { 716 Bundle bundle = (Bundle) listeners[i + LISTENER_BUNDLE_OFFSET]; 717 EventListener l = (EventListener) listeners[i + LISTENER_OBJECT_OFFSET]; 718 Filter filter = (Filter) listeners[i + LISTENER_FILTER_OFFSET]; 719 Object acc = listeners[i + LISTENER_SECURITY_OFFSET]; 720 try 721 { 722 if (type == Request.FRAMEWORK_EVENT) 723 { 724 invokeFrameworkListenerCallback(bundle, l, event); 725 } 726 else if (type == Request.BUNDLE_EVENT) 727 { 728 invokeBundleListenerCallback(bundle, l, event); 729 } 730 else if (type == Request.SERVICE_EVENT) 731 { 732 invokeServiceListenerCallback( 733 bundle, l, filter, acc, event, oldProps); 734 } 735 } 736 catch (Throwable th) 737 { 738 logger.log( 739 Logger.LOG_ERROR, 740 "EventDispatcher: Error during dispatch.", th); 741 } 742 } 743 } 744 } 745 746 private static void invokeFrameworkListenerCallback( 747 Bundle bundle, final EventListener l, final EventObject event) 748 { 749 // The spec says only active bundles receive asynchronous events, 750 // but we will include starting bundles too otherwise 751 // it is impossible to see everything. 752 if ((bundle.getState() == Bundle.STARTING) || 753 (bundle.getState() == Bundle.ACTIVE)) 754 { 755 if (System.getSecurityManager() != null) 756 { 757 AccessController.doPrivileged(new PrivilegedAction() { 758 public Object run() 759 { 760 ((FrameworkListener) l).frameworkEvent((FrameworkEvent) event); 761 return null; 762 } 763 }); 764 } 765 else 766 { 767 ((FrameworkListener) l).frameworkEvent((FrameworkEvent) event); 768 } 769 } 770 } 771 772 private static void invokeBundleListenerCallback( 773 Bundle bundle, final EventListener l, final EventObject event) 774 { 775 // A bundle listener is either synchronous or asynchronous. 776 // If the bundle listener is synchronous, then deliver the 777 // event to bundles with a state of STARTING, STOPPING, or 778 // ACTIVE. If the listener is asynchronous, then deliver the 779 // event only to bundles that are STARTING or ACTIVE. 780 if (((SynchronousBundleListener.class.isAssignableFrom(l.getClass())) && 781 ((bundle.getState() == Bundle.STARTING) || 782 (bundle.getState() == Bundle.STOPPING) || 783 (bundle.getState() == Bundle.ACTIVE))) 784 || 785 ((bundle.getState() == Bundle.STARTING) || 786 (bundle.getState() == Bundle.ACTIVE))) 787 { 788 if (System.getSecurityManager() != null) 789 { 790 AccessController.doPrivileged(new PrivilegedAction() { 791 public Object run() 792 { 793 ((BundleListener) l).bundleChanged((BundleEvent) event); 794 return null; 795 } 796 }); 797 } 798 else 799 { 800 ((BundleListener) l).bundleChanged((BundleEvent) event); 801 } 802 } 803 } 804 805 private static void invokeServiceListenerCallback( 806 Bundle bundle, final EventListener l, Filter filter, Object acc, 807 final EventObject event, final Dictionary oldProps) 808 { 809 // Service events should be delivered to STARTING, 810 // STOPPING, and ACTIVE bundles. 811 if ((bundle.getState() != Bundle.STARTING) && 812 (bundle.getState() != Bundle.STOPPING) && 813 (bundle.getState() != Bundle.ACTIVE)) 814 { 815 return; 816 } 817 818 // Check that the bundle has permission to get at least 819 // one of the service interfaces; the objectClass property 820 // of the service stores its service interfaces. 821 ServiceReference ref = ((ServiceEvent) event).getServiceReference(); 822 823 boolean hasPermission = true; 824 Object sm = System.getSecurityManager(); 825 if ((acc != null) && (sm != null)) 826 { 827 try 828 { 829 ServicePermission perm = 830 new ServicePermission( 831 ref, ServicePermission.GET); 832 ((SecurityManager) sm).checkPermission(perm, acc); 833 } 834 catch (Exception ex) 835 { 836 hasPermission = false; 837 } 838 } 839 840 if (hasPermission) 841 { 842 // Dispatch according to the filter. 843 boolean matched = (filter == null) 844 || filter.match(((ServiceEvent) event).getServiceReference()); 845 846 if (matched) 847 { 848 if ((l instanceof AllServiceListener) || 849 Util.isServiceAssignable(bundle, ((ServiceEvent) event).getServiceReference())) 850 { 851 if (System.getSecurityManager() != null) 852 { 853 AccessController.doPrivileged(new PrivilegedAction() 854 { 855 public Object run() 856 { 857 ((ServiceListener) l).serviceChanged((ServiceEvent) event); 858 return null; 859 } 860 }); 861 } 862 else 863 { 864 ((ServiceListener) l).serviceChanged((ServiceEvent) event); 865 } 866 } 867 } 868 // We need to send an MODIFIED_ENDMATCH event if the listener 869 // matched previously. 870 else if (((ServiceEvent) event).getType() == ServiceEvent.MODIFIED) 871 { 872 if (filter.match(oldProps)) 873 { 874 final ServiceEvent se = new ServiceEvent( 875 ServiceEvent.MODIFIED_ENDMATCH, 876 ((ServiceEvent) event).getServiceReference()); 877 if (System.getSecurityManager() != null) 878 { 879 AccessController.doPrivileged(new PrivilegedAction() 880 { 881 public Object run() 882 { 883 ((ServiceListener) l).serviceChanged(se); 884 return null; 885 } 886 }); 887 } 888 else 889 { 890 ((ServiceListener) l).serviceChanged(se); 891 } 892 } 893 } 894 } 895 } 896 897 /** 898 * This is the dispatching thread's main loop. 899 **/ 900 private static void run() 901 { 902 Request req = null; 903 while (true) 904 { 905 // Lock the request list so we can try to get a 906 // dispatch request from it. 907 synchronized (m_requestList) 908 { 909 // Wait while there are no requests to dispatch. If the 910 // dispatcher thread is supposed to stop, then let the 911 // dispatcher thread exit the loop and stop. 912 while ((m_requestList.size() == 0) && !m_stopping) 913 { 914 // Wait until some signals us for work. 915 try 916 { 917 m_requestList.wait(); 918 } 919 catch (InterruptedException ex) 920 { 921 // Not much we can do here except for keep waiting. 922 } 923 } 924 925 // If there are no events to dispatch and shutdown 926 // has been called then exit, otherwise dispatch event. 927 if ((m_requestList.size() == 0) && (m_stopping)) 928 { 929 return; 930 } 931 932 // Get the dispatch request. 933 req = (Request) m_requestList.remove(0); 934 } 935 936 // Deliver event outside of synchronized block 937 // so that we don't block other requests from being 938 // queued during event processing. 939 // NOTE: We don't catch any exceptions here, because 940 // the invoked method shields us from exceptions by 941 // catching Throwables when it invokes callbacks. 942 fireEventImmediately(req.m_logger, req.m_type, req.m_listeners, req.m_event, null); 943 944 // Put dispatch request in cache. 945 synchronized (m_requestPool) 946 { 947 req.m_logger = null; 948 req.m_type = -1; 949 req.m_listeners = null; 950 req.m_event = null; 951 m_requestPool.add(req); 952 } 953 } 954 } 955 956 static class ListenerBundleContextCollectionWrapper implements Collection 957 { 958 private Object[] m_listeners; 959 960 ListenerBundleContextCollectionWrapper(Object [] listeners) 961 { 962 m_listeners = listeners; 963 } 964 965 Object [] getListeners() 966 { 967 return m_listeners; 968 } 969 970 public boolean add(Object o) 971 { 972 throw new UnsupportedOperationException(); 973 } 974 975 public boolean addAll(Collection c) 976 { 977 throw new UnsupportedOperationException(); 978 } 979 980 public void clear() 981 { 982 m_listeners = new Object[0]; 983 } 984 985 public boolean contains(Object o) 986 { 987 return indexOf(o) >= 0; 988 } 989 990 public boolean containsAll(Collection c) 991 { 992 for (Iterator it = c.iterator(); it.hasNext(); ) 993 { 994 if (!contains(it.next())) 995 { 996 return false; 997 } 998 } 999 return true; 1000 } 1001 1002 private int indexOf(Object o) 1003 { 1004 if (!(o instanceof BundleContext)) 1005 { 1006 return -1; 1007 } 1008 1009 for (int i = m_listeners.length - LISTENER_ARRAY_INCREMENT; 1010 i >= 0; 1011 i -= LISTENER_ARRAY_INCREMENT) 1012 { 1013 Bundle bundle = (Bundle) m_listeners[i + LISTENER_BUNDLE_OFFSET]; 1014 if (bundle != null) 1015 { 1016 if (bundle.getBundleContext().equals(o)) 1017 { 1018 return i; 1019 } 1020 } 1021 } 1022 return -1; 1023 } 1024 1025 public boolean isEmpty() 1026 { 1027 return m_listeners.length == 0; 1028 } 1029 1030 public Iterator iterator() 1031 { 1032 return new WrapperIterator(); 1033 } 1034 1035 public boolean remove(Object o) 1036 { 1037 return removeIndex(indexOf(o)); 1038 } 1039 1040 private boolean removeIndex(int idx) 1041 { 1042 if (idx < 0) 1043 { 1044 return false; 1045 } 1046 1047 Object [] newListeners = new Object[m_listeners.length - LISTENER_ARRAY_INCREMENT]; 1048 System.arraycopy(m_listeners, 0, newListeners, 0, idx); 1049 System.arraycopy(m_listeners, idx + LISTENER_ARRAY_INCREMENT, 1050 newListeners, idx, newListeners.length - idx); 1051 m_listeners = newListeners; 1052 1053 return true; 1054 } 1055 1056 public boolean removeAll(Collection c) 1057 { 1058 boolean rv = false; 1059 1060 for (Iterator it = c.iterator(); it.hasNext(); ) 1061 { 1062 if (remove(it.next())) 1063 { 1064 rv = true; 1065 } 1066 } 1067 1068 return rv; 1069 } 1070 1071 public boolean retainAll(Collection c) 1072 { 1073 boolean rv = false; 1074 1075 for (Iterator it = iterator(); it.hasNext(); ) 1076 { 1077 if (!(c.contains(it.next()))) 1078 { 1079 it.remove(); 1080 rv = true; 1081 } 1082 } 1083 1084 return rv; 1085 } 1086 1087 public int size() 1088 { 1089 return m_listeners.length / LISTENER_ARRAY_INCREMENT; 1090 } 1091 1092 public Object[] toArray() 1093 { 1094 Object [] array = new Object[size()]; 1095 int idx = 0; 1096 for (Iterator it = iterator(); it.hasNext(); ) 1097 { 1098 array[idx++] = it.next(); 1099 } 1100 return array; 1101 } 1102 1103 public Object[] toArray(Object[] a) 1104 { 1105 if (!(a.getClass().equals(Object[].class))) 1106 { 1107 throw new ArrayStoreException(); 1108 } 1109 return toArray(); 1110 } 1111 1112 private class WrapperIterator implements Iterator 1113 { 1114 int curIdx = 0; 1115 int lastIdx = -1; 1116 1117 private WrapperIterator() {} 1118 1119 public boolean hasNext() 1120 { 1121 return curIdx < m_listeners.length; 1122 } 1123 1124 public Object next() 1125 { 1126 if (!hasNext()) 1127 { 1128 throw new NoSuchElementException(); 1129 } 1130 1131 Bundle b = (Bundle) m_listeners[curIdx + LISTENER_BUNDLE_OFFSET]; 1132 lastIdx = curIdx; 1133 curIdx += LISTENER_ARRAY_INCREMENT; 1134 return b.getBundleContext(); 1135 } 1136 1137 public void remove() 1138 { 1139 if (lastIdx < 0) 1140 { 1141 throw new IllegalStateException(); 1142 } 1143 removeIndex(lastIdx); 1144 1145 curIdx = lastIdx; 1146 lastIdx = -1; 1147 } 1148 } 1149 } 1150 1151 private static class Request 1152 { 1153 public static final int FRAMEWORK_EVENT = 0; 1154 public static final int BUNDLE_EVENT = 1; 1155 public static final int SERVICE_EVENT = 2; 1156 1157 public Logger m_logger = null; 1158 public int m_type = -1; 1159 public Object[] m_listeners = null; 1160 public EventObject m_event = null; 1161 } 1162 }