1 /*******************************************************************************
2 * Copyright (c) 2009, 2010 Ericsson
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
10 * Francois Chouinard - Initial API and implementation
11 *******************************************************************************/
13 package org
.eclipse
.linuxtools
.tmf
.core
.signal
;
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
;
22 import org
.eclipse
.linuxtools
.internal
.tmf
.core
.Activator
;
23 import org
.eclipse
.linuxtools
.internal
.tmf
.core
.Tracer
;
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.
31 * @author Francois Chouinard
33 public class TmfSignalManager
{
35 // The set of event listeners and their corresponding handler methods.
36 // Note: listeners could be restricted to ITmfComponents but there is no
37 // harm in letting anyone use this since it is not tied to anything but
38 // the signal data type.
39 static private Map
<Object
, Method
[]> fListeners
= new HashMap
<Object
, Method
[]>();
40 static private Map
<Object
, Method
[]> fVIPListeners
= new HashMap
<Object
, Method
[]>();
42 // If requested, add universal signal tracer
43 // TODO: Temporary solution: should be enabled/disabled dynamically
44 private static boolean fTraceIsActive
= false;
45 private static TmfSignalTracer fSignalTracer
;
48 fSignalTracer
= TmfSignalTracer
.getInstance();
49 register(fSignalTracer
);
53 public static synchronized void register(Object listener
) {
54 Method
[] methods
= getSignalHandlerMethods(listener
);
55 if (methods
.length
> 0)
56 fListeners
.put(listener
, methods
);
59 public static synchronized void registerVIP(Object listener
) {
60 Method
[] methods
= getSignalHandlerMethods(listener
);
61 if (methods
.length
> 0)
62 fVIPListeners
.put(listener
, methods
);
65 public static synchronized void deregister(Object listener
) {
66 fVIPListeners
.remove(listener
);
67 fListeners
.remove(listener
);
71 * Returns the list of signal handlers in the listener. Signal handler name
72 * is irrelevant; only the annotation (@TmfSignalHandler) is important.
77 static private Method
[] getSignalHandlerMethods(Object listener
) {
78 List
<Method
> handlers
= new ArrayList
<Method
>();
79 Method
[] methods
= listener
.getClass().getMethods();
80 for (Method method
: methods
) {
81 if (method
.isAnnotationPresent(TmfSignalHandler
.class)) {
85 return handlers
.toArray(new Method
[handlers
.size()]);
89 * Invokes the handling methods that listens to signals of a given type.
91 * The list of handlers is built on-the-fly to allow for the dynamic
92 * creation/deletion of signal handlers. Since the number of signal
93 * handlers shouldn't be too high, this is not a big performance issue
94 * to pay for the flexibility.
96 * For synchronization purposes, the signal is bracketed by two synch signals.
98 * @param signal the signal to dispatch
100 static int fSignalId
= 0;
101 static public synchronized void dispatchSignal(TmfSignal signal
) {
102 int signalId
= fSignalId
++;
103 sendSignal(new TmfStartSynchSignal(signalId
));
104 signal
.setReference(signalId
);
106 sendSignal(new TmfEndSynchSignal(signalId
));
109 static private void sendSignal(TmfSignal signal
) {
110 sendSignal(fVIPListeners
, signal
);
111 sendSignal(fListeners
, signal
);
114 static private void sendSignal(Map
<Object
, Method
[]> listeners
, TmfSignal signal
) {
116 if (Tracer
.isSignalTraced()) Tracer
.traceSignal(signal
, "(start)"); //$NON-NLS-1$
118 // Build the list of listener methods that are registered for this signal
119 Class
<?
> signalClass
= signal
.getClass();
120 Map
<Object
, List
<Method
>> targets
= new HashMap
<Object
, List
<Method
>>();
122 for (Map
.Entry
<Object
, Method
[]> entry
: listeners
.entrySet()) {
123 List
<Method
> matchingMethods
= new ArrayList
<Method
>();
124 for (Method method
: entry
.getValue()) {
125 if (method
.getParameterTypes()[0].isAssignableFrom(signalClass
)) {
126 matchingMethods
.add(method
);
129 if (!matchingMethods
.isEmpty()) {
130 targets
.put(entry
.getKey(), matchingMethods
);
134 // Call the signal handlers
135 for (Map
.Entry
<Object
, List
<Method
>> entry
: targets
.entrySet()) {
136 for (Method method
: entry
.getValue()) {
138 method
.invoke(entry
.getKey(), new Object
[] { signal
});
139 if (Tracer
.isSignalTraced()) {
140 Object key
= entry
.getKey();
141 String hash
= String
.format("%1$08X", entry
.getKey().hashCode()); //$NON-NLS-1$
142 String target
= "[" + hash
+ "] " + key
.getClass().getSimpleName() + ":" + method
.getName(); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
143 Tracer
.traceSignal(signal
, target
);
145 } catch (IllegalArgumentException e
) {
146 Activator
.getDefault().logError("Exception handling signal " + signal
+ " in method " + method
, e
); //$NON-NLS-1$ //$NON-NLS-2$
147 } catch (IllegalAccessException e
) {
148 Activator
.getDefault().logError("Exception handling signal " + signal
+ " in method " + method
, e
); //$NON-NLS-1$ //$NON-NLS-2$
149 } catch (InvocationTargetException e
) {
150 Activator
.getDefault().logError("Exception handling signal " + signal
+ " in method " + method
, e
); //$NON-NLS-1$ //$NON-NLS-2$
155 if (Tracer
.isSignalTraced()) Tracer
.traceSignal(signal
, "(end)"); //$NON-NLS-1$