001package jmri.jmrix.rps;
002
003import java.util.Vector;
004import org.slf4j.Logger;
005import org.slf4j.LoggerFactory;
006
007/**
008 * Distributes Readings and the Measurements calculated from them.
009 *
010 * @author Bob Jacobsen Copyright (C) 2006, 2008
011 */
012public class Distributor {
013
014    /**
015     * Request being informed when a new Reading is available.
016     * @param l the reading listener to add.
017     */
018    public void addReadingListener(ReadingListener l) {
019        // add only if not already registered
020        if (!readingListeners.contains(l)) {
021            readingListeners.addElement(l);
022        }
023    }
024
025    /**
026     * Request to no longer be informed when new Readings arrive.
027     * @param l the reading listener to remove.
028     */
029    public void removeReadingListener(ReadingListener l) {
030        if (readingListeners.contains(l)) {
031            readingListeners.removeElement(l);
032        }
033    }
034
035    /**
036     * Invoked when a new Reading is created.
037     * @param s the reading.
038     */
039    @SuppressWarnings("unchecked")
040    public void submitReading(Reading s) {
041        // make a copy of the listener vector to synchronized not needed for transmit
042        Vector<ReadingListener> v;
043        synchronized (this) {
044            v = (Vector<ReadingListener>) readingListeners.clone();
045        }
046        log.debug("notify {} ReadingListeners about item", v.size());
047        // forward to all listeners
048        int cnt = v.size();
049        for (int i = 0; i < cnt; i++) {
050            ReadingListener client = v.elementAt(i);
051            javax.swing.SwingUtilities.invokeLater(new ForwardReading(s, client));
052        }
053    }
054
055    /**
056     * Request being informed when a new Measurement is available.
057     * @param l the listener to add.
058     */
059    public void addMeasurementListener(MeasurementListener l) {
060        // add only if not already registered
061        if (!measurementListeners.contains(l)) {
062            measurementListeners.addElement(l);
063        }
064    }
065
066    /**
067     * Request to no longer be informed when new Measurements arrive.
068     * @param l the listener to remove.
069     */
070    public void removeMeasurementListener(MeasurementListener l) {
071        if (measurementListeners.contains(l)) {
072            measurementListeners.removeElement(l);
073        }
074    }
075
076    /**
077     * Invoked when a new Measurement is created.
078     * @param s the measurement.
079     */
080    @SuppressWarnings("unchecked")
081    public void submitMeasurement(Measurement s) {
082        // make a copy of the listener vector to synchronized not needed for transmit
083        Vector<MeasurementListener> v;
084        synchronized (this) {
085            v = (Vector<MeasurementListener>) measurementListeners.clone();
086        }
087        log.debug("notify {} MeasurementListeners about item", v.size());
088        // forward to all listeners
089        int cnt = v.size();
090        for (int i = 0; i < cnt; i++) {
091            MeasurementListener client = v.elementAt(i);
092            javax.swing.SwingUtilities.invokeLater(new ForwardMeasurement(s, client));
093        }
094    }
095
096    static volatile private Distributor instance = null;
097
098    public static Distributor instance() {
099        if (instance == null) {
100            instance = new Distributor();
101        }
102        return instance;
103    }
104
105    ////////////////////////////
106    // Implementation details //
107    ////////////////////////////
108    final private Vector<ReadingListener> readingListeners = new Vector<ReadingListener>();
109    final private Vector<MeasurementListener> measurementListeners = new Vector<MeasurementListener>();
110
111    /**
112     * Forward the Reading from the Swing thread.
113     */
114    static class ForwardReading implements Runnable {
115
116        Reading s;
117        ReadingListener client;
118
119        ForwardReading(Reading s, ReadingListener client) {
120            this.s = s;
121            this.client = client;
122        }
123
124        @Override
125        public void run() {
126            client.notify(s);
127        }
128    }
129
130    /**
131     * Forward the Measurement from the Swing thread.
132     */
133    static class ForwardMeasurement implements Runnable {
134
135        Measurement s;
136        MeasurementListener client;
137
138        ForwardMeasurement(Measurement s, MeasurementListener client) {
139            this.s = s;
140            this.client = client;
141        }
142
143        @Override
144        public void run() {
145            client.notify(s);
146        }
147    }
148
149    private final static Logger log = LoggerFactory.getLogger(Distributor.class);
150
151}