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