001package jmri.implementation; 002 003import java.beans.PropertyChangeEvent; 004import java.beans.PropertyChangeListener; 005import java.beans.PropertyVetoException; 006import java.beans.VetoableChangeListener; 007import java.util.*; 008 009import javax.annotation.Nonnull; 010 011import jmri.*; 012import jmri.jmrit.display.EditorManager; 013import jmri.jmrit.display.layoutEditor.ConnectivityUtil; 014import jmri.jmrit.display.layoutEditor.LayoutBlock; 015import jmri.jmrit.display.layoutEditor.LayoutBlockConnectivityTools; 016import jmri.jmrit.display.layoutEditor.LayoutBlockManager; 017import jmri.jmrit.display.layoutEditor.LayoutEditor; 018import jmri.jmrit.display.layoutEditor.LayoutSlip; 019import jmri.jmrit.display.layoutEditor.LayoutTrackExpectedState; 020import jmri.jmrit.display.layoutEditor.LayoutTurnout; 021import jmri.jmrit.display.layoutEditor.LayoutTurntable; 022import jmri.jmrit.display.layoutEditor.LevelXing; 023import jmri.util.ThreadingUtil; 024 025/** 026 * Default implementation of {@link jmri.SignalMastLogic}. 027 * 028 * @author Kevin Dickerson Copyright (C) 2011 029 */ 030public class DefaultSignalMastLogic extends AbstractNamedBean implements SignalMastLogic, VetoableChangeListener { 031 032 SignalMast source; 033 SignalMast destination; 034 String stopAspect; 035 036 Hashtable<SignalMast, DestinationMast> destList = new Hashtable<>(); 037 LayoutEditor editor; 038 039 LayoutBlock facingBlock = null; 040 LayoutBlock remoteProtectingBlock = null; 041 042 boolean disposing = false; 043 044 /** 045 * Initialise a Signal Mast Logic for a given source Signal Mast. 046 * 047 * @param source The Signal Mast we are configuring an SML for 048 */ 049 public DefaultSignalMastLogic(@Nonnull SignalMast source) { 050 super(source.toString()); // default system name 051 this.source = source; 052 try { 053 this.stopAspect = source.getAppearanceMap().getSpecificAppearance(SignalAppearanceMap.DANGER); 054 this.source.addPropertyChangeListener(propertySourceMastListener); 055 if (source.getAspect() == null) { 056 source.setAspect(stopAspect); 057 } 058 } catch (Exception ex) { 059 log.error("Error while creating Signal Logic", ex); 060 } 061 } 062 063 // Most of the following methods will inherit Javadoc from SignalMastLogic.java 064 /** 065 * {@inheritDoc } 066 */ 067 @Override 068 public void setFacingBlock(LayoutBlock facing) { 069 facingBlock = facing; 070 } 071 072 /** 073 * {@inheritDoc } 074 */ 075 @Override 076 public LayoutBlock getFacingBlock() { 077 return facingBlock; 078 } 079 080 /** 081 * {@inheritDoc } 082 */ 083 @Override 084 public LayoutBlock getProtectingBlock(@Nonnull SignalMast dest) { 085 if (!destList.containsKey(dest)) { 086 return null; 087 } 088 return destList.get(dest).getProtectingBlock(); 089 } 090 091 /** 092 * {@inheritDoc } 093 */ 094 @Override 095 public SignalMast getSourceMast() { 096 return source; 097 } 098 099 /** 100 * {@inheritDoc } 101 */ 102 @Override 103 public void replaceSourceMast(SignalMast oldMast, SignalMast newMast) { 104 if (oldMast != source) { 105 // Old mast does not match new mast so will exit replace 106 return; 107 } 108 source.removePropertyChangeListener(propertySourceMastListener); 109 source = newMast; 110 stopAspect = source.getAppearanceMap().getSpecificAppearance(SignalAppearanceMap.DANGER); 111 source.addPropertyChangeListener(propertySourceMastListener); 112 if (source.getAspect() == null) { 113 source.setAspect(stopAspect); 114 } 115 getDestinationList().forEach(sm -> { 116 DestinationMast destMast = destList.get(sm); 117 if (destMast.getAssociatedSection() != null) { 118 String oldUserName = destMast.getAssociatedSection().getUserName(); 119 String newUserName = source.getDisplayName() + ":" + sm.getDisplayName(); 120 if (oldUserName != null) { 121 InstanceManager.getDefault(NamedBeanHandleManager.class) 122 .renameBean(oldUserName, newUserName, ((NamedBean) destMast.getAssociatedSection())); 123 } else { 124 log.warn("AssociatedSection oldUserName null for destination mast {}, skipped", 125 destMast.getDisplayName()); 126 } 127 } 128 }); 129 firePropertyChange(PROPERTY_UPDATED_SOURCE, oldMast, newMast); 130 } 131 132 /** 133 * {@inheritDoc } 134 */ 135 @Override 136 public void replaceDestinationMast(SignalMast oldMast, SignalMast newMast) { 137 if (!destList.containsKey(oldMast)) { 138 return; 139 } 140 DestinationMast destMast = destList.get(oldMast); 141 destMast.updateDestinationMast(newMast); 142 if (destination == oldMast) { 143 oldMast.removePropertyChangeListener(propertyDestinationMastListener); 144 newMast.addPropertyChangeListener(propertyDestinationMastListener); 145 destination = newMast; 146 setSignalAppearance(); 147 } 148 destList.remove(oldMast); 149 if (destMast.getAssociatedSection() != null) { 150 String oldUserName = destMast.getAssociatedSection().getUserName(); 151 String newUserName = source.getDisplayName() + ":" + newMast.getDisplayName(); 152 if (oldUserName != null) { 153 InstanceManager.getDefault(NamedBeanHandleManager.class) 154 .renameBean(oldUserName, newUserName, destMast.getAssociatedSection()); 155 } else { 156 log.warn("AssociatedSection oldUserName null for destination mast {}, skipped", 157 destMast.getDisplayName()); 158 } 159 } 160 destList.put(newMast, destMast); 161 firePropertyChange(PROPERTY_UPDATED_DESTINATION, oldMast, newMast); 162 } 163 164 /** 165 * {@inheritDoc } 166 */ 167 @Override 168 public void setDestinationMast(SignalMast dest) { 169 if (destList.containsKey(dest)) { 170 // if already present, not a change 171 log.debug("Destination mast '{}' was already defined in SML with this source mast", dest.getDisplayName()); 172 return; 173 } 174 int oldSize = destList.size(); 175 destList.put(dest, new DestinationMast(dest)); 176 //InstanceManager.getDefault(SignalMastLogicManager.class).addDestinationMastToLogic(this, dest); 177 firePropertyChange(PROPERTY_LENGTH, oldSize, destList.size()); 178 // make new dest mast appear in (update of) SignallingSourcePanel Table by having that table listen to PropertyChange Events from SML TODO 179 } 180 181 /** 182 * {@inheritDoc } 183 */ 184 @Override 185 public boolean isDestinationValid(SignalMast dest) { 186 if (dest == null) { 187 return false; 188 } 189 return destList.containsKey(dest); 190 } 191 192 /** 193 * {@inheritDoc } 194 */ 195 @Override 196 public List<SignalMast> getDestinationList() { 197 List<SignalMast> out = new ArrayList<>(); 198 Enumeration<SignalMast> en = destList.keys(); 199 while (en.hasMoreElements()) { 200 out.add(en.nextElement()); 201 } 202 return out; 203 } 204 205 /** 206 * {@inheritDoc } 207 */ 208 @Override 209 public String getComment(SignalMast dest) { 210 if (!destList.containsKey(dest)) { 211 return ""; 212 } 213 return destList.get(dest).getComment(); 214 } 215 216 /** 217 * {@inheritDoc } 218 */ 219 @Override 220 public void setComment(String comment, SignalMast dest) { 221 if (!destList.containsKey(dest)) { 222 return; 223 } 224 destList.get(dest).setComment(comment); 225 } 226 227 /** 228 * {@inheritDoc } 229 */ 230 @Override 231 public void setStore(int store, SignalMast destination) { 232 if (!destList.containsKey(destination)) { 233 return; 234 } 235 destList.get(destination).setStore(store); 236 } 237 238 /** 239 * {@inheritDoc } 240 */ 241 @Override 242 public int getStoreState(SignalMast destination) { 243 if (!destList.containsKey(destination)) { 244 return STORENONE; 245 } 246 return destList.get(destination).getStoreState(); 247 } 248 249 /** 250 * {@inheritDoc } 251 */ 252 @Override 253 public void setEnabled(SignalMast dest) { 254 if (!destList.containsKey(dest)) { 255 return; 256 } 257 destList.get(dest).setEnabled(); 258 } 259 260 /** 261 * {@inheritDoc } 262 */ 263 @Override 264 public void setDisabled(SignalMast dest) { 265 if (!destList.containsKey(dest)) { 266 return; 267 } 268 destList.get(dest).setDisabled(); 269 } 270 271 /** 272 * {@inheritDoc } 273 */ 274 @Override 275 public boolean isEnabled(SignalMast dest) { 276 if (!destList.containsKey(dest)) { 277 return false; 278 } 279 return destList.get(dest).isEnabled(); 280 } 281 282 /** 283 * {@inheritDoc } 284 */ 285 @Override 286 public boolean isActive(SignalMast dest) { 287 if (!destList.containsKey(dest)) { 288 return false; 289 } 290 return destList.get(dest).isActive(); 291 } 292 293 /** 294 * {@inheritDoc } 295 */ 296 @Override 297 public SignalMast getActiveDestination() { 298 for (SignalMast sm : getDestinationList()) { 299 if (destList.get(sm).isActive()) { 300 return sm; 301 } 302 } 303 return null; 304 } 305 306 /** 307 * {@inheritDoc } 308 */ 309 @Override 310 public boolean removeDestination(SignalMast dest) { 311 int oldSize = destList.size(); 312 if (destList.containsKey(dest)) { 313 //InstanceManager.getDefault(SignalMastLogicManager.class).removeDestinationMastToLogic(this, dest); 314 destList.get(dest).dispose(); 315 destList.remove(dest); 316 firePropertyChange(PROPERTY_LENGTH, oldSize, destList.size()); 317 } 318 return destList.isEmpty(); 319 } 320 321 /** 322 * {@inheritDoc } 323 */ 324 @Override 325 public void disableLayoutEditorUse() { 326 destList.values().forEach(dest -> { 327 try { 328 dest.useLayoutEditor(false); 329 } catch (JmriException e) { 330 log.error("Could not disable LayoutEditor ", e); 331 } 332 }); 333 } 334 335 /** 336 * {@inheritDoc } 337 */ 338 @Override 339 public void useLayoutEditor(boolean boo, SignalMast destination) throws JmriException { 340 if (!destList.containsKey(destination)) { 341 return; 342 } 343 if (boo) { 344 log.debug("Set use layout editor"); 345 Set<LayoutEditor> layout = InstanceManager.getDefault(EditorManager.class).getAll(LayoutEditor.class); 346 /*We don't care which layout editor panel the signalmast is on, just so long as 347 the routing is done via layout blocks*/ 348 // TODO: what is this? 349 log.debug("userLayoutEditor finds layout list size is {}", layout.size()); 350 for (LayoutEditor findeditor : layout) { 351 log.debug("layouteditor {}", findeditor.getLayoutName()); 352 if (facingBlock == null) { 353 facingBlock = InstanceManager.getDefault(LayoutBlockManager.class) 354 .getFacingBlockByMast(getSourceMast(), findeditor); 355 } 356 } 357 } 358 destList.get(destination).useLayoutEditor(boo); 359 } 360 361 /** 362 * Add direction sensors to SML 363 * 364 * @return number of errors 365 */ 366 @Override 367 public int setupDirectionSensors() { 368 // iterrate over the signal masts 369 int errorCount = 0; 370 for (SignalMast sm : getDestinationList()) { 371 String displayName = sm.getDisplayName(); 372 Section sec = getAssociatedSection(sm); 373 if (sec != null) { 374 Block thisFacingBlock; 375 Sensor fwd = sec.getForwardBlockingSensor(); 376 Sensor rev = sec.getReverseBlockingSensor(); 377 LayoutBlock lBlock = getFacingBlock(); 378 if (lBlock == null) { 379 try { 380 useLayoutEditor(true, sm); // force a refind 381 } catch (JmriException ex) { 382 continue; 383 } 384 } 385 if (lBlock != null) { 386 thisFacingBlock = lBlock.getBlock(); 387 EntryPoint fwdEntryPoint = sec.getEntryPointFromBlock(thisFacingBlock, Section.FORWARD); 388 EntryPoint revEntryPoint = sec.getEntryPointFromBlock(thisFacingBlock, Section.REVERSE); 389 log.debug("Mast[{}] Sec[{}] Fwd[{}] Rev [{}]", 390 displayName, sec, fwd, rev); 391 if (fwd != null && fwdEntryPoint != null) { 392 addSensor(fwd.getUserName(), Sensor.INACTIVE, sm); 393 log.debug("Mast[{}] Sec[{}] Fwd[{}] fwdEP[{}]", 394 displayName, sec, fwd, 395 fwdEntryPoint.getBlock().getUserName()); 396 397 } else if (rev != null && revEntryPoint != null) { 398 addSensor(rev.getUserName(), Sensor.INACTIVE, sm); 399 log.debug("Mast[{}] Sec[{}] Rev [{}] revEP[{}]", 400 displayName, sec, rev, 401 revEntryPoint.getBlock().getUserName()); 402 403 } else { 404 log.error("Mast[{}] Cannot Establish entry point to protected section", displayName); 405 errorCount += 1; 406 } 407 } else { 408 log.error("Mast[{}] No Facing Block", displayName); 409 errorCount += 1; 410 } 411 } else { 412 log.error("Mast[{}] No Associated Section", displayName); 413 errorCount += 1; 414 } 415 } 416 return errorCount; 417 } 418 419 /** 420 * {@inheritDoc } 421 */ 422 @Override 423 public void removeDirectionSensors() { 424 //TODO find aaway of easilty identifying the ones we added. 425 } 426 427 /** 428 * {@inheritDoc } 429 */ 430 @Override 431 public boolean useLayoutEditor(SignalMast destination) { 432 if (!destList.containsKey(destination)) { 433 return false; 434 } 435 return destList.get(destination).useLayoutEditor(); 436 } 437 438 /** 439 * {@inheritDoc } 440 */ 441 @Override 442 public void useLayoutEditorDetails(boolean turnouts, boolean blocks, SignalMast destination) throws JmriException { 443 if (!destList.containsKey(destination)) { 444 return; 445 } 446 destList.get(destination).useLayoutEditorDetails(turnouts, blocks); 447 } 448 449 /** 450 * {@inheritDoc } 451 */ 452 @Override 453 public boolean useLayoutEditorBlocks(SignalMast destination) { 454 if (!destList.containsKey(destination)) { 455 return false; 456 } 457 return destList.get(destination).useLayoutEditorBlocks(); 458 } 459 460 /** 461 * {@inheritDoc } 462 */ 463 @Override 464 public boolean useLayoutEditorTurnouts(SignalMast destination) { 465 if (!destList.containsKey(destination)) { 466 return false; 467 } 468 return destList.get(destination).useLayoutEditorTurnouts(); 469 } 470 471 /** 472 * {@inheritDoc } 473 */ 474 @Override 475 public Section getAssociatedSection(SignalMast destination) { 476 if (!destList.containsKey(destination)) { 477 return null; 478 } 479 return destList.get(destination).getAssociatedSection(); 480 } 481 482 /** 483 * {@inheritDoc } 484 */ 485 @Override 486 public void setAssociatedSection(Section sec, SignalMast destination) { 487 if (!destList.containsKey(destination)) { 488 return; 489 } 490 destList.get(destination).setAssociatedSection(sec); 491 } 492 493 /** 494 * {@inheritDoc } 495 */ 496 @Override 497 public boolean allowAutoMaticSignalMastGeneration(SignalMast destination) { 498 if (!destList.containsKey(destination)) { 499 return false; 500 } 501 return destList.get(destination).allowAutoSignalMastGen(); 502 } 503 504 /** 505 * {@inheritDoc } 506 */ 507 @Override 508 public void allowAutoMaticSignalMastGeneration(boolean allow, SignalMast destination) { 509 if (!destList.containsKey(destination)) { 510 return; 511 } 512 destList.get(destination).allowAutoSignalMastGen(allow); 513 } 514 515 /** 516 * {@inheritDoc } 517 */ 518 @Override 519 public void allowTurnoutLock(boolean lock, SignalMast destination) { 520 if (!destList.containsKey(destination)) { 521 return; 522 } 523 destList.get(destination).allowTurnoutLock(lock); 524 } 525 526 /** 527 * {@inheritDoc } 528 */ 529 @Override 530 public boolean isTurnoutLockAllowed(SignalMast destination) { 531 if (!destList.containsKey(destination)) { 532 return false; 533 } 534 return destList.get(destination).isTurnoutLockAllowed(); 535 } 536 537 /** 538 * {@inheritDoc } 539 */ 540 @Override 541 public void setTurnouts(Hashtable<NamedBeanHandle<Turnout>, Integer> turnouts, SignalMast destination) { 542 if (!destList.containsKey(destination)) { 543 return; 544 } 545 destList.get(destination).setTurnouts(turnouts); 546 } 547 548 /** 549 * {@inheritDoc } 550 */ 551 @Override 552 public void setAutoTurnouts(Hashtable<Turnout, Integer> turnouts, SignalMast destination) { 553 if (!destList.containsKey(destination)) { 554 return; 555 } 556 destList.get(destination).setAutoTurnouts(turnouts); 557 } 558 559 /** 560 * {@inheritDoc } 561 */ 562 @Override 563 public void setBlocks(Hashtable<Block, Integer> blocks, SignalMast destination) { 564 if (!destList.containsKey(destination)) { 565 return; 566 } 567 destList.get(destination).setBlocks(blocks); 568 } 569 570 /** 571 * {@inheritDoc } 572 */ 573 @Override 574 public void setAutoBlocks(LinkedHashMap<Block, Integer> blocks, SignalMast destination) { 575 if (!destList.containsKey(destination)) { 576 return; 577 } 578 destList.get(destination).setAutoBlocks(blocks); 579 } 580 581 /** 582 * {@inheritDoc } 583 */ 584 @Override 585 public void setMasts(Hashtable<SignalMast, String> masts, SignalMast destination) { 586 if (!destList.containsKey(destination)) { 587 return; 588 } 589 destList.get(destination).setMasts(masts); 590 } 591 592 /** 593 * {@inheritDoc } 594 */ 595 @Override 596 public void setAutoMasts(Hashtable<SignalMast, String> masts, SignalMast destination) { 597 if (!destList.containsKey(destination)) { 598 return; 599 } 600 destList.get(destination).setAutoMasts(masts, true); 601 } 602 603 /** 604 * {@inheritDoc } 605 */ 606 @Override 607 public void setSensors(Hashtable<NamedBeanHandle<Sensor>, Integer> sensors, SignalMast destination) { 608 if (!destList.containsKey(destination)) { 609 return; 610 } 611 destList.get(destination).setSensors(sensors); 612 } 613 614 /** 615 * {@inheritDoc } 616 */ 617 @Override 618 public void addSensor(String sensorName, int state, SignalMast destination) { 619 if (!destList.containsKey(destination)) { 620 return; 621 } 622 Sensor sen = InstanceManager.sensorManagerInstance().getSensor(sensorName); 623 if (sen != null) { 624 NamedBeanHandle<Sensor> namedSensor = InstanceManager.getDefault(NamedBeanHandleManager.class) 625 .getNamedBeanHandle(sensorName, sen); 626 destList.get(destination).addSensor(namedSensor, state); 627 } 628 } 629 630 /** 631 * {@inheritDoc } 632 */ 633 @Override 634 public void removeSensor(String sensorName, SignalMast destination) { 635 Sensor sen = InstanceManager.sensorManagerInstance().getSensor(sensorName); 636 removeSensor(sen, destination); 637 } 638 639 public void removeSensor(Sensor sen, SignalMast destination) { 640 if (!destList.containsKey(destination)) { 641 return; 642 } 643 if (sen != null) { 644 destList.get(destination).removeSensor(sen); 645 } 646 } 647 648 /** 649 * {@inheritDoc } 650 */ 651 @Override 652 public List<Block> getBlocks(SignalMast destination) { 653 if (!destList.containsKey(destination)) { 654 return new ArrayList<>(); 655 } 656 return destList.get(destination).getBlocks(); 657 } 658 659 /** 660 * {@inheritDoc } 661 */ 662 @Override 663 public List<Block> getAutoBlocks(SignalMast destination) { 664 if (!destList.containsKey(destination)) { 665 return new ArrayList<>(); 666 } 667 return destList.get(destination).getAutoBlocks(); 668 } 669 670 /** 671 * {@inheritDoc } 672 */ 673 @Override 674 public List<Block> getAutoBlocksBetweenMasts(SignalMast destination) { 675 if (!destList.containsKey(destination)) { 676 return new ArrayList<>(); 677 } 678 return destList.get(destination).getAutoBlocksBetweenMasts(); 679 } 680 681 /** 682 * {@inheritDoc } 683 */ 684 @Override 685 public List<Turnout> getTurnouts(SignalMast destination) { 686 if (!destList.containsKey(destination)) { 687 return new ArrayList<>(); 688 } 689 return destList.get(destination).getTurnouts(); 690 } 691 692 /** 693 * {@inheritDoc } 694 */ 695 @Override 696 public List<NamedBeanHandle<Turnout>> getNamedTurnouts(SignalMast destination) { 697 if (!destList.containsKey(destination)) { 698 return new ArrayList<>(); 699 } 700 return destList.get(destination).getNamedTurnouts(); 701 } 702 703 public void removeTurnout(Turnout turn, SignalMast destination) { 704 if (!destList.containsKey(destination)) { 705 return; 706 } 707 708 if (turn != null) { 709 destList.get(destination).removeTurnout(turn); 710 } 711 } 712 713 /** 714 * {@inheritDoc } 715 */ 716 @Override 717 public List<Turnout> getAutoTurnouts(SignalMast destination) { 718 if (!destList.containsKey(destination)) { 719 return new ArrayList<>(); 720 } 721 return destList.get(destination).getAutoTurnouts(); 722 } 723 724 /** 725 * {@inheritDoc } 726 */ 727 @Override 728 public List<Sensor> getSensors(SignalMast destination) { 729 if (!destList.containsKey(destination)) { 730 return new ArrayList<>(); 731 } 732 return destList.get(destination).getSensors(); 733 } 734 735 /** 736 * {@inheritDoc } 737 */ 738 @Override 739 public List<NamedBeanHandle<Sensor>> getNamedSensors(SignalMast destination) { 740 if (!destList.containsKey(destination)) { 741 return new ArrayList<>(); 742 } 743 return destList.get(destination).getNamedSensors(); 744 } 745 746 /** 747 * {@inheritDoc } 748 */ 749 @Override 750 public List<SignalMast> getSignalMasts(SignalMast destination) { 751 if (!destList.containsKey(destination)) { 752 return new ArrayList<>(); 753 } 754 return destList.get(destination).getSignalMasts(); 755 } 756 757 /** 758 * {@inheritDoc } 759 */ 760 @Override 761 public List<SignalMast> getAutoMasts(SignalMast destination) { 762 if (!destList.containsKey(destination)) { 763 return new ArrayList<>(); 764 } 765 return destList.get(destination).getAutoSignalMasts(); 766 } 767 768 /** 769 * {@inheritDoc } 770 */ 771 @Override 772 public void initialise() { 773 Enumeration<SignalMast> en = destList.keys(); 774 while (en.hasMoreElements()) { 775 destList.get(en.nextElement()).initialise(); 776 } 777 } 778 779 /** 780 * {@inheritDoc } 781 */ 782 @Override 783 public void initialise(SignalMast destination) { 784 if (disposing) { 785 return; 786 } 787 788 if (!destList.containsKey(destination)) { 789 return; 790 } 791 destList.get(destination).initialise(); 792 } 793 794 /** 795 * {@inheritDoc } 796 */ 797 @Override 798 public LinkedHashMap<Block, Integer> setupLayoutEditorTurnoutDetails(List<LayoutBlock> blks, SignalMast destination) { 799 if (disposing) { 800 return new LinkedHashMap<>(); 801 } 802 803 if (!destList.containsKey(destination)) { 804 return new LinkedHashMap<>(); 805 } 806 return destList.get(destination).setupLayoutEditorTurnoutDetails(blks); 807 } 808 809 /** 810 * {@inheritDoc } 811 */ 812 @Override 813 public void setupLayoutEditorDetails() { 814 if (disposing) { 815 return; 816 } 817 Enumeration<SignalMast> en = destList.keys(); 818 while (en.hasMoreElements()) { 819 try { 820 destList.get(en.nextElement()).setupLayoutEditorDetails(); 821 } catch (JmriException e) { 822 //Considered normal if no route is valid on a Layout Editor panel 823 } 824 } 825 } 826 827 /** 828 * Check if routes to the destination Signal Mast are clear. 829 * 830 * @return true if the path to the next signal is clear 831 */ 832 boolean checkStates() { 833 SignalMast oldActiveMast = destination; 834 if (destination != null) { 835 firePropertyChange(PROPERTY_STATE, oldActiveMast, null); 836 log.debug("Remove listener from destination"); 837 destination.removePropertyChangeListener(propertyDestinationMastListener); 838 if (destList.containsKey(destination)) { 839 destList.get(destination).clearTurnoutLock(); 840 } 841 } 842 843 Enumeration<SignalMast> en = destList.keys(); 844 log.debug("checkStates enumerates over {} mast(s)", destList.size()); 845 while (en.hasMoreElements()) { 846 SignalMast key = en.nextElement(); 847 log.debug(" Destination mast {}", key.getDisplayName()); 848 log.debug(" isEnabled: {}", (destList.get(key)).isEnabled()); 849 log.debug(" isActive: {}", destList.get(key).isActive()); 850 851 if ((destList.get(key)).isEnabled() && (destList.get(key).isActive())) { 852 destination = key; 853 log.debug(" Add listener to destination"); 854 destination.addPropertyChangeListener(propertyDestinationMastListener); 855 log.debug(" firePropertyChange: \"state\""); 856 firePropertyChange(PROPERTY_STATE, oldActiveMast, destination); 857 destList.get(key).lockTurnouts(); 858 return true; 859 } 860 } 861 return false; 862 } 863 864 /** 865 * {@inheritDoc } 866 */ 867 @Override 868 public boolean areBlocksIncluded(List<Block> blks) { 869 Enumeration<SignalMast> en = destList.keys(); 870 while (en.hasMoreElements()) { 871 SignalMast dm = en.nextElement(); 872 boolean included; 873 for (int i = 0; i < blks.size(); i++) { 874 included = destList.get(dm).isBlockIncluded(blks.get(i)); 875 if (included) { 876 return true; 877 } 878 included = destList.get(dm).isAutoBlockIncluded(blks.get(i)); 879 if (included) { 880 return true; 881 } 882 } 883 } 884 return false; 885 } 886 887 /** 888 * {@inheritDoc } 889 */ 890 @Override 891 public int getBlockState(Block block, SignalMast destination) { 892 if (!destList.containsKey(destination)) { 893 return -1; 894 } 895 return destList.get(destination).getBlockState(block); 896 } 897 898 /** 899 * {@inheritDoc } 900 */ 901 @Override 902 public boolean isBlockIncluded(Block block, SignalMast destination) { 903 if (!destList.containsKey(destination)) { 904 return false; 905 } 906 return destList.get(destination).isBlockIncluded(block); 907 } 908 909 /** 910 * {@inheritDoc } 911 */ 912 @Override 913 public boolean isTurnoutIncluded(Turnout turnout, SignalMast destination) { 914 if (!destList.containsKey(destination)) { 915 return false; 916 } 917 return destList.get(destination).isTurnoutIncluded(turnout); 918 } 919 920 /** 921 * {@inheritDoc } 922 */ 923 @Override 924 public boolean isSensorIncluded(Sensor sensor, SignalMast destination) { 925 if (!destList.containsKey(destination)) { 926 return false; 927 } 928 return destList.get(destination).isSensorIncluded(sensor); 929 } 930 931 /** 932 * {@inheritDoc } 933 */ 934 @Override 935 public boolean isSignalMastIncluded(SignalMast signal, SignalMast destination) { 936 if (!destList.containsKey(destination)) { 937 return false; 938 } 939 return destList.get(destination).isSignalMastIncluded(signal); 940 } 941 942 /** 943 * {@inheritDoc } 944 */ 945 @Override 946 public int getAutoBlockState(Block block, SignalMast destination) { 947 if (!destList.containsKey(destination)) { 948 return -1; 949 } 950 return destList.get(destination).getAutoBlockState(block); 951 } 952 953 /** 954 * {@inheritDoc } 955 */ 956 @Override 957 public int getSensorState(Sensor sensor, SignalMast destination) { 958 if (!destList.containsKey(destination)) { 959 return -1; 960 } 961 return destList.get(destination).getSensorState(sensor); 962 } 963 964 /** 965 * {@inheritDoc } 966 */ 967 @Override 968 public int getTurnoutState(Turnout turnout, SignalMast destination) { 969 if (!destList.containsKey(destination)) { 970 return -1; 971 } 972 return destList.get(destination).getTurnoutState(turnout); 973 } 974 975 /** 976 * {@inheritDoc } 977 */ 978 @Override 979 public int getAutoTurnoutState(Turnout turnout, SignalMast destination) { 980 if (!destList.containsKey(destination)) { 981 return -1; 982 } 983 return destList.get(destination).getAutoTurnoutState(turnout); 984 } 985 986 /** 987 * {@inheritDoc } 988 */ 989 @Override 990 public String getSignalMastState(SignalMast mast, SignalMast destination) { 991 if (!destList.containsKey(destination)) { 992 return null; 993 } 994 return destList.get(destination).getSignalMastState(mast); 995 } 996 997 /** 998 * {@inheritDoc } 999 */ 1000 @Override 1001 public String getAutoSignalMastState(SignalMast mast, SignalMast destination) { 1002 if (!destList.containsKey(destination)) { 1003 return null; 1004 } 1005 return destList.get(destination).getAutoSignalMastState(mast); 1006 } 1007 1008 /** 1009 * {@inheritDoc } 1010 */ 1011 @Override 1012 public float getMaximumSpeed(SignalMast destination) { 1013 if (!destList.containsKey(destination)) { 1014 return -1; 1015 } 1016 return destList.get(destination).getMinimumSpeed(); 1017 } 1018 1019 volatile boolean inWait = false; 1020 1021 /** 1022 * Before going active or checking that we can go active, wait 500ms 1023 * for things to settle down to help prevent a race condition. 1024 */ 1025 synchronized void setSignalAppearance() { 1026 log.debug("setMastAppearance (Aspect) called for {}", source.getDisplayName()); 1027 if (inWait) { 1028 log.debug("setMastAppearance (Aspect) called with inWait set, returning"); 1029 return; 1030 } 1031 inWait = true; 1032 1033 // The next line forces a single initialization of InstanceManager.getDefault(SignalSpeedMap.class) 1034 // before launching parallel threads 1035 InstanceManager.getDefault(SignalSpeedMap.class); 1036 1037 // The next line forces a single initialization of InstanceManager.getDefault(SignalMastLogicManager.class) 1038 // before launching delay 1039 int tempDelay = InstanceManager.getDefault(SignalMastLogicManager.class).getSignalLogicDelay() / 2; 1040 log.debug("SignalMastLogicManager started (delay)"); 1041 ThreadingUtil.runOnLayoutDelayed( 1042 () -> { 1043 setMastAppearance(); 1044 inWait = false; 1045 }, 1046 tempDelay 1047 ); 1048 1049 } 1050 1051 /** 1052 * Evaluate the destination signal mast Aspect and set ours accordingly. 1053 */ 1054 void setMastAppearance() { 1055 log.debug("Set source Signal Mast Aspect"); 1056 if (getSourceMast().getHeld()) { 1057 log.debug("Signal is at a Held state so will set to the aspect defined for Held or Danger"); 1058 1059 String heldAspect = getSourceMast().getAppearanceMap().getSpecificAppearance(SignalAppearanceMap.HELD); 1060 if (heldAspect != null) { 1061 log.debug(" Setting to HELD value of {}", heldAspect); 1062 ThreadingUtil.runOnLayout(() -> { 1063 getSourceMast().setAspect(heldAspect); 1064 }); 1065 } else { 1066 String dangerAspect = getSourceMast().getAppearanceMap().getSpecificAppearance(SignalAppearanceMap.DANGER); 1067 log.debug(" Setting to DANGER value of {}", dangerAspect); 1068 ThreadingUtil.runOnLayout(() -> { 1069 getSourceMast().setAspect(dangerAspect); 1070 }); 1071 } 1072 return; 1073 } 1074 if (!checkStates()) { 1075 log.debug("Advanced routes not clear, set Stop aspect"); 1076 getSourceMast().setAspect(stopAspect); 1077 return; 1078 } 1079 String[] advancedAspect; 1080 if (destination.getHeld()) { 1081 if (destination.getAppearanceMap().getSpecificAppearance(SignalAppearanceMap.HELD) != null) { 1082 advancedAspect = getSourceMast().getAppearanceMap().getValidAspectsForAdvancedAspect(destination.getAppearanceMap().getSpecificAppearance(SignalAppearanceMap.HELD)); 1083 } else { 1084 advancedAspect = getSourceMast().getAppearanceMap().getValidAspectsForAdvancedAspect(destination.getAppearanceMap().getSpecificAppearance(SignalAppearanceMap.DANGER)); 1085 } 1086 } else { 1087 advancedAspect = getSourceMast().getAppearanceMap().getValidAspectsForAdvancedAspect(destination.getAspect()); 1088 } 1089 1090 log.debug("distant aspect is {}", destination.getAspect()); 1091 log.debug("advanced aspect is {}", advancedAspect != null ? advancedAspect : "<null>"); 1092 1093 if (advancedAspect != null) { 1094 String aspect = stopAspect; 1095 if (destList.get(destination).permissiveBlock) { 1096 if (!getSourceMast().isPermissiveSmlDisabled()) { 1097 //if a block is in a permissive state then we set the permissive appearance 1098 aspect = getSourceMast().getAppearanceMap().getSpecificAppearance(SignalAppearanceMap.PERMISSIVE); 1099 } 1100 } else { 1101 for (String advancedAspect1 : advancedAspect) { 1102 if (!getSourceMast().isAspectDisabled(advancedAspect1)) { 1103 aspect = advancedAspect1; 1104 break; 1105 } 1106 } 1107 List<Integer> divergAspects = new ArrayList<>(); 1108 List<Integer> nonDivergAspects = new ArrayList<>(); 1109 List<Integer> eitherAspects = new ArrayList<>(); 1110 if (advancedAspect.length > 1) { 1111 float maxSigSpeed = -1; 1112 float maxPathSpeed = destList.get(destination).getMinimumSpeed(); 1113 boolean divergRoute = destList.get(destination).turnoutThrown; 1114 1115 log.debug("Diverging route? {}", divergRoute); 1116 boolean divergFlagsAvailable = false; 1117 //We split the aspects into two lists, one with diverging flag set, the other without. 1118 for (int i = 0; i < advancedAspect.length; i++) { 1119 String div = null; 1120 if (!getSourceMast().isAspectDisabled(advancedAspect[i])) { 1121 div = (String) getSourceMast().getSignalSystem().getProperty(advancedAspect[i], "route"); 1122 } 1123 if (div != null) { 1124 if (div.equals("Diverging")) { 1125 log.debug("Aspect {} added as Diverging Route", advancedAspect[i]); 1126 divergAspects.add(i); 1127 divergFlagsAvailable = true; 1128 log.debug("Using Diverging Flag"); 1129 } else if (div.equals("Either")) { 1130 log.debug("Aspect {} added as both Diverging and Normal Route", advancedAspect[i]); 1131 nonDivergAspects.add(i); 1132 divergAspects.add(i); 1133 divergFlagsAvailable = true; 1134 eitherAspects.add(i); 1135 log.debug("Using Diverging Flag"); 1136 } else { 1137 log.debug("Aspect {} added as Normal Route", advancedAspect[i]); 1138 nonDivergAspects.add(i); 1139 log.debug("Aspect {} added as Normal Route", advancedAspect[i]); 1140 } 1141 } else { 1142 nonDivergAspects.add(i); 1143 log.debug("Aspect {} added as Normal Route", advancedAspect[i]); 1144 } 1145 } 1146 if ((eitherAspects.equals(divergAspects)) && (divergAspects.size() < nonDivergAspects.size())) { 1147 //There are no unique diverging aspects 1148 log.debug("'Either' aspects equals divergAspects and is less than non-diverging aspects"); 1149 divergFlagsAvailable = false; 1150 } 1151 log.debug("path max speed : {}", maxPathSpeed); 1152 for (int i = 0; i < advancedAspect.length; i++) { 1153 if (!getSourceMast().isAspectDisabled(advancedAspect[i])) { 1154 String strSpeed = (String) getSourceMast().getSignalSystem().getProperty(advancedAspect[i], "speed"); 1155 log.debug("Aspect Speed = {} for aspect {}", strSpeed, advancedAspect[i]); 1156 /* if the diverg flags available is set and the diverg aspect 1157 array contains the entry then we will check this aspect. 1158 1159 If the diverg flag has not been set then we will check. 1160 */ 1161 log.debug("advanced aspect {}",advancedAspect[i]); 1162 if ((divergRoute && (divergFlagsAvailable) && (divergAspects.contains(i))) || ((divergRoute && !divergFlagsAvailable) || (!divergRoute)) && (nonDivergAspects.contains(i))) { 1163 log.debug("In list"); 1164 if ((strSpeed != null) && (!strSpeed.isEmpty())) { 1165 float speed = 0.0f; 1166 try { 1167 speed = Float.parseFloat(strSpeed); 1168 } catch (NumberFormatException nx) { 1169 // not a number, perhaps a name? 1170 try { 1171 speed = InstanceManager.getDefault(SignalSpeedMap.class).getSpeed(strSpeed); 1172 } catch (IllegalArgumentException ex) { 1173 // not a name either 1174 log.warn("Using speed = 0.0 because could not understand \"{}\"", strSpeed); 1175 } 1176 } 1177 //Integer state = Integer.parseInt(strSpeed); 1178 /* This pics out either the highest speed signal if there 1179 * is no block speed specified or the highest speed signal 1180 * that is under the minimum block speed. 1181 */ 1182 log.debug("{} signal state speed {} maxSigSpeed {} maxPathSpeed {}", destination.getDisplayName(), speed, maxSigSpeed, maxPathSpeed); 1183 if (maxPathSpeed == 0) { 1184 if (maxSigSpeed == -1) { 1185 log.debug("min speed on this route is equal to 0 so will set this as our max speed"); 1186 maxSigSpeed = speed; 1187 aspect = advancedAspect[i]; 1188 log.debug("Aspect to set is {}", aspect); 1189 } else if (speed > maxSigSpeed) { 1190 log.debug("new speed is faster than old will use this"); 1191 maxSigSpeed = speed; 1192 aspect = advancedAspect[i]; 1193 log.debug("Aspect to set is {}", aspect); 1194 } 1195 } else if ((speed > maxSigSpeed) && (maxSigSpeed < maxPathSpeed) && (speed <= maxPathSpeed)) { 1196 //Only set the speed to the lowest if the max speed is greater than the path speed 1197 //and the new speed is less than the last max speed 1198 log.debug("our minimum speed on this route is less than our state speed, we will set this as our max speed"); 1199 maxSigSpeed = speed; 1200 aspect = advancedAspect[i]; 1201 log.debug("Aspect to set is {}", aspect); 1202 } else if ((maxSigSpeed > maxPathSpeed) && (speed < maxSigSpeed)) { 1203 log.debug("our max signal speed is greater than our path speed on this route, our speed is less that the maxSigSpeed"); 1204 maxSigSpeed = speed; 1205 aspect = advancedAspect[i]; 1206 log.debug("Aspect to set is {}", aspect); 1207 1208 } else if (maxSigSpeed == -1) { 1209 log.debug("maxSigSpeed returned as -1"); 1210 maxSigSpeed = speed; 1211 aspect = advancedAspect[i]; 1212 log.debug("Aspect to set is {}", aspect); 1213 } 1214 } 1215 } 1216 } else { 1217 log.debug("Aspect has been disabled {}", advancedAspect[i]); 1218 } 1219 } 1220 } 1221 } 1222 if ((aspect != null) && (!aspect.isEmpty())) { 1223 log.debug("setMastAppearance setting aspect \"{}\"", aspect); 1224 String aspectSet = aspect; // for lambda 1225 try { 1226 ThreadingUtil.runOnLayout(() -> { 1227 getSourceMast().setAspect(aspectSet); 1228 }); 1229 } catch (Exception ex) { 1230 log.error("Exception while setting Signal Logic", ex); 1231 } 1232 return; 1233 } 1234 } 1235 log.debug("Aspect returned is not valid, setting stop"); 1236 ThreadingUtil.runOnLayout(() -> { 1237 getSourceMast().setAspect(stopAspect); 1238 }); 1239 } 1240 1241 /** 1242 * {@inheritDoc } 1243 */ 1244 @Override 1245 public void setConflictingLogic(SignalMast sm, LevelXing lx) { 1246 if (sm == null) { 1247 return; 1248 } 1249 log.debug("setConflicting logic mast {}", sm.getDisplayName()); 1250 if (sm == source) { 1251 log.debug("source is us so exit"); 1252 return; 1253 } 1254 Enumeration<SignalMast> en = destList.keys(); 1255 while (en.hasMoreElements()) { 1256 SignalMast dm = en.nextElement(); 1257 if (destList.get(dm).isBlockIncluded(lx.getLayoutBlockAC())) { 1258 destList.get(dm).addAutoSignalMast(sm); 1259 } else if (destList.get(dm).isBlockIncluded(lx.getLayoutBlockBD())) { 1260 destList.get(dm).addAutoSignalMast(sm); 1261 } else if (destList.get(dm).isAutoBlockIncluded(lx.getLayoutBlockAC())) { 1262 destList.get(dm).addAutoSignalMast(sm); 1263 } else if (destList.get(dm).isAutoBlockIncluded(lx.getLayoutBlockBD())) { 1264 destList.get(dm).addAutoSignalMast(sm); 1265 } else { 1266 log.debug("Block not found"); 1267 } 1268 } 1269 } 1270 1271 /** 1272 * {@inheritDoc } 1273 */ 1274 @Override 1275 public void removeConflictingLogic(SignalMast sm, LevelXing lx) { 1276 if (sm == source) { 1277 return; 1278 } 1279 Enumeration<SignalMast> en = destList.keys(); 1280 while (en.hasMoreElements()) { 1281 SignalMast dm = en.nextElement(); 1282 if (destList.get(dm).isBlockIncluded(lx.getLayoutBlockAC())) { 1283 destList.get(dm).removeAutoSignalMast(sm); 1284 } else if (destList.get(dm).isBlockIncluded(lx.getLayoutBlockBD())) { 1285 destList.get(dm).removeAutoSignalMast(sm); 1286 } 1287 } 1288 } 1289 1290 /** 1291 * Class to store SML properties for a destination mast paired with this 1292 * source mast. 1293 */ 1294 private class DestinationMast { 1295 1296 LayoutBlock destinationBlock = null; 1297 LayoutBlock protectingBlock = null; //this is the block that the source signal is protecting 1298 1299 List<NamedBeanSetting> userSetTurnouts = new ArrayList<>(0); 1300 Hashtable<Turnout, Integer> autoTurnouts = new Hashtable<>(0); 1301 //Hashtable<Turnout, Boolean> turnoutThroats = new Hashtable<Turnout, Boolean>(0); 1302 //Hashtable<Turnout, Boolean> autoTurnoutThroats = new Hashtable<Turnout, Boolean>(0); 1303 1304 List<NamedBeanSetting> userSetMasts = new ArrayList<>(0); 1305 Hashtable<SignalMast, String> autoMasts = new Hashtable<>(0); 1306 List<NamedBeanSetting> userSetSensors = new ArrayList<>(0); 1307 List<NamedBeanSetting> userSetBlocks = new ArrayList<>(0); 1308 boolean turnoutThrown = false; 1309 boolean permissiveBlock = false; 1310 boolean disposed = false; 1311 1312 List<LevelXing> blockInXings = new ArrayList<>(); 1313 1314 //autoBlocks are for those automatically generated by the system. 1315 LinkedHashMap<Block, Integer> autoBlocks = new LinkedHashMap<>(0); 1316 1317 List<Block> xingAutoBlocks = new ArrayList<>(0); 1318 List<Block> dblCrossoverAutoBlocks = new ArrayList<>(0); 1319 SignalMast destinationSignalMast; 1320 boolean active = false; 1321 boolean destMastInit = false; 1322 1323 float minimumBlockSpeed = 0.0f; 1324 1325 boolean useLayoutEditor = false; 1326 boolean useLayoutEditorTurnouts = false; 1327 boolean useLayoutEditorBlocks = false; 1328 boolean lockTurnouts = false; 1329 1330 NamedBeanHandle<Section> associatedSection = null; 1331 1332 DestinationMast(SignalMast destination) { 1333 this.destinationSignalMast = destination; 1334 if (destination.getAspect() == null) { 1335 try { 1336 destination.setAspect(destination.getAppearanceMap().getSpecificAppearance(SignalAppearanceMap.DANGER)); 1337 } catch (Exception ex) { 1338 log.error("Error while creating Signal Logic", ex); 1339 } 1340 } 1341 } 1342 1343 void updateDestinationMast(SignalMast newMast) { 1344 destinationSignalMast = newMast; 1345 if (destinationSignalMast.getAspect() == null) { 1346 try { 1347 destinationSignalMast.setAspect(destinationSignalMast.getAppearanceMap().getSpecificAppearance(SignalAppearanceMap.DANGER)); 1348 } catch (Exception ex) { 1349 log.error("Error while creating Signal Logic", ex); 1350 } 1351 } 1352 } 1353 1354 LayoutBlock getProtectingBlock() { 1355 return protectingBlock; 1356 } 1357 1358 String getDisplayName() { 1359 return destinationSignalMast.getDisplayName(); 1360 } 1361 1362 String comment; 1363 1364 String getComment() { 1365 return comment; 1366 } 1367 1368 void setComment(String comment) { 1369 String old = this.comment; 1370 this.comment = comment; 1371 firePropertyChange(PROPERTY_COMMENT, old, comment); 1372 } 1373 1374 boolean isActive() { 1375 if (disposed) { 1376 log.error("checkState called even though this has been disposed of"); 1377 return false; 1378 } 1379 return active; 1380 } 1381 1382 float getMinimumSpeed() { 1383 return minimumBlockSpeed; 1384 } 1385 1386 boolean enable = true; 1387 1388 void setEnabled() { 1389 enable = true; 1390 firePropertyChange(PROPERTY_ENABLED, false, this.destinationSignalMast); 1391 } 1392 1393 void setDisabled() { 1394 enable = false; 1395 firePropertyChange(PROPERTY_ENABLED, true, this.destinationSignalMast); 1396 } 1397 1398 boolean isEnabled() { 1399 return enable; 1400 } 1401 1402 int store = STOREALL; 1403 1404 void setStore(int store) { 1405 this.store = store; 1406 } 1407 1408 int getStoreState() { 1409 return store; 1410 } 1411 1412 void setAssociatedSection(Section section) { 1413 if (section != null && (!useLayoutEditor || !useLayoutEditorBlocks)) { 1414 log.warn("This Logic {} to {} is not using the Layout Editor or its Blocks, the associated Section will not be populated correctly", source.getDisplayName(), destinationSignalMast.getDisplayName()); 1415 } 1416 if (section == null) { 1417 associatedSection = null; 1418 return; 1419 } 1420 associatedSection = InstanceManager.getDefault(NamedBeanHandleManager.class).getNamedBeanHandle(section.getDisplayName(), section); 1421 if (!autoBlocks.isEmpty()) { // associatedSection is guaranteed to exist 1422 createSectionDetails(); 1423 } 1424 } 1425 1426 Section getAssociatedSection() { 1427 if (associatedSection != null) { 1428 return associatedSection.getBean(); 1429 } 1430 return null; 1431 } 1432 1433 void createSectionDetails() { 1434 getAssociatedSection().removeAllBlocksFromSection(); 1435 getAutoBlocksBetweenMasts().forEach(key -> { 1436 getAssociatedSection().addBlock(key); 1437 }); 1438 String dir = Path.decodeDirection(getFacingBlock().getNeighbourDirection(getProtectingBlock())); 1439 EntryPoint ep = new EntryPoint(getProtectingBlock().getBlock(), getFacingBlock().getBlock(), dir); 1440 ep.setTypeForward(); 1441 getAssociatedSection().addToForwardList(ep); 1442 1443 LayoutBlock proDestLBlock = InstanceManager.getDefault(LayoutBlockManager.class).getProtectedBlockByNamedBean(destinationSignalMast, destinationBlock.getMaxConnectedPanel()); 1444 if (proDestLBlock != null) { 1445 log.debug("Add protecting Block {}", proDestLBlock.getDisplayName()); 1446 dir = Path.decodeDirection(proDestLBlock.getNeighbourDirection(destinationBlock)); 1447 ep = new EntryPoint(destinationBlock.getBlock(), proDestLBlock.getBlock(), dir); 1448 ep.setTypeReverse(); 1449 getAssociatedSection().addToReverseList(ep); 1450 } else { 1451 log.debug(" ### Protecting Block not found ### "); 1452 } 1453 } 1454 1455 boolean isTurnoutLockAllowed() { 1456 return lockTurnouts; 1457 } 1458 1459 void allowTurnoutLock(boolean lock) { 1460 if (lockTurnouts == lock) { 1461 return; 1462 } 1463 if (!lock) { 1464 clearTurnoutLock(); 1465 } 1466 lockTurnouts = lock; 1467 } 1468 1469 void setTurnouts(Hashtable<NamedBeanHandle<Turnout>, Integer> turnouts) { 1470 if (this.userSetTurnouts != null) { 1471 userSetTurnouts.forEach(nbh -> 1472 nbh.getBean().removePropertyChangeListener(propertyTurnoutListener)); 1473 } 1474 destMastInit = false; 1475 if (turnouts == null) { 1476 userSetTurnouts = new ArrayList<>(0); 1477 } else { 1478 userSetTurnouts = new ArrayList<>(); 1479 Enumeration<NamedBeanHandle<Turnout>> e = turnouts.keys(); 1480 while (e.hasMoreElements()) { 1481 NamedBeanHandle<Turnout> nbh = e.nextElement(); 1482 NamedBeanSetting nbs = new NamedBeanSetting(nbh, turnouts.get(nbh)); 1483 userSetTurnouts.add(nbs); 1484 } 1485 } 1486 firePropertyChange(PROPERTY_TURNOUTS, null, this.destinationSignalMast); 1487 } 1488 1489 void setAutoTurnouts(Hashtable<Turnout, Integer> turnouts) { 1490 log.debug("{} called setAutoTurnouts with {}", destinationSignalMast.getDisplayName(), 1491 (turnouts != null ? "" + turnouts.size() + " turnouts in hash table" : "null hash table reference")); 1492 if (this.autoTurnouts != null) { 1493 Enumeration<Turnout> keys = this.autoTurnouts.keys(); 1494 while (keys.hasMoreElements()) { 1495 Turnout key = keys.nextElement(); 1496 key.removePropertyChangeListener(propertyTurnoutListener); 1497 } 1498 //minimumBlockSpeed = 0; 1499 } 1500 destMastInit = false; 1501 if (turnouts == null) { 1502 this.autoTurnouts = new Hashtable<>(0); 1503 } else { 1504 this.autoTurnouts = new Hashtable<>(turnouts); 1505 } 1506 firePropertyChange(PROPERTY_AUTO_TURNOUTS, null, this.destinationSignalMast); 1507 } 1508 1509 void setBlocks(Hashtable<Block, Integer> blocks) { 1510 log.debug("{} Set blocks called", destinationSignalMast.getDisplayName()); 1511 if (this.userSetBlocks != null) { 1512 userSetBlocks.forEach( nbh -> 1513 nbh.getBean().removePropertyChangeListener(propertyBlockListener)); 1514 } 1515 destMastInit = false; 1516 1517 userSetBlocks = new ArrayList<>(0); 1518 if (blocks != null) { 1519 userSetBlocks = new ArrayList<>(); 1520 Enumeration<Block> e = blocks.keys(); 1521 while (e.hasMoreElements()) { 1522 Block blk = e.nextElement(); 1523 NamedBeanHandle<?> nbh = InstanceManager.getDefault(NamedBeanHandleManager.class).getNamedBeanHandle(blk.getDisplayName(), blk); 1524 NamedBeanSetting nbs = new NamedBeanSetting(nbh, blocks.get(blk)); 1525 userSetBlocks.add(nbs); 1526 } 1527 } 1528 firePropertyChange(PROPERTY_BLOCKS, null, this.destinationSignalMast); 1529 } 1530 1531 public void setAutoBlocks(LinkedHashMap<Block, Integer> blocks) { 1532 if (log.isDebugEnabled()) { 1533 log.debug("{} called setAutoBlocks with {}", destinationSignalMast.getDisplayName(), 1534 (blocks != null ? "" + blocks.size() + " blocks in hash table" : "null hash table reference")); 1535 } 1536 if (this.autoBlocks != null) { 1537 autoBlocks.keySet().forEach( key -> 1538 key.removePropertyChangeListener(propertyBlockListener)); 1539 } 1540 destMastInit = false; 1541 if (blocks == null) { 1542 this.autoBlocks = new LinkedHashMap<>(0); 1543 1544 } else { 1545 this.autoBlocks = new LinkedHashMap<>(blocks); 1546 //We shall remove the facing block in the list. 1547 if (facingBlock != null && autoBlocks.containsKey(facingBlock.getBlock())) { 1548 autoBlocks.remove(facingBlock.getBlock()); 1549 } 1550 if (getAssociatedSection() != null) { 1551 createSectionDetails(); 1552 } 1553 } 1554 firePropertyChange(PROPERTY_AUTO_BLOCKS, null, this.destinationSignalMast); 1555 } 1556 1557 void setMasts(Hashtable<SignalMast, String> masts) { 1558 if (this.userSetMasts != null) { 1559 userSetMasts.forEach( nbh -> 1560 nbh.getBean().removePropertyChangeListener(propertySignalMastListener)); 1561 } 1562 1563 destMastInit = false; 1564 1565 if (masts == null) { 1566 userSetMasts = new ArrayList<>(0); 1567 } else { 1568 userSetMasts = new ArrayList<>(); 1569 Enumeration<SignalMast> e = masts.keys(); 1570 while (e.hasMoreElements()) { 1571 SignalMast mast = e.nextElement(); 1572 NamedBeanHandle<?> nbh = InstanceManager.getDefault(NamedBeanHandleManager.class) 1573 .getNamedBeanHandle(mast.getDisplayName(), mast); 1574 NamedBeanSetting nbs = new NamedBeanSetting(nbh, masts.get(mast)); 1575 userSetMasts.add(nbs); 1576 } 1577 } 1578 firePropertyChange(PROPERTY_MASTS, null, this.destinationSignalMast); 1579 } 1580 1581 /** 1582 * 1583 * @param newAutoMasts Hashtable of signal masts and set to Aspects 1584 * @param overwrite When true, replace an existing autoMasts list in 1585 * the SML 1586 */ 1587 void setAutoMasts(Hashtable<SignalMast, String> newAutoMasts, boolean overwrite) { 1588 log.debug("{} setAutoMast Called", destinationSignalMast.getDisplayName()); 1589 if (this.autoMasts != null) { 1590 Enumeration<SignalMast> keys = this.autoMasts.keys(); 1591 while (keys.hasMoreElements()) { 1592 SignalMast key = keys.nextElement(); 1593 key.removePropertyChangeListener(propertySignalMastListener); 1594 } 1595 //minimumBlockSpeed = 0; 1596 } 1597 destMastInit = false; 1598 if (overwrite) { 1599 if (newAutoMasts == null) { 1600 this.autoMasts = new Hashtable<>(0); 1601 } else { 1602 this.autoMasts = new Hashtable<>(newAutoMasts); 1603 } 1604 } else { 1605 if (newAutoMasts == null) { 1606 this.autoMasts = new Hashtable<>(0); 1607 } else { 1608 Enumeration<SignalMast> keys = newAutoMasts.keys(); 1609 while (keys.hasMoreElements()) { 1610 SignalMast key = keys.nextElement(); 1611 this.autoMasts.put(key, newAutoMasts.get(key)); 1612 } 1613 } 1614 } 1615 //kick off the process to add back in signal masts at crossings. 1616 for (int i = 0; i < blockInXings.size(); i++) { 1617 blockInXings.get(i).addSignalMastLogic(source); 1618 } 1619 1620 firePropertyChange(PROPERTY_AUTO_MASTS, null, this.destinationSignalMast); 1621 } 1622 1623 void setSensors(Hashtable<NamedBeanHandle<Sensor>, Integer> sensors) { 1624 if (this.userSetSensors != null) { 1625 userSetSensors.forEach(nbh -> 1626 nbh.getBean().removePropertyChangeListener(propertySensorListener)); 1627 } 1628 destMastInit = false; 1629 1630 if (sensors == null) { 1631 userSetSensors = new ArrayList<>(0); 1632 } else { 1633 userSetSensors = new ArrayList<>(); 1634 Enumeration<NamedBeanHandle<Sensor>> e = sensors.keys(); 1635 while (e.hasMoreElements()) { 1636 NamedBeanHandle<Sensor> nbh = e.nextElement(); 1637 NamedBeanSetting nbs = new NamedBeanSetting(nbh, sensors.get(nbh)); 1638 userSetSensors.add(nbs); 1639 } 1640 } 1641 firePropertyChange(PROPERTY_SENSORS, null, this.destinationSignalMast); 1642 } 1643 1644 void addSensor(NamedBeanHandle<Sensor> sen, int state) { 1645 for (NamedBeanSetting nbh : userSetSensors) { 1646 if (nbh.getBean().equals(sen.getBean())) { 1647 return; 1648 } 1649 } 1650 sen.getBean().addPropertyChangeListener(propertySensorListener); 1651 NamedBeanSetting nbs = new NamedBeanSetting(sen, state); 1652 userSetSensors.add(nbs); 1653 firePropertyChange(PROPERTY_SENSORS, null, this.destinationSignalMast); 1654 } 1655 1656// not used now, preserved for later use 1657// void removeSensor(NamedBeanHandle<Sensor> sen) { 1658// for (NamedBeanSetting nbh : userSetSensors) { 1659// if (nbh.getBean().equals(sen.getBean())) { 1660// sen.getBean().removePropertyChangeListener(propertySensorListener); 1661// userSetSensors.remove(nbh); 1662// firePropertyChange("sensors", null, this.destination); 1663// return; 1664// } 1665// } 1666// } 1667 1668 void removeSensor(Sensor sen) { 1669 for (NamedBeanSetting nbh : userSetSensors) { 1670 if (nbh.getBean().equals(sen)) { 1671 sen.removePropertyChangeListener(propertySensorListener); 1672 userSetSensors.remove(nbh); 1673 firePropertyChange(PROPERTY_SENSORS, null, this.destinationSignalMast); 1674 return; 1675 } 1676 } 1677 } 1678 1679 List<Block> getBlocks() { 1680 List<Block> out = new ArrayList<>(); 1681 userSetBlocks.forEach( nbh -> out.add((Block) nbh.getBean())); 1682 return out; 1683 } 1684 1685 List<Block> getAutoBlocks() { 1686 List<Block> out = new ArrayList<>(); 1687 Set<Block> blockKeys = autoBlocks.keySet(); 1688 blockKeys.forEach(key -> out.add(key)); 1689 return out; 1690 } 1691 1692 List<Block> getAutoBlocksBetweenMasts() { 1693 if (destList.get(destinationSignalMast).xingAutoBlocks.isEmpty() 1694 && destList.get(destinationSignalMast).dblCrossoverAutoBlocks.isEmpty()) { 1695 return getAutoBlocks(); 1696 } 1697 List<Block> returnList = getAutoBlocks(); 1698 for (Block blk : getAutoBlocks()) { 1699 if (xingAutoBlocks.contains(blk)) { 1700 returnList.remove(blk); 1701 } 1702 if (dblCrossoverAutoBlocks.contains(blk)) { 1703 returnList.remove(blk); 1704 } 1705 } 1706 1707 return returnList; 1708 } 1709 1710 List<Turnout> getTurnouts() { 1711 List<Turnout> out = new ArrayList<>(); 1712 userSetTurnouts.forEach( nbh -> out.add((Turnout) nbh.getBean())); 1713 return out; 1714 } 1715 1716 void removeTurnout(Turnout turn) { 1717 Iterator<NamedBeanSetting> nbh = userSetTurnouts.iterator(); 1718 while (nbh.hasNext()) { 1719 NamedBeanSetting i = nbh.next(); 1720 if (i.getBean().equals(turn)) { 1721 turn.removePropertyChangeListener(propertyTurnoutListener); 1722 nbh.remove(); 1723 firePropertyChange(PROPERTY_TURNOUTS, null, this.destinationSignalMast); 1724 } 1725 } 1726 } 1727 1728 @SuppressWarnings("unchecked") // (NamedBeanHandle<Turnout>) nbh.getNamedBean() is unchecked cast 1729 List<NamedBeanHandle<Turnout>> getNamedTurnouts() { 1730 List<NamedBeanHandle<Turnout>> out = new ArrayList<>(); 1731 userSetTurnouts.forEach(nbh -> 1732 out.add((NamedBeanHandle<Turnout>) nbh.getNamedBean())); 1733 return out; 1734 } 1735 1736 List<Turnout> getAutoTurnouts() { 1737 List<Turnout> out = new ArrayList<>(); 1738 Enumeration<Turnout> en = autoTurnouts.keys(); 1739 while (en.hasMoreElements()) { 1740 out.add(en.nextElement()); 1741 } 1742 return out; 1743 } 1744 1745 List<SignalMast> getSignalMasts() { 1746 List<SignalMast> out = new ArrayList<>(); 1747 userSetMasts.forEach( nbh -> out.add((SignalMast) nbh.getBean())); 1748 return out; 1749 } 1750 1751 List<SignalMast> getAutoSignalMasts() { 1752 List<SignalMast> out = new ArrayList<>(); 1753 Enumeration<SignalMast> en = autoMasts.keys(); 1754 while (en.hasMoreElements()) { 1755 out.add(en.nextElement()); 1756 } 1757 return out; 1758 } 1759 1760 List<Sensor> getSensors() { 1761 List<Sensor> out = new ArrayList<>(); 1762 userSetSensors.forEach( nbh -> out.add((Sensor) nbh.getBean())); 1763 return out; 1764 } 1765 1766 @SuppressWarnings("unchecked") // (NamedBeanHandle<Sensor>) nbh.getNamedBean() is unchecked cast 1767 List<NamedBeanHandle<Sensor>> getNamedSensors() { 1768 List<NamedBeanHandle<Sensor>> out = new ArrayList<>(); 1769 userSetSensors.forEach( nbh -> out.add((NamedBeanHandle<Sensor>) nbh.getNamedBean())); 1770 return out; 1771 } 1772 1773 boolean isBlockIncluded(Block block) { 1774 return userSetBlocks.stream().anyMatch(nbh -> (nbh.getBean().equals(block))); 1775 } 1776 1777 boolean isAutoBlockIncluded(LayoutBlock block) { 1778 if (block != null) { 1779 return autoBlocks.containsKey(block.getBlock()); 1780 } 1781 return false; 1782 } 1783 1784 boolean isAutoBlockIncluded(Block block) { 1785 return autoBlocks.containsKey(block); 1786 } 1787 1788 boolean isBlockIncluded(LayoutBlock block) { 1789 return userSetBlocks.stream().anyMatch(nbh -> (nbh.getBean().equals(block.getBlock()))); 1790 } 1791 1792 boolean isTurnoutIncluded(Turnout turnout) { 1793 return userSetTurnouts.stream().anyMatch(nbh -> (nbh.getBean().equals(turnout))); 1794 } 1795 1796 boolean isSensorIncluded(Sensor sensor) { 1797 return userSetSensors.stream().anyMatch(nbh -> (nbh.getBean().equals(sensor))); 1798 } 1799 1800 boolean isSignalMastIncluded(SignalMast signal) { 1801 return userSetMasts.stream().anyMatch(nbh -> (nbh.getBean().equals(signal))); 1802 } 1803 1804 int getAutoBlockState(Block block) { 1805 if (autoBlocks == null) { 1806 return -1; 1807 } 1808 return autoBlocks.get(block); 1809 } 1810 1811 int getBlockState(Block block) { 1812 if (userSetBlocks == null) { 1813 return -1; 1814 } 1815 for (NamedBeanSetting nbh : userSetBlocks) { 1816 if (nbh.getBean().equals(block)) { 1817 return nbh.getSetting(); 1818 } 1819 } 1820 return -1; 1821 } 1822 1823 int getSensorState(Sensor sensor) { 1824 if (userSetSensors == null) { 1825 return -1; 1826 } 1827 for (NamedBeanSetting nbh : userSetSensors) { 1828 if (nbh.getBean().equals(sensor)) { 1829 return nbh.getSetting(); 1830 } 1831 } 1832 return -1; 1833 } 1834 1835 int getTurnoutState(Turnout turnout) { 1836 if (userSetTurnouts == null) { 1837 return -1; 1838 } 1839 for (NamedBeanSetting nbh : userSetTurnouts) { 1840 if (nbh.getBean().equals(turnout)) { 1841 return nbh.getSetting(); 1842 } 1843 } 1844 return -1; 1845 } 1846 1847 int getAutoTurnoutState(Turnout turnout) { 1848 if (autoTurnouts == null) { 1849 return -1; 1850 } 1851 if (autoTurnouts.containsKey(turnout)) { 1852 return autoTurnouts.get(turnout); 1853 } 1854 return -1; 1855 } 1856 1857 String getSignalMastState(SignalMast mast) { 1858 if (userSetMasts == null) { 1859 return null; 1860 } 1861 for (NamedBeanSetting nbh : userSetMasts) { 1862 if (nbh.getBean().equals(mast)) { 1863 return nbh.getStringSetting(); 1864 } 1865 } 1866 return null; 1867 } 1868 1869 String getAutoSignalMastState(SignalMast mast) { 1870 if (autoMasts == null) { 1871 return null; 1872 } 1873 return autoMasts.get(mast); 1874 } 1875 1876 // the following 2 methods are not supplied in the implementation 1877 boolean inWait = false; 1878 1879 /* 1880 * Before going active or checking that we can go active, wait 1881 * for things to settle down to help prevent a race condition. 1882 */ 1883 void checkState() { 1884 if (disposed) { 1885 log.error("checkState called even though this has been disposed of {}", 1886 getSourceMast().getDisplayName()); 1887 return; 1888 } 1889 1890 if (!enable) { 1891 return; 1892 } 1893 if (inWait) { 1894 return; 1895 } 1896 1897 log.debug("check Signal Dest State called"); 1898 inWait = true; 1899 1900 // The next line forces a single initialization of InstanceManager.getDefault(SignalMastLogicManager.class) 1901 // before launching parallel threads 1902 int tempDelay = InstanceManager.getDefault(SignalMastLogicManager.class).getSignalLogicDelay(); 1903 1904 ThreadingUtil.runOnLayoutDelayed( 1905 () -> { 1906 checkStateDetails(); 1907 inWait = false; 1908 }, tempDelay 1909 ); 1910 } 1911 1912 /** 1913 * Check the details of this source-destination signal mast logic pair. 1914 * Steps through every sensor, turnout etc. before setting the SML 1915 * Aspect on the source mast via { 1916 * 1917 * @see #setSignalAppearance } and { 1918 * @see #setMastAppearance } 1919 */ 1920 private void checkStateDetails() { 1921 turnoutThrown = false; 1922 permissiveBlock = false; 1923 if (disposed) { 1924 log.error("checkStateDetails called even though this has been disposed of {} {}", 1925 getSourceMast().getDisplayName(), destinationSignalMast.getDisplayName()); 1926 return; 1927 } 1928 if (!enable) { 1929 return; 1930 } 1931 log.debug("From {} to {} internal check state", getSourceMast().getDisplayName(), 1932 destinationSignalMast.getDisplayName()); 1933 active = false; 1934 if ((useLayoutEditor) && (autoTurnouts.isEmpty()) && (autoBlocks.isEmpty())) { 1935 return; 1936 } 1937 boolean state = true; 1938 Enumeration<Turnout> keys = autoTurnouts.keys(); 1939 while (keys.hasMoreElements()) { 1940 Turnout key = keys.nextElement(); 1941 if (key.getKnownState() != autoTurnouts.get(key)) { 1942 if (key.getState() != autoTurnouts.get(key)) { 1943 if (isTurnoutIncluded(key)) { 1944 if (key.getState() != getTurnoutState(key)) { 1945 state = false; 1946 } else if (key.getState() == Turnout.THROWN) { 1947 turnoutThrown = true; 1948 } 1949 } else { 1950 state = false; 1951 } 1952 } 1953 } else if (key.getState() == Turnout.THROWN) { 1954 turnoutThrown = true; 1955 } 1956 } 1957 1958 for (NamedBeanSetting nbh : userSetTurnouts) { 1959 Turnout key = (Turnout) nbh.getBean(); 1960 if (key.getKnownState() != nbh.getSetting()) { 1961 state = false; 1962 } else if (key.getState() == Turnout.THROWN) { 1963 turnoutThrown = true; 1964 } 1965 } 1966 1967 Enumeration<SignalMast> mastKeys = autoMasts.keys(); 1968 while (mastKeys.hasMoreElements()) { 1969 SignalMast key = mastKeys.nextElement(); 1970 String aspect = key.getAspect(); 1971 log.debug("key {} {} {}", key.getDisplayName(), aspect, autoMasts.get(key)); 1972 if ((aspect != null) && (!aspect.equals(autoMasts.get(key)))) { 1973 if (isSignalMastIncluded(key)) { 1974 //Basically if we have a blank aspect, we don't care about the state of the signalmast 1975 if (!getSignalMastState(key).isEmpty()) { 1976 if (!aspect.equals(getSignalMastState(key))) { 1977 state = false; 1978 } 1979 } 1980 } else { 1981 state = false; 1982 } 1983 } 1984 } 1985 for (NamedBeanSetting nbh : userSetMasts) { 1986 SignalMast key = (SignalMast) nbh.getBean(); 1987 String aspect = key.getAspect(); 1988 if ((aspect == null) || (!aspect.equals(nbh.getStringSetting()))) { 1989 state = false; 1990 } 1991 } 1992 1993 for (NamedBeanSetting nbh : userSetSensors) { 1994 Sensor key = (Sensor) nbh.getBean(); 1995 if (key.getKnownState() != nbh.getSetting()) { 1996 state = false; 1997 } 1998 } 1999 2000 for (Map.Entry<Block, Integer> entry : this.autoBlocks.entrySet()) { 2001 log.debug(" entry {} {} {}", entry.getKey().getDisplayName(), 2002 entry.getKey().getState(), entry.getValue()); 2003 if (entry.getKey().getState() != autoBlocks.get(entry.getKey())) { 2004 if (isBlockIncluded(entry.getKey())) { 2005 if (getBlockState(entry.getKey()) != 0x03) { 2006 if (entry.getKey().getState() != getBlockState(entry.getKey())) { 2007 if (entry.getKey().getState() == Block.OCCUPIED && entry.getKey().getPermissiveWorking()) { 2008 permissiveBlock = true; 2009 } else { 2010 state = false; 2011 } 2012 } 2013 } 2014 } else { 2015 if (entry.getKey().getState() == Block.OCCUPIED && entry.getKey().getPermissiveWorking()) { 2016 permissiveBlock = true; 2017 } else if (entry.getKey().getState() == Block.UNDETECTED) { 2018 log.debug("Block {} is UNDETECTED so treat as unoccupied", entry.getKey().getDisplayName()); 2019 } else { 2020 state = false; 2021 } 2022 } 2023 } 2024 } 2025 2026 for (NamedBeanSetting nbh : userSetBlocks) { 2027 Block key = (Block) nbh.getBean(); 2028 if (nbh.getSetting() != 0x03) { 2029 if (key.getState() != nbh.getSetting()) { 2030 if (key.getState() == Block.OCCUPIED && key.getPermissiveWorking()) { 2031 permissiveBlock = true; 2032 } else { 2033 state = false; 2034 } 2035 } 2036 } 2037 } 2038 if (permissiveBlock 2039 /*If a block has been found to be permissive, but the source signalmast 2040 does not support a call-on/permissive aspect then the route can not be set*/ 2041 && getSourceMast().getAppearanceMap().getSpecificAppearance(SignalAppearanceMap.PERMISSIVE) == null) { 2042 state = false; 2043 } 2044 2045 /*This check is purely for use with the dispatcher, it will check to see if any of the blocks are set to "useExtraColor" 2046 which is a means to determine if the block is in a section that is occupied and it not ours thus we can set the signal to danger.*/ 2047 if (state && getAssociatedSection() != null 2048 && InstanceManager.getNullableDefault(jmri.jmrit.dispatcher.DispatcherFrame.class) != null 2049 && InstanceManager.getNullableDefault(LayoutBlockManager.class) != null 2050 && getAssociatedSection().getState() != Section.FORWARD) { 2051 2052 LayoutBlockManager lbm = InstanceManager.getDefault(LayoutBlockManager.class); 2053 for (Block key : autoBlocks.keySet()) { 2054 LayoutBlock lb = lbm.getLayoutBlock(key); 2055 if (lb != null && lb.getUseExtraColor()) { 2056 state = false; 2057 break; 2058 } 2059 } 2060 if (!state) { 2061 for (NamedBeanSetting nbh : userSetBlocks) { 2062 Block key = (Block) nbh.getBean(); 2063 LayoutBlock lb = lbm.getLayoutBlock(key); 2064 if (lb != null && lb.getUseExtraColor()) { 2065 state = false; 2066 break; 2067 } 2068 } 2069 } 2070 } 2071 2072 if (!state) { 2073 turnoutThrown = false; 2074 permissiveBlock = false; 2075 } 2076 2077 active = state; 2078 ThreadingUtil.runOnLayout(() -> { 2079 setSignalAppearance(); 2080 }); 2081 } 2082 2083 /** 2084 * Set up this source-destination signal mast logic pair. Steps through 2085 * every list defined on the source mast. 2086 */ 2087 void initialise() { 2088 if ((destMastInit) || (disposed)) { 2089 return; 2090 } 2091 2092 active = false; 2093 turnoutThrown = false; 2094 permissiveBlock = false; 2095 boolean routeclear = true; 2096 if ((useLayoutEditor) && (autoTurnouts.isEmpty()) && (autoBlocks.isEmpty()) && (autoMasts.isEmpty())) { 2097 return; 2098 } 2099 2100 calculateSpeed(); 2101 2102 Enumeration<Turnout> keys = autoTurnouts.keys(); 2103 while (keys.hasMoreElements()) { 2104 Turnout key = keys.nextElement(); 2105 key.addPropertyChangeListener(propertyTurnoutListener); 2106 2107 if (key.getKnownState() != autoTurnouts.get(key)) { 2108 if (key.getState() != autoTurnouts.get(key)) { 2109 if (isTurnoutIncluded(key)) { 2110 if (key.getState() != getTurnoutState(key)) { 2111 routeclear = false; 2112 } else if (key.getState() == Turnout.THROWN) { 2113 turnoutThrown = true; 2114 } 2115 } else { 2116 routeclear = false; 2117 } 2118 } 2119 } else if (key.getState() == Turnout.THROWN) { 2120 turnoutThrown = true; 2121 } 2122 } 2123 2124 for (NamedBeanSetting nbh : userSetTurnouts) { 2125 Turnout key = (Turnout) nbh.getBean(); 2126 key.addPropertyChangeListener(propertyTurnoutListener, nbh.getBeanName(), 2127 "Signal Mast Logic:" + source.getDisplayName() + " to " + destinationSignalMast.getDisplayName()); 2128 if (key.getKnownState() != nbh.getSetting()) { 2129 routeclear = false; 2130 } else if (key.getState() == Turnout.THROWN) { 2131 turnoutThrown = true; 2132 } 2133 } 2134 2135 Enumeration<SignalMast> mastKeys = autoMasts.keys(); 2136 while (mastKeys.hasMoreElements()) { 2137 SignalMast key = mastKeys.nextElement(); 2138 log.debug("{} auto mast add list {}", destinationSignalMast.getDisplayName(), key.getDisplayName()); 2139 key.addPropertyChangeListener(propertySignalMastListener); 2140 String aspect = key.getAspect(); 2141 if ( aspect != null && !aspect.equals(autoMasts.get(key))) { 2142 if (isSignalMastIncluded(key)) { 2143 if (aspect.equals(getSignalMastState(key))) { 2144 routeclear = false; 2145 } 2146 } else { 2147 routeclear = false; 2148 } 2149 } 2150 } 2151 2152 for (NamedBeanSetting nbh : userSetMasts) { 2153 SignalMast key = (SignalMast) nbh.getBean(); 2154 key.addPropertyChangeListener(propertySignalMastListener); 2155 String aspect = key.getAspect(); 2156 log.debug("mast '{}' key aspect '{}'", destinationSignalMast.getDisplayName(), aspect); 2157 if ((aspect == null) || (!aspect.equals(nbh.getStringSetting()))) { 2158 routeclear = false; 2159 } 2160 } 2161 for (NamedBeanSetting nbh : userSetSensors) { 2162 Sensor sensor = (Sensor) nbh.getBean(); 2163 sensor.addPropertyChangeListener(propertySensorListener, nbh.getBeanName(), 2164 "Signal Mast Logic:" + source.getDisplayName() + " to " + destinationSignalMast.getDisplayName()); 2165 if (sensor.getKnownState() != nbh.getSetting()) { 2166 routeclear = false; 2167 } 2168 } 2169 2170 for (Map.Entry<Block, Integer> entry : this.autoBlocks.entrySet()) { 2171 log.debug("{} auto block add list {}", destinationSignalMast.getDisplayName(), 2172 entry.getKey().getDisplayName()); 2173 entry.getKey().addPropertyChangeListener(propertyBlockListener); 2174 if (entry.getKey().getState() != entry.getValue()) { 2175 if (isBlockIncluded(entry.getKey())) { 2176 if (entry.getKey().getState() != getBlockState(entry.getKey())) { 2177 if (entry.getKey().getState() == Block.OCCUPIED && entry.getKey().getPermissiveWorking()) { 2178 permissiveBlock = true; 2179 } else { 2180 routeclear = false; 2181 } 2182 } 2183 } else { 2184 if (entry.getKey().getState() == Block.OCCUPIED && entry.getKey().getPermissiveWorking()) { 2185 permissiveBlock = true; 2186 } else if (entry.getKey().getState() == Block.UNDETECTED) { 2187 log.debug("Block {} is UNDETECTED so treat as unoccupied", entry.getKey().getDisplayName()); 2188 } else { 2189 routeclear = false; 2190 } 2191 } 2192 } 2193 } 2194 2195 for (NamedBeanSetting nbh : userSetBlocks) { 2196 Block key = (Block) nbh.getBean(); 2197 key.addPropertyChangeListener(propertyBlockListener); 2198 if (key.getState() != getBlockState(key)) { 2199 if (key.getState() == Block.OCCUPIED && key.getPermissiveWorking()) { 2200 permissiveBlock = true; 2201 } else { 2202 routeclear = false; 2203 } 2204 } 2205 } 2206 if ( permissiveBlock 2207 /* If a block has been found to be permissive, but the source signalmast 2208 does not support a call-on/permissive aspect then the route can not be set */ 2209 && getSourceMast().getAppearanceMap().getSpecificAppearance(SignalAppearanceMap.PERMISSIVE) == null) { 2210 routeclear = false; 2211 } 2212 if (routeclear) { 2213 active = true; 2214 setSignalAppearance(); 2215 } else { 2216 permissiveBlock = false; 2217 turnoutThrown = false; 2218 } 2219 destMastInit = true; 2220 } 2221 2222 void useLayoutEditor(boolean boo) throws JmriException { 2223 log.debug("{} called useLayoutEditor({}), is {}", 2224 destinationSignalMast.getDisplayName(), boo, useLayoutEditor); 2225 if (useLayoutEditor == boo) { 2226 return; 2227 } 2228 useLayoutEditor = boo; 2229 if ((boo) && (InstanceManager.getDefault(LayoutBlockManager.class).routingStablised())) { 2230 // JmriException considered normal if there is no valid path using the layout editor. 2231 setupLayoutEditorDetails(); 2232 } else { 2233 destinationBlock = null; 2234 facingBlock = null; 2235 protectingBlock = null; 2236 setAutoBlocks(null); 2237 setAutoTurnouts(null); 2238 } 2239 } 2240 2241 void useLayoutEditorDetails(boolean turnouts, boolean blocks) throws JmriException { 2242 log.debug("{} use layout editor details called {}", 2243 destinationSignalMast.getDisplayName(), useLayoutEditor); 2244 useLayoutEditorTurnouts = turnouts; 2245 useLayoutEditorBlocks = blocks; 2246 if ((useLayoutEditor) && (InstanceManager.getDefault(LayoutBlockManager.class).routingStablised())) { 2247 // JmriException considered normal if there is no valid path using the Layout Editor. 2248 setupLayoutEditorDetails(); 2249 } 2250 } 2251 2252 void setupLayoutEditorDetails() throws JmriException { 2253 log.debug("setupLayoutEditorDetails: useLayoutEditor={} disposed={}", useLayoutEditor, disposed); 2254 if ((!useLayoutEditor) || (disposed)) { 2255 return; 2256 } 2257 LayoutBlockManager lbm = InstanceManager.getDefault(LayoutBlockManager.class); 2258 if ( destinationBlock != null) { 2259 log.debug("{} Set use layout editor", destinationSignalMast.getDisplayName()); 2260 } 2261 Set<LayoutEditor> layout = InstanceManager.getDefault(EditorManager.class).getAll(LayoutEditor.class); 2262 List<LayoutBlock> protectingBlocks = new ArrayList<>(); 2263 // We don't care which Layout Editor panel the signal mast is on, just so long as 2264 // the routing is done via layout blocks. 2265 remoteProtectingBlock = null; 2266 for (int i = 0; i < layout.size(); i++) { 2267 log.debug("{} Layout name {}", destinationSignalMast.getDisplayName(), editor ); 2268 if (facingBlock == null) { 2269 facingBlock = lbm.getFacingBlockByNamedBean(getSourceMast(), editor); 2270 } 2271 if (protectingBlock == null && protectingBlocks.isEmpty()) { 2272 //This is wrong 2273 protectingBlocks = lbm.getProtectingBlocksByNamedBean(getSourceMast(), editor); 2274 } 2275 if (destinationBlock == null) { 2276 destinationBlock = lbm.getFacingBlockByNamedBean(destinationSignalMast, editor); 2277 } 2278 if (remoteProtectingBlock == null) { 2279 remoteProtectingBlock = lbm.getProtectedBlockByNamedBean(destinationSignalMast, editor); 2280 } 2281 } 2282 // At this point, if we are not using the Layout Editor turnout or block 2283 // details then there is no point in trying to gather them. 2284 if ((!useLayoutEditorTurnouts) && (!useLayoutEditorBlocks)) { 2285 return; 2286 } 2287 if (facingBlock == null) { 2288 log.error("No facing block found for source mast {}", getSourceMast().getDisplayName()); 2289 throw new JmriException("No facing block found for source mast " + getSourceMast().getDisplayName()); 2290 } 2291 if (destinationBlock == null) { 2292 log.error("No facing block found for destination mast {}", destinationSignalMast.getDisplayName()); 2293 throw new JmriException("No facing block found for destination mast " + destinationSignalMast.getDisplayName()); 2294 } 2295 List<LayoutBlock> lblks = new ArrayList<>(); 2296 if (protectingBlock == null) { 2297 log.debug("protecting block is null"); 2298 String pBlkNames = ""; 2299 StringBuffer lBlksNamesBuf = new StringBuffer(); 2300 for (LayoutBlock pBlk : protectingBlocks) { 2301 log.debug("checking layoutBlock {}", pBlk.getDisplayName()); 2302 pBlkNames = pBlkNames + pBlk.getDisplayName() + " (" + lbm.getLayoutBlockConnectivityTools().checkValidDest(facingBlock, pBlk, destinationBlock, remoteProtectingBlock, LayoutBlockConnectivityTools.Routing.MASTTOMAST) + "), "; 2303 if (lbm.getLayoutBlockConnectivityTools().checkValidDest(facingBlock, pBlk, destinationBlock, remoteProtectingBlock, LayoutBlockConnectivityTools.Routing.MASTTOMAST)) { 2304 try { 2305 lblks = lbm.getLayoutBlockConnectivityTools().getLayoutBlocks(facingBlock, destinationBlock, pBlk, true, LayoutBlockConnectivityTools.Routing.MASTTOMAST); 2306 protectingBlock = pBlk; 2307 log.debug("building path names..."); 2308 for (LayoutBlock lBlk : lblks) { 2309 lBlksNamesBuf.append(" "); 2310 lBlksNamesBuf.append(lBlk.getDisplayName()); 2311 } 2312 break; 2313 } catch (JmriException ee) { 2314 log.debug("path not found this time"); 2315 } 2316 } 2317 } 2318 String lBlksNames = new String(lBlksNamesBuf); 2319 2320 if (protectingBlock == null) { 2321 throw new JmriException("Path not valid, protecting block is null. Protecting block: " + pBlkNames 2322 + " not connected to " + facingBlock.getDisplayName() + ". Layout block names: " + lBlksNames); 2323 } 2324 } 2325 if (!lbm.getLayoutBlockConnectivityTools().checkValidDest(facingBlock,protectingBlock, 2326 destinationBlock, remoteProtectingBlock, LayoutBlockConnectivityTools.Routing.MASTTOMAST)) { 2327 throw new JmriException("Path not valid, destination check failed."); 2328 } 2329 if (log.isDebugEnabled()) { 2330 log.debug("{} face {}", destinationSignalMast.getDisplayName(), facingBlock); 2331 log.debug("{} prot {}", destinationSignalMast.getDisplayName(), protectingBlock); 2332 log.debug("{} dest {}", destinationSignalMast.getDisplayName(), destinationBlock); 2333 } 2334 2335 if (destinationBlock != null && protectingBlock != null && facingBlock != null) { 2336 setAutoMasts(null, true); 2337 if (log.isDebugEnabled()) { 2338 log.debug("{} face {}", destinationSignalMast.getDisplayName(), facingBlock.getDisplayName()); 2339 log.debug("{} prot {}", destinationSignalMast.getDisplayName(), protectingBlock.getDisplayName()); 2340 log.debug("{} dest {}", destinationSignalMast.getDisplayName(), destinationBlock.getDisplayName()); 2341 } 2342 2343 try { 2344 lblks = lbm.getLayoutBlockConnectivityTools().getLayoutBlocks( 2345 facingBlock, destinationBlock, protectingBlock, 2346 true, LayoutBlockConnectivityTools.Routing.MASTTOMAST); 2347 } catch (JmriException ee) { 2348 log.error("No blocks found by the layout editor for pair {}-{}", 2349 source.getDisplayName(), destinationSignalMast.getDisplayName()); 2350 } 2351 LinkedHashMap<Block, Integer> block = setupLayoutEditorTurnoutDetails(lblks); 2352 2353 for (int i = 0; i < blockInXings.size(); i++) { 2354 blockInXings.get(i).removeSignalMastLogic(source); 2355 } 2356 blockInXings = new ArrayList<>(0); 2357 xingAutoBlocks = new ArrayList<>(0); 2358 for (LayoutEditor lay : layout) { 2359 for (LevelXing levelXing : lay.getLevelXings()) { 2360 //Looking for a crossing that both layout blocks defined and they are individual. 2361 if ((levelXing.getLayoutBlockAC() != null) 2362 && (levelXing.getLayoutBlockBD() != null) 2363 && (levelXing.getLayoutBlockAC() != levelXing.getLayoutBlockBD())) { 2364 if (lblks.contains(levelXing.getLayoutBlockAC()) && 2365 levelXing.getLayoutBlockAC() != facingBlock) { // Don't include the facing xing blocks 2366 block.put(levelXing.getLayoutBlockBD().getBlock(), Block.UNOCCUPIED); 2367 xingAutoBlocks.add(levelXing.getLayoutBlockBD().getBlock()); 2368 blockInXings.add(levelXing); 2369 } else if (lblks.contains(levelXing.getLayoutBlockBD()) && 2370 levelXing.getLayoutBlockBD() != facingBlock) { // Don't include the facing xing blocks 2371 block.put(levelXing.getLayoutBlockAC().getBlock(), Block.UNOCCUPIED); 2372 xingAutoBlocks.add(levelXing.getLayoutBlockAC().getBlock()); 2373 blockInXings.add(levelXing); 2374 } 2375 } 2376 } 2377 } 2378 if (useLayoutEditorBlocks) { 2379 setAutoBlocks(block); 2380 } else { 2381 setAutoBlocks(null); 2382 } 2383 if (!useLayoutEditorTurnouts) { 2384 setAutoTurnouts(null); 2385 } 2386 2387 setupAutoSignalMast(null, false); 2388 } 2389 initialise(); 2390 } 2391 2392 /** 2393 * From a list of Layout Blocks, search for included Turnouts and their 2394 * Set To state. 2395 * 2396 * @param lblks List of Layout Blocks 2397 * @return a list of block - turnout state pairs 2398 */ 2399 LinkedHashMap<Block, Integer> setupLayoutEditorTurnoutDetails(List<LayoutBlock> lblks) { 2400 ConnectivityUtil connection; 2401 List<LayoutTrackExpectedState<LayoutTurnout>> turnoutList; 2402 Hashtable<Turnout, Integer> turnoutSettings = new Hashtable<>(); 2403 LinkedHashMap<Block, Integer> block = new LinkedHashMap<>(); 2404 for (int i = 0; i < lblks.size(); i++) { 2405 log.debug("layoutblock {}",lblks.get(i).getDisplayName()); 2406 block.put(lblks.get(i).getBlock(), Block.UNOCCUPIED); 2407 if ((i > 0)) { 2408 int nxtBlk = i + 1; 2409 int preBlk = i - 1; 2410 if (i == lblks.size() - 1) { 2411 nxtBlk = i; 2412 } 2413 //We use the best connectivity for the current block. 2414 connection = new ConnectivityUtil(lblks.get(i).getMaxConnectedPanel()); 2415 if (i == lblks.size() - 1 && remoteProtectingBlock != null) { 2416 turnoutList = connection.getTurnoutList(lblks.get(i) 2417 .getBlock(), lblks.get(preBlk).getBlock(), remoteProtectingBlock.getBlock()); 2418 }else{ 2419 turnoutList = connection.getTurnoutList(lblks.get(i) 2420 .getBlock(), lblks.get(preBlk).getBlock(), lblks.get(nxtBlk).getBlock()); 2421 } 2422 for (int x = 0; x < turnoutList.size(); x++) { 2423 LayoutTurnout lt = turnoutList.get(x).getObject(); 2424 if (lt instanceof LayoutSlip) { 2425 LayoutSlip ls = (LayoutSlip) lt; 2426 int slipState = turnoutList.get(x).getExpectedState(); 2427 int taState = ls.getTurnoutState(slipState); 2428 Turnout tTemp = ls.getTurnout(); 2429 if (tTemp == null ) { 2430 log.error("Unexpected null Turnout in {}, skipped", ls); 2431 continue; // skip this one in loop, what else can you do? 2432 } 2433 turnoutSettings.put(ls.getTurnout(), taState); 2434 int tbState = ls.getTurnoutBState(slipState); 2435 turnoutSettings.put(ls.getTurnoutB(), tbState); 2436 } else if ( lt != null ) { 2437 String t = lt.getTurnoutName(); 2438 // temporary = why is this looking up the Turnout instead of using getTurnout()? 2439 Turnout turnout = InstanceManager.turnoutManagerInstance().getTurnout(t); 2440 if (log.isDebugEnabled()) { 2441 if ( (lt.getTurnoutType() == LayoutTurnout.TurnoutType.RH_TURNOUT || 2442 lt.getTurnoutType() == LayoutTurnout.TurnoutType.LH_TURNOUT || 2443 lt.getTurnoutType() == LayoutTurnout.TurnoutType.WYE_TURNOUT) 2444 && (!lt.getBlockName().isEmpty())) { 2445 log.debug("turnout in list is straight left/right wye"); 2446 log.debug("turnout block Name {}", lt.getBlockName()); 2447 log.debug("current {} - pre {}", lblks.get(i).getBlock().getDisplayName(), lblks.get(preBlk).getBlock().getDisplayName()); 2448 log.debug("A {}", lt.getConnectA()); 2449 log.debug("B {}", lt.getConnectB()); 2450 log.debug("C {}", lt.getConnectC()); 2451 log.debug("D {}", lt.getConnectD()); 2452 } 2453 } 2454 if (turnout != null ) { 2455 turnoutSettings.put(turnout, turnoutList.get(x).getExpectedState()); 2456 } 2457 Turnout tempT; 2458 if ((tempT = lt.getSecondTurnout()) != null) { 2459 turnoutSettings.put(tempT, turnoutList.get(x).getExpectedState()); 2460 } 2461 /* TODO: We could do with a more intelligent way to deal with double crossovers, other than 2462 just looking at the state of the other conflicting blocks, such as looking at Signalmasts 2463 that protect the other blocks and the settings of any other turnouts along the way. 2464 */ 2465 if (lt.getTurnoutType() == LayoutTurnout.TurnoutType.DOUBLE_XOVER) { 2466 LayoutBlock tempLB; 2467 if (turnoutList.get(x).getExpectedState() == Turnout.THROWN) { 2468 if (lt.getLayoutBlock() == lblks.get(i) || lt.getLayoutBlockC() == lblks.get(i)) { 2469 // A or C, add B and D to remove list unless A=B or C=D 2470 if ((tempLB = lt.getLayoutBlockB()) != null) { 2471 if (!tempLB.equals(lt.getLayoutBlock())) { 2472 dblCrossoverAutoBlocks.add(tempLB.getBlock()); 2473 } 2474 block.put(tempLB.getBlock(), Block.UNOCCUPIED); 2475 } 2476 if ((tempLB = lt.getLayoutBlockD()) != null) { 2477 if (!tempLB.equals(lt.getLayoutBlockC())) { 2478 dblCrossoverAutoBlocks.add(tempLB.getBlock()); 2479 } 2480 block.put(tempLB.getBlock(), Block.UNOCCUPIED); 2481 } 2482 } else if (lt.getLayoutBlockB() == lblks.get(i) || lt.getLayoutBlockD() == lblks.get(i)) { 2483 // B or D, add A and C to remove list unless A=B or C=D 2484 if ((tempLB = lt.getLayoutBlock()) != null) { 2485 if (!tempLB.equals(lt.getLayoutBlockB())) { 2486 dblCrossoverAutoBlocks.add(tempLB.getBlock()); 2487 } 2488 block.put(tempLB.getBlock(), Block.UNOCCUPIED); 2489 } 2490 if ((tempLB = lt.getLayoutBlockC()) != null) { 2491 if (!tempLB.equals(lt.getLayoutBlockD())) { 2492 dblCrossoverAutoBlocks.add(tempLB.getBlock()); 2493 } 2494 block.put(tempLB.getBlock(), Block.UNOCCUPIED); 2495 } 2496 } 2497 } 2498 } 2499 } 2500 } 2501 } 2502 } 2503 // ----- Begin Turntable Alignment Check ----- 2504 // For paths onto a turntable, we must add a condition for the turntable's alignment. The 2505 // turnout that controls the turntable position is associated with the specific ray track. 2506 // Each ray track can have a control turnout assigned. Setting this turnout to a specific 2507 // state (usually THROWN) is the command to align the turntable to that ray. 2508 // The following logic adds a CONDITION to the Signal Mast Logic, requiring that the 2509 // correct ray's turnout is in its required state before the signal will clear. 2510 // This does NOT command the turnout to move; it only checks its state for the interlocking. 2511 Set<LayoutEditor> layout = InstanceManager.getDefault(EditorManager.class).getAll(LayoutEditor.class); 2512 for (LayoutEditor lay : layout) { 2513 for (LayoutTurntable turntable : lay.getLayoutTurntables()) { 2514 // Check for a path from an Approach Mast to the Buffer Mast (Path 3). 2515 // The destination block is the turntable block, and the destination mast is the buffer mast. 2516 if (turntable.getLayoutBlock() == destinationBlock && turntable.getBufferMast() == destinationSignalMast) { 2517 // The source mast's facing block is the ray block for this path. 2518 for (LayoutTurntable.RayTrack ray : turntable.getRayTrackList()) { 2519 if (ray.getConnect() != null && ray.getConnect().getLayoutBlock() == DefaultSignalMastLogic.this.facingBlock) { 2520 // This is the correct ray. Get its control turnout and required state. 2521 Turnout rayTurnout = ray.getTurnout(); 2522 int requiredState = ray.getTurnoutState(); 2523 if (rayTurnout != null) { 2524 turnoutSettings.put(rayTurnout, requiredState); 2525 } 2526 break; // Found the ray, no need to check others. 2527 } 2528 } 2529 } 2530 // Check for a path from the Exit Mast to a remote mast (Path 1). 2531 // The source mast is the turntable's exit mast. 2532 if (turntable.getExitSignalMast() == getSourceMast()) { 2533 // The protecting block is the ray block for this path. 2534 for (LayoutTurntable.RayTrack ray : turntable.getRayTrackList()) { 2535 if (ray.getConnect() != null && ray.getConnect().getLayoutBlock() == protectingBlock) { 2536 // This is the correct ray. Get its control turnout and required state. 2537 Turnout rayTurnout = ray.getTurnout(); 2538 int requiredState = ray.getTurnoutState(); 2539 if (rayTurnout != null) { 2540 turnoutSettings.put(rayTurnout, requiredState); 2541 } 2542 break; // Found the ray, no need to check others. 2543 } 2544 } 2545 } 2546 } 2547 } 2548 // ----- End Turntable Alignment Check ----- 2549 if (useLayoutEditorTurnouts) { 2550 setAutoTurnouts(turnoutSettings); 2551 } 2552 return block; 2553 } 2554 2555 /** 2556 * Generate auto signalmast for a given SML. Looks through all the other 2557 * logics to see if there are any blocks that are in common and thus 2558 * will add the other signal mast protecting that block. 2559 * 2560 * @param sml The Signal Mast Logic for which to set up 2561 * autoSignalMasts 2562 * @param overwrite When true, replace an existing autoMasts list in the 2563 * SML 2564 */ 2565 void setupAutoSignalMast(SignalMastLogic sml, boolean overwrite) { 2566 if (!allowAutoSignalMastGeneration) { 2567 return; 2568 } 2569 List<SignalMastLogic> smlList = InstanceManager.getDefault(SignalMastLogicManager.class) 2570 .getLogicsByDestination(destinationSignalMast); 2571 List<Block> allBlock = new ArrayList<>(); 2572 2573 userSetBlocks.forEach(nbh -> allBlock.add((Block) nbh.getBean())); 2574 2575 Set<Block> blockKeys = autoBlocks.keySet(); 2576 blockKeys.stream().filter(key -> (!allBlock.contains(key))).forEachOrdered(key -> 2577 allBlock.add(key)); 2578 Hashtable<SignalMast, String> masts; 2579 if (sml != null) { 2580 masts = autoMasts; 2581 if (sml.areBlocksIncluded(allBlock)) { 2582 SignalMast mast = sml.getSourceMast(); 2583 String danger = mast.getAppearanceMap().getSpecificAppearance(SignalAppearanceMap.DANGER); 2584 masts.put(mast, danger); 2585 } else { 2586 //No change so will leave. 2587 return; 2588 } 2589 } else { 2590 masts = new Hashtable<>(); 2591 for (int i = 0; i < smlList.size(); i++) { 2592 if (smlList.get(i).areBlocksIncluded(allBlock)) { 2593 SignalMast mast = smlList.get(i).getSourceMast(); 2594 String danger = mast.getAppearanceMap().getSpecificAppearance(SignalAppearanceMap.DANGER); 2595 masts.put(mast, danger); 2596 } 2597 } 2598 } 2599 setAutoMasts(masts, overwrite); 2600 } 2601 2602 /** 2603 * Add a certain Signal Mast to the list of AutoSignalMasts for this 2604 * SML. 2605 * 2606 * @param mast The Signal Mast to be added 2607 */ 2608 void addAutoSignalMast(SignalMast mast) { 2609 log.debug("{} add mast to auto list {}", destinationSignalMast.getDisplayName(), mast); 2610 String danger = mast.getAppearanceMap().getSpecificAppearance(SignalAppearanceMap.DANGER); 2611 if (danger == null) { 2612 log.error("Can not add SignalMast {} to logic for {} to {} " 2613 + "as it does not have a Danger appearance configured", 2614 mast.getDisplayName(), source.getDisplayName(), destinationSignalMast.getDisplayName()); 2615 return; 2616 } 2617 this.autoMasts.put(mast, danger); 2618 if (destMastInit) { 2619 mast.addPropertyChangeListener(propertySignalMastListener); 2620 } 2621 firePropertyChange(PROPERTY_AUTO_MASTS, null, this.destinationSignalMast); 2622 } 2623 2624 /** 2625 * Remove a certain Signal Mast from the list of AutoSignalMasts for 2626 * this SML. 2627 * 2628 * @param mast The Signal Mast to be removed 2629 */ 2630 void removeAutoSignalMast(SignalMast mast) { 2631 this.autoMasts.remove(mast); 2632 if (destMastInit) { 2633 mast.removePropertyChangeListener(propertySignalMastListener); 2634 } 2635 firePropertyChange(PROPERTY_AUTO_MASTS, this.destinationSignalMast, null); 2636 } 2637 2638 boolean useLayoutEditor() { 2639 return useLayoutEditor; 2640 } 2641 2642 boolean useLayoutEditorBlocks() { 2643 return useLayoutEditorBlocks; 2644 } 2645 2646 boolean useLayoutEditorTurnouts() { 2647 return useLayoutEditorTurnouts; 2648 } 2649 2650 boolean allowAutoSignalMastGeneration = false; 2651 2652 boolean allowAutoSignalMastGen() { 2653 return allowAutoSignalMastGeneration; 2654 } 2655 2656 void allowAutoSignalMastGen(boolean gen) { 2657 if (allowAutoSignalMastGeneration == gen) { 2658 return; 2659 } 2660 allowAutoSignalMastGeneration = gen; 2661 } 2662 2663 /** 2664 * Remove references from this Destination Mast and clear lists, so that 2665 * it can eventually be garbage-collected. 2666 * <p> 2667 * Note: This does not stop any delayed operations that might be queued. 2668 */ 2669 void dispose() { 2670 disposed = true; 2671 clearTurnoutLock(); 2672 destinationSignalMast.removePropertyChangeListener(propertyDestinationMastListener); 2673 setBlocks(null); 2674 setAutoBlocks(null); 2675 setTurnouts(null); 2676 setAutoTurnouts(null); 2677 setSensors(null); 2678 setMasts(null); 2679 setAutoMasts(null, true); 2680 } 2681 2682 void lockTurnouts() { 2683 // We do not allow the turnouts to be locked if we are disposing the logic, 2684 // if the logic is not active, or if we do not allow the turnouts to be locked. 2685 if ((disposed) || (!lockTurnouts) || (!active)) { 2686 return; 2687 } 2688 2689 userSetTurnouts.stream().map(nbh -> (Turnout) nbh.getBean()).forEachOrdered(key -> { 2690 key.setLocked(Turnout.CABLOCKOUT + Turnout.PUSHBUTTONLOCKOUT, true); 2691 }); 2692 Enumeration<Turnout> keys = autoTurnouts.keys(); 2693 while (keys.hasMoreElements()) { 2694 Turnout key = keys.nextElement(); 2695 key.setLocked(Turnout.CABLOCKOUT + Turnout.PUSHBUTTONLOCKOUT, true); 2696 } 2697 } 2698 2699 void clearTurnoutLock() { 2700 // We do not allow the turnout lock to be cleared if we are not active, 2701 // and the lock flag has not been set. 2702 if ((!lockTurnouts) && (!active)) { 2703 return; 2704 } 2705 2706 Enumeration<Turnout> keys = autoTurnouts.keys(); 2707 while (keys.hasMoreElements()) { 2708 Turnout key = keys.nextElement(); 2709 key.setLocked(Turnout.CABLOCKOUT + Turnout.PUSHBUTTONLOCKOUT, false); 2710 } 2711 2712 userSetTurnouts.stream().map(nbh -> (Turnout) nbh.getBean()).forEachOrdered(key -> 2713 key.setLocked(Turnout.CABLOCKOUT + Turnout.PUSHBUTTONLOCKOUT, false)); 2714 } 2715 2716 protected void calculateSpeed() { 2717 log.debug("{} calculate the speed setting for this logic ie what the signalmast will display", destinationSignalMast.getDisplayName()); 2718 minimumBlockSpeed = 0.0f; 2719 Enumeration<Turnout> keys = autoTurnouts.keys(); 2720 while (keys.hasMoreElements()) { 2721 Turnout key = keys.nextElement(); 2722 log.debug("{} turnout {}", destinationSignalMast.getDisplayName(), key.getDisplayName()); 2723 if (!isTurnoutIncluded(key)) { 2724 if (autoTurnouts.get(key) == Turnout.CLOSED) { 2725 if (((key.getStraightLimit() < minimumBlockSpeed) || (minimumBlockSpeed == 0)) && (key.getStraightLimit() != -1)) { 2726 minimumBlockSpeed = key.getStraightLimit(); 2727 log.debug("{} turnout {} set speed to {}", destinationSignalMast.getDisplayName(), key.getDisplayName(), minimumBlockSpeed); 2728 } 2729 } else { 2730 if (((key.getDivergingLimit() < minimumBlockSpeed) || (minimumBlockSpeed == 0)) && (key.getDivergingLimit() != -1)) { 2731 minimumBlockSpeed = key.getDivergingLimit(); 2732 log.debug("{} turnout {} set speed to {}", destinationSignalMast.getDisplayName(), key.getDisplayName(), minimumBlockSpeed); 2733 } 2734 } 2735 } 2736 } 2737 2738 userSetTurnouts.forEach(nbh -> { 2739 Turnout key = (Turnout) nbh.getBean(); 2740 if (nbh.getSetting() == Turnout.CLOSED) { 2741 if (((key.getStraightLimit() < minimumBlockSpeed) || (minimumBlockSpeed == 0)) && (key.getStraightLimit() != -1)) { 2742 minimumBlockSpeed = key.getStraightLimit(); 2743 log.debug("{} turnout {} set speed to {}", destinationSignalMast.getDisplayName(), key.getDisplayName(), minimumBlockSpeed); 2744 } 2745 } else if (nbh.getSetting() == Turnout.THROWN) { 2746 if (((key.getDivergingLimit() < minimumBlockSpeed) || (minimumBlockSpeed == 0)) && (key.getDivergingLimit() != -1)) { 2747 minimumBlockSpeed = key.getDivergingLimit(); 2748 log.debug("{} turnout {} set speed to {}", destinationSignalMast.getDisplayName(), key.getDisplayName(), minimumBlockSpeed); 2749 } 2750 } 2751 }); 2752 2753 Set<Block> autoBlockKeys = autoBlocks.keySet(); 2754 for (Block key : autoBlockKeys) { 2755 log.debug("{} auto block add list {}", destinationSignalMast.getDisplayName(), key.getDisplayName()); 2756 if (!isBlockIncluded(key)) { 2757 if (((key.getSpeedLimit() < minimumBlockSpeed) || (minimumBlockSpeed == 0)) && (key.getSpeedLimit() != -1)) { 2758 minimumBlockSpeed = key.getSpeedLimit(); 2759 log.debug("{} block {} set speed to {}", destinationSignalMast.getDisplayName(), key.getDisplayName(), minimumBlockSpeed); 2760 } 2761 } 2762 } 2763 for (NamedBeanSetting nbh : userSetBlocks) { 2764 Block key = (Block) nbh.getBean(); 2765 if (((key.getSpeedLimit() < minimumBlockSpeed) || (minimumBlockSpeed == 0)) && (key.getSpeedLimit() != -1)) { 2766 log.debug("{} block {} set speed to {}", destinationSignalMast.getDisplayName(), key.getDisplayName(), minimumBlockSpeed); 2767 minimumBlockSpeed = key.getSpeedLimit(); 2768 } 2769 } 2770 /*if(minimumBlockSpeed==-0.1f) 2771 minimumBlockSpeed==0.0f;*/ 2772 } 2773 2774 protected PropertyChangeListener propertySensorListener = new PropertyChangeListener() { 2775 @Override 2776 public void propertyChange(PropertyChangeEvent e) { 2777 Sensor sen = (Sensor) e.getSource(); 2778 log.debug("{} to {} destination sensor {} trigger {}",source.getDisplayName(), destinationSignalMast.getDisplayName(), sen.getDisplayName(), e.getPropertyName()); 2779 if ( Sensor.PROPERTY_KNOWN_STATE.equals(e.getPropertyName())) { 2780 int now = ((Integer) e.getNewValue()); 2781 log.debug("current value {} value we want {}", now, getSensorState(sen)); 2782 if (isSensorIncluded(sen) && getSensorState(sen) != now) { 2783 log.debug("Sensor {} caused the signalmast to be set to danger", sen.getDisplayName()); 2784 //getSourceMast().setAspect(stopAspect); 2785 if (active == true) { 2786 active = false; 2787 setSignalAppearance(); 2788 } 2789 } else if (getSensorState(sen) == now) { 2790 log.debug("{} sensor {} triggers a calculation of change", destinationSignalMast.getDisplayName(), sen.getDisplayName()); 2791 checkState(); 2792 } 2793 } 2794 } 2795 }; 2796 2797 protected PropertyChangeListener propertyTurnoutListener = new PropertyChangeListener() { 2798 @Override 2799 public void propertyChange(PropertyChangeEvent e) { 2800 Turnout turn = (Turnout) e.getSource(); 2801 // log.debug(destination.getDisplayName() + " destination sensor "+ sen.getDisplayName() + "trigger"); 2802 if ( Turnout.PROPERTY_KNOWN_STATE.equals(e.getPropertyName())) { 2803 //Need to check this against the manual list vs auto list 2804 //The manual list should over-ride the auto list 2805 int now = ((Integer) e.getNewValue()); 2806 if (isTurnoutIncluded(turn)) { 2807 if (getTurnoutState(turn) != now) { 2808 log.debug("Turnout {} caused the signalmast to be set", turn.getDisplayName()); 2809 log.debug("From {} to {} Turnout {} caused the signalmast to be set to danger", getSourceMast().getDisplayName(), destinationSignalMast.getDisplayName(), turn.getDisplayName()); 2810 if (active == true) { 2811 active = false; 2812 setSignalAppearance(); 2813 } 2814 } else { 2815 log.debug("{} turnout {} triggers a calculation of change", destinationSignalMast.getDisplayName(), turn.getDisplayName()); 2816 checkState(); 2817 } 2818 } else if (autoTurnouts.containsKey(turn)) { 2819 if (getAutoTurnoutState(turn) != now) { 2820 log.debug("Turnout {} auto caused the signalmast to be set", turn.getDisplayName()); 2821 log.debug("From {} to {} Auto Turnout {} auto caused the signalmast to be set to danger", getSourceMast().getDisplayName(), destinationSignalMast.getDisplayName(), turn.getDisplayName()); 2822 if (active == true) { 2823 active = false; 2824 setSignalAppearance(); 2825 } 2826 } else { 2827 log.debug("From {} to {} turnout {} triggers a calculation of change", getSourceMast().getDisplayName(), destinationSignalMast.getDisplayName(), turn.getDisplayName()); 2828 checkState(); 2829 } 2830 } 2831 2832 } else if ( Turnout.PROPERTY_TURNOUT_STRAIGHT_SPEED.equals(e.getPropertyName()) 2833 || Turnout.PROPERTY_TURNOUT_DIVERGING_SPEED.equals(e.getPropertyName())) { 2834 calculateSpeed(); 2835 } 2836 } 2837 }; 2838 2839 protected PropertyChangeListener propertyBlockListener = new PropertyChangeListener() { 2840 @Override 2841 public void propertyChange(PropertyChangeEvent e) { 2842 Block block = (Block) e.getSource(); 2843 log.debug("{} destination block {} trigger {} {}", destinationSignalMast.getDisplayName(), block.getDisplayName(), e.getPropertyName(), e.getNewValue()); 2844 if ( Block.PROPERTY_STATE.equals(e.getPropertyName()) || Block.PROPERTY_ALLOCATED.equals(e.getPropertyName())) { 2845 // TODO: what is this? 2846 log.debug("Included in user entered block {}", Boolean.toString(isBlockIncluded(block))); 2847 log.debug("Included in AutoGenerated Block {}", Boolean.toString(autoBlocks.containsKey(block))); 2848 if (isBlockIncluded(block)) { 2849 log.debug("{} in manual block", destinationSignalMast.getDisplayName()); 2850 log.debug(" state: {} {}", getBlockState(block), block.getState()); 2851 checkState(); 2852 } else if (autoBlocks.containsKey(block)) { 2853 log.debug("{} in auto block", destinationSignalMast.getDisplayName()); 2854 log.debug(" states: {} {}", getAutoBlockState(block), block.getState()); 2855 checkState(); 2856 } else { 2857 log.debug("{} Not found", destinationSignalMast.getDisplayName()); 2858 } 2859 } else if ( e.getPropertyName().equals("BlockSpeedChange")) { 2860 calculateSpeed(); 2861 } 2862 } 2863 }; 2864 2865 protected PropertyChangeListener propertySignalMastListener = new PropertyChangeListener() { 2866 @Override 2867 public void propertyChange(PropertyChangeEvent e) { 2868 2869 SignalMast mast = (SignalMast) e.getSource(); 2870 log.debug("{} signalmast change {} {}", destinationSignalMast.getDisplayName(), mast.getDisplayName(), e.getPropertyName()); 2871 // log.debug(destination.getDisplayName() + " destination sensor "+ sen.getDisplayName() + "trigger"); 2872 if ( SignalMast.PROPERTY_ASPECT.equals(e.getPropertyName())) { 2873 2874 String now = ((String) e.getNewValue()); 2875 log.debug("{} match property {}", destinationSignalMast.getDisplayName(), now); 2876 if (isSignalMastIncluded(mast)) { 2877 if (!now.equals(getSignalMastState(mast))) { 2878 log.debug("{} in mast list SignalMast {} caused the signalmast to be set", destinationSignalMast.getDisplayName(), mast.getDisplayName()); 2879 log.debug("SignalMast {} caused the signalmast to be set", mast.getDisplayName()); 2880 if (active) { 2881 active = false; 2882 setSignalAppearance(); 2883 } 2884 } else { 2885 log.debug("{} in mast list signalmast change", destinationSignalMast.getDisplayName()); 2886 checkState(); 2887 } 2888 } else if (autoMasts.containsKey(mast)) { 2889 if (!now.equals(getAutoSignalMastState(mast))) { 2890 log.debug("SignalMast {} caused the signalmast to be set", mast.getDisplayName()); 2891 log.debug("{} in auto mast list SignalMast {} caused the signalmast to be set", destinationSignalMast.getDisplayName(), mast.getDisplayName()); 2892 if (active) { 2893 active = false; 2894 setSignalAppearance(); 2895 } 2896 } else { 2897 log.debug("{} in auto mast list signalmast change", destinationSignalMast.getDisplayName()); 2898 checkState(); 2899 } 2900 } 2901 } 2902 } 2903 }; 2904 2905 private class NamedBeanSetting { 2906 2907 NamedBeanHandle<?> namedBean; 2908 int setting = 0; 2909 String strSetting = null; 2910 2911 NamedBeanSetting(NamedBeanHandle<?> namedBean, int setting) { 2912 this.namedBean = namedBean; 2913 this.setting = setting; 2914 } 2915 2916 NamedBeanSetting(NamedBeanHandle<?> namedBean, String setting) { 2917 this.namedBean = namedBean; 2918 strSetting = setting; 2919 } 2920 2921 NamedBean getBean() { 2922 return namedBean.getBean(); 2923 } 2924 2925 NamedBeanHandle<?> getNamedBean() { 2926 return namedBean; 2927 } 2928 2929 int getSetting() { 2930 return setting; 2931 } 2932 2933 String getStringSetting() { 2934 return strSetting; 2935 } 2936 2937 String getBeanName() { 2938 return namedBean.getName(); 2939 } 2940 } 2941 } 2942 2943 /** 2944 * The listener on the destination Signal Mast. 2945 */ 2946 private PropertyChangeListener propertyDestinationMastListener = new PropertyChangeListener() { 2947 @Override 2948 public void propertyChange(PropertyChangeEvent e) { 2949 SignalMast mast = (SignalMast) e.getSource(); 2950 if (mast == destination) { 2951 log.debug("destination mast change {}", mast.getDisplayName()); 2952 setSignalAppearance(); 2953 } 2954 } 2955 }; 2956 2957 /** 2958 * The listener on the source Signal Mast. 2959 */ 2960 private PropertyChangeListener propertySourceMastListener = new PropertyChangeListener() { 2961 @Override 2962 public void propertyChange(PropertyChangeEvent e) { 2963 SignalMast mast = (SignalMast) e.getSource(); 2964 if ((mast == source) && ( SignalMast.PROPERTY_HELD.equals(e.getPropertyName()))) { 2965 log.debug("source mast change {} {}", mast.getDisplayName(), e.getPropertyName()); 2966 setSignalAppearance(); 2967 } 2968 } 2969 }; 2970 2971 //@todo need to think how we deal with auto generated lists based upon the layout editor. 2972 @Override 2973 public void vetoableChange(PropertyChangeEvent evt) throws PropertyVetoException { 2974 NamedBean nb = (NamedBean) evt.getOldValue(); 2975 if (Manager.PROPERTY_CAN_DELETE.equals(evt.getPropertyName())) { 2976 boolean found = false; 2977 StringBuilder message = new StringBuilder(); 2978 if (nb instanceof SignalMast) { 2979 if (nb.equals(source)) { 2980 message.append("Has SignalMast Logic attached which will be <b>Deleted</b> to <ul>"); 2981 for (SignalMast sm : getDestinationList()) { 2982 message.append("<li>"); 2983 message.append(sm.getDisplayName()); 2984 message.append("</li>"); 2985 } 2986 message.append("</ul>"); 2987 throw new PropertyVetoException(message.toString(), evt); 2988 2989 } else if (isDestinationValid((SignalMast) nb)) { 2990 throw new PropertyVetoException("Is the end point mast for logic attached to signal mast " + source.getDisplayName() + " which will be <b>Deleted</b> ", evt); 2991 } 2992 for (SignalMast sm : getDestinationList()) { 2993 if (isSignalMastIncluded((SignalMast) nb, sm)) { 2994 message.append("<li>"); 2995 message.append("Used in conflicting logic of ").append(source.getDisplayName()) 2996 .append(" & ").append(sm.getDisplayName()).append("</li>"); 2997 } 2998 } 2999 } 3000 if (nb instanceof Turnout) { 3001 for (SignalMast sm : getDestinationList()) { 3002 if (isTurnoutIncluded((Turnout) nb, sm)) { 3003 message.append("<li>Is in logic between Signal Masts ").append(source.getDisplayName()) 3004 .append(" ").append(sm.getDisplayName()).append("</li>"); 3005 found = true; 3006 } 3007 } 3008 } 3009 if (nb instanceof Sensor) { 3010 for (SignalMast sm : getDestinationList()) { 3011 if (isSensorIncluded((Sensor) nb, sm)) { 3012 message.append("<li>"); 3013 message.append("Is in logic between Signal Masts ").append(source.getDisplayName()) 3014 .append(" ").append(sm.getDisplayName()).append("</li>"); 3015 found = true; 3016 } 3017 } 3018 } 3019 if (found) { 3020 throw new PropertyVetoException(message.toString(), evt); 3021 } 3022 } else if (Manager.PROPERTY_DO_DELETE.equals(evt.getPropertyName())) { 3023 if (nb instanceof SignalMast) { 3024 if (nb.equals(source)) { 3025 dispose(); 3026 } 3027 if (isDestinationValid((SignalMast) nb)) { 3028 removeDestination((SignalMast) nb); 3029 } 3030 for (SignalMast sm : getDestinationList()) { 3031 if (isSignalMastIncluded((SignalMast) nb, sm)) { 3032 log.warn("Unhandled condition: signal mast included during DoDelete"); 3033 // @todo need to deal with this situation 3034 } 3035 } 3036 } 3037 if (nb instanceof Turnout) { 3038 Turnout t = (Turnout) nb; 3039 getDestinationList().stream().filter(sm -> (isTurnoutIncluded(t, sm))).forEachOrdered(sm -> { 3040 removeTurnout(t, sm); 3041 }); 3042 } 3043 if (nb instanceof Sensor) { 3044 Sensor s = (Sensor) nb; 3045 getDestinationList().stream().filter(sm -> (isSensorIncluded(s, sm))).forEachOrdered(sm -> { 3046 removeSensor(s, sm); 3047 }); 3048 } 3049 } 3050 } 3051 3052 /** 3053 * Note: This does not stop any delayed operations that might be queued. 3054 */ 3055 @Override 3056 public void dispose() { 3057 disposing = true; 3058 getSourceMast().removePropertyChangeListener(propertySourceMastListener); 3059 Enumeration<SignalMast> en = destList.keys(); 3060 while (en.hasMoreElements()) { 3061 SignalMast dm = en.nextElement(); 3062 destList.get(dm).dispose(); 3063 } 3064 super.dispose(); // release any prop change listeners 3065 } 3066 3067 /** 3068 * {@inheritDoc } 3069 */ 3070 @Override 3071 public String getBeanType() { 3072 return Bundle.getMessage("BeanNameSignalMastLogic"); 3073 } 3074 3075 /** 3076 * No valid integer state, always return a constant. 3077 * 3078 * @return Always zero 3079 */ 3080 @Override 3081 public int getState() { 3082 return 0; 3083 } 3084 3085 @Override 3086 public void setState(int i) { 3087 } 3088 3089 /** 3090 * {@inheritDoc } 3091 */ 3092 @Override 3093 public List<NamedBeanUsageReport> getUsageReport(NamedBean bean) { 3094 List<NamedBeanUsageReport> report = new ArrayList<>(); 3095 if (bean != null) { 3096 if (bean.equals(getSourceMast())) { 3097 report.add(new NamedBeanUsageReport("SMLSourceMast")); // NOI18N 3098 } 3099 getDestinationList().forEach((dest) -> { 3100 if (bean.equals(dest)) { 3101 report.add(new NamedBeanUsageReport("SMLDestinationMast")); // NOI18N 3102 } 3103 getAutoBlocks(dest).forEach((block) -> { 3104 if (bean.equals(block)) { 3105 report.add(new NamedBeanUsageReport("SMLBlockAuto", dest)); // NOI18N 3106 } 3107 }); 3108 getBlocks(dest).forEach((block) -> { 3109 if (bean.equals(block)) { 3110 report.add(new NamedBeanUsageReport("SMLBlockUser", dest)); // NOI18N 3111 } 3112 }); 3113 getAutoTurnouts(dest).forEach((turnout) -> { 3114 if (bean.equals(turnout)) { 3115 report.add(new NamedBeanUsageReport("SMLTurnoutAuto", dest)); // NOI18N 3116 } 3117 }); 3118 getTurnouts(dest).forEach((turnout) -> { 3119 if (bean.equals(turnout)) { 3120 report.add(new NamedBeanUsageReport("SMLTurnoutUser", dest)); // NOI18N 3121 } 3122 }); 3123 getSensors(dest).forEach((sensor) -> { 3124 if (bean.equals(sensor)) { 3125 report.add(new NamedBeanUsageReport("SMLSensor", dest)); // NOI18N 3126 } 3127 }); 3128 getAutoMasts(dest).forEach((mast) -> { 3129 if (bean.equals(mast)) { 3130 report.add(new NamedBeanUsageReport("SMLMastAuto", dest)); // NOI18N 3131 } 3132 }); 3133 getSignalMasts(dest).forEach((mast) -> { 3134 if (bean.equals(mast)) { 3135 report.add(new NamedBeanUsageReport("SMLMastUser", dest)); // NOI18N 3136 } 3137 }); 3138 }); 3139 } 3140 return report; 3141 } 3142 3143 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DefaultSignalMastLogic.class); 3144 3145}