001package jmri.jmris; 002 003import java.beans.PropertyChangeEvent; 004import java.beans.PropertyChangeListener; 005import java.io.IOException; 006import java.util.HashMap; 007import java.util.Map; 008import jmri.InstanceManager; 009import jmri.JmriException; 010import jmri.Sensor; 011import jmri.Route; 012 013/** 014 * Abstract interface between the a JMRI route and a network connection 015 * 016 * @author Paul Bender Copyright (C) 2010 017 * @author Randall Wood Copyright (C) 2013 018 */ 019abstract public class AbstractRouteServer { 020 021 private final HashMap<String, RouteListener> routes; 022 023 public AbstractRouteServer() { 024 routes = new HashMap<>(); 025 } 026 027 /* 028 * Protocol Specific Abstract Functions 029 */ 030 abstract public void sendStatus(String route, int Status) throws IOException; 031 032 abstract public void sendErrorStatus(String route) throws IOException; 033 034 abstract public void parseStatus(String statusString) throws JmriException, IOException; 035 036 synchronized protected void addRouteToList(String routeName) { 037 if (!routes.containsKey(routeName)) { 038 Route r = InstanceManager.getDefault(jmri.RouteManager.class).getRoute(routeName); 039 if(r!=null) { 040 Sensor tas = r.getTurnoutsAlgdSensor(); 041 if (tas != null) { //only add listener if there is a turnout-aligned sensor defined 042 RouteListener rl = new RouteListener(routeName); 043 tas.addPropertyChangeListener(rl); 044 routes.put(routeName, rl); 045 } 046 } 047 } 048 } 049 050 synchronized protected void removeRouteFromList(String routeName) { 051 if (routes.containsKey(routeName)) { 052 Route r = InstanceManager.getDefault(jmri.RouteManager.class).getRoute(routeName); 053 if(r!=null) { 054 Sensor tas = r.getTurnoutsAlgdSensor(); 055 if (tas != null) { //only remove listener if there is a turnout-aligned sensor defined 056 tas.removePropertyChangeListener(routes.get(routeName)); 057 } 058 routes.remove(routeName); 059 } 060 } 061 } 062 063 public void setRoute(String routeName) throws IOException { 064 Route route = InstanceManager.getDefault(jmri.RouteManager.class).getRoute(routeName); 065 if ( route != null ) { 066 route.setRoute(); 067 addRouteToList(routeName); 068 } else { 069 sendErrorStatus(routeName); 070 } 071 } 072 073 public void dispose() { 074 for (Map.Entry<String, RouteListener> route : this.routes.entrySet()) { 075 Route r = InstanceManager.getDefault(jmri.RouteManager.class).getRoute(route.getKey()); 076 if (r!=null) { 077 Sensor tas = r.getTurnoutsAlgdSensor(); 078 if (tas != null) { //only remove listener if there is a turnout-aligned sensor defined 079 tas.removePropertyChangeListener(route.getValue()); 080 } 081 } 082 } 083 this.routes.clear(); 084 } 085 086 class RouteListener implements PropertyChangeListener { 087 088 String name = null; 089 Sensor sensor = null; 090 091 RouteListener(String routeName) { 092 name = routeName; 093 Route r = InstanceManager.getDefault(jmri.RouteManager.class).getRoute(name); 094 if(r!=null) { 095 sensor = r.getTurnoutsAlgdSensor(); 096 } 097 } 098 099 // update state as state of route changes 100 @Override 101 public void propertyChange(PropertyChangeEvent e) { 102 // If the Commanded State changes, show transition state as "<inconsistent>" 103 if (e.getPropertyName().equals("KnownState")) { 104 try { 105 sendStatus(name, ((Integer) e.getNewValue())); 106 } catch (IOException ie) { 107 log.debug("Error Sending Status"); 108 // if we get an error, de-register 109 sensor.removePropertyChangeListener(this); 110 removeRouteFromList(name); 111 } 112 } 113 } 114 } 115 116 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(AbstractRouteServer.class); 117 118}