001package jmri.jmrit.blockboss.configurexml; 002 003import jmri.InstanceManager; 004import jmri.Manager; 005import jmri.SignalHeadManager; 006import jmri.jmrit.blockboss.BlockBossLogic; 007import jmri.jmrit.blockboss.BlockBossLogicProvider; 008import org.jdom2.DataConversionException; 009import org.jdom2.Element; 010import org.slf4j.Logger; 011import org.slf4j.LoggerFactory; 012 013import java.util.Collections; 014import java.util.Enumeration; 015import java.util.List; 016 017/** 018 * Handle XML persistance of Simple Signal Logic objects. 019 * 020 * <p> 021 * In JMRI 2.1.5, the XML written by this package was changed. 022 * <p> 023 * Previously, it wrote a single "blocks" element, which contained multiple 024 * "block" elements to represent each individual BlockBoss (Simple Signal Logic) 025 * object. 026 * <p> 027 * These names were too generic, and conflicted with storing true Block objects. 028 * <p> 029 * Starting in JMRI 2.1.5 (May 2008), these were changed to "signalelements" and 030 * "signalelement" respectively. 031 * 032 * @author Bob Jacobsen Copyright: Copyright (c) 2003, 2005 033 * 034 * Revisions to add facing point sensors, approach lighting, and limited speed. 035 * Dick Bronson (RJB) 2006 036 */ 037public class BlockBossLogicProviderXml extends jmri.configurexml.AbstractXmlAdapter { 038 039 private static final String SYSTEM_NAME = "systemName"; 040 private static final String SIGNAL = "signal"; 041 private static final String APPROACHSENSOR_1 = "approachsensor1"; 042 private static final String WATCHEDTURNOUT = "watchedturnout"; 043 private static final String WATCHEDSIGNAL_1 = "watchedsignal1"; 044 private static final String WATCHEDSIGNAL_1_ALT = "watchedsignal1alt"; 045 private static final String WATCHEDSIGNAL_2 = "watchedsignal2"; 046 private static final String WATCHEDSIGNAL_2_ALT = "watchedsignal2alt"; 047 private static final String WATCHEDSENSOR_1 = "watchedsensor1"; 048 private static final String WATCHEDSENSOR_1_ALT = "watchedsensor1alt"; 049 private static final String WATCHEDSENSOR_2 = "watchedsensor2"; 050 private static final String WATCHEDSENSOR_2_ALT = "watchedsensor2alt"; 051 private static final String LIMITSPEED_1 = "limitspeed1"; 052 private static final String LIMITSPEED_2 = "limitspeed2"; 053 private static final String RESTRICTINGSPEED_1 = "restrictingspeed1"; 054 private static final String RESTRICTINGSPEED_2 = "restrictingspeed2"; 055 private static final String USEFLASHYELLOW = "useflashyellow"; 056 private static final String DISTANTSIGNAL = "distantsignal"; 057 private final BlockBossLogicProvider blockBossLogicProvider; 058 059 public BlockBossLogicProviderXml() { 060 blockBossLogicProvider = InstanceManager.getDefault(BlockBossLogicProvider.class); 061 } 062 063 /** 064 * Default implementation for storing the contents of all the BLockBossLogic 065 * elements. 066 * <p> 067 * Static members in the BlockBossLogic class record the complete set of 068 * items. This function writes those out as a single XML element. 069 * 070 * @param o Object to start process, but not actually used 071 * @return Element containing the complete info 072 */ 073 @Override 074 public Element store(Object o) { 075 076 Enumeration<BlockBossLogic> e = Collections.enumeration(blockBossLogicProvider.provideAll()); 077 if (!e.hasMoreElements()) { 078 return null; // nothing to write! 079 } 080 Element blocks = new Element("signalelements"); 081 blocks.setAttribute("class", this.getClass().getName()); 082 083 while (e.hasMoreElements()) { 084 BlockBossLogic p = e.nextElement(); 085 Element block = getElementFromBlockBossLogic(p); 086 blocks.addContent(block); 087 } 088 089 return blocks; 090 } 091 092 private Element getElementFromBlockBossLogic(BlockBossLogic p) { 093 Element block = new Element("signalelement"); 094 block.setAttribute(SIGNAL, p.getDrivenSignal()); 095 block.setAttribute("mode", "" + p.getMode()); 096 097 if (p.getApproachSensor1() != null) { 098 block.setAttribute(APPROACHSENSOR_1, p.getApproachSensor1()); 099 } 100 101 if (p.getSensor1() != null) { 102 block.addContent(storeSensor(p.getSensor1())); 103 } 104 if (p.getSensor2() != null) { 105 block.addContent(storeSensor(p.getSensor2())); 106 } 107 if (p.getSensor3() != null) { 108 block.addContent(storeSensor(p.getSensor3())); 109 } 110 if (p.getSensor4() != null) { 111 block.addContent(storeSensor(p.getSensor4())); 112 } 113 if (p.getSensor5() != null) { 114 block.addContent(storeSensor(p.getSensor5())); 115 } 116 117 if (p.getTurnout() != null) { 118 block.setAttribute(WATCHEDTURNOUT, p.getTurnout()); 119 } 120 if (p.getWatchedSignal1() != null) { 121 block.setAttribute(WATCHEDSIGNAL_1, p.getWatchedSignal1()); 122 } 123 if (p.getWatchedSignal1Alt() != null) { 124 block.setAttribute(WATCHEDSIGNAL_1_ALT, p.getWatchedSignal1Alt()); 125 } 126 if (p.getWatchedSignal2() != null) { 127 block.setAttribute(WATCHEDSIGNAL_2, p.getWatchedSignal2()); 128 } 129 if (p.getWatchedSignal2Alt() != null) { 130 block.setAttribute(WATCHEDSIGNAL_2_ALT, p.getWatchedSignal2Alt()); 131 } 132 if (p.getWatchedSensor1() != null) { 133 block.setAttribute(WATCHEDSENSOR_1, p.getWatchedSensor1()); 134 } 135 if (p.getWatchedSensor1Alt() != null) { 136 block.setAttribute(WATCHEDSENSOR_1_ALT, p.getWatchedSensor1Alt()); 137 } 138 if (p.getWatchedSensor2() != null) { 139 block.setAttribute(WATCHEDSENSOR_2, p.getWatchedSensor2()); 140 } 141 if (p.getWatchedSensor2Alt() != null) { 142 block.setAttribute(WATCHEDSENSOR_2_ALT, p.getWatchedSensor2Alt()); 143 } 144 145 block.setAttribute(LIMITSPEED_1, "" + p.getLimitSpeed1()); 146 block.setAttribute(LIMITSPEED_2, "" + p.getLimitSpeed2()); 147 if (p.getRestrictingSpeed1()) 148 block.setAttribute(RESTRICTINGSPEED_1, "" + p.getRestrictingSpeed1()); 149 if (p.getRestrictingSpeed2()) 150 block.setAttribute(RESTRICTINGSPEED_2, "" + p.getRestrictingSpeed2()); 151 block.setAttribute(USEFLASHYELLOW, "" + p.getUseFlash()); 152 block.setAttribute(DISTANTSIGNAL, "" + p.getDistantSignal()); 153 154 // add comment, if present 155 if (p.getComment() != null) { 156 Element c = new Element("comment"); 157 c.addContent(p.getComment()); 158 block.addContent(c); 159 } 160 return block; 161 } 162 163 private Element storeSensor(String name) { 164 Element e = new Element("sensorname"); 165 e.addContent(name); 166 return e; 167 } 168 169 @Override 170 public boolean load(Element shared, Element perNode) { 171 List<Element> l = shared.getChildren("signalelement"); 172 173 // try old format if there are no new entries 174 // this is for backward compatibility only 175 if (l.size() == 0) { 176 l = shared.getChildren("block"); 177 } 178 179 // process each item 180 for (Element block : l) { 181 BlockBossLogic bb = getBlockBossLogicFromElement(block); 182 if (bb == null) { 183 continue; 184 } 185 loadBlockBossLogicDetailsFromElement(block, bb); 186 } 187 return true; 188 } 189 190 private boolean loadBlockBossLogicDetailsFromElement(Element block, BlockBossLogic bb) { 191 boolean result = loadOptionalApproachSensor(block, bb); 192 193 result &= loadOptionalWatchedSensor(block, bb); 194 195 result &= loadOldFormSensorNames(block, bb); 196 197 try { 198 bb.setMode(block.getAttribute("mode").getIntValue()); 199 if (block.getAttribute(DISTANTSIGNAL) != null) { 200 bb.setDistantSignal(block.getAttribute(DISTANTSIGNAL).getBooleanValue()); 201 } 202 if (block.getAttribute(LIMITSPEED_1) != null) { 203 bb.setLimitSpeed1(block.getAttribute(LIMITSPEED_1).getBooleanValue()); 204 } 205 if (block.getAttribute(RESTRICTINGSPEED_1) != null) { 206 bb.setRestrictingSpeed1(block.getAttribute(RESTRICTINGSPEED_1).getBooleanValue()); 207 } 208 if (block.getAttribute(LIMITSPEED_2) != null) { 209 bb.setLimitSpeed2(block.getAttribute(LIMITSPEED_2).getBooleanValue()); 210 } 211 if (block.getAttribute(RESTRICTINGSPEED_2) != null) { 212 bb.setRestrictingSpeed2(block.getAttribute(RESTRICTINGSPEED_2).getBooleanValue()); 213 } 214 result &= loadWatchedTurnout(block, bb); 215 216 result &= loadWatchedSignal1(block, bb); 217 218 result &= loadWAtchedSignal1Alt(block, bb); 219 220 result &= loadWatchedSignal2(block, bb); 221 222 result &= loadWatchedSignal2Alt(block, bb); 223 224 result &= loadWatchedSensor1(block, bb); 225 226 result &= loadWatchedSensor1Alt(block, bb); 227 228 result &= loadWatchedSensor2(block, bb); 229 230 result &= loadWatchedSensor2Alt(block, bb); 231 232 // load comment, if present 233 String c = block.getChildText("comment"); 234 if (c != null) { 235 bb.setComment(c); 236 } 237 238 } catch (org.jdom2.DataConversionException e) { 239 log.warn("error reading blocks from file", e); 240 result = false; 241 } catch (IllegalArgumentException e) { 242 log.error("An error occurred in the signal element attribute list"); 243 result = false; 244 } 245 try { 246 blockBossLogicProvider.register(bb); 247 bb.start(); 248 } catch (IllegalArgumentException e) { 249 log.debug("An error occurred trying to start the signal logic {} :: message = {}", bb.getDrivenSignal(), e.getMessage()); 250 result = false; 251 } 252 return result; 253 } 254 255 private boolean loadOldFormSensorNames(Element block, BlockBossLogic bb) { 256 boolean result = true; 257 // old form of sensors with system names 258 List<Element> sl = block.getChildren("sensor"); 259 try { 260 getSensorAttributesUsingSystemName(bb, sl); 261 } catch (IllegalArgumentException e) { 262 log.error("An error occurred loading the sensors list in the SSL"); 263 result = false; 264 } 265 // new form of sensors with system names 266 sl = block.getChildren("sensorname"); 267 try { 268 if (sl.size() >= 1 && sl.get(0) != null) { 269 bb.setSensor1(sl.get(0).getText()); 270 } 271 } catch (IllegalArgumentException e) { 272 log.error("An error occurred loading the sensor1 list in the SSL for {}", bb.getDrivenSignal()); 273 result = false; 274 } 275 276 try { 277 if (sl.size() >= 2 && sl.get(1) != null) { 278 bb.setSensor2(sl.get(1).getText()); 279 } 280 } catch (IllegalArgumentException e) { 281 log.error("An error occurred loading the sensor2 list in the SSL for {}", bb.getDrivenSignal()); 282 result = false; 283 } 284 285 try { 286 if (sl.size() >= 3 && sl.get(2) != null) { 287 bb.setSensor3(sl.get(2).getText()); 288 } 289 } catch (IllegalArgumentException e) { 290 log.error("An error occurred loading the sensor3 list in the SSL for {}", bb.getDrivenSignal()); 291 result = false; 292 } 293 294 try { 295 if (sl.size() >= 4 && sl.get(3) != null) { 296 bb.setSensor4(sl.get(3).getText()); 297 } 298 } catch (IllegalArgumentException e) { 299 log.error("An error occurred loading the sensor4 list in the SSL for {}", bb.getDrivenSignal()); 300 result = false; 301 } 302 303 try { 304 if (sl.size() >= 5 && sl.get(4) != null) { 305 bb.setSensor5(sl.get(4).getText()); 306 } 307 } catch (IllegalArgumentException e) { 308 log.error("An error occurred loading the sensor5 list in the SSL for {}", bb.getDrivenSignal()); 309 result = false; 310 } 311 return result; 312 } 313 314 private boolean loadOptionalWatchedSensor(Element block, BlockBossLogic bb) { 315 boolean result = true; 316 if (block.getAttribute("watchedsensor") != null) { // for older XML files 317 try { 318 bb.setSensor1(block.getAttributeValue("watchedsensor")); 319 } catch (IllegalArgumentException e) { 320 log.error("An error occurred loading the watched sensor in the SSL for {}", bb.getDrivenSignal()); 321 result = false; 322 } 323 } 324 return result; 325 } 326 327 private boolean loadOptionalApproachSensor(Element block, BlockBossLogic bb) { 328 boolean result = true; 329 if (block.getAttribute(APPROACHSENSOR_1) != null) { 330 try { 331 bb.setApproachSensor1(block.getAttributeValue(APPROACHSENSOR_1)); 332 } catch (IllegalArgumentException e) { 333 log.error("An error occurred loading the approach sensor for the signal elements for {}", bb.getDrivenSignal()); 334 result = false; 335 } 336 } 337 return result; 338 } 339 340 private boolean loadWatchedSensor2Alt(Element block, BlockBossLogic bb) { 341 boolean result = true; 342 try { 343 if (block.getAttribute(WATCHEDSENSOR_2_ALT) != null) { 344 bb.setWatchedSensor2Alt(block.getAttributeValue(WATCHEDSENSOR_2_ALT)); 345 } 346 } catch (IllegalArgumentException e) { 347 log.error("An error occurred in retrieving the watched sensor 2 alt ({})element attribute list for {}", block.getAttributeValue(WATCHEDSENSOR_2_ALT), bb.getDrivenSignal()); 348 result = false; 349 } 350 return result; 351 } 352 353 private boolean loadWatchedSensor2(Element block, BlockBossLogic bb) { 354 boolean result = true; 355 try { 356 if (block.getAttribute(WATCHEDSENSOR_2) != null) { 357 bb.setWatchedSensor2(block.getAttributeValue(WATCHEDSENSOR_2)); 358 } 359 } catch (IllegalArgumentException e) { 360 log.error("An error occurred in retrieving the watched sensor 2 ({}) element attribute list for {}", block.getAttributeValue(WATCHEDSENSOR_2), bb.getDrivenSignal()); 361 result = false; 362 } 363 return result; 364 } 365 366 private boolean loadWatchedSensor1Alt(Element block, BlockBossLogic bb) { 367 boolean result = true; 368 try { 369 if (block.getAttribute(WATCHEDSENSOR_1_ALT) != null) { 370 bb.setWatchedSensor1Alt(block.getAttributeValue(WATCHEDSENSOR_1_ALT)); 371 } 372 } catch (IllegalArgumentException e) { 373 log.error("An error occurred in retrieving the watched sensor 1 alt ({}) element attribute list for {}", block.getAttributeValue(WATCHEDSENSOR_1_ALT), bb.getDrivenSignal()); 374 result = false; 375 } 376 return result; 377 } 378 379 private boolean loadWatchedSensor1(Element block, BlockBossLogic bb) { 380 boolean result = true; 381 try { 382 if (block.getAttribute(WATCHEDSENSOR_1) != null) { 383 bb.setWatchedSensor1(block.getAttributeValue(WATCHEDSENSOR_1)); 384 } 385 } catch (IllegalArgumentException e) { 386 log.error("An error occurred in retrieving the watched sensor 1 ({}) element attribute list for {}", block.getAttributeValue(WATCHEDSENSOR_1), bb.getDrivenSignal()); 387 result = false; 388 } 389 return result; 390 } 391 392 private boolean loadWatchedSignal2Alt(Element block, BlockBossLogic bb) { 393 boolean result = true; 394 try { 395 if (block.getAttribute(WATCHEDSIGNAL_2_ALT) != null) { 396 bb.setWatchedSignal2Alt(block.getAttributeValue(WATCHEDSIGNAL_2_ALT)); 397 } 398 } catch (IllegalArgumentException e) { 399 log.error("An error occurred in retrieving the watched signal 2 alt ({}) element attribute list for {}", block.getAttributeValue(WATCHEDSIGNAL_2_ALT), bb.getDrivenSignal()); 400 result = false; 401 } 402 return result; 403 } 404 405 private boolean loadWatchedSignal2(Element block, BlockBossLogic bb) { 406 boolean result = true; 407 try { 408 if (block.getAttribute(WATCHEDSIGNAL_2) != null) { 409 bb.setWatchedSignal2(block.getAttributeValue(WATCHEDSIGNAL_2)); 410 } 411 412 } catch (IllegalArgumentException e) { 413 log.error("An error occurred in retrieving the watched signal 2 ({})element attribute list for {}", block.getAttributeValue(WATCHEDSIGNAL_2), bb.getDrivenSignal()); 414 result = false; 415 } 416 return result; 417 } 418 419 private boolean loadWAtchedSignal1Alt(Element block, BlockBossLogic bb) { 420 boolean result = true; 421 try { 422 if (block.getAttribute(WATCHEDSIGNAL_1_ALT) != null) { 423 bb.setWatchedSignal1Alt(block.getAttributeValue(WATCHEDSIGNAL_1_ALT)); 424 } 425 } catch (IllegalArgumentException e) { 426 log.error("An error occurred in retrieving the watched signal 1 alt ({})element attribute list for {}", block.getAttributeValue(WATCHEDSIGNAL_1_ALT), bb.getDrivenSignal()); 427 result = false; 428 } 429 return result; 430 } 431 432 private boolean loadWatchedSignal1(Element block, BlockBossLogic bb) throws DataConversionException { 433 boolean result = true; 434 try { 435 if (block.getAttribute(WATCHEDSIGNAL_1) != null) { 436 bb.setWatchedSignal1(block.getAttributeValue(WATCHEDSIGNAL_1), block.getAttribute(USEFLASHYELLOW).getBooleanValue()); 437 } 438 } catch (IllegalArgumentException e) { 439 log.error("An error occurred in retrieving the watched signal 1 ({})element attribute list for {}", block.getAttributeValue(WATCHEDSIGNAL_1), bb.getDrivenSignal()); 440 result = false; 441 } 442 return result; 443 } 444 445 private boolean loadWatchedTurnout(Element block, BlockBossLogic bb) { 446 boolean result = true; 447 try { 448 if (block.getAttribute(WATCHEDTURNOUT) != null) { 449 bb.setTurnout(block.getAttributeValue(WATCHEDTURNOUT)); 450 } 451 } catch (IllegalArgumentException e) { 452 log.error("An error occurred in retrieving the watched turnout ({})element attribute list for {}", block.getAttributeValue(WATCHEDTURNOUT), bb.getDrivenSignal()); 453 result = false; 454 } 455 return result; 456 } 457 458 private BlockBossLogic getBlockBossLogicFromElement(Element block) { 459 BlockBossLogic blockBossLogic; 460 String signalName = block.getAttributeValue(SIGNAL); 461 if (signalName == null || signalName.isEmpty()) { 462 // this is an error 463 log.error("Ignoring a <signalelement> element with no signal attribute value"); 464 return null; 465 } 466 467 if (InstanceManager.getDefault(SignalHeadManager.class).getSignalHead(signalName) == null) { 468 // this is an error 469 log.error("SignalHead {} not defined, <signalelement> element referring to it is ignored", signalName); 470 return null; 471 } 472 473 try { 474 blockBossLogic = BlockBossLogic.getStoppedObject(signalName); 475 } catch (IllegalArgumentException e) { 476 // Potential exception in BLockBossProvider:provide via BlockBossLogic. 477 return null; 478 } 479 return blockBossLogic; 480 } 481 482 private void getSensorAttributesUsingSystemName(BlockBossLogic bb, List<Element> sl) { 483 if (sl.size() >= 1 && sl.get(0) != null) { 484 bb.setSensor1(sl.get(0).getAttributeValue(SYSTEM_NAME)); 485 } 486 if (sl.size() >= 2 && sl.get(1) != null) { 487 bb.setSensor2(sl.get(1).getAttributeValue(SYSTEM_NAME)); 488 } 489 if (sl.size() >= 3 && sl.get(2) != null) { 490 bb.setSensor3(sl.get(2).getAttributeValue(SYSTEM_NAME)); 491 } 492 if (sl.size() >= 4 && sl.get(3) != null) { 493 bb.setSensor4(sl.get(3).getAttributeValue(SYSTEM_NAME)); 494 } 495 if (sl.size() >= 5 && sl.get(4) != null) { 496 bb.setSensor5(sl.get(4).getAttributeValue(SYSTEM_NAME)); 497 } 498 } 499 500 /** 501 * Update static data from XML file 502 * 503 * @param element Top level Element to unpack. 504 * @param o ignored 505 */ 506 @Override 507 public void load(Element element, Object o) { 508 log.error("load(Element, Object) called unexpectedly"); 509 } 510 511 @Override 512 public int loadOrder() { 513 return Manager.BLOCKBOSS; 514 } 515 516 private static final Logger log = LoggerFactory.getLogger(BlockBossLogicProviderXml.class); 517 518}