001package jmri.jmrit.logix.configurexml; 002 003import java.util.List; 004import java.util.SortedSet; 005 006import jmri.DccLocoAddress; 007import jmri.InstanceManager; 008import jmri.SpeedStepMode; 009import jmri.jmrit.logix.BlockOrder; 010import jmri.jmrit.logix.OBlock; 011import jmri.jmrit.logix.SCWarrant; 012import jmri.jmrit.logix.SpeedUtil; 013import jmri.jmrit.logix.ThrottleSetting; 014import jmri.jmrit.logix.ThrottleSetting.Command; 015import jmri.jmrit.logix.ThrottleSetting.CommandValue; 016import jmri.jmrit.logix.ThrottleSetting.ValueType; 017import jmri.jmrit.logix.Warrant; 018import jmri.jmrit.logix.WarrantManager; 019import org.jdom2.Attribute; 020import org.jdom2.DataConversionException; 021import org.jdom2.Element; 022 023/** 024 * Provides the abstract base and store functionality for 025 * configuring the WarrantManager. 026 * <p> 027 * Typically, a subclass will just implement the load(Element warrant) 028 * class, relying on implementation here to load the individual Warrant objects. 029 * 030 * @author Pete Cressman Copyright: Copyright (c) 2009 031 */ 032public class WarrantManagerXml extends jmri.configurexml.AbstractXmlAdapter { 033 034 public WarrantManagerXml() { 035 } 036 037 /** 038 * Store the contents of a WarrantManager. 039 * 040 * @param o Object to store, of type warrantManager 041 * @return Element containing the complete info 042 */ 043 @Override 044 public Element store(Object o) { 045 Element warrants = new Element("warrants"); 046 warrants.setAttribute("class", "jmri.jmrit.logix.configurexml.WarrantManagerXml"); 047 WarrantManager wm = (WarrantManager) o; 048 if (wm != null) { 049 SortedSet<Warrant> warrantList = wm.getNamedBeanSet(); 050 // don't return an element if there are no warrants to include 051 if (warrantList.isEmpty()) { 052 return null; 053 } 054 for (Warrant warrant : warrantList) { 055 String sName = warrant.getSystemName(); 056 String uName = warrant.getUserName(); 057 log.debug("Warrant: sysName= {}, userName= {}", sName, uName); 058 Element elem = new Element("warrant"); 059 elem.setAttribute("systemName", sName); 060 if (uName == null) { 061 uName = ""; 062 } 063 if (uName.length() > 0) { 064 elem.setAttribute("userName", uName); 065 } 066 if (warrant instanceof SCWarrant) { 067 elem.setAttribute("wtype", "SC"); 068 elem.setAttribute("speedFactor", "" + ((SCWarrant) warrant).getSpeedFactor()); 069 elem.setAttribute("timeToPlatform", "" + ((SCWarrant) warrant).getTimeToPlatform()); 070 elem.setAttribute("forward", ((SCWarrant) warrant).getForward() ? "true" : "false"); 071 } else { 072 elem.setAttribute("wtype", "normal"); 073 } 074 String comment = warrant.getComment(); 075 if (comment != null) { 076 Element c = new Element("comment"); 077 c.addContent(comment); 078 elem.addContent(c); 079 } 080 081 List<BlockOrder> orders = warrant.getBlockOrders(); 082 if (orders == null) { 083 log.error("Warrant {} has no Route defined. (no BlockOrders) Cannot store.", warrant.getDisplayName()); 084 continue; 085 } 086 for (BlockOrder bo : orders) { 087 elem.addContent(storeOrder(bo, "blockOrder")); 088 } 089 090 BlockOrder viaOrder = warrant.getViaOrder(); 091 if (viaOrder != null) { 092 elem.addContent(storeOrder(viaOrder, "viaOrder")); 093 } 094 BlockOrder avoidOrder = warrant.getAvoidOrder(); 095 if (avoidOrder != null) { 096 elem.addContent(storeOrder(avoidOrder, "avoidOrder")); 097 } 098 099 List<ThrottleSetting> throttleCmds = warrant.getThrottleCommands(); 100 for (ThrottleSetting ts : throttleCmds) { 101 elem.addContent(storeThrottleSetting(ts)); 102 } 103 104 elem.addContent(storeTrain(warrant, "train")); 105 106 // and put this element out 107 warrants.addContent(elem); 108 } 109 } 110 return warrants; 111 } 112 113 private static Element storeTrain(Warrant warrant, String type) { 114 Element elem = new Element(type); 115 SpeedUtil speedUtil = warrant.getSpeedUtil(); 116 String str = speedUtil.getRosterId(); 117 if (str==null) { 118 str = ""; 119 } 120 elem.setAttribute("trainId", str); 121 122 DccLocoAddress addr = speedUtil.getDccAddress(); 123 if (addr != null) { 124 elem.setAttribute("dccAddress", ""+addr.getNumber()); 125 elem.setAttribute("dccType", ""+addr.getProtocol().getShortName()); 126 } 127 elem.setAttribute("runBlind", warrant.getRunBlind()?"true":"false"); 128 elem.setAttribute("shareRoute", warrant.getShareRoute()?"true":"false"); 129 elem.setAttribute("noRamp", warrant.getNoRamp()?"true":"false"); 130 131 str = warrant.getTrainName(); 132 if (str==null) { 133 str = ""; 134 } 135 elem.setAttribute("trainName", str); 136 137 return elem; 138 } 139 140 private static Element storeOrder(BlockOrder order, String type) { 141 Element elem = new Element(type); 142 OBlock block = order.getBlock(); 143 Element blk = new Element("block"); 144 blk.setAttribute("systemName", block.getSystemName()); 145 String uname = block.getUserName(); 146 if (uname==null) { 147 uname = ""; 148 } 149 if (uname.length()>0) { 150 blk.setAttribute("userName", uname); 151 } 152 elem.addContent(blk); 153 154 String str = order.getPathName(); 155 if (str == null) { 156 str = ""; 157 } 158 elem.setAttribute("pathName", str); 159 160 str = order.getEntryName(); 161 if (str == null) { 162 str = ""; 163 } 164 elem.setAttribute("entryName", str); 165 166 str = order.getExitName(); 167 if (str == null) { 168 str = ""; 169 } 170 elem.setAttribute("exitName", str); 171 172 return elem; 173 } 174 private static Element storeThrottleSetting(ThrottleSetting ts) { 175 Element element = new Element("throttleSetting"); 176 element.setAttribute("elapsedTime", String.valueOf(ts.getTime())); 177 String name = ts.getBeanSystemName(); 178 if (name != null) { 179 element.setAttribute("beanName", name); 180 } else { 181 element.setAttribute("beanName", ""); 182 } 183 element.setAttribute("trackSpeed", String.valueOf(ts.getTrackSpeed())); 184 185 Element elem = new Element("command"); 186 Command cmd = ts.getCommand(); 187 elem.setAttribute("commandType", String.valueOf(cmd.getIntId())); 188 elem.setAttribute("fKey", String.valueOf(ts.getKeyNum())); 189 element.addContent(elem); 190 191 elem = new Element("commandValue"); 192 CommandValue cmdVal = ts.getValue(); 193 elem.setAttribute("valueType", String.valueOf(cmdVal.getType().getIntId())); 194 elem.setAttribute("speedMode", cmdVal.getMode().name); 195 elem.setAttribute("floatValue", String.valueOf(cmdVal.getFloat())); 196 if (!cmdVal.getText().isEmpty()) { 197 elem.setAttribute("textValue", cmdVal.getText()); 198 } 199 element.addContent(elem); 200 201 return element; 202 } 203 204 @Override 205 public boolean load(Element shared, Element perNode) { 206 207 WarrantManager manager = InstanceManager.getDefault(WarrantManager.class); 208 209 if (shared.getChildren().isEmpty()) { 210 return true; 211 } 212 213 List<Element> warrantList = shared.getChildren("warrant"); 214 log.debug("Found {} Warrant objects", warrantList.size()); 215 boolean previouslyLoaded = false; 216 for (Element elem : warrantList) { 217 if (elem.getAttribute("systemName") == null) { 218 log.warn("unexpected null for systemName in elem {}", elem); 219 break; 220 } 221 String sysName = null; 222 if (elem.getAttribute("systemName") != null) { 223 sysName = elem.getAttribute("systemName").getValue(); 224 } 225 String userName = null; 226 if (elem.getAttribute("userName") != null) { 227 userName = elem.getAttribute("userName").getValue(); 228 } 229 boolean SCWa = true; 230 log.debug("loading warrant {}", sysName); 231 Attribute wType = elem.getAttribute("wtype"); 232 if (wType == null) { 233 log.debug("wtype is null for {}", sysName); 234 SCWa = false; 235 } else if (!wType.getValue().equals("SC")) { 236 log.debug("wtype is {} for {}", wType.getValue(), sysName); 237 SCWa = false; 238 } 239 240 long timeToPlatform = 500; 241 Attribute TTP = elem.getAttribute("timeToPlatform"); 242 if (TTP != null) { 243 try { 244 timeToPlatform = TTP.getLongValue(); 245 } catch (DataConversionException e) { 246 log.debug("ignoring DataConversionException (and reverting to default value): {}", e.toString()); 247 } 248 } 249 250 Warrant warrant = manager.createNewWarrant(sysName, userName, SCWa, timeToPlatform); 251 if (warrant == null) { 252 log.info("Warrant \"{}\" (userName={}) previously loaded. This version not loaded.", sysName, userName); 253 previouslyLoaded = true; 254 continue; 255 } 256 previouslyLoaded = false; 257 if (SCWa && warrant instanceof SCWarrant) { 258 if (elem.getAttribute("forward") != null) { 259 ((SCWarrant)warrant).setForward(elem.getAttribute("forward").getValue().equals("true")); 260 } 261 if (elem.getAttribute("speedFactor") != null) { 262 try { 263 ((SCWarrant)warrant).setSpeedFactor(elem.getAttribute("speedFactor").getFloatValue()); 264 } catch (DataConversionException e) { 265 log.warn("error converting speed value"); 266 } 267 } 268 warrant.setNoRamp(SCWa); 269 warrant.setShareRoute(SCWa); 270 } 271 List<Element> orders = elem.getChildren("blockOrder"); 272 int count = 0; 273 for (Element ord : orders) { 274 BlockOrder bo = loadBlockOrder(ord); 275 if (bo == null) { 276 log.error("Bad BlockOrder in warrant \"{}\" elem= {}.", warrant.getDisplayName(), elem.getText()); 277 } else { 278 bo.setIndex(count++); 279 warrant.addBlockOrder(bo); 280 } 281 } 282 String c = elem.getChildText("comment"); 283 if (c != null) { 284 warrant.setComment(c); 285 } 286 287 Element order = elem.getChild("viaOrder"); 288 if (order!=null) { 289 warrant.setViaOrder(loadBlockOrder(order)); 290 } 291 order = elem.getChild("avoidOrder"); 292 if (order!=null) { 293 warrant.setAvoidOrder(loadBlockOrder(order)); 294 } 295 296 if (SCWa) { 297 boolean forward =true; 298 if (elem.getAttribute("forward") != null) { 299 forward = elem.getAttribute("forward").getValue().equals("true"); 300 } 301 if (warrant instanceof SCWarrant) { 302 ((SCWarrant)warrant).setForward(forward); 303 } 304 warrant.setNoRamp(SCWa); 305 warrant.setShareRoute(SCWa); 306 } 307 Element train = elem.getChild("train"); 308 if (train!=null) { 309 loadTrain(train, warrant); 310 } 311 } 312 if (!previouslyLoaded) { 313 // A second pass through the warrant list done to load the commands. This is done so that 314 // references made to warrants in commands are fully specified. Due to ThrottleSetting 315 // Ctor using provideWarrant to establish the referenced warrant. 316 warrantList = shared.getChildren("warrant"); 317 for (Element elem : warrantList) { 318 // boolean forward = true; // variable not used, see GitHub JMRI/JMRI Issue #5661 319 if (elem.getAttribute("systemName") == null) { 320 break; 321 } 322 if (elem.getAttribute("systemName") != null) { 323 String sysName = elem.getAttribute("systemName").getValue(); 324 if (sysName != null) { 325 Warrant warrant = manager.getBySystemName(sysName); 326 List<Element> throttleCmds; 327 if (warrant != null) { 328 log.debug("warrant: {}", warrant.getDisplayName()); 329 throttleCmds = elem.getChildren("throttleCommand"); 330 if (throttleCmds != null && !throttleCmds.isEmpty()) { 331 log.debug("throttleCommand size= {}",throttleCmds.size()); 332 throttleCmds.forEach((e) -> { 333 warrant.addThrottleCommand(loadThrottleCommand(e, warrant)); 334 }); 335 warrant.setTrackSpeeds(); 336 } else { 337 throttleCmds = elem.getChildren("throttleSetting"); 338 if (throttleCmds != null) { 339 log.debug("throttleSetting size= {}",throttleCmds.size()); 340 throttleCmds.forEach((e) -> { 341 warrant.addThrottleCommand(loadThrottleSetting(e, warrant)); 342 }); 343 } 344 } 345 } 346 } 347 } 348 } 349 } 350 return true; 351 } 352 353 private static void loadTrain(Element elem, Warrant warrant) { 354 SpeedUtil speedUtil = warrant.getSpeedUtil(); 355 // if a RosterEntry exists "trainId" will be the Roster Id, otherwise a train name 356 if (elem.getAttribute("trainId") != null) { 357 speedUtil.setRosterId(elem.getAttribute("trainId").getValue()); 358 } 359 if (speedUtil.getRosterEntry() == null) { 360 if (elem.getAttribute("dccAddress") != null) { 361 try { 362 int address = elem.getAttribute("dccAddress").getIntValue(); 363 String type = "L"; 364 if (elem.getAttribute("dccType") != null) { 365 type = elem.getAttribute("dccType").getValue(); 366 } 367 if (!speedUtil.setDccAddress(address, type)) { 368 log.error("dccAddress {}, dccType {} in Warrant {}", 369 address, type, warrant.getDisplayName()); 370 } 371 } catch (org.jdom2.DataConversionException dce) { 372 log.error("{} for dccAddress in Warrant {}", dce, warrant.getDisplayName()); 373 } 374 } 375 } 376 if (elem.getAttribute("runBlind") != null) { 377 warrant.setRunBlind(elem.getAttribute("runBlind").getValue().equals("true")); 378 } 379 if (elem.getAttribute("shareRoute") != null) { 380 warrant.setShareRoute(elem.getAttribute("shareRoute").getValue().equals("true")); 381 } 382 if (elem.getAttribute("noRamp") != null) { 383 warrant.setNoRamp(elem.getAttribute("noRamp").getValue().equals("true")); 384 } 385 if (elem.getAttribute("trainName") != null) { 386 warrant.setTrainName(elem.getAttribute("trainName").getValue()); 387 } 388 } 389 390 private static BlockOrder loadBlockOrder(Element elem) { 391 392 OBlock block; 393 List<Element> blocks = elem.getChildren("block"); 394 if (blocks.size()>1) log.error("More than one block present: {}", blocks.size()); 395 if (blocks.size()>0) { 396 String name = blocks.get(0).getAttribute("systemName").getValue(); 397 block = InstanceManager.getDefault(jmri.jmrit.logix.OBlockManager.class).getOBlock(name); 398 if (block == null) { 399 log.error("No such Block \"{}\" found.", name); 400 return null; 401 } 402 if (log.isDebugEnabled()) log.debug("Load Block {}.", name); 403 } else { 404 log.error("Null BlockOrder element"); 405 return null; 406 } 407 Attribute attr = elem.getAttribute("pathName"); 408 String pathName = null; 409 if (attr != null) { 410 pathName = attr.getValue(); 411 } 412 413 attr = elem.getAttribute("entryName"); 414 String entryName = null; 415 if (attr != null) { 416 entryName =attr.getValue(); 417 } 418 attr = elem.getAttribute("exitName"); 419 String exitName = null; 420 if (attr != null) { 421 exitName =attr.getValue(); 422 } 423 return new BlockOrder(block, pathName, entryName, exitName); 424 } 425 426 private static ThrottleSetting loadThrottleSetting(Element element, Warrant w) { 427 428 ThrottleSetting ts = new ThrottleSetting(); 429 430 Attribute attr = element.getAttribute("elapsedTime"); 431 if (attr != null) { 432 ts.setTime(Long.parseLong(attr.getValue())); 433 } 434 435 Command cmd = null; 436 Element elem = element.getChild("command"); 437 if (elem != null) { 438 attr = elem.getAttribute("commandType"); 439 if (attr != null) { 440 try { 441 cmd = ThrottleSetting.getCommandTypeFromInt(Integer.parseInt(attr.getValue())); 442 ts.setCommand(cmd); 443 } catch (IllegalArgumentException iae) { 444 log.error("{} for {} in warrant {}",iae.getMessage(), ts.toString(), w.getDisplayName()); 445 } 446 } else { 447 log.error("Command type is null for {} in warrant {}", ts.toString(), w.getDisplayName()); 448 } 449 attr = elem.getAttribute("fKey"); 450 if (attr != null) { 451 ts.setKeyNum(Integer.parseInt(attr.getValue())); 452 } 453 } 454 455 elem = element.getChild("commandValue"); 456 ValueType valType = null; 457 SpeedStepMode mode = null; 458 float floatVal = 0; 459 String textVal = ""; 460 if (elem != null) { 461 attr = elem.getAttribute("valueType"); 462 if (attr != null) { 463 try { 464 valType = ThrottleSetting.getValueTypeFromInt(Integer.parseInt(attr.getValue())); 465 } catch (IllegalArgumentException iae) { 466 log.error("{} for throttleSetting {} in warrant {}",iae.getMessage(), ts.toString(), w.getDisplayName()); 467 } 468 } else { 469 log.error("Value type is null for {} in warrant {}", ts.toString(), w.getDisplayName()); 470 } 471 attr = elem.getAttribute("speedMode"); 472 if (attr != null) { 473 mode = SpeedStepMode.getByName(attr.getValue()); 474 } 475 attr = elem.getAttribute("floatValue"); 476 if (attr != null) { 477 floatVal = Float.parseFloat(attr.getValue()); 478 } 479 480 attr = elem.getAttribute("textValue"); 481 if (attr != null) { 482 textVal = attr.getValue(); 483 } 484 } 485 ts.setValue(valType, mode, floatVal, textVal); 486 487 attr = element.getAttribute("trackSpeed"); 488 if (attr != null) { 489 ts.setTrackSpeed(Float.parseFloat(attr.getValue())); 490 } 491 492 attr = element.getAttribute("beanName"); 493 if (attr != null) { 494 String errMsg = ts.setNamedBean(cmd, attr.getValue()); 495 if (errMsg != null) { 496 log.error("{} for {} in warrant {}", errMsg, ts.toString(), w.getDisplayName()); 497 } 498 } 499 return ts; 500 } 501 502 // pre 4.21.3 503// @SuppressFBWarnings(value="NP_LOAD_OF_KNOWN_NULL_VALUE", justification="nothing wrong about a null return") 504 private static ThrottleSetting loadThrottleCommand(Element elem, Warrant w) { 505 long time = 0; 506 try { 507 time = elem.getAttribute("time").getLongValue(); 508 } catch (org.jdom2.DataConversionException dce) { 509 log.warn("error loading throttle command"); 510 } 511 512 Attribute attr = elem.getAttribute("command"); 513 String command; 514 if (attr != null) { 515 command = attr.getValue(); 516 } else { 517 log.error("Command type is null. ThrottleSetting not loaded for warrant {}", w.getDisplayName()); 518 return null; 519 } 520 521 attr = elem.getAttribute("value"); 522 String value = null; 523 if (attr != null) { 524 value =attr.getValue(); 525 } 526 attr = elem.getAttribute("block"); 527 String block = null; 528 if (attr != null) { 529 block =attr.getValue(); 530 } 531 float speed = 0.0f; 532 attr = elem.getAttribute("trackSpeed"); 533 if (attr != null) { 534 try { 535 speed = attr.getFloatValue(); 536 } catch (DataConversionException ex) { 537 speed = 0.0f; 538 log.error("Unable to read speed of command.", ex); 539 } 540 } 541 542 return new ThrottleSetting(time, command, value, block, speed); 543 } 544 545 @Override 546 public int loadOrder(){ 547 return InstanceManager.getDefault(WarrantManager.class).getXMLOrder(); 548 } 549 550 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(WarrantManagerXml.class); 551 552}