import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* This class manages the set of signal listeners and the signals they are
- * interested in. When a signal is broadcasted, the appropriate listeners
- * signal handlers are invoked.
+ * interested in. When a signal is broadcasted, the appropriate listeners signal
+ * handlers are invoked.
*
* @version 1.0
* @author Francois Chouinard
// the signal data type.
private static Map<Object, Method[]> fListeners = new HashMap<>();
private static Map<Object, Method[]> fVIPListeners = new HashMap<>();
+ private static Map<Object, Throwable> fContexts = new HashMap<>();
// The signal executor for asynchronous signals
private static final ExecutorService fExecutor = Executors.newSingleThreadExecutor();
deregister(listener); // make sure that listener is only registered once
Method[] methods = getSignalHandlerMethods(listener);
if (methods.length > 0) {
+ fContexts.put(listener, new Throwable());
fListeners.put(listener, methods);
}
}
deregister(listener); // make sure that listener is only registered once
Method[] methods = getSignalHandlerMethods(listener);
if (methods.length > 0) {
+ fContexts.put(listener, new Throwable());
fVIPListeners.put(listener, methods);
}
}
public static synchronized void deregister(Object listener) {
fVIPListeners.remove(listener);
fListeners.remove(listener);
+ fContexts.remove(listener);
}
/**
}
/**
- * Invokes the handling methods that listens to signals of a given type
- * in a separate thread which will call
+ * Invokes the handling methods that listens to signals of a given type in a
+ * separate thread which will call
* {@link TmfSignalManager#dispatchSignal(TmfSignal)}.
*
- * If a signal is already processed the signal will be queued and
- * dispatched after the ongoing signal finishes.
+ * If a signal is already processed the signal will be queued and dispatched
+ * after the ongoing signal finishes.
*
* @param signal
* the signal to dispatch
* Disposes the signal manager
*/
public static void dispose() {
+ for (Entry<Object, Throwable> entry : fContexts.entrySet()) {
+ System.err.println(getWarningMessage(entry.getKey()));
+ StackTraceElement[] stackTrace = entry.getValue().getStackTrace();
+ for (StackTraceElement elem : stackTrace) {
+ System.err.println("\t" + elem); //$NON-NLS-1$
+ }
+ }
fExecutor.shutdown();
}
+ private static String getWarningMessage(Object listener) {
+ return "Resource leak: " + listener + " was not deregistered."; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
private static void sendSignal(TmfSignal signal) {
sendSignal(fVIPListeners, signal);
sendSignal(fListeners, signal);
TmfCoreTracer.traceSignal(signal, "(start)"); //$NON-NLS-1$
}
- // Build the list of listener methods that are registered for this signal
+ // Build the list of listener methods that are registered for this
+ // signal
Class<?> signalClass = signal.getClass();
Map<Object, List<Method>> targets = new HashMap<>();
targets.clear();
if (TmfCoreTracer.isSignalTraced()) {
Object key = entry.getKey();
String hash = String.format("%1$08X", entry.getKey().hashCode()); //$NON-NLS-1$
- String target = "[" + hash + "] " + key.getClass().getSimpleName() + ":" + method.getName(); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
+ String target = "[" + hash + "] " + key.getClass().getSimpleName() + ":" + method.getName(); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
TmfCoreTracer.traceSignal(signal, target);
}
} catch (IllegalArgumentException e) {