Commit | Line | Data |
---|---|---|
8c8bf09f ASL |
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 | /** | |
23 | * <b><u>TmfSignalHandler</u></b> | |
24 | * <p> | |
25 | * This class manages the set of signal listeners and the signals they are | |
26 | * interested in. When a signal is broadcasted, the appropriate listeners | |
27 | * signal handlers are invoked. | |
28 | * <p> | |
29 | */ | |
30 | public class TmfSignalManager { | |
31 | ||
32 | // The set of event listeners and their corresponding handler methods. | |
33 | // Note: listeners could be restricted to ITmfComponents but there is no | |
34 | // harm in letting anyone use this since it is not tied to anything but | |
35 | // the signal data type. | |
36 | static private Map<Object, Method[]> fListeners = new HashMap<Object, Method[]>(); | |
37 | ||
38 | // If requested, add universal signal tracer | |
39 | // TODO: Temporary solution: should be enabled/disabled dynamically | |
40 | private static boolean fTraceIsActive = false; | |
41 | private static TmfSignalTracer fSignalTracer; | |
42 | static { | |
43 | if (fTraceIsActive) { | |
44 | fSignalTracer = TmfSignalTracer.getInstance(); | |
45 | register(fSignalTracer); | |
46 | } | |
47 | } | |
48 | ||
49 | public static synchronized void register(Object listener) { | |
50 | Method[] methods = getSignalHandlerMethods(listener); | |
51 | if (methods.length > 0) | |
52 | fListeners.put(listener, methods); | |
53 | } | |
54 | ||
55 | public static synchronized void deregister(Object listener) { | |
56 | fListeners.remove(listener); | |
57 | } | |
58 | ||
59 | /** | |
60 | * Returns the list of signal handlers in the listener. Signal handler name | |
61 | * is irrelevant; only the annotation (@TmfSignalHandler) is important. | |
62 | * | |
63 | * @param listener | |
64 | * @return | |
65 | */ | |
66 | static private Method[] getSignalHandlerMethods(Object listener) { | |
67 | List<Method> handlers = new ArrayList<Method>(); | |
68 | Method[] methods = listener.getClass().getMethods(); | |
69 | for (Method method : methods) { | |
70 | if (method.isAnnotationPresent(TmfSignalHandler.class)) { | |
71 | handlers.add(method); | |
72 | } | |
73 | } | |
74 | return handlers.toArray(new Method[handlers.size()]); | |
75 | } | |
76 | ||
77 | /** | |
78 | * Invokes the handling methods that listens to signals of a given type. | |
79 | * | |
80 | * The list of handlers is built on-the-fly to allow for the dynamic | |
81 | * creation/deletion of signal handlers. Since the number of signal | |
82 | * handlers shouldn't be too high, this is not a big performance issue | |
83 | * to pay for the flexibility. | |
84 | * | |
85 | * For synchronization purposes, the signal is bracketed by two synch signals. | |
86 | * | |
87 | * @param signal the signal to dispatch | |
88 | */ | |
89 | static int fSynchId = 0; | |
90 | static public synchronized void dispatchSignal(TmfSignal signal) { | |
91 | fSynchId++; | |
92 | sendSignal(new TmfStartSynchSignal(fSynchId)); | |
93 | signal.setReference(fSynchId); | |
94 | sendSignal(signal); | |
95 | sendSignal(new TmfEndSynchSignal(fSynchId)); | |
96 | } | |
97 | ||
98 | static private void sendSignal(TmfSignal signal) { | |
99 | ||
100 | // Build the list of listener methods that are registered for this signal | |
101 | Class<?> signalClass = signal.getClass(); | |
102 | Map<Object, List<Method>> listeners = new HashMap<Object, List<Method>>(); | |
103 | listeners.clear(); | |
104 | for (Map.Entry<Object, Method[]> entry : fListeners.entrySet()) { | |
105 | List<Method> matchingMethods = new ArrayList<Method>(); | |
106 | for (Method method : entry.getValue()) { | |
107 | if (method.getParameterTypes()[0].isAssignableFrom(signalClass)) { | |
108 | matchingMethods.add(method); | |
109 | } | |
110 | } | |
111 | if (!matchingMethods.isEmpty()) { | |
112 | listeners.put(entry.getKey(), matchingMethods); | |
113 | } | |
114 | } | |
115 | ||
116 | // Call the signal handlers | |
117 | for (Map.Entry<Object, List<Method>> entry : listeners.entrySet()) { | |
118 | for (Method method : entry.getValue()) { | |
119 | try { | |
120 | method.invoke(entry.getKey(), new Object[] { signal }); | |
121 | } catch (IllegalArgumentException e) { | |
122 | // TODO Auto-generated catch block | |
123 | } catch (IllegalAccessException e) { | |
124 | // TODO Auto-generated catch block | |
125 | } catch (InvocationTargetException e) { | |
126 | // TODO Auto-generated catch block | |
127 | } | |
128 | } | |
129 | } | |
130 | } | |
131 | ||
132 | } |