/******************************************************************************* * Copyright (c) 2013, 2014 Ericsson * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v1.0 which * accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Alexandre Montplaisir - Initial API and implementation *******************************************************************************/ package org.eclipse.tracecompass.tmf.core.signal; import java.util.Timer; import java.util.TimerTask; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.tracecompass.tmf.core.component.ITmfComponent; /** * "Buffer" between a TmfComponent and the signal manager. You can use this if * you want to throttle the amount of signals your component will send. * * It works by specifying a delay, then calling {@link #queue}. The signals will * only be really sent if no other call to {@link #queue} happens within $delay * milliseconds afterwards. This guarantees that only the *last* signal is * actually broadcasted. * * Note that this class does not discriminate for signal types, sources, or * whatever. If you want to throttle different signals in different ways, you * can use multiple signal throttlers in your component and call them * accordingly. * * @author Alexandre Montplaisir */ @NonNullByDefault public class TmfSignalThrottler { private final @Nullable ITmfComponent fComponent; private final long fDelay; private final Timer fTimer; private TimerTask fCurrentTask; /** * Constructor * * @param component * The optional source component of the signals. If non-null, its * {@link ITmfComponent#broadcast} method will be used to finally * send the signal. If null, the generic * {@link TmfSignalManager#dispatchSignal} is used. * @param delay * Time to wait before actually sending signals (in ms) */ public TmfSignalThrottler(@Nullable ITmfComponent component, long delay) { this.fComponent = component; this.fDelay = delay; this.fTimer = new Timer(); /* * Initialize currentTask to something, so we don't have to do a null * check every time. */ fCurrentTask = new TimerTask() { @Override public void run() { } }; } /** * Queue a signal for sending. It will only be forward to the centralized * signal handler if 'delay' elapses without another signal being sent * through this method. * * You call this instead of {@link ITmfComponent#broadcast} or * {@link TmfSignalManager#dispatchSignal}. * * @param signal * The signal to queue for broadcasting */ public synchronized void queue(TmfSignal signal) { fCurrentTask.cancel(); fCurrentTask = new BroadcastRequest(signal); fTimer.schedule(fCurrentTask, fDelay); } /** * Dispose method. Will prevent any pending signal from being sent, and this * throttler from be used again. */ public synchronized void dispose() { fTimer.cancel(); fTimer.purge(); } private class BroadcastRequest extends TimerTask { private final TmfSignal signal; BroadcastRequest(TmfSignal signal) { this.signal = signal; } @Override public void run() { if (fComponent != null) { fComponent.broadcast(signal); } else { TmfSignalManager.dispatchSignal(signal); } } } }