Improve internal signal handling
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf / src / org / eclipse / linuxtools / tmf / signal / TmfSignalManager.java
1 /*******************************************************************************
2 * Copyright (c) 2009, 2010 Ericsson
3 *
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
8 *
9 * Contributors:
10 * Francois Chouinard - Initial API and implementation
11 *******************************************************************************/
12
13 package org.eclipse.linuxtools.tmf.signal;
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
22 import org.eclipse.linuxtools.tmf.Tracer;
23
24 /**
25 * <b><u>TmfSignalHandler</u></b>
26 * <p>
27 * This class manages the set of signal listeners and the signals they are
28 * interested in. When a signal is broadcasted, the appropriate listeners
29 * signal handlers are invoked.
30 * <p>
31 */
32 public class TmfSignalManager {
33
34 // The set of event listeners and their corresponding handler methods.
35 // Note: listeners could be restricted to ITmfComponents but there is no
36 // harm in letting anyone use this since it is not tied to anything but
37 // the signal data type.
38 static private Map<Object, Method[]> fListeners = new HashMap<Object, Method[]>();
39
40 // If requested, add universal signal tracer
41 // TODO: Temporary solution: should be enabled/disabled dynamically
42 private static boolean fTraceIsActive = false;
43 private static TmfSignalTracer fSignalTracer;
44 static {
45 if (fTraceIsActive) {
46 fSignalTracer = TmfSignalTracer.getInstance();
47 register(fSignalTracer);
48 }
49 }
50
51 public static synchronized void register(Object listener) {
52 Method[] methods = getSignalHandlerMethods(listener);
53 if (methods.length > 0)
54 fListeners.put(listener, methods);
55 }
56
57 public static synchronized void deregister(Object listener) {
58 fListeners.remove(listener);
59 }
60
61 /**
62 * Returns the list of signal handlers in the listener. Signal handler name
63 * is irrelevant; only the annotation (@TmfSignalHandler) is important.
64 *
65 * @param listener
66 * @return
67 */
68 static private Method[] getSignalHandlerMethods(Object listener) {
69 List<Method> handlers = new ArrayList<Method>();
70 Method[] methods = listener.getClass().getMethods();
71 for (Method method : methods) {
72 if (method.isAnnotationPresent(TmfSignalHandler.class)) {
73 handlers.add(method);
74 }
75 }
76 return handlers.toArray(new Method[handlers.size()]);
77 }
78
79 /**
80 * Invokes the handling methods that listens to signals of a given type.
81 *
82 * The list of handlers is built on-the-fly to allow for the dynamic
83 * creation/deletion of signal handlers. Since the number of signal
84 * handlers shouldn't be too high, this is not a big performance issue
85 * to pay for the flexibility.
86 *
87 * For synchronization purposes, the signal is bracketed by two synch signals.
88 *
89 * @param signal the signal to dispatch
90 */
91 static int fSignalId = 0;
92 static public synchronized void dispatchSignal(TmfSignal signal) {
93 fSignalId++;
94 sendSignal(new TmfStartSynchSignal(fSignalId));
95 signal.setReference(fSignalId);
96 sendSignal(signal);
97 sendSignal(new TmfEndSynchSignal(fSignalId));
98 }
99
100 static private void sendSignal(TmfSignal signal) {
101
102 if (Tracer.isSignalTraced()) Tracer.traceSignal(signal, "(start)"); //$NON-NLS-1$
103
104 // Build the list of listener methods that are registered for this signal
105 Class<?> signalClass = signal.getClass();
106 Map<Object, List<Method>> listeners = new HashMap<Object, List<Method>>();
107 listeners.clear();
108 for (Map.Entry<Object, Method[]> entry : fListeners.entrySet()) {
109 List<Method> matchingMethods = new ArrayList<Method>();
110 for (Method method : entry.getValue()) {
111 if (method.getParameterTypes()[0].isAssignableFrom(signalClass)) {
112 matchingMethods.add(method);
113 }
114 }
115 if (!matchingMethods.isEmpty()) {
116 listeners.put(entry.getKey(), matchingMethods);
117 }
118 }
119
120 // Call the signal handlers
121 for (Map.Entry<Object, List<Method>> entry : listeners.entrySet()) {
122 for (Method method : entry.getValue()) {
123 try {
124 method.invoke(entry.getKey(), new Object[] { signal });
125 if (Tracer.isSignalTraced()) {
126 Object key = entry.getKey();
127 String hash = String.format("%1$08X", entry.getKey().hashCode()); //$NON-NLS-1$
128 String target = "[" + hash + "] " + key.getClass().getSimpleName() + ":" + method.getName(); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
129 Tracer.traceSignal(signal, target);
130 }
131 } catch (IllegalArgumentException e) {
132 // TODO Auto-generated catch block
133 } catch (IllegalAccessException e) {
134 // TODO Auto-generated catch block
135 } catch (InvocationTargetException e) {
136 // TODO Auto-generated catch block
137 }
138 }
139 }
140
141 if (Tracer.isSignalTraced()) Tracer.traceSignal(signal, "(end)"); //$NON-NLS-1$
142 }
143
144 }
This page took 0.034654 seconds and 5 git commands to generate.