001package jmri.managers.configurexml; 002 003// import java.util.ArrayList; 004import java.util.List; 005import java.util.SortedSet; 006 007import jmri.*; 008import jmri.implementation.DefaultLightControl; 009 010import org.jdom2.Element; 011import org.slf4j.Logger; 012import org.slf4j.LoggerFactory; 013 014/** 015 * Provides the abstract base and store functionality for configuring 016 * LightManagers, working with AbstractLightManagers. 017 * <p> 018 * Typically, a subclass will just implement the load(Element sensors) class, 019 * relying on implementation here to load the individual lights. Note that these 020 * are stored explicitly, so the resolution mechanism doesn't need to see *Xml 021 * classes for each specific Light or AbstractLight subclass at store time. 022 * <p> 023 * Based on AbstractSensorManagerConfigXML.java 024 * 025 * @author Dave Duchamp Copyright (c) 2004, 2008, 2010 026 */ 027public abstract class AbstractLightManagerConfigXML extends AbstractNamedBeanManagerConfigXML { 028 029 public AbstractLightManagerConfigXML() { 030 } 031 032 /** 033 * Default implementation for storing the contents of a LightManager. 034 * 035 * @param o Object to store, of type LightManager 036 * @return Element containing the complete info 037 */ 038 @Override 039 public Element store(Object o) { 040 Element lights = new Element("lights"); 041 setStoreElementClass(lights); 042 LightManager lm = (LightManager) o; 043 if (lm != null) { 044 SortedSet<Light> lightList = lm.getNamedBeanSet(); 045 // don't return an element if there are no lights to include 046 if (lightList.isEmpty()) { 047 return null; 048 } 049 for (Light lgt : lightList) { 050 // store the lights 051 String lName = lgt.getSystemName(); 052 log.debug("system name is {}", lName); 053 Element elem = new Element("light"); 054 elem.addContent(new Element("systemName").addContent(lName)); 055 056 // store common parts 057 storeCommon(lgt, elem); 058 059 // write variable intensity attributes 060 if (lgt instanceof VariableLight) { 061 elem.setAttribute("minIntensity", "" + ((VariableLight)lgt).getMinIntensity()); 062 elem.setAttribute("maxIntensity", "" + ((VariableLight)lgt).getMaxIntensity()); 063 064 // write transition attribute 065 elem.setAttribute("transitionTime", "" + ((VariableLight)lgt).getTransitionTime()); 066 } else { 067 elem.setAttribute("minIntensity", "0.0"); 068 elem.setAttribute("maxIntensity", "1.0"); 069 070 // write transition attribute 071 elem.setAttribute("transitionTime", "0.0"); 072 } 073 074 // save child lightcontrol entries 075 List<LightControl> lcList = lgt.getLightControlList(); 076 for (LightControl lc : lcList) { 077 if (lc != null) { 078 Element lcElem = new Element("lightcontrol"); 079 int type = lc.getControlType(); 080 lcElem.setAttribute("controlType", "" + type); 081 if (type == Light.SENSOR_CONTROL) { 082 lcElem.setAttribute("controlSensor", lc.getControlSensorName()); 083 lcElem.setAttribute("sensorSense", "" + lc.getControlSensorSense()); 084 } else if (type == Light.FAST_CLOCK_CONTROL) { 085 lcElem.setAttribute("fastClockOnHour", "" + lc.getFastClockOnHour()); 086 lcElem.setAttribute("fastClockOnMin", "" + lc.getFastClockOnMin()); 087 lcElem.setAttribute("fastClockOffHour", "" + lc.getFastClockOffHour()); 088 lcElem.setAttribute("fastClockOffMin", "" + lc.getFastClockOffMin()); 089 } else if (type == Light.TURNOUT_STATUS_CONTROL) { 090 lcElem.setAttribute("controlTurnout", lc.getControlTurnoutName()); 091 lcElem.setAttribute("turnoutState", "" + lc.getControlTurnoutState()); 092 } else if (type == Light.TIMED_ON_CONTROL) { 093 lcElem.setAttribute("timedControlSensor", lc.getControlTimedOnSensorName()); 094 lcElem.setAttribute("duration", "" + lc.getTimedOnDuration()); 095 } 096 if (type == Light.TWO_SENSOR_CONTROL) { 097 lcElem.setAttribute("controlSensor", lc.getControlSensorName()); 098 lcElem.setAttribute("controlSensor2", lc.getControlSensor2Name()); 099 lcElem.setAttribute("sensorSense", "" + lc.getControlSensorSense()); 100 } 101 elem.addContent(lcElem); 102 } 103 } 104 lights.addContent(elem); 105 } 106 } 107 return lights; 108 } 109 110 /** 111 * Subclass provides implementation to create the correct top element, 112 * including the type information. Default implementation is to use the 113 * local class here. 114 * 115 * @param lights The top-level element being created 116 */ 117 abstract public void setStoreElementClass(Element lights); 118 119 /** 120 * Utility method to load the individual Light objects. If there's no 121 * additional info needed for a specific light type, invoke this with the 122 * parent of the set of Light elements. 123 * 124 * @param lights Element containing the Light elements to load. 125 * @return true when complete, false on error. 126 */ 127 public boolean loadLights(Element lights) { 128 boolean result = true; 129 List<Element> lightList = lights.getChildren("light"); 130 log.debug("Found {} lights", lightList.size()); 131 LightManager lm = InstanceManager.lightManagerInstance(); 132 lm.setPropertyChangesSilenced("beans", true); 133 134 for (Element el : lightList) { 135 String sysName = getSystemName(el); 136 if (sysName == null) { 137 log.warn("unexpected null in systemName {} {}", el, el.getAttributes()); 138 result = false; 139 break; 140 } 141 142 String userName = getUserName(el); 143 144 checkNameNormalization(sysName, userName, lm); 145 146 log.debug("create light: ({})({})", sysName, (userName == null ? "<null>" : userName)); 147 148 Light lgt = null; 149 try { 150 lgt = lm.newLight(sysName, userName); 151 } catch (IllegalArgumentException e) { 152 log.error("failed to create Light: {}", sysName); 153 return false; 154 } 155 156 // load common parts 157 loadCommon(lgt, el); 158 159 if (lgt instanceof VariableLight) { 160 // variable intensity, transition attributes 161 double value; 162 value = Double.parseDouble(el.getAttribute("minIntensity").getValue()); 163 ((VariableLight)lgt).setMinIntensity(value); 164 165 value = Double.parseDouble(el.getAttribute("maxIntensity").getValue()); 166 ((VariableLight)lgt).setMaxIntensity(value); 167 168 value = Double.parseDouble(el.getAttribute("transitionTime").getValue()); 169 ((VariableLight)lgt).setTransitionTime(value); 170 } 171 172 // provide for legacy light control - panel files written by 2.9.5 or before 173 if (el.getAttribute("controlType") != null) { 174 // this is a legacy Light - create a LightControl from the input 175 String temString = el.getAttribute("controlType").getValue(); 176 int type; 177 try { 178 type = Integer.parseInt(temString); 179 } catch (NumberFormatException e) { 180 log.error("error when converting control type in legacy Light load support"); 181 type = Light.NO_CONTROL; 182 } 183 if (type != Light.NO_CONTROL) { 184 // this legacy light has a control - capture it 185 LightControl lc = new DefaultLightControl(lgt); 186 lc.setControlType(type); 187 if (type == Light.SENSOR_CONTROL) { 188 lc.setControlSensorName(el.getAttribute("controlSensor").getValue()); 189 try { 190 lc.setControlSensorSense(Integer.parseInt(el. 191 getAttribute("sensorSense").getValue())); 192 } catch (NumberFormatException e) { 193 log.error("error when converting control sensor sense in legacy Light load"); 194 } 195 } else if (type == Light.FAST_CLOCK_CONTROL) { 196 int onHour = 0; 197 int onMin = 0; 198 int offHour = 0; 199 int offMin = 0; 200 try { 201 onHour = Integer.parseInt(el. 202 getAttribute("fastClockOnHour").getValue()); 203 onMin = Integer.parseInt(el. 204 getAttribute("fastClockOnMin").getValue()); 205 offHour = Integer.parseInt(el. 206 getAttribute("fastClockOffHour").getValue()); 207 offMin = Integer.parseInt(el. 208 getAttribute("fastClockOffMin").getValue()); 209 } catch (NumberFormatException e) { 210 log.error("error when converting fast clock items in legacy Light load"); 211 } 212 lc.setFastClockControlSchedule(onHour, onMin, offHour, offMin); 213 } else if (type == Light.TURNOUT_STATUS_CONTROL) { 214 lc.setControlTurnout(el. 215 getAttribute("controlTurnout").getValue()); 216 try { 217 lc.setControlTurnoutState(Integer.parseInt(el. 218 getAttribute("turnoutState").getValue())); 219 } catch (NumberFormatException e) { 220 log.error("error when converting turnout state in legacy Light load"); 221 } 222 } else if (type == Light.TIMED_ON_CONTROL) { 223 lc.setControlTimedOnSensorName(el. 224 getAttribute("timedControlSensor").getValue()); 225 try { 226 lc.setTimedOnDuration(Integer.parseInt(el. 227 getAttribute("duration").getValue())); 228 } catch (NumberFormatException e) { 229 log.error("error when converting timed sensor items in legacy Light load"); 230 } 231 232 } 233 lgt.addLightControl(lc); 234 } 235 } 236 237 // load lightcontrol children, if any 238 List<Element> lightControlList = el.getChildren("lightcontrol"); 239 for (Element elem : lightControlList) { 240 boolean noErrors = true; 241 LightControl lc = new DefaultLightControl(lgt); 242 String tem = elem.getAttribute("controlType").getValue(); 243 int type = Light.NO_CONTROL; 244 try { 245 type = Integer.parseInt(tem); 246 lc.setControlType(type); 247 } catch (NumberFormatException e) { 248 log.error("error when converting control type while loading light {}", sysName); 249 noErrors = false; 250 } 251 if (type == Light.SENSOR_CONTROL) { 252 lc.setControlSensorName(elem.getAttribute("controlSensor").getValue()); 253 try { 254 lc.setControlSensorSense(Integer.parseInt(elem. 255 getAttribute("sensorSense").getValue())); 256 } catch (NumberFormatException e) { 257 log.error("error when converting control sensor sense while loading light {}", sysName); 258 noErrors = false; 259 } 260 } else if (type == Light.FAST_CLOCK_CONTROL) { 261 int onHour = 0; 262 int onMin = 0; 263 int offHour = 0; 264 int offMin = 0; 265 try { 266 onHour = Integer.parseInt(elem. 267 getAttribute("fastClockOnHour").getValue()); 268 onMin = Integer.parseInt(elem. 269 getAttribute("fastClockOnMin").getValue()); 270 offHour = Integer.parseInt(elem. 271 getAttribute("fastClockOffHour").getValue()); 272 offMin = Integer.parseInt(elem. 273 getAttribute("fastClockOffMin").getValue()); 274 lc.setFastClockControlSchedule(onHour, onMin, offHour, offMin); 275 } catch (NumberFormatException e) { 276 log.error("error when converting fast clock items while loading light {}", sysName); 277 noErrors = false; 278 } 279 } else if (type == Light.TURNOUT_STATUS_CONTROL) { 280 lc.setControlTurnout(elem.getAttribute("controlTurnout").getValue()); 281 try { 282 lc.setControlTurnoutState(Integer.parseInt(elem. 283 getAttribute("turnoutState").getValue())); 284 } catch (NumberFormatException e) { 285 log.error("error when converting turnout state while loading light {}", sysName); 286 noErrors = false; 287 } 288 } else if (type == Light.TIMED_ON_CONTROL) { 289 lc.setControlTimedOnSensorName(elem.getAttribute("timedControlSensor").getValue()); 290 try { 291 lc.setTimedOnDuration(Integer.parseInt(elem. 292 getAttribute("duration").getValue())); 293 } catch (NumberFormatException e) { 294 log.error("error when converting timed sensor items while loading light {}", sysName); 295 noErrors = false; 296 } 297 } else if (type == Light.TWO_SENSOR_CONTROL) { 298 lc.setControlSensorName(elem.getAttribute("controlSensor").getValue()); 299 lc.setControlSensor2Name(elem.getAttribute("controlSensor2").getValue()); 300 try { 301 lc.setControlSensorSense(Integer.parseInt(elem. 302 getAttribute("sensorSense").getValue())); 303 } catch (NumberFormatException e) { 304 log.error("error when converting control sensor2 sense while loading light {}", sysName); 305 noErrors = false; 306 } 307 } 308 if (noErrors) { 309 lgt.addLightControl(lc); 310 } 311 } 312 313 // done, start it working 314 lgt.activateLight(); 315 } 316 317 lm.setPropertyChangesSilenced("beans", false); 318 return result; 319 } 320 321 @Override 322 public int loadOrder() { 323 return InstanceManager.lightManagerInstance().getXMLOrder(); 324 } 325 326 private final static Logger log = LoggerFactory.getLogger(AbstractLightManagerConfigXML.class); 327 328}