Commit | Line | Data |
---|---|---|
8c8bf09f | 1 | /******************************************************************************* |
61759503 | 2 | * Copyright (c) 2009, 2012 Ericsson |
6256d8ad | 3 | * |
8c8bf09f ASL |
4 | * All rights reserved. This program and the accompanying materials are |
5 | * made available under the terms of the Eclipse Public License v1.0 which | |
6 | * accompanies this distribution, and is available at | |
7 | * http://www.eclipse.org/legal/epl-v10.html | |
6256d8ad | 8 | * |
8c8bf09f ASL |
9 | * Contributors: |
10 | * Francois Chouinard - Initial API and implementation | |
11 | *******************************************************************************/ | |
12 | ||
6c13869b | 13 | package org.eclipse.linuxtools.tmf.core.signal; |
8c8bf09f ASL |
14 | |
15 | import java.lang.reflect.InvocationTargetException; | |
16 | import java.lang.reflect.Method; | |
17 | import java.util.ArrayList; | |
18 | import java.util.HashMap; | |
19 | import java.util.List; | |
20 | import java.util.Map; | |
21 | ||
8555a0f3 | 22 | import org.eclipse.linuxtools.internal.tmf.core.Activator; |
5500a7f0 | 23 | import org.eclipse.linuxtools.internal.tmf.core.TmfCoreTracer; |
dc299841 | 24 | |
8c8bf09f | 25 | /** |
8d2e2848 FC |
26 | * This class manages the set of signal listeners and the signals they are |
27 | * interested in. When a signal is broadcasted, the appropriate listeners | |
28 | * signal handlers are invoked. | |
6256d8ad | 29 | * |
4b7b3670 FC |
30 | * @version 1.0 |
31 | * @author Francois Chouinard | |
4f8ca6a1 | 32 | */ |
8c8bf09f ASL |
33 | public class TmfSignalManager { |
34 | ||
8d2e2848 FC |
35 | // The set of event listeners and their corresponding handler methods. |
36 | // Note: listeners could be restricted to ITmfComponents but there is no | |
e31e01e8 FC |
37 | // harm in letting anyone use this since it is not tied to anything but |
38 | // the signal data type. | |
8c8bf09f | 39 | static private Map<Object, Method[]> fListeners = new HashMap<Object, Method[]>(); |
d5c13688 | 40 | static private Map<Object, Method[]> fVIPListeners = new HashMap<Object, Method[]>(); |
8c8bf09f | 41 | |
8d2e2848 | 42 | // If requested, add universal signal tracer |
6256d8ad | 43 | // TODO: Temporary solution: should be enabled/disabled dynamically |
8f965dd5 | 44 | private static boolean fTraceIsActive = false; |
8d2e2848 | 45 | private static TmfSignalTracer fSignalTracer; |
82b08e62 FC |
46 | static { |
47 | if (fTraceIsActive) { | |
8d2e2848 | 48 | fSignalTracer = TmfSignalTracer.getInstance(); |
e31e01e8 | 49 | register(fSignalTracer); |
82b08e62 FC |
50 | } |
51 | } | |
8c8bf09f | 52 | |
4f8ca6a1 AM |
53 | /** |
54 | * Register an object to the signal manager. This object can then implement | |
55 | * handler methods, marked with @TmfSignalHandler and with the expected | |
56 | * signal type as parameter. | |
57 | * | |
58 | * @param listener | |
59 | * The object that will be notified of new signals | |
60 | */ | |
61 | public static synchronized void register(Object listener) { | |
62 | Method[] methods = getSignalHandlerMethods(listener); | |
63 | if (methods.length > 0) { | |
64 | fListeners.put(listener, methods); | |
65 | } | |
66 | } | |
8c8bf09f | 67 | |
4f8ca6a1 AM |
68 | /** |
69 | * Register an object to the signal manager as a "VIP" listener. All VIP | |
70 | * listeners will all receive the signal before the manager moves on to the | |
71 | * lowly, non-VIP listeners. | |
72 | * | |
73 | * @param listener | |
74 | * The object that will be notified of new signals | |
75 | */ | |
d5c13688 FC |
76 | public static synchronized void registerVIP(Object listener) { |
77 | Method[] methods = getSignalHandlerMethods(listener); | |
6256d8ad | 78 | if (methods.length > 0) { |
d5c13688 | 79 | fVIPListeners.put(listener, methods); |
6256d8ad | 80 | } |
d5c13688 FC |
81 | } |
82 | ||
4f8ca6a1 AM |
83 | /** |
84 | * De-register a listener object from the signal manager. This means that | |
85 | * its @TmfSignalHandler methods will no longer be called. | |
86 | * | |
87 | * @param listener | |
88 | * The object to de-register | |
89 | */ | |
90 | public static synchronized void deregister(Object listener) { | |
91 | fVIPListeners.remove(listener); | |
d5c13688 | 92 | fListeners.remove(listener); |
4f8ca6a1 | 93 | } |
8c8bf09f ASL |
94 | |
95 | /** | |
8d2e2848 FC |
96 | * Returns the list of signal handlers in the listener. Signal handler name |
97 | * is irrelevant; only the annotation (@TmfSignalHandler) is important. | |
6256d8ad | 98 | * |
8d2e2848 FC |
99 | * @param listener |
100 | * @return | |
101 | */ | |
102 | static private Method[] getSignalHandlerMethods(Object listener) { | |
103 | List<Method> handlers = new ArrayList<Method>(); | |
104 | Method[] methods = listener.getClass().getMethods(); | |
105 | for (Method method : methods) { | |
106 | if (method.isAnnotationPresent(TmfSignalHandler.class)) { | |
107 | handlers.add(method); | |
108 | } | |
109 | } | |
110 | return handlers.toArray(new Method[handlers.size()]); | |
111 | } | |
112 | ||
063f0d27 AM |
113 | static int fSignalId = 0; |
114 | ||
8d2e2848 FC |
115 | /** |
116 | * Invokes the handling methods that listens to signals of a given type. | |
6256d8ad | 117 | * |
8c8bf09f ASL |
118 | * The list of handlers is built on-the-fly to allow for the dynamic |
119 | * creation/deletion of signal handlers. Since the number of signal | |
120 | * handlers shouldn't be too high, this is not a big performance issue | |
121 | * to pay for the flexibility. | |
6256d8ad | 122 | * |
fc6ccf6f | 123 | * For synchronization purposes, the signal is bracketed by two synch signals. |
6256d8ad | 124 | * |
fc6ccf6f | 125 | * @param signal the signal to dispatch |
8c8bf09f | 126 | */ |
8d2e2848 | 127 | static public synchronized void dispatchSignal(TmfSignal signal) { |
1b70b6dc PT |
128 | int signalId = fSignalId++; |
129 | sendSignal(new TmfStartSynchSignal(signalId)); | |
130 | signal.setReference(signalId); | |
fc6ccf6f | 131 | sendSignal(signal); |
1b70b6dc | 132 | sendSignal(new TmfEndSynchSignal(signalId)); |
fc6ccf6f FC |
133 | } |
134 | ||
d5c13688 FC |
135 | static private void sendSignal(TmfSignal signal) { |
136 | sendSignal(fVIPListeners, signal); | |
137 | sendSignal(fListeners, signal); | |
138 | } | |
139 | ||
140 | static private void sendSignal(Map<Object, Method[]> listeners, TmfSignal signal) { | |
141 | ||
5500a7f0 FC |
142 | if (TmfCoreTracer.isSignalTraced()) { |
143 | TmfCoreTracer.traceSignal(signal, "(start)"); //$NON-NLS-1$ | |
6256d8ad | 144 | } |
d5c13688 FC |
145 | |
146 | // Build the list of listener methods that are registered for this signal | |
147 | Class<?> signalClass = signal.getClass(); | |
148 | Map<Object, List<Method>> targets = new HashMap<Object, List<Method>>(); | |
149 | targets.clear(); | |
150 | for (Map.Entry<Object, Method[]> entry : listeners.entrySet()) { | |
151 | List<Method> matchingMethods = new ArrayList<Method>(); | |
152 | for (Method method : entry.getValue()) { | |
153 | if (method.getParameterTypes()[0].isAssignableFrom(signalClass)) { | |
154 | matchingMethods.add(method); | |
155 | } | |
156 | } | |
157 | if (!matchingMethods.isEmpty()) { | |
158 | targets.put(entry.getKey(), matchingMethods); | |
159 | } | |
160 | } | |
161 | ||
6256d8ad | 162 | // Call the signal handlers |
d5c13688 FC |
163 | for (Map.Entry<Object, List<Method>> entry : targets.entrySet()) { |
164 | for (Method method : entry.getValue()) { | |
165 | try { | |
166 | method.invoke(entry.getKey(), new Object[] { signal }); | |
5500a7f0 | 167 | if (TmfCoreTracer.isSignalTraced()) { |
d5c13688 FC |
168 | Object key = entry.getKey(); |
169 | String hash = String.format("%1$08X", entry.getKey().hashCode()); //$NON-NLS-1$ | |
170 | String target = "[" + hash + "] " + key.getClass().getSimpleName() + ":" + method.getName(); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ | |
5500a7f0 | 171 | TmfCoreTracer.traceSignal(signal, target); |
d5c13688 FC |
172 | } |
173 | } catch (IllegalArgumentException e) { | |
5500a7f0 | 174 | Activator.logError("Exception handling signal " + signal + " in method " + method, e); //$NON-NLS-1$ //$NON-NLS-2$ |
d5c13688 | 175 | } catch (IllegalAccessException e) { |
5500a7f0 | 176 | Activator.logError("Exception handling signal " + signal + " in method " + method, e); //$NON-NLS-1$ //$NON-NLS-2$ |
d5c13688 | 177 | } catch (InvocationTargetException e) { |
5500a7f0 | 178 | Activator.logError("Exception handling signal " + signal + " in method " + method, e); //$NON-NLS-1$ //$NON-NLS-2$ |
d5c13688 FC |
179 | } |
180 | } | |
181 | } | |
182 | ||
5500a7f0 FC |
183 | if (TmfCoreTracer.isSignalTraced()) { |
184 | TmfCoreTracer.traceSignal(signal, "(end)"); //$NON-NLS-1$ | |
6256d8ad | 185 | } |
d5c13688 | 186 | } |
dc299841 | 187 | |
dc299841 | 188 | } |