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