Add logging of exceptions in signal manager.
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.core / src / org / eclipse / linuxtools / tmf / core / 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.core.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.internal.tmf.core.Activator;
23 import org.eclipse.linuxtools.internal.tmf.core.Tracer;
24
25 /**
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.
29 *
30 * @version 1.0
31 * @author Francois Chouinard
32 + */
33 public class TmfSignalManager {
34
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[]>();
41
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;
46 static {
47 if (fTraceIsActive) {
48 fSignalTracer = TmfSignalTracer.getInstance();
49 register(fSignalTracer);
50 }
51 }
52
53 public static synchronized void register(Object listener) {
54 Method[] methods = getSignalHandlerMethods(listener);
55 if (methods.length > 0)
56 fListeners.put(listener, methods);
57 }
58
59 public static synchronized void registerVIP(Object listener) {
60 Method[] methods = getSignalHandlerMethods(listener);
61 if (methods.length > 0)
62 fVIPListeners.put(listener, methods);
63 }
64
65 public static synchronized void deregister(Object listener) {
66 fVIPListeners.remove(listener);
67 fListeners.remove(listener);
68 }
69
70 /**
71 * Returns the list of signal handlers in the listener. Signal handler name
72 * is irrelevant; only the annotation (@TmfSignalHandler) is important.
73 *
74 * @param listener
75 * @return
76 */
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)) {
82 handlers.add(method);
83 }
84 }
85 return handlers.toArray(new Method[handlers.size()]);
86 }
87
88 /**
89 * Invokes the handling methods that listens to signals of a given type.
90 *
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.
95 *
96 * For synchronization purposes, the signal is bracketed by two synch signals.
97 *
98 * @param signal the signal to dispatch
99 */
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);
105 sendSignal(signal);
106 sendSignal(new TmfEndSynchSignal(signalId));
107 }
108
109 static private void sendSignal(TmfSignal signal) {
110 sendSignal(fVIPListeners, signal);
111 sendSignal(fListeners, signal);
112 }
113
114 static private void sendSignal(Map<Object, Method[]> listeners, TmfSignal signal) {
115
116 if (Tracer.isSignalTraced()) Tracer.traceSignal(signal, "(start)"); //$NON-NLS-1$
117
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>>();
121 targets.clear();
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);
127 }
128 }
129 if (!matchingMethods.isEmpty()) {
130 targets.put(entry.getKey(), matchingMethods);
131 }
132 }
133
134 // Call the signal handlers
135 for (Map.Entry<Object, List<Method>> entry : targets.entrySet()) {
136 for (Method method : entry.getValue()) {
137 try {
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);
144 }
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$
151 }
152 }
153 }
154
155 if (Tracer.isSignalTraced()) Tracer.traceSignal(signal, "(end)"); //$NON-NLS-1$
156 }
157
158 }
This page took 0.034985 seconds and 6 git commands to generate.