001package jmri.implementation; 002 003import java.util.ArrayList; 004import java.util.HashMap; 005import java.util.List; 006import java.util.regex.Pattern; 007 008import javax.annotation.*; 009 010import jmri.*; 011import jmri.jmrit.beantable.LRouteTableAction; 012import jmri.jmrit.entryexit.EntryExitPairs; 013 014/** 015 * Class providing the basic logic of the Logix interface. 016 * 017 * @author Dave Duchamp Copyright (C) 2007 018 * @author Pete Cressman Copyright (C) 2009 019 */ 020public class DefaultLogix extends AbstractNamedBean 021 implements Logix { 022 023 private final ConditionalManager conditionalManager; 024 025 public DefaultLogix(String systemName, String userName) { 026 this(systemName,userName,InstanceManager.getDefault(ConditionalManager.class)); 027 } 028 029 public DefaultLogix(String systemName,String userName,ConditionalManager conditionalManager) { 030 super(systemName, userName); 031 this.conditionalManager = conditionalManager; 032 } 033 034 public DefaultLogix(String systemName) { 035 this(systemName,InstanceManager.getDefault(ConditionalManager.class)); 036 } 037 038 public DefaultLogix(String systemName,ConditionalManager conditionalManager) { 039 super(systemName); 040 this.conditionalManager = conditionalManager; 041 } 042 043 @Override 044 @Nonnull 045 public String getBeanType() { 046 return Bundle.getMessage("BeanNameLogix"); // NOI18N 047 } 048 049 /** 050 * Persistant instance variables (saved between runs). Order is significant. 051 */ 052 private final ArrayList<String> _conditionalSystemNames = new ArrayList<>(); 053 private ArrayList<JmriSimplePropertyListener> _listeners = new ArrayList<>(); 054 055 /** 056 * Maintain a list of conditional objects. The key is the conditional system name 057 * @since 4.7.4 058 */ 059 private final HashMap<String, Conditional> _conditionalMap = new HashMap<>(); 060 061 /** 062 * Operational instance variables (not saved between runs) 063 */ 064 private boolean mEnabled = true; 065 066 private boolean _isActivated = false; 067 068 private boolean _isGuiSet = false; 069 070 /** 071 * Get number of Conditionals for this Logix 072 */ 073 @Override 074 public int getNumConditionals() { 075 return _conditionalSystemNames.size(); 076 } 077 078 /** 079 * Move 'row' to 'nextInOrder' and shift all between 'row' and 'nextInOrder' 080 * up one position {@literal ( row > nextInOrder )} 081 */ 082 @Override 083 public void swapConditional(int nextInOrder, int row) { 084 if (row <= nextInOrder) { 085 return; 086 } 087 String temp = _conditionalSystemNames.get(row); 088 for (int i = row; i > nextInOrder; i--) { 089 _conditionalSystemNames.set(i, _conditionalSystemNames.get(i - 1)); 090 } 091 _conditionalSystemNames.set(nextInOrder, temp); 092 } 093 094 /** 095 * Returns the system name of the conditional that will calculate in the 096 * specified order. This is also the order the Conditional is listed in the 097 * Add/Edit Logix dialog. If 'order' is greater than the number of 098 * Conditionals for this Logix, null is returned. 099 * 100 * @param order order in which the Conditional calculates. 101 */ 102 @Override 103 @CheckForNull 104 public String getConditionalByNumberOrder(int order) { 105 try { 106 return _conditionalSystemNames.get(order); 107 } catch (java.lang.IndexOutOfBoundsException ioob) { 108 return null; 109 } 110 } 111 112 /** 113 * Add a Conditional to this Logix R 114 * 115 * @param systemName The Conditional system name 116 * @param order the order this conditional should calculate in if 117 * order is negative, the conditional is added at the end 118 * of current group of conditionals 119 */ 120 @Override 121 public void addConditional(String systemName, int order) { 122 _conditionalSystemNames.add(systemName); 123 } 124 125 /** 126 * Add a child Conditional to the parent Logix. 127 * 128 * @since 4.7.4 129 * @param systemName The system name for the Conditional object. 130 * @param conditional The Conditional object. 131 * @return true if the Conditional was added, false otherwise. 132 */ 133 @Override 134 public boolean addConditional(String systemName, Conditional conditional) { 135 Conditional chkDuplicate = _conditionalMap.putIfAbsent(systemName, conditional); 136 if (chkDuplicate == null) { 137 return true; 138 } 139 log.error("Conditional '{}' has already been added to Logix '{}'", systemName, getSystemName()); // NOI18N 140 return false; 141 } 142 143 /** 144 * Get a Conditional belonging to this Logix. 145 * 146 * @since 4.7.4 147 * @param systemName The name of the Conditional object. 148 * @return the Conditional object or null if not found. 149 */ 150 @Override 151 @CheckForNull 152 public Conditional getConditional(String systemName) { 153 return _conditionalMap.get(systemName); 154 } 155 156 /** 157 * Set enabled status. Enabled is a bound property All conditionals are set 158 * to UNKNOWN state and recalculated when the Logix is enabled, provided the 159 * Logix has been previously activated. 160 */ 161 @Override 162 public void setEnabled(boolean state) { 163 164 boolean old = mEnabled; 165 mEnabled = state; 166 if (old != state) { 167 boolean active = _isActivated; 168 deActivateLogix(); 169 activateLogix(); 170 _isActivated = active; 171 for (int i = _listeners.size() - 1; i >= 0; i--) { 172 _listeners.get(i).setEnabled(state); 173 } 174 firePropertyChange(PROPERTY_ENABLED, old, state); 175 } 176 } 177 178 /** 179 * Get enabled status 180 */ 181 @Override 182 public boolean getEnabled() { 183 return mEnabled; 184 } 185 186 /** 187 * Delete a Conditional and remove it from this Logix 188 * <p> 189 * Note: Since each Logix must have at least one Conditional to do anything, 190 * the user is warned in Logix Table Action when the last Conditional is 191 * deleted. 192 * 193 * @param systemName The Conditional system name 194 * @return null if Conditional was successfully deleted or not present, otherwise 195 * returns a string array list of current usage that prevent deletion, used to present 196 * a warning dialog to the user 197 */ 198 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "PZLA_PREFER_ZERO_LENGTH_ARRAYS", 199 justification = "null returned is documented in each method to mean completed without problems") 200 @Override 201 public String[] deleteConditional(String systemName) { 202 if (_conditionalSystemNames.isEmpty()) { 203 return null; 204 } 205 206 // check other Logix(es) for use of this conditional (systemName) for use as a 207 // variable in one of their conditionals 208 ArrayList<String> checkReferences = conditionalManager.getWhereUsed(systemName); 209 if (checkReferences != null) { 210 Conditional c = getConditional(systemName); 211 String refName = checkReferences.get(0); 212 Logix x = conditionalManager.getParentLogix(refName); 213 if ( x == null ) { 214 log.error("Unable to get Parent Logix {} while deleting Conditional {}", 215 refName, systemName); 216 return null; 217 } 218 Conditional cRef = x.getConditional(refName); 219 return new String[]{c.getUserName(), c.getSystemName(), cRef.getUserName(), 220 cRef.getSystemName(), x.getUserName(), x.getSystemName()}; 221 } 222 223 // Confirm the presence of the Conditional object 224 Conditional c = conditionalManager.getBySystemName(systemName); 225 if (c == null) { 226 log.error("attempt to delete non-existing Conditional - {}", systemName); // NOI18N 227 return null; 228 } 229 230 // Remove Conditional from this logix 231 if (!_conditionalSystemNames.remove(systemName)) { 232 log.error("attempt to delete Conditional not in Logix: {}", systemName); // NOI18N 233 return null; 234 } 235 236 _conditionalMap.remove(systemName); 237 return null; 238 } 239 240 /** 241 * Calculate all Conditionals, triggering action if the user specified 242 * conditions are met, and the Logix is enabled. 243 */ 244 @Override 245 public void calculateConditionals() { 246 for (String conditionalSystemName : _conditionalSystemNames) { 247 Conditional c = getConditional(conditionalSystemName); 248 if (c == null) { 249 log.error("Invalid conditional system name when calculating Logix - {}", 250 conditionalSystemName); 251 } else { 252 // calculate without taking any action unless Logix is enabled 253 c.calculate(mEnabled, null); 254 } 255 } 256 } 257 258 /** 259 * Activate the Logix, starts Logix processing by connecting all inputs that 260 * are included the Conditionals in this Logix. 261 * <p> 262 * A Logix must be activated before it will calculate any of its 263 * Conditionals. 264 */ 265 @Override 266 public void activateLogix() { 267 // if the Logix is already busy, simply return 268 if (_isActivated) { 269 return; 270 } 271 // set the state of all Conditionals to UNKNOWN 272 resetConditionals(); 273 // assemble a list of needed listeners 274 assembleListenerList(); 275 // create and attach the needed property change listeners 276 // start a minute Listener if needed 277 for (JmriSimplePropertyListener listener : _listeners) { 278 startListener(listener); 279 } 280 // mark this Logix as busy 281 _isActivated = true; 282 // calculate this Logix to set initial state of Conditionals 283 calculateConditionals(); 284 } 285 286 private void resetConditionals() { 287 for (String conditionalSystemName : _conditionalSystemNames) { 288 Conditional conditional = getConditional(conditionalSystemName); 289 if (conditional != null) { 290 try { 291 conditional.setState(NamedBean.UNKNOWN); 292 } catch (JmriException ignore) { 293 } 294 } 295 } 296 } 297 298 // Pattern to check for new style NX system name 299 static final Pattern NXUUID = Pattern.compile( 300 "^IN:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", // NOI18N 301 Pattern.CASE_INSENSITIVE); 302 303 /** 304 * ConditionalVariables only have a single name field. For user interface purposes 305 * a gui name is used for the referenced conditional user name. This is not used 306 * for other object types. 307 * <p> 308 * In addition to setting the GUI name, any state variable references are changed to 309 * conditional system names. This converts the XML system/user name field to the system name 310 * for conditional references. It does not affect other objects such as sensors, turnouts, etc. 311 * <p> 312 * For Entry/Exit references, replace NX user names and old style NX UUID references 313 * with the new style "IN:" + UUID reference. If the referenced NX does not exist, 314 * it will be removed from the Variable or Action list. (4.11.4) 315 * <p> 316 * Called by {@link jmri.managers.DefaultLogixManager#activateAllLogixs} 317 * @since 4.7.4 318 */ 319 @Override 320 public void setGuiNames() { 321 if (_isGuiSet) { 322 return; 323 } 324 if ("SYS".equals(getSystemName())) { 325 _isGuiSet = true; 326 return; 327 } 328 for (String cName : _conditionalSystemNames) { 329 Conditional conditional = getConditional(cName); 330 if (conditional == null) { 331 // A Logix index entry exists without a corresponding conditional. This 332 // should never happen. 333 log.error("setGuiNames: Missing conditional for Logix index entry, " 334 + " Logix name = '{}', Conditional index name = '{}'", // NOI18N 335 getSystemName(), cName); 336 continue; 337 } 338 List<ConditionalVariable> varList = conditional.getCopyOfStateVariables(); 339 boolean isDirty = false; 340 ArrayList<ConditionalVariable> badVariable = new ArrayList<>(); 341 for (ConditionalVariable condVar : varList) { 342 // Find any Conditional State Variables 343 if (condVar.getType() == Conditional.Type.CONDITIONAL_TRUE 344 || condVar.getType() == Conditional.Type.CONDITIONAL_FALSE) { 345 // Get the referenced (target) conditonal -- The name can be either a system name or a user name 346 Conditional cRef = conditionalManager.getConditional(condVar.getName()); 347 if (cRef != null) { 348 // re-arrange names as needed 349 condVar.setName(cRef.getSystemName()); // The state variable reference is now a conditional system name 350 String uName = cRef.getUserName(); 351 if (uName == null || uName.isEmpty()) { 352 condVar.setGuiName(cRef.getSystemName()); 353 } else { 354 condVar.setGuiName(uName); 355 } 356 // Add the conditional reference to the where used map 357 conditionalManager.addWhereUsed(condVar.getName(), cName); 358 isDirty = true; 359 } else { 360 log.error("setGuiNames: For conditional '{}' in logix '{}', " 361 + "the referenced conditional, '{}', does not exist", 362 cName, getSystemName(), condVar.getName()); 363 } 364 } 365 366 // Find any Entry/Exit State Variables 367 if (condVar.getType() == Conditional.Type.ENTRYEXIT_ACTIVE 368 || condVar.getType() == Conditional.Type.ENTRYEXIT_INACTIVE) { 369 if (!NXUUID.matcher(condVar.getName()).find()) { 370 // Either a user name or an old style system name (plain UUID) 371 jmri.jmrit.entryexit.DestinationPoints dp = 372 InstanceManager.getDefault(EntryExitPairs.class). 373 getNamedBean(condVar.getName()); 374 if (dp != null) { 375 // Replace name with current system name 376 condVar.setName(dp.getSystemName()); 377 isDirty = true; 378 } else { 379 log.error("setGuiNames: For conditional '{}' in logix '{}', " 380 + "the referenced Entry Exit Pair, '{}', does not exist", 381 cName, getSystemName(), condVar.getName()); 382 badVariable.add(condVar); 383 } 384 } 385 } 386 } 387 if (!badVariable.isEmpty()) { 388 isDirty = true; 389 badVariable.forEach(varList::remove); 390 } 391 if (isDirty) { 392 conditional.setStateVariables(varList); 393 } 394 395 List<ConditionalAction> actionList = conditional.getCopyOfActions(); 396 isDirty = false; 397 ArrayList<ConditionalAction> badAction = new ArrayList<>(); 398 for (ConditionalAction action : actionList) { 399 // Find any Entry/Exit Actions 400 if (action.getType() == Conditional.Action.SET_NXPAIR_ENABLED 401 || action.getType() == Conditional.Action.SET_NXPAIR_DISABLED 402 || action.getType() == Conditional.Action.SET_NXPAIR_SEGMENT) { 403 if (!NXUUID.matcher(action.getDeviceName()).find()) { 404 // Either a user name or an old style system name (plain UUID) 405 jmri.jmrit.entryexit.DestinationPoints dp = 406 InstanceManager.getDefault(EntryExitPairs.class). 407 getNamedBean(action.getDeviceName()); 408 if (dp != null) { 409 // Replace name with current system name 410 action.setDeviceName(dp.getSystemName()); 411 isDirty = true; 412 } else { 413 log.error("setGuiNames: For conditional '{}' in logix '{}', " 414 + "the referenced Entry Exit Pair, '{}', does not exist", // NOI18N 415 cName, getSystemName(), action.getDeviceName()); 416 badAction.add(action); 417 } 418 } 419 } 420 } 421 if (!badAction.isEmpty()) { 422 isDirty = true; 423 badAction.forEach(actionList::remove); 424 } 425 if (isDirty) { 426 conditional.setAction(actionList); 427 } 428 } 429 _isGuiSet = true; 430 } 431 432 /** 433 * Assemble a list of Listeners needed to activate this Logix. 434 */ 435 private void assembleListenerList() { 436 // initialize by cleaning up 437 // start from end down to safely delete preventing concurrent modification ex 438 for (int i = _listeners.size() - 1; i >= 0; i--) { 439 removeListener(_listeners.get(i)); 440 } 441 _listeners = new ArrayList<>(); 442 // cycle thru Conditionals to find objects to listen to 443 for (int i = 0; i < _conditionalSystemNames.size(); i++) { 444 Conditional conditional = getConditional(_conditionalSystemNames.get(i)); 445 if (conditional != null) { 446 List<ConditionalVariable> variableList = conditional.getCopyOfStateVariables(); 447 for (ConditionalVariable variable : variableList) { 448 // check if listening for a change has been suppressed 449 int varListenerType = 0; 450 String varName = variable.getName(); 451 NamedBeanHandle<?> namedBean = variable.getNamedBean(); 452 Conditional.Type varType = variable.getType(); 453 int signalAspect = -1; 454 // Get Listener type from variable type 455 switch (varType) { 456 case SENSOR_ACTIVE: 457 case SENSOR_INACTIVE: 458 varListenerType = LISTENER_TYPE_SENSOR; 459 break; 460 case TURNOUT_THROWN: 461 case TURNOUT_CLOSED: 462 varListenerType = LISTENER_TYPE_TURNOUT; 463 break; 464 case CONDITIONAL_TRUE: 465 case CONDITIONAL_FALSE: 466 varListenerType = LISTENER_TYPE_CONDITIONAL; 467 break; 468 case LIGHT_ON: 469 case LIGHT_OFF: 470 varListenerType = LISTENER_TYPE_LIGHT; 471 break; 472 case MEMORY_EQUALS: 473 case MEMORY_COMPARE: 474 case MEMORY_EQUALS_INSENSITIVE: 475 case MEMORY_COMPARE_INSENSITIVE: 476 varListenerType = LISTENER_TYPE_MEMORY; 477 break; 478 case ROUTE_FREE: 479 case ROUTE_OCCUPIED: 480 case ROUTE_ALLOCATED: 481 case ROUTE_SET: 482 case TRAIN_RUNNING: 483 varListenerType = LISTENER_TYPE_WARRANT; 484 break; 485 case FAST_CLOCK_RANGE: 486 varListenerType = LISTENER_TYPE_FASTCLOCK; 487 varName = "clock"; // NOI18N 488 break; 489 case SIGNAL_HEAD_RED: 490 varListenerType = LISTENER_TYPE_SIGNALHEAD; 491 signalAspect = SignalHead.RED; 492 break; 493 case SIGNAL_HEAD_YELLOW: 494 varListenerType = LISTENER_TYPE_SIGNALHEAD; 495 signalAspect = SignalHead.YELLOW; 496 break; 497 case SIGNAL_HEAD_GREEN: 498 varListenerType = LISTENER_TYPE_SIGNALHEAD; 499 signalAspect = SignalHead.GREEN; 500 break; 501 case SIGNAL_HEAD_DARK: 502 varListenerType = LISTENER_TYPE_SIGNALHEAD; 503 signalAspect = SignalHead.DARK; 504 break; 505 case SIGNAL_HEAD_LUNAR: 506 varListenerType = LISTENER_TYPE_SIGNALHEAD; 507 signalAspect = SignalHead.LUNAR; 508 break; 509 case SIGNAL_HEAD_FLASHRED: 510 varListenerType = LISTENER_TYPE_SIGNALHEAD; 511 signalAspect = SignalHead.FLASHRED; 512 break; 513 case SIGNAL_HEAD_FLASHYELLOW: 514 varListenerType = LISTENER_TYPE_SIGNALHEAD; 515 signalAspect = SignalHead.FLASHYELLOW; 516 break; 517 case SIGNAL_HEAD_FLASHGREEN: 518 varListenerType = LISTENER_TYPE_SIGNALHEAD; 519 signalAspect = SignalHead.FLASHGREEN; 520 break; 521 case SIGNAL_HEAD_FLASHLUNAR: 522 varListenerType = LISTENER_TYPE_SIGNALHEAD; 523 signalAspect = SignalHead.FLASHLUNAR; 524 break; 525 case SIGNAL_HEAD_LIT: 526 case SIGNAL_HEAD_HELD: 527 varListenerType = LISTENER_TYPE_SIGNALHEAD; 528 break; 529 case SIGNAL_MAST_ASPECT_EQUALS: 530 case SIGNAL_MAST_LIT: 531 case SIGNAL_MAST_HELD: 532 varListenerType = LISTENER_TYPE_SIGNALMAST; 533 break; 534 case BLOCK_STATUS_EQUALS: 535 varListenerType = LISTENER_TYPE_OBLOCK; 536 break; 537 case ENTRYEXIT_ACTIVE: 538 case ENTRYEXIT_INACTIVE: 539 varListenerType = LISTENER_TYPE_ENTRYEXIT; 540 break; 541 default: 542 if (!LRouteTableAction.getLogixInitializer().equals(varName)) { 543 log.warn("Unhandled conditional variable type: {}", varType); // NOI18N 544 } 545 break; 546 } 547 int positionOfListener = getPositionOfListener(varListenerType, varType, varName); 548 // add to list if new 549 JmriSimplePropertyListener listener; 550 if (positionOfListener == -1) { 551 switch (varListenerType) { 552 case LISTENER_TYPE_SENSOR: 553 listener = new JmriTwoStatePropertyListener(Sensor.PROPERTY_KNOWN_STATE, 554 LISTENER_TYPE_SENSOR, namedBean, varType, conditional); 555 break; 556 case LISTENER_TYPE_TURNOUT: 557 listener = new JmriTwoStatePropertyListener(Turnout.PROPERTY_KNOWN_STATE, 558 LISTENER_TYPE_TURNOUT, namedBean, varType, conditional); 559 break; 560 case LISTENER_TYPE_CONDITIONAL: 561 listener = new JmriTwoStatePropertyListener(Conditional.PROPERTY_KNOWN_STATE, 562 LISTENER_TYPE_CONDITIONAL, namedBean, varType, conditional); 563 break; 564 case LISTENER_TYPE_LIGHT: 565 listener = new JmriTwoStatePropertyListener(Light.PROPERTY_KNOWN_STATE, 566 LISTENER_TYPE_LIGHT, namedBean, varType, conditional); 567 break; 568 case LISTENER_TYPE_MEMORY: 569 listener = new JmriTwoStatePropertyListener(Memory.PROPERTY_VALUE, 570 LISTENER_TYPE_MEMORY, namedBean, varType, conditional); 571 break; 572 case LISTENER_TYPE_WARRANT: 573 listener = new JmriSimplePropertyListener(null, 574 LISTENER_TYPE_WARRANT, namedBean, varType, conditional); 575 break; 576 case LISTENER_TYPE_FASTCLOCK: 577 listener = new JmriClockPropertyListener(Timebase.PROPERTY_CHANGE_MINUTES, 578 LISTENER_TYPE_FASTCLOCK, varName, varType, conditional, 579 variable.getNum1(), variable.getNum2()); 580 break; 581 case LISTENER_TYPE_SIGNALHEAD: 582 if (signalAspect < 0) { 583 if (varType == Conditional.Type.SIGNAL_HEAD_LIT) { 584 listener = new JmriTwoStatePropertyListener(SignalHead.PROPERTY_LIT, 585 LISTENER_TYPE_SIGNALHEAD, namedBean, varType, conditional); 586 } else { // varType == Conditional.TYPE_SIGNAL_HEAD_HELD 587 listener = new JmriTwoStatePropertyListener(SignalHead.PROPERTY_HELD, 588 LISTENER_TYPE_SIGNALHEAD, namedBean, varType, conditional); 589 } 590 } else { 591 listener = new JmriMultiStatePropertyListener(SignalHead.PROPERTY_APPEARANCE, 592 LISTENER_TYPE_SIGNALHEAD, namedBean, varType, conditional, signalAspect); 593 } 594 break; 595 case LISTENER_TYPE_SIGNALMAST: 596 switch (varType) { 597 case SIGNAL_MAST_LIT: 598 listener = new JmriTwoStatePropertyListener(SignalMast.PROPERTY_LIT, 599 LISTENER_TYPE_SIGNALMAST, namedBean, varType, conditional); 600 break; 601 case SIGNAL_MAST_HELD: 602 listener = new JmriTwoStatePropertyListener(SignalMast.PROPERTY_HELD, 603 LISTENER_TYPE_SIGNALMAST, namedBean, varType, conditional); 604 break; 605 default: 606 listener = new JmriTwoStatePropertyListener(SignalMast.PROPERTY_ASPECT, 607 LISTENER_TYPE_SIGNALMAST, namedBean, varType, conditional); 608 break; 609 } 610 break; 611 case LISTENER_TYPE_OBLOCK: 612 listener = new JmriTwoStatePropertyListener(jmri.jmrit.logix.OBlock.PROPERTY_STATE, 613 LISTENER_TYPE_OBLOCK, namedBean, varType, conditional); 614 break; 615 case LISTENER_TYPE_ENTRYEXIT: 616 listener = new JmriTwoStatePropertyListener(EntryExitPairs.PROPERTY_ACTIVE, 617 LISTENER_TYPE_ENTRYEXIT, namedBean, varType, conditional); 618 break; 619 default: 620 if (!LRouteTableAction.getLogixInitializer().equals(varName)) { 621 log.error("Unknown (new) Variable Listener type= {}, for varName= {}, varType= {} in Conditional, {}", 622 varListenerType, varName, varType, _conditionalSystemNames.get(i)); 623 } 624 continue; 625 } 626 _listeners.add(listener); 627 } else { 628 switch (varListenerType) { 629 case LISTENER_TYPE_SENSOR: 630 case LISTENER_TYPE_TURNOUT: 631 case LISTENER_TYPE_CONDITIONAL: 632 case LISTENER_TYPE_LIGHT: 633 case LISTENER_TYPE_MEMORY: 634 case LISTENER_TYPE_WARRANT: 635 case LISTENER_TYPE_SIGNALMAST: 636 case LISTENER_TYPE_OBLOCK: 637 case LISTENER_TYPE_ENTRYEXIT: 638 listener = _listeners.get(positionOfListener); 639 listener.addConditional(conditional); 640 break; 641 case LISTENER_TYPE_FASTCLOCK: 642 JmriClockPropertyListener cpl = (JmriClockPropertyListener) _listeners.get(positionOfListener); 643 cpl.setRange(variable.getNum1(), variable.getNum2()); 644 cpl.addConditional(conditional); 645 break; 646 case LISTENER_TYPE_SIGNALHEAD: 647 if (signalAspect < 0) { 648 listener = _listeners.get(positionOfListener); 649 listener.addConditional(conditional); 650 } else { 651 JmriMultiStatePropertyListener mpl = (JmriMultiStatePropertyListener) _listeners.get(positionOfListener); 652 mpl.addConditional(conditional); 653 mpl.setState(signalAspect); 654 } 655 break; 656 default: 657 log.error("Unknown (old) Variable Listener type= {}, for varName= {}, varType= {} in Conditional, {}", 658 varListenerType, varName, varType, _conditionalSystemNames.get(i)); 659 } 660 } 661 // addition listeners needed for memory compare 662 if (varType == Conditional.Type.MEMORY_COMPARE || varType == Conditional.Type.MEMORY_COMPARE_INSENSITIVE) { 663 positionOfListener = getPositionOfListener(varListenerType, varType, variable.getDataString()); 664 if (positionOfListener == -1) { 665 String name = variable.getDataString(); 666 try { 667 Memory my = InstanceManager.memoryManagerInstance().provideMemory(name); 668 NamedBeanHandle<?> nb = InstanceManager.getDefault(NamedBeanHandleManager.class).getNamedBeanHandle(name, my); 669 670 listener = new JmriTwoStatePropertyListener(Memory.PROPERTY_VALUE, LISTENER_TYPE_MEMORY, 671 nb, varType, conditional); 672 _listeners.add(listener); 673 } catch (IllegalArgumentException ex) { 674 log.error("invalid memory name= \"{}\" in state variable", name); // NOI18N 675 break; 676 } 677 } else { 678 listener = _listeners.get(positionOfListener); 679 listener.addConditional(conditional); 680 } 681 } 682 } 683 } else { 684 log.error("invalid conditional system name in Logix \"{}\" " 685 + "assembleListenerList DELETING {} from Conditional list.", 686 getSystemName(), _conditionalSystemNames.get(i)); 687 _conditionalSystemNames.remove(i); 688 } 689 } 690 } 691 692 private int getPositionOfListener(int varListenerType, Conditional.Type varType, String varName) { 693 // check if already in list 694 for (int j = 0; (j < _listeners.size()); j++) { 695 if (varListenerType == _listeners.get(j).getType()) { 696 if (varName.equals(_listeners.get(j).getDevName())) { 697 if (varListenerType == LISTENER_TYPE_SIGNALHEAD) { 698 if (varType == Conditional.Type.SIGNAL_HEAD_LIT 699 || varType == Conditional.Type.SIGNAL_HEAD_HELD) { 700 if (varType == _listeners.get(j).getVarType()) { 701 return j; 702 } 703 } else if (SignalHead.PROPERTY_APPEARANCE.equals(_listeners.get(j).getPropertyName())) { 704 // the Appearance Listener can handle all aspects 705 return j; 706 } 707 } else { 708 return j; 709 } 710 } 711 } 712 713 } 714 return -1; 715 } 716 717 /* /** 718 * Assembles and returns a list of state variables that are used by 719 * conditionals of this Logix including the number of occurances of each 720 * variable that trigger a calculation, and the number of occurances where 721 * the triggering has been suppressed. The main use of this method is to 722 * return information that can be used to test for inconsistency in 723 * suppressing triggering of a calculation among multiple occurances of the 724 * same state variable. Caller provides an ArrayList of the variables to 725 * check and an empty Array list to return the counts for triggering or 726 * suppressing calculation. The first index is a count that the 727 * correspondeing variable triggers calculation and second is a count that 728 * the correspondeing variable suppresses Calculation. Note this method must 729 * not modify the supplied variable list in any way. 730 * 731 * public void getStateVariableList(ArrayList <ConditionalVariable> varList, 732 * ArrayList <int[]> triggerPair) { // initialize Conditional c = null; 733 * String testSystemName = ""; String testUserName = ""; String testVarName 734 * = ""; // cycle thru Conditionals to find state variables 735 * ConditionalManager cm = InstanceManager.getDefault(jmri.ConditionalManager.class); for 736 * (int i=0; i<_conditionalSystemNames.size(); i++) { c = 737 * cm.getBySystemName(_conditionalSystemNames.get(i)); if (c!=null) { 738 * ArrayList variableList = c.getCopyOfStateVariables(); for (int k = 0; 739 * k<variableList.size(); k++) { ConditionalVariable variable = 740 * (ConditionalVariable)variableList.get(k); testVarName = 741 * variable.getName(); testSystemName = ""; testUserName = ""; // initialize 742 * this state variable switch (variable.getType()) { case 743 * Conditional.TYPE_SENSOR_ACTIVE: case Conditional.TYPE_SENSOR_INACTIVE: 744 * Sensor s = InstanceManager.sensorManagerInstance(). 745 * getSensor(testVarName); if (s!=null) { testSystemName = 746 * s.getSystemName(); testUserName = s.getUserName(); } break; case 747 * Conditional.TYPE_TURNOUT_THROWN: case Conditional.TYPE_TURNOUT_CLOSED: 748 * Turnout t = InstanceManager.turnoutManagerInstance(). 749 * getTurnout(testVarName); if (t!=null) { testSystemName = 750 * t.getSystemName(); testUserName = t.getUserName(); } break; case 751 * Conditional.TYPE_CONDITIONAL_TRUE: case 752 * Conditional.TYPE_CONDITIONAL_FALSE: Conditional cx = 753 * InstanceManager.getDefault(jmri.ConditionalManager.class). 754 * getConditional(this,testVarName); if (cx==null) { cx = 755 * InstanceManager.getDefault(jmri.ConditionalManager.class). 756 * getBySystemName(testVarName); } if (cx!=null) { testSystemName = 757 * cx.getSystemName(); testUserName = cx.getUserName(); } break; case 758 * Conditional.TYPE_LIGHT_ON: case Conditional.TYPE_LIGHT_OFF: Light lgt = 759 * InstanceManager.lightManagerInstance(). getLight(testVarName); if 760 * (lgt!=null) { testSystemName = lgt.getSystemName(); testUserName = 761 * lgt.getUserName(); } break; case Conditional.TYPE_MEMORY_EQUALS: Memory m 762 * = InstanceManager.memoryManagerInstance(). getMemory(testVarName); if 763 * (m!=null) { testSystemName = m.getSystemName(); testUserName = 764 * m.getUserName(); } break; case Conditional.TYPE_SIGNAL_HEAD_RED: case 765 * Conditional.TYPE_SIGNAL_HEAD_YELLOW: case 766 * Conditional.TYPE_SIGNAL_HEAD_GREEN: case 767 * Conditional.TYPE_SIGNAL_HEAD_DARK: case 768 * Conditional.TYPE_SIGNAL_HEAD_FLASHRED: case 769 * Conditional.TYPE_SIGNAL_HEAD_FLASHYELLOW: case 770 * Conditional.TYPE_SIGNAL_HEAD_FLASHGREEN: SignalHead h = 771 * InstanceManager.getDefault(jmri.SignalHeadManager.class). getSignalHead(testVarName); 772 * if (h!=null) { testSystemName = h.getSystemName(); testUserName = 773 * h.getUserName(); } break; case Conditional.TYPE_SIGNAL_HEAD_LIT: 774 * SignalHead hx = InstanceManager.getDefault(jmri.SignalHeadManager.class). 775 * getSignalHead(testVarName); if (hx!=null) { testSystemName = 776 * hx.getSystemName(); testUserName = hx.getUserName(); } break; case 777 * Conditional.TYPE_SIGNAL_HEAD_HELD: SignalHead hy = 778 * InstanceManager.getDefault(jmri.SignalHeadManager.class). getSignalHead(testVarName); 779 * if (hy!=null) { testSystemName = hy.getSystemName(); testUserName = 780 * hy.getUserName(); } break; default: testSystemName = ""; } // check if 781 * this state variable is already in the list to be returned boolean inList 782 * = false; int indexOfRepeat = -1; if (testSystemName!="") { // getXXXXXX 783 * succeeded, process this state variable for (int j=0; j<varList.size(); 784 * j++) { ConditionalVariable v = varList.get(j); if ( 785 * v.getName().equals(testSystemName) || v.getName().equals(testUserName) ) 786 * { inList = true; indexOfRepeat = j; break; } } // add to list if new and 787 * if there is room if ( inList ) { int[] trigs = 788 * triggerPair.get(indexOfRepeat); if ( variable.doCalculation() ) { 789 * trigs[0]++; } else { trigs[1]++; 790 * 791 * } 792 * } 793 * } 794 * } 795 * } 796 * else { log.error("invalid conditional system name in Logix 797 * getStateVariableList - "+ _conditionalSystemNames.get(i)); 798 * 799 * } 800 * } 801 * } // getStateVariableList 802 */ 803 804 /** 805 * Deactivate the Logix. This method disconnects the Logix from all input 806 * objects and stops it from being triggered to calculate. 807 * <p> 808 * A Logix must be deactivated before its Conditionals are changed. 809 */ 810 @Override 811 public void deActivateLogix() { 812 if (_isActivated) { 813 // Logix is active, deactivate it and all listeners 814 _isActivated = false; 815 // remove listeners if there are any 816 for (int i = _listeners.size() - 1; i >= 0; i--) { 817 removeListener(_listeners.get(i)); 818 } 819 } 820 } 821 822 /** 823 * Creates a listener of the required type and starts it 824 */ 825 private void startListener(JmriSimplePropertyListener listener) { 826 827 if (listener.getType() == LISTENER_TYPE_FASTCLOCK) { 828 Timebase tb = InstanceManager.getDefault(Timebase.class); 829 tb.addMinuteChangeListener(listener); 830 } else { 831 NamedBeanHandle<?> namedBeanHandle = listener.getNamedBean(); 832 if (namedBeanHandle == null) { 833 log.error("Bad name for {} '{}' when setting up Logix listener [ {} ]", 834 getListenerTypeName(listener.getType()), listener.getDevName(), this.getSystemName()); 835 } else { 836 NamedBean nb = namedBeanHandle.getBean(); 837 nb.addPropertyChangeListener(listener, namedBeanHandle.getName(), 838 "Logix " + getDisplayName()); 839 } 840 } 841 } 842 843 /** 844 * Remove a listener of the required type 845 */ 846 private void removeListener(JmriSimplePropertyListener listener) { 847 String typeName = null; 848 NamedBean nb; 849 NamedBeanHandle<?> namedBeanHandle; 850 try { 851 switch (listener.getType()) { 852 case LISTENER_TYPE_FASTCLOCK: 853 Timebase tb = InstanceManager.getDefault(Timebase.class); 854 tb.removeMinuteChangeListener(listener); 855 return; 856 case LISTENER_TYPE_ENTRYEXIT: 857 NamedBean ex = InstanceManager.getDefault(EntryExitPairs.class) 858 .getNamedBean(listener.getDevName()); 859 if (ex == null) { 860 typeName = "entryexit"; // NOI18N 861 break; 862 } 863 ex.removePropertyChangeListener(listener); 864 return; 865 default: 866 namedBeanHandle = listener.getNamedBean(); 867 if (namedBeanHandle == null) { 868 typeName = getListenerTypeName(listener.getType()); 869 break; 870 } 871 nb = namedBeanHandle.getBean(); 872 nb.removePropertyChangeListener(listener); 873 return; 874 } 875 } catch (Exception ex) { 876 log.error("Bad name for listener on \"{}\": ", listener.getDevName(), ex); // NOI18N 877 } 878 log.error("Bad name for {} listener on \"{}\" when removing", typeName, listener.getDevName()); // NOI18N 879 } 880 881 /** 882 * Get an I18N String of the Bean Listener type. 883 * @param listenerType the LISTENER_TYPE constant. 884 * @return I18N String of the Bean type, non-plural. 885 */ 886 private static String getListenerTypeName(int listenerType) { 887 String msg; 888 switch (listenerType) { 889 case LISTENER_TYPE_SENSOR: 890 msg = InstanceManager.getDefault(SensorManager.class).getBeanTypeHandled(); 891 break; 892 case LISTENER_TYPE_TURNOUT: 893 msg = InstanceManager.getDefault(TurnoutManager.class).getBeanTypeHandled(); 894 break; 895 case LISTENER_TYPE_LIGHT: 896 msg = InstanceManager.getDefault(LightManager.class).getBeanTypeHandled(); 897 break; 898 case LISTENER_TYPE_CONDITIONAL: 899 msg = InstanceManager.getDefault(ConditionalManager.class).getBeanTypeHandled(); 900 break; 901 case LISTENER_TYPE_SIGNALHEAD: 902 msg = InstanceManager.getDefault(SignalHeadManager.class).getBeanTypeHandled(); 903 break; 904 case LISTENER_TYPE_SIGNALMAST: 905 msg = InstanceManager.getDefault(SignalMastManager.class).getBeanTypeHandled(); 906 break; 907 case LISTENER_TYPE_MEMORY: 908 msg = InstanceManager.getDefault(MemoryManager.class).getBeanTypeHandled(); 909 break; 910 case LISTENER_TYPE_WARRANT: 911 msg = InstanceManager.getDefault(jmri.jmrit.logix.WarrantManager.class).getBeanTypeHandled(); 912 break; 913 case LISTENER_TYPE_OBLOCK: 914 msg = InstanceManager.getDefault(jmri.jmrit.logix.OBlockManager.class).getBeanTypeHandled(); 915 break; 916 case LISTENER_TYPE_ENTRYEXIT: 917 msg = InstanceManager.getDefault(EntryExitPairs.class).getBeanTypeHandled(); 918 break; 919 default: 920 msg = "unknown Listener type number: " + listenerType; // NOI18N 921 } 922 return msg; 923 } 924 925 /* /** 926 * Assembles a list of state variables that both trigger the Logix, and are 927 * changed by it. Returns true if any such variables were found. Returns 928 * false otherwise. Can be called when Logix is enabled. 929 * 930 * public boolean checkLoopCondition() { loopGremlins = new 931 * ArrayList<String[]>(); if (!_isActivated) { // Prepare a list of all 932 * variables used in conditionals java.util.HashSet <ConditionalVariable> 933 * variableList = new java.util.HashSet<ConditionalVariable>(); 934 * ConditionalManager cm = InstanceManager.getDefault(jmri.ConditionalManager.class); for 935 * (int i=0; i<_conditionalSystemNames.size(); i++) { Conditional c = null; 936 * c = cm.getBySystemName(_conditionalSystemNames.get(i)); if (c!=null) { // 937 * Not necesary to modify methods, equals and hashcode. Redundacy checked in 938 * addGremlin variableList.addAll(c.getCopyOfStateVariables()); } } 939 * java.util.HashSet <ConditionalVariable> variableList = new 940 * java.util.HashSet<ConditionalVariable>(); ConditionalVariable v = null; 941 * // check conditional action items Conditional c = null; for (int i=0; 942 * i<_conditionalSystemNames.size(); i++) { // get next conditional c = 943 * cm.getBySystemName(_conditionalSystemNames.get(i)); if (c!=null) { 944 * ArrayList <ConditionalAction> actionList = c.getCopyOfActions(); for (int 945 * j = 0; j < actionList.size(); j++) { ConditionalAction action = 946 * actionList.get(j); String sName = ""; String uName = ""; switch 947 * (action.getType()) { case Conditional.ACTION_NONE: break; case 948 * Conditional.ACTION_SET_TURNOUT: case Conditional.ACTION_DELAYED_TURNOUT: 949 * case Conditional.ACTION_RESET_DELAYED_TURNOUT: case 950 * Conditional.ACTION_CANCEL_TURNOUT_TIMERS: Turnout t = 951 * InstanceManager.turnoutManagerInstance(). 952 * provideTurnout(action.getDeviceName()); if (t!=null) { sName = 953 * t.getSystemName(); uName = t.getUserName(); // check for action on the 954 * same turnout Iterator <ConditionalVariable>it= variableList.iterator(); 955 * while(it.hasNext()) { v = it.next(); if (v.getType() == 956 * Conditional.TYPE_TURNOUT_CLOSED || v.getType() == 957 * Conditional.TYPE_TURNOUT_THROWN) { if ( (v.getName().equals(sName)) || 958 * (v.getName().equals(uName)) ) { // possible conflict found 959 * addGremlin("Turnout", sName, uName); } } } } break; case 960 * Conditional.ACTION_SET_SIGNAL_APPEARANCE: case 961 * Conditional.ACTION_SET_SIGNAL_HELD: case 962 * Conditional.ACTION_CLEAR_SIGNAL_HELD: case 963 * Conditional.ACTION_SET_SIGNAL_DARK: case 964 * Conditional.ACTION_SET_SIGNAL_LIT: SignalHead h = 965 * InstanceManager.getDefault(jmri.SignalHeadManager.class). 966 * getSignalHead(action.getDeviceName()); if (h!=null) { sName = 967 * h.getSystemName(); uName = h.getUserName(); // check for action on the 968 * same signal head Iterator <ConditionalVariable>it= 969 * variableList.iterator(); while(it.hasNext()) { v = it.next(); if 970 * (v.getType() >= Conditional.TYPE_SIGNAL_HEAD_RED || v.getType() <= 971 * Conditional.TYPE_SIGNAL_HEAD_HELD) { if ( (v.getName().equals(sName)) || 972 * (v.getName().equals(uName)) ) { // possible conflict found 973 * addGremlin("SignalHead", sName, uName); } } } } break; case 974 * Conditional.ACTION_SET_SENSOR: case Conditional.ACTION_DELAYED_SENSOR: 975 * case Conditional.ACTION_RESET_DELAYED_SENSOR: case 976 * Conditional.ACTION_CANCEL_SENSOR_TIMERS: Sensor s = 977 * InstanceManager.sensorManagerInstance(). 978 * provideSensor(action.getDeviceName()); if (s!=null) { sName = 979 * s.getSystemName(); uName = s.getUserName(); // check for action on the 980 * same sensor Iterator <ConditionalVariable>it= variableList.iterator(); 981 * while(it.hasNext()) { v = it.next(); if (v.getType() == 982 * Conditional.TYPE_SENSOR_ACTIVE || v.getType() == 983 * Conditional.TYPE_SENSOR_INACTIVE) { 984 * 985 * if ( (v.getName().equals(sName)) || (v.getName().equals(uName)) ) { // 986 * possible conflict found addGremlin("Sensor",sName, uName); } } } } break; 987 * case Conditional.ACTION_SET_LIGHT: case 988 * Conditional.ACTION_SET_LIGHT_TRANSITION_TIME: case 989 * Conditional.ACTION_SET_LIGHT_INTENSITY: Light lgt = 990 * InstanceManager.lightManagerInstance(). getLight(action.getDeviceName()); 991 * if (lgt!=null) { sName = lgt.getSystemName(); uName = lgt.getUserName(); 992 * // check for listener on the same light Iterator <ConditionalVariable>it= 993 * variableList.iterator(); while(it.hasNext()) { v = it.next(); if 994 * (v.getType() == Conditional.TYPE_LIGHT_ON || v.getType() == 995 * Conditional.TYPE_LIGHT_OFF) { if ( (v.getName().equals(sName)) || 996 * (v.getName().equals(uName)) ) { // possible conflict found 997 * addGremlin("Light", sName, uName); } } } } break; case 998 * Conditional.ACTION_SET_MEMORY: case Conditional.ACTION_COPY_MEMORY: 999 * Memory m = InstanceManager.memoryManagerInstance(). 1000 * provideMemory(action.getDeviceName()); if (m!=null) { sName = 1001 * m.getSystemName(); uName = m.getUserName(); // check for variable on the 1002 * same memory Iterator <ConditionalVariable>it= variableList.iterator(); 1003 * while(it.hasNext()) { v = it.next(); if (v.getType() == 1004 * Conditional.TYPE_MEMORY_EQUALS) { if ( (v.getName().equals(sName)) || 1005 * (v.getName().equals(uName)) ) { // possible conflict found 1006 * addGremlin("Memory", sName, uName); } } } } break; case 1007 * Conditional.ACTION_SET_FAST_CLOCK_TIME: case 1008 * Conditional.ACTION_START_FAST_CLOCK: case 1009 * Conditional.ACTION_STOP_FAST_CLOCK: Iterator <ConditionalVariable>it= 1010 * variableList.iterator(); while(it.hasNext()) { v = it.next(); if 1011 * (v.getType() == Conditional.TYPE_FAST_CLOCK_RANGE) { 1012 * addGremlin("FastClock", null, v.getName()); } } break; default: } } } } } 1013 * return (loopGremlins.size()>0); } 1014 * 1015 * private void addGremlin(String type, String sName, String uName) { // 1016 * check for redundancy String names = uName+ (sName == null ? "" : " 1017 * ("+sName+")"); for (int i=0; i<loopGremlins.size(); i++) { String[] str = 1018 * loopGremlins.get(i); if (str[0].equals(type) && str[1].equals(names)) { 1019 * return; } } String[] item = new String[2]; item[0] = type; item[1] = 1020 * names; loopGremlins.add(item); } 1021 * 1022 * ArrayList <String[]> loopGremlins = null; 1023 * 1024 * /** 1025 * Returns a string listing state variables that might result in a loop. 1026 * Returns an empty string if there are none, probably because 1027 * "checkLoopCondition" was not invoked before the call, or returned false. 1028 * 1029 * public ArrayList 1030 * <String[]> getLoopGremlins() {return(loopGremlins);} 1031 */ 1032 1033 /** 1034 * Not needed for Logixs - included to complete implementation of the 1035 * NamedBean interface. 1036 */ 1037 @Override 1038 public int getState() { 1039 log.warn("Unexpected call to getState in DefaultLogix."); // NOI18N 1040 return UNKNOWN; 1041 } 1042 1043 /** 1044 * Not needed for Logixs - included to complete implementation of the 1045 * NamedBean interface. 1046 * @param state unused. 1047 */ 1048 @Override 1049 public void setState(int state) { 1050 log.warn("Unexpected call to setState in DefaultLogix."); // NOI18N 1051 } 1052 1053 @Override 1054 public void vetoableChange(java.beans.PropertyChangeEvent evt) throws java.beans.PropertyVetoException { 1055 if (Manager.PROPERTY_CAN_DELETE.equals(evt.getPropertyName())) { 1056 NamedBean nb = (NamedBean) evt.getOldValue(); 1057 for (JmriSimplePropertyListener listener : _listeners) { 1058 if (nb.equals(listener.getBean())) { 1059 var e = new java.beans.PropertyChangeEvent(this, Manager.PROPERTY_DO_NOT_DELETE, null, null); 1060 throw new java.beans.PropertyVetoException( 1061 Bundle.getMessage("InUseLogixListener", nb.getBeanType(), getDisplayName()), e); // NOI18N 1062 } 1063 } 1064 1065 String cName; 1066 Conditional c; 1067 for (String conditionalSystemName : _conditionalSystemNames) { 1068 cName = conditionalSystemName; 1069 c = conditionalManager.getBySystemName(cName); 1070 if (c != null) { 1071 for (ConditionalAction ca : c.getCopyOfActions()) { 1072 if (nb.equals(ca.getBean())) { 1073 var e = new java.beans.PropertyChangeEvent( 1074 this, Manager.PROPERTY_DO_NOT_DELETE, null, null); 1075 throw new java.beans.PropertyVetoException( 1076 Bundle.getMessage("InUseLogixAction", nb.getBeanType(), getDisplayName()), e); // NOI18N 1077 } 1078 } 1079 for (ConditionalVariable v : c.getCopyOfStateVariables()) { 1080 if (nb.equals(v.getBean()) || nb.equals(v.getNamedBeanData())) { 1081 var e = new java.beans.PropertyChangeEvent(this, 1082 Manager.PROPERTY_DO_NOT_DELETE, null, null); 1083 throw new java.beans.PropertyVetoException( Bundle.getMessage("InUseLogixVariable", 1084 nb.getBeanType(), getDisplayName()), e); 1085 } 1086 } 1087 } 1088 } 1089 } 1090 } 1091 1092 @Override 1093 public List<NamedBeanUsageReport> getUsageReport(NamedBean bean) { 1094 List<NamedBeanUsageReport> report = new ArrayList<>(); 1095 if (bean != null) { 1096 for (int i = 0; i < getNumConditionals(); i++) { 1097 DefaultConditional cdl = (DefaultConditional) getConditional(getConditionalByNumberOrder(i)); 1098 if ( cdl == null ) { 1099 continue; 1100 } 1101 cdl.getStateVariableList().forEach( variable -> { 1102 if (bean.equals(variable.getBean())) { 1103 report.add(new NamedBeanUsageReport("ConditionalVariable", cdl, variable.toString())); 1104 } 1105 if (bean.equals(variable.getNamedBeanData())) { 1106 report.add(new NamedBeanUsageReport("ConditionalVariableData", cdl, variable.toString())); 1107 } 1108 }); 1109 cdl.getActionList().forEach( action -> { 1110 if (bean.equals(action.getBean())) { 1111 boolean triggerType = cdl.getTriggerOnChange(); 1112 report.add(new NamedBeanUsageReport("ConditionalAction", cdl, action.description(triggerType))); 1113 } 1114 }); 1115 } 1116 } 1117 return report; 1118 } 1119 1120 /** {@inheritDoc} */ 1121 @Override 1122 @OverridingMethodsMustInvokeSuper 1123 public void dispose() { 1124 super.dispose(); 1125 for (int i = 0; i < getNumConditionals(); i++) { 1126 Conditional c = getConditional(getConditionalByNumberOrder(i)); 1127 if ( c != null ) { 1128 c.dispose(); 1129 } 1130 } 1131 } 1132 1133 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DefaultLogix.class); 1134 1135}