| 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2013, 2014 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 | * Alexandre Montplaisir - Initial API and implementation |
| 11 | *******************************************************************************/ |
| 12 | |
| 13 | package org.eclipse.tracecompass.tmf.core.signal; |
| 14 | |
| 15 | import java.util.Timer; |
| 16 | import java.util.TimerTask; |
| 17 | |
| 18 | import org.eclipse.tracecompass.tmf.core.component.ITmfComponent; |
| 19 | import org.eclipse.tracecompass.tmf.core.component.TmfComponent; |
| 20 | |
| 21 | /** |
| 22 | * "Buffer" between a TmfComponent and the signal manager. You can use this if |
| 23 | * you want to throttle the amount of signals your component will send. |
| 24 | * |
| 25 | * It works by specifying a delay, then calling {@link #queue}. The signals will |
| 26 | * only be really sent if no other call to {@link #queue} happens within $delay |
| 27 | * milliseconds afterwards. This guarantees that only the *last* signal is |
| 28 | * actually broadcasted. |
| 29 | * |
| 30 | * Note that this class does not discriminate for signal types, sources, or |
| 31 | * whatever. If you want to throttle different signals in different ways, you |
| 32 | * can use multiple signal throttlers in your component and call them |
| 33 | * accordingly. |
| 34 | * |
| 35 | * @author Alexandre Montplaisir |
| 36 | */ |
| 37 | public class TmfSignalThrottler { |
| 38 | |
| 39 | private final ITmfComponent fComponent; |
| 40 | private final long fDelay; |
| 41 | private final Timer fTimer; |
| 42 | private TimerTask fCurrentTask; |
| 43 | |
| 44 | /** |
| 45 | * Constructor |
| 46 | * |
| 47 | * @param component |
| 48 | * The source component of the signals |
| 49 | * @param delay |
| 50 | * Time to wait before actually sending signals (in ms) |
| 51 | */ |
| 52 | public TmfSignalThrottler(ITmfComponent component, long delay) { |
| 53 | this.fComponent = component; |
| 54 | this.fDelay = delay; |
| 55 | this.fTimer = new Timer(); |
| 56 | |
| 57 | /* |
| 58 | * Initialize currentTask to something, so we don't have to do a null |
| 59 | * check every time |
| 60 | */ |
| 61 | fCurrentTask = new TimerTask() { @Override public void run() {} }; |
| 62 | } |
| 63 | |
| 64 | /** |
| 65 | * Queue a signal for sending. It will only be forward to the centralized |
| 66 | * signal handler if 'delay' elapses without another signal being sent |
| 67 | * through this method. |
| 68 | * |
| 69 | * You call this instead of calling {@link TmfComponent#broadcast}. |
| 70 | * |
| 71 | * @param signal |
| 72 | * The signal to queue for broadcasting |
| 73 | */ |
| 74 | public synchronized void queue(TmfSignal signal) { |
| 75 | fCurrentTask.cancel(); |
| 76 | fCurrentTask = new BroadcastRequest(signal); |
| 77 | fTimer.schedule(fCurrentTask, fDelay); |
| 78 | } |
| 79 | |
| 80 | /** |
| 81 | * Dispose method. Will prevent any pending signal from being sent, and this |
| 82 | * throttler from be used again. |
| 83 | */ |
| 84 | public synchronized void dispose() { |
| 85 | fTimer.cancel(); |
| 86 | fTimer.purge(); |
| 87 | } |
| 88 | |
| 89 | private class BroadcastRequest extends TimerTask { |
| 90 | |
| 91 | private final TmfSignal signal; |
| 92 | |
| 93 | BroadcastRequest(TmfSignal signal) { |
| 94 | this.signal = signal; |
| 95 | } |
| 96 | |
| 97 | @Override |
| 98 | public void run() { |
| 99 | fComponent.broadcast(signal); |
| 100 | } |
| 101 | } |
| 102 | } |