Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/eclipse/osgi/framework/eventmgr/EventManager.java


1   /*******************************************************************************
2    * Copyright (c) 2003, 2004 IBM Corporation and others.
3    * All rights reserved. This program and the accompanying materials 
4    * are made available under the terms of the Common Public License v1.0
5    * which accompanies this distribution, and is available at
6    * http://www.eclipse.org/legal/cpl-v10.html
7    * 
8    * Contributors:
9    *     IBM Corporation - initial API and implementation
10   *******************************************************************************/
11  
12  package org.eclipse.osgi.framework.eventmgr;
13  
14  /**
15   * This class is the central class for the Event Manager. Each
16   * program that wishes to use the Event Manager should construct
17   * an EventManager object and use that object to construct
18   * ListenerQueue for dispatching events. EventListeners objects
19   * should be used to manage listener lists.
20   *
21   * <p>This example uses the ficticous SomeEvent class and shows how to use this package 
22   * to deliver a SomeEvent to a set of SomeEventListeners.  
23   * <pre>
24   *
25   *     // Create an EventManager with a name for an asynchronous event dispatch thread
26   *     EventManager eventManager = new EventManager("SomeEvent Async Event Dispatcher Thread");
27   *     // Create an EventListeners to hold the list of SomeEventListeners
28   *    EventListeners eventListeners = new EventListeners();
29   *
30   *    // Add a SomeEventListener to the listener list
31   *      eventListeners.addListener(someEventListener, null);
32   *
33   *    // Asynchronously deliver a SomeEvent to registered SomeEventListeners
34   *    // Create the listener queue for this event delivery
35   *    ListenerQueue listenerQueue = new ListenerQueue(eventManager);
36   *    // Add the listeners to the queue and associate them with the event dispatcher
37   *    listenerQueue.queueListeners(eventListeners, new EventDispatcher() {
38   *          public void dispatchEvent(Object eventListener, Object listenerObject, 
39   *                                    int eventAction, Object eventObject) {
40   *         try {
41   *          (SomeEventListener)eventListener.someEventOccured((SomeEvent)eventObject);
42   *         } catch (Throwable t) {
43   *           // properly log/handle any Throwable thrown by the listener
44   *         }
45   *      }
46   *    });
47   *    // Deliver the event to the listeners. 
48   *    listenerQueue.dispatchEventAsynchronous(0, new SomeEvent());
49   *    
50   *    // Remove the listener from the listener list
51   *      eventListeners.removeListener(someEventListener);
52   *
53   *    // Close EventManager to clean when done to terminate async event dispatch thread
54   *    eventManager.close();
55   * </pre>
56   * 
57   * <p>At first glance, this package may seem more complicated than necessary
58   * but it has support for some important features. The listener list supports
59   * companion objects for each listener object. This is used by the OSGi framework
60   * to create wrapper objects for a listener which are passed to the event dispatcher.
61   * The ListenerQueue class is used to build a snap shot of the listeners prior to beginning
62   * event dispatch. 
63   * 
64   * The OSGi framework uses a 2 level listener list (EventListeners) for each listener type (4 types). 
65   * Level one is managed by the framework and contains the list of BundleContexts which have 
66   * registered a listener. Level 2 is managed by each BundleContext for the listeners in that 
67   * context. This allows all the listeners of a bundle to be easily and atomically removed from 
68   * the level one list. To use a "flat" list for all bundles would require the list to know which 
69   * bundle registered a listener object so that the list could be traversed when stopping a bundle 
70   * to remove all the bundle's listeners. 
71   * 
72   * When an event is fired, a snapshot list (ListenerQueue) must be made of the current listeners before delivery 
73   * is attempted. The snapshot list is necessary to allow the listener list to be modified while the 
74   * event is being delivered to the snapshot list. The memory cost of the snapshot list is
75   * low since the ListenerQueue object shares the array of listeners with the EventListeners object.
76   * EventListeners uses copy-on-write semantics for managing the array and will copy the array
77   * before changing it IF the array has been shared with a ListenerQueue. This minimizes 
78   * object creation while guaranteeing the snapshot list is never modified once created.
79   * 
80   * The OSGi framework also uses a 2 level dispatch technique (EventDispatcher).
81   * Level one dispatch is used by the framework to add the level 2 listener list of each 
82   * BundleContext to the snapshot in preparation for delivery of the event.
83   * Level 2 dispatch is used as the final event deliverer and must cast the listener 
84   * and event objects to the proper type before calling the listener. Level 2 dispatch
85   * will cancel delivery of an event 
86   * to a bundle that has stopped bewteen the time the snapshot was created and the
87   * attempt was made to deliver the event.
88   * 
89   * <p> The highly dynamic nature of the OSGi framework had necessitated these features for 
90   * proper and efficient event delivery.  
91   */
92  
93  public class EventManager {
94    static final boolean DEBUG = false;
95  
96    /**
97     * EventThread for asynchronous dispatch of events.
98       * Access to this field must be protected by a synchronized region.
99     */
100   private EventThread thread;
101 
102   /**
103    * EventThread Name
104    */
105   protected final String threadName;
106 
107   /**
108    * EventManager constructor. An EventManager object is responsible for
109    * the delivery of events to listeners via an EventDispatcher.
110    *
111    */
112   public EventManager() {
113     this(null);
114   }
115 
116   /**
117    * EventManager constructor. An EventManager object is responsible for
118    * the delivery of events to listeners via an EventDispatcher.
119    *
120    * @param threadName The name to give the event thread associated with
121    * this EventManager.
122    */
123   public EventManager(String threadName) {
124     thread = null;
125     this.threadName = threadName;
126   }
127 
128   /**
129    * This method can be called to release any resources associated with this
130    * EventManager.
131    *
132    */
133   public synchronized void close() {
134     if (thread != null) {
135       thread.close();
136       thread = null;
137     }
138   }
139 
140   /**
141    * Returns the EventThread to use for dispatching events asynchronously for
142    * this EventManager.
143    *
144    * @return EventThread to use for dispatching events asynchronously for
145    * this EventManager.
146    */
147   synchronized EventThread getEventThread() {
148     if (thread == null) {
149       /* if there is no thread, then create a new one */
150       if (threadName == null) {
151         thread = new EventThread();
152       } 
153       else {
154         thread = new EventThread(threadName);
155       }
156       thread.start(); /* start the new thread */
157     }
158 
159     return thread;
160   }
161 
162   /**
163    * This method calls the EventDispatcher object to complete the dispatch of
164    * the event. If there are more elements in the list, call dispatchEvent
165    * on the next item on the list.
166    * This method is package private.
167    *
168    * @param listeners A null terminated array of ListElements with each element containing the primary and 
169    * companion object for a listener. This array must not be modified.
170    * @param dispatcher Call back object which is called to complete the delivery of
171    * the event.
172    * @param eventAction This value was passed by the event source and
173    * is passed to this method. This is passed on to the call back object.
174    * @param eventObject This object was created by the event source and
175    * is passed to this method. This is passed on to the call back object.
176    */
177   static void dispatchEvent(ListElement[] listeners, EventDispatcher dispatcher, int eventAction, Object eventObject) {
178     int size = listeners.length;
179     for (int i = 0; i < size; i++) { /* iterate over the list of listeners */
180       ListElement listener = listeners[i];
181       if (listener == null) {    /* a null element terminates the list */
182         break;
183       }
184       try {
185         /* Call the EventDispatcher to complete the delivery of the event. */
186         dispatcher.dispatchEvent(listener.primary, listener.companion, eventAction, eventObject);
187       } 
188       catch (Throwable t) {
189         /* Consume and ignore any exceptions thrown by the listener */
190         if (DEBUG) {
191           System.out.println("Exception in " + listener.primary); //$NON-NLS-1$
192           t.printStackTrace();
193         }
194       }
195     }
196   }
197 }