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 }