001package jmri.jmris;
002
003import java.beans.PropertyChangeEvent;
004import java.beans.PropertyChangeListener;
005import java.io.IOException;
006import java.util.HashMap;
007import java.util.Map;
008
009import jmri.InstanceManager;
010import jmri.JmriException;
011import jmri.Sensor;
012import jmri.SensorManager;
013import org.slf4j.Logger;
014import org.slf4j.LoggerFactory;
015
016/**
017 * Abstract interface between the a JMRI sensor and a network connection
018 *
019 * @author Paul Bender Copyright (C) 2010
020 */
021public abstract class AbstractSensorServer {
022
023    private static final String ERROR_SENDING_STATUS = "Error Sending Status";
024    private final HashMap<String, SensorListener> sensors;
025    private static final Logger log = LoggerFactory.getLogger(AbstractSensorServer.class);
026
027    public AbstractSensorServer(){
028        sensors = new HashMap<>();
029    }
030
031    /*
032     * Protocol Specific Abstract Functions
033     */
034    public abstract void sendStatus(String sensor, int Status) throws IOException;
035
036    public abstract void sendErrorStatus(String sensor) throws IOException;
037
038    public abstract void parseStatus(String statusString) throws JmriException, IOException;
039
040    protected synchronized void addSensorToList(String sensorName) {
041        if (!sensors.containsKey(sensorName)) {
042            Sensor s = InstanceManager.getDefault(SensorManager.class).getSensor(sensorName);
043            if(s!=null) {
044               SensorListener sl = new SensorListener(sensorName);
045               s.addPropertyChangeListener(sl);
046               sensors.put(sensorName, sl );
047            }
048        }
049    }
050
051    protected synchronized void removeSensorFromList(String sensorName) {
052        if (sensors.containsKey(sensorName)) {
053            Sensor s = InstanceManager.getDefault(SensorManager.class).getSensor(sensorName);
054            if(s!=null) {
055               s.removePropertyChangeListener(sensors.get(sensorName));
056               sensors.remove(sensorName);
057            }
058        }
059    }
060
061    public Sensor initSensor(String sensorName) {
062        Sensor sensor = InstanceManager.getDefault(SensorManager.class).provideSensor(sensorName);
063        this.addSensorToList(sensorName);
064        return sensor;
065    }
066
067    public void setSensorActive(String sensorName) {
068        Sensor sensor;
069        // load address from sensorAddrTextField
070        try {
071            addSensorToList(sensorName);
072            sensor = InstanceManager.getDefault(SensorManager.class).getSensor(sensorName);
073            if (sensor == null) {
074                log.error("Sensor {} is not available", sensorName);
075            } else {
076                if (sensor.getKnownState() != Sensor.ACTIVE) {
077                    // set state to ACTIVE
078                    log.debug("changing sensor '{}' to Active ({}->{})", sensorName, sensor.getKnownState(), Sensor.ACTIVE);
079                    sensor.setKnownState(Sensor.ACTIVE);
080                } else {
081                    // just notify the client.
082                    log.debug("not changing sensor '{}', already Active ({})", sensorName, sensor.getKnownState());
083                    sendStatusWithErrorHandling(sensorName,Sensor.ACTIVE);
084                }
085            }
086        } catch (JmriException ex) {
087            log.error("set sensor active", ex);
088        }
089    }
090
091    public void dispose() {
092        for (Map.Entry<String, SensorListener> sensor : this.sensors.entrySet()) {
093            Sensor s = InstanceManager.getDefault(SensorManager.class).getSensor(sensor.getKey());
094            if(s!=null) {
095               s.removePropertyChangeListener(sensor.getValue());
096            }
097        }
098        this.sensors.clear();
099    }
100
101    public void setSensorInactive(String sensorName) {
102        Sensor sensor;
103        try {
104            addSensorToList(sensorName);
105            sensor = InstanceManager.getDefault(SensorManager.class).getSensor(sensorName);
106
107            if (sensor == null) {
108                log.error("Sensor {} is not available",sensorName);
109            } else {
110                if (sensor.getKnownState() != Sensor.INACTIVE) {
111                    // set state to INACTIVE
112                    log.debug("changing sensor '{}' to InActive ({}->{})", sensorName, sensor.getKnownState(), Sensor.INACTIVE);
113                    sensor.setKnownState(Sensor.INACTIVE);
114                } else {
115                    // just notify the client.
116                    log.debug("not changing sensor '{}', already InActive ({})", sensorName, sensor.getKnownState());
117                    sendStatusWithErrorHandling(sensorName,Sensor.INACTIVE);
118                }
119            }
120        } catch (JmriException ex) {
121            log.error("set sensor inactive", ex);
122        }
123    }
124
125    private void sendStatusWithErrorHandling(String sensorName,int status){
126        try {
127            sendStatus(sensorName, status);
128        } catch (IOException ie) {
129            log.error(ERROR_SENDING_STATUS);
130        }
131    }
132
133    class SensorListener implements PropertyChangeListener {
134
135        SensorListener(String sensorName) {
136            name = sensorName;
137            sensor = InstanceManager.getDefault(SensorManager.class).getSensor(sensorName);
138        }
139
140        // update state as state of sensor changes
141        @Override
142        public void propertyChange(PropertyChangeEvent e) {
143            // If the Commanded State changes, show transition state as "<inconsistent>"
144            if (e.getPropertyName().equals("KnownState")) {
145                int now = ((Integer) e.getNewValue()).intValue();
146                try {
147                    sendStatus(name, now);
148                } catch (IOException ie) {
149                    log.debug(ERROR_SENDING_STATUS);
150                    // if we get an error, de-register
151                    sensor.removePropertyChangeListener(this);
152                    removeSensorFromList(name);
153                }
154            }
155        }
156        String name = null;
157        Sensor sensor = null;
158    }
159}