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