001package jmri.managers.configurexml; 002 003import java.util.List; 004import java.util.SortedSet; 005import jmri.InstanceManager; 006import jmri.Sensor; 007import jmri.SensorManager; 008import jmri.configurexml.JmriConfigureXmlException; 009import org.jdom2.Element; 010import org.slf4j.Logger; 011import org.slf4j.LoggerFactory; 012 013/** 014 * Provides the abstract base and store functionality for configuring 015 * SensorManagers, working with AbstractSensorManagers. 016 * <p> 017 * Typically, a subclass will just implement the load(Element sensors) class, 018 * relying on implementation here to load the individual sensors. Note that 019 * these are stored explicitly, so the resolution mechanism doesn't need to see 020 * *Xml classes for each specific Sensor or AbstractSensor subclass at store 021 * time. 022 * 023 * @author Bob Jacobsen Copyright: Copyright (c) 2002, 2008 024 */ 025public abstract class AbstractSensorManagerConfigXML extends AbstractNamedBeanManagerConfigXML { 026 027 public AbstractSensorManagerConfigXML() { 028 } 029 030 /** 031 * Default implementation for storing the contents of a SensorManager. 032 * 033 * @param o Object to store, of type SensorManager 034 * @return Element containing the complete info 035 */ 036 @Override 037 public Element store(Object o) { 038 Element sensors = new Element("sensors"); 039 return store(o, sensors); 040 } 041 042 public Element store(Object o, Element sensors) { 043 setStoreElementClass(sensors); 044 SensorManager sm = (SensorManager) o; 045 if (sm.getDefaultSensorDebounceGoingActive() > 0 || sm.getDefaultSensorDebounceGoingInActive() > 0) { 046 Element elem = new Element("globalDebounceTimers"); 047 elem.addContent(new Element("goingActive").addContent(String.valueOf(sm.getDefaultSensorDebounceGoingActive()))); 048 elem.addContent(new Element("goingInActive").addContent(String.valueOf(sm.getDefaultSensorDebounceGoingInActive()))); 049 sensors.addContent(elem); 050 } 051 SortedSet<Sensor> sensorList = sm.getNamedBeanSet(); 052 // don't return an element if there are no sensors to include 053 if (sensorList.isEmpty()) { 054 return null; 055 } 056 // store the sensors 057 for (Sensor s : sensorList) { 058 String sName = s.getSystemName(); 059 log.debug("system name is {}", sName); 060 String inverted = (s.getInverted() ? "true" : "false"); 061 062 Element elem = new Element("sensor").setAttribute("inverted", inverted); 063 elem.addContent(new Element("systemName").addContent(sName)); 064 065 // store common part 066 storeCommon(s, elem); 067 068 log.debug("store Sensor {}", sName); 069 if (s.getUseDefaultTimerSettings()) { 070 elem.addContent(new Element("useGlobalDebounceTimer").addContent("yes")); 071 } else { 072 if (s.getSensorDebounceGoingActiveTimer() > 0 || s.getSensorDebounceGoingInActiveTimer() > 0) { 073 Element timer = new Element("debounceTimers"); 074 timer.addContent(new Element("goingActive").addContent(String.valueOf(s.getSensorDebounceGoingActiveTimer()))); 075 timer.addContent(new Element("goingInActive").addContent(String.valueOf(s.getSensorDebounceGoingInActiveTimer()))); 076 elem.addContent(timer); 077 } 078 } 079 if (sm.isPullResistanceConfigurable()) { 080 // store the sensor's value for pull resistance. 081 elem.addContent(new Element("pullResistance").addContent(s.getPullResistance().getShortName())); 082 } 083 084 sensors.addContent(elem); 085 } 086 return sensors; 087 } 088 089 /** 090 * Subclass provides implementation to create the correct top element, 091 * including the type information. Default implementation is to use the 092 * local class here. 093 * 094 * @param sensors The top-level element being created 095 */ 096 abstract public void setStoreElementClass(Element sensors); 097 098 /** 099 * Create a SensorManager object of the correct class, then register and 100 * fill it. 101 * 102 * @param sharedSensors Shared top level Element to unpack. 103 * @param perNodeSensors Per-node top level Element to unpack. 104 * @return true if successful 105 * @throws jmri.configurexml.JmriConfigureXmlException if error during load 106 */ 107 @Override 108 abstract public boolean load(Element sharedSensors, Element perNodeSensors) throws JmriConfigureXmlException; 109 110 /** 111 * Utility method to load the individual Sensor objects. If there's no 112 * additional info needed for a specific sensor type, invoke this with the 113 * parent of the set of Sensor elements. 114 * 115 * @param sensors Element containing the Sensor elements to load. 116 * @return true if succeeded. 117 * @throws JmriConfigureXmlException on error. 118 */ 119 public boolean loadSensors(Element sensors) throws jmri.configurexml.JmriConfigureXmlException { 120 boolean result = true; 121 List<Element> sensorList = sensors.getChildren("sensor"); 122 log.debug("Found {} sensors", sensorList.size()); 123 SensorManager tm = InstanceManager.sensorManagerInstance(); 124 tm.setPropertyChangesSilenced("beans", true); 125 126 if (sensors.getChild("globalDebounceTimers") != null) { 127 Element timer = sensors.getChild("globalDebounceTimers"); 128 try { 129 if (timer.getChild("goingActive") != null) { 130 String active = timer.getChild("goingActive").getText(); 131 long goingActive = Long.parseLong(active); 132 tm.setDefaultSensorDebounceGoingActive(goingActive); 133 } 134 } catch (NumberFormatException ex) { 135 log.error("Could not set DefaultSensor Debounce GoingActive : {}", ex.getMessage() ); 136 } 137 138 try { 139 if (timer.getChild("goingInActive") != null) { 140 String inActive = timer.getChild("goingInActive").getText(); 141 long goingInActive = Long.parseLong(inActive); 142 tm.setDefaultSensorDebounceGoingInActive(goingInActive); 143 } 144 } catch (NumberFormatException ex) { 145 log.error("Could not set DefaultSensor Debounce GoingInActive : {}", ex.getMessage() ); 146 } 147 } 148 149 for (Element sen : sensorList) { 150 String sysName = getSystemName(sen); 151 if (sysName == null) { 152 handleException("Unexpected missing system name while loading sensors", 153 null, null, null, null); 154 result = false; 155 break; 156 } 157 boolean inverted = false; 158 159 String userName = getUserName(sen); 160 161 checkNameNormalization(sysName, userName, tm); 162 163 if (sen.getAttribute("inverted") != null) { 164 if (sen.getAttribute("inverted").getValue().equals("true")) { 165 inverted = true; 166 } 167 } 168 169 log.debug("create sensor: ({})", sysName); 170 171 Sensor s; 172 173 try { 174 s = tm.newSensor(sysName, userName); 175 } catch (IllegalArgumentException e) { 176 handleException("Could not create sensor", null, sysName, userName, null); 177 result = false; 178 continue; 179 } 180 181 // load common parts 182 loadCommon(s, sen); 183 184 if (sen.getChild("debounceTimers") != null) { 185 Element timer = sen.getChild("debounceTimers"); 186 try { 187 if (timer.getChild("goingActive") != null) { 188 String active = timer.getChild("goingActive").getText(); 189 s.setSensorDebounceGoingActiveTimer(Long.parseLong(active)); 190 } 191 } catch (NumberFormatException ex) { 192 log.error("Could not set Sensor {} Debounce GoingActive : {}", s, ex.getMessage() ); 193 } 194 195 try { 196 if (timer.getChild("goingInActive") != null) { 197 String inActive = timer.getChild("goingInActive").getText(); 198 s.setSensorDebounceGoingInActiveTimer(Long.parseLong(inActive)); 199 } 200 } catch (NumberFormatException ex) { 201 log.error("Could not set Sensor {} Debounce GoingInActive : {}", s, ex.getMessage() ); 202 } 203 } 204 205 if (sen.getChild("useGlobalDebounceTimer") != null) { 206 if (sen.getChild("useGlobalDebounceTimer").getText().equals("yes")) { 207 s.setUseDefaultTimerSettings(true); 208 } 209 } 210 s.setInverted(inverted); 211 212 if (sen.getChild("pullResistance") != null) { 213 String pull = sen.getChild("pullResistance") 214 .getText(); 215 log.debug("setting pull to {} for sensor {}", pull, s); 216 s.setPullResistance(jmri.Sensor.PullResistance.getByShortName(pull)); 217 } 218 } 219 tm.setPropertyChangesSilenced("beans", false); 220 return result; 221 } 222 223 @Override 224 public int loadOrder() { 225 return InstanceManager.sensorManagerInstance().getXMLOrder(); 226 } 227 228 private final static Logger log = LoggerFactory.getLogger(AbstractSensorManagerConfigXML.class); 229 230}