001package jmri.jmrit.logixng.implementation; 002 003import java.io.PrintWriter; 004import java.util.*; 005 006import jmri.InstanceManager; 007import jmri.JmriException; 008import jmri.Manager; 009import jmri.NamedBean; 010import jmri.NamedBeanUsageReport; 011import jmri.implementation.AbstractNamedBean; 012import jmri.jmrit.logixng.*; 013 014import org.apache.commons.lang3.mutable.MutableInt; 015 016/** 017 * The default implementation of LogixNG. 018 * 019 * @author Daniel Bergqvist Copyright 2018 020 * @author Dave Sand Copyright 2021 021 */ 022public class DefaultLogixNG extends AbstractNamedBean 023 implements LogixNG { 024 025 private final LogixNG_Manager _manager = InstanceManager.getDefault(LogixNG_Manager.class); 026 private boolean _startup = true; 027 private boolean _inline = false; 028 private InlineLogixNG _inlineLogixNG = null; 029 private boolean _enabled = false; 030 private boolean _isActive = false; 031 private final List<ConditionalNG_Entry> _conditionalNG_Entries = new ArrayList<>(); 032 033 034 public DefaultLogixNG(String sys, String user) throws BadUserNameException, BadSystemNameException { 035 super(sys, user); 036 037 // Do this test here to ensure all the tests are using correct system names 038 Manager.NameValidity isNameValid = InstanceManager.getDefault(LogixNG_Manager.class).validSystemNameFormat(mSystemName); 039 if (isNameValid != Manager.NameValidity.VALID) { 040 throw new IllegalArgumentException("system name is not valid"); 041 } 042 } 043 044 public DefaultLogixNG(String sys, String user, boolean inline) throws BadUserNameException, BadSystemNameException { 045 super(sys, user); 046 047 _inline = inline; 048 049 // Do this test here to ensure all the tests are using correct system names 050 Manager.NameValidity isNameValid = InstanceManager.getDefault(LogixNG_Manager.class).validSystemNameFormat(mSystemName); 051 if (isNameValid != Manager.NameValidity.VALID) { 052 throw new IllegalArgumentException("system name is not valid"); 053 } 054 } 055 056 /** {@inheritDoc} */ 057 @Override 058 public Base getParent() { 059 return null; 060 } 061 062 /** {@inheritDoc} */ 063 @Override 064 public void setParent(Base parent) { 065 throw new UnsupportedOperationException("A LogixNG cannot have a parent"); 066 } 067 068 @Override 069 public String getBeanType() { 070 return Bundle.getMessage("BeanNameLogixNG"); 071 } 072 073 @Override 074 public void setState(int s) throws JmriException { 075 log.warn("Unexpected call to setState in DefaultLogixNG."); // NOI18N 076 } 077 078 @Override 079 public int getState() { 080 log.warn("Unexpected call to getState in DefaultLogixNG."); // NOI18N 081 return UNKNOWN; 082 } 083 084 @Override 085 public String getShortDescription(Locale locale) { 086 return "LogixNG"; 087 } 088 089 @Override 090 public String getLongDescription(Locale locale) { 091 return "LogixNG: "+getDisplayName(); 092 } 093 094 @Override 095 public FemaleSocket getChild(int index) throws IllegalArgumentException, UnsupportedOperationException { 096 throw new UnsupportedOperationException("Not supported."); 097 } 098 099 @Override 100 public int getChildCount() { 101 throw new UnsupportedOperationException("Not supported."); 102 } 103 104 @Override 105 public Category getCategory() { 106 throw new UnsupportedOperationException("Not supported."); 107 } 108 109 /** {@inheritDoc} */ 110 @Override 111 final public void setup() { 112 for (ConditionalNG_Entry entry : _conditionalNG_Entries) { 113 if ( entry._conditionalNG == null 114 || !entry._conditionalNG.getSystemName() 115 .equals(entry._systemName)) { 116 117 String systemName = entry._systemName; 118 if (systemName != null) { 119 entry._conditionalNG = 120 InstanceManager.getDefault(ConditionalNG_Manager.class) 121 .getBySystemName(systemName); 122 if (entry._conditionalNG != null) { 123 entry._conditionalNG.setup(); 124 } else { 125 log.error("cannot load conditionalNG {}", systemName); 126 } 127 } 128 } else { 129 entry._conditionalNG.setup(); 130 } 131 } 132 } 133 134 /** {@inheritDoc} */ 135 @Override 136 public void clearStartup() { 137 _startup = false; 138 } 139 140 /** {@inheritDoc} */ 141 @Override 142 public boolean isStartup() { 143 return _startup; 144 } 145 146 /** {@inheritDoc} */ 147 @Override 148 public void setInline(boolean inline) { 149 boolean old = _inline; 150 _inline = inline; 151 firePropertyChange(LogixNG.PROPERTY_INLINE, old, _inline); 152 } 153 154 /** {@inheritDoc} */ 155 @Override 156 public boolean isInline() { 157 return _inline; 158 } 159 160 /** {@inheritDoc} */ 161 @Override 162 public void setInlineLogixNG(InlineLogixNG inlineLogixNG) { 163 _inlineLogixNG = inlineLogixNG; 164 } 165 166 /** {@inheritDoc} */ 167 @Override 168 public InlineLogixNG getInlineLogixNG() { 169 return _inlineLogixNG; 170 } 171 172 /** {@inheritDoc} */ 173 @Override 174 public void setEnabled(boolean enable) { 175 boolean old = _enabled; 176 _enabled = enable; 177 checkIfActiveAndEnabled(); 178 firePropertyChange(PROPERTY_ENABLED, old, _enabled); 179 } 180 181 /** {@inheritDoc} */ 182 @Override 183 public void activate() { 184 _isActive = true; 185 } 186 187 /** {@inheritDoc} */ 188 @Override 189 public void setActive(boolean active) { 190 _isActive = active; 191 checkIfActiveAndEnabled(); 192 } 193 194 private void checkIfActiveAndEnabled() { 195 if (isActive()) { 196 registerListeners(); 197 execute(true, true); 198 } else { 199 unregisterListeners(); 200 } 201 } 202 203 /** {@inheritDoc} */ 204 @Override 205 public boolean isEnabled() { 206 return _enabled; 207 } 208 209 /** {@inheritDoc} */ 210 @Override 211 public String getConditionalNG_SystemName(int index) { 212 return _conditionalNG_Entries.get(index)._systemName; 213 } 214 215 /** {@inheritDoc} */ 216 @Override 217 public void setConditionalNG_SystemName(int index, String systemName) { 218 if (index == _conditionalNG_Entries.size()) { 219 _conditionalNG_Entries.add(new ConditionalNG_Entry(systemName)); 220 } else { 221 ConditionalNG_Entry entry = _conditionalNG_Entries.get(index); 222 entry._systemName = systemName; 223 entry._conditionalNG = null; 224 } 225 } 226 227 /** {@inheritDoc} */ 228 @Override 229 public int getNumConditionalNGs() { 230 return _conditionalNG_Entries.size(); 231 } 232 233 /** {@inheritDoc} */ 234 @Override 235 public void swapConditionalNG(int nextInOrder, int row) { 236 if (row <= nextInOrder) { 237 return; 238 } 239 ConditionalNG_Entry temp = _conditionalNG_Entries.get(row); 240 for (int i = row; i > nextInOrder; i--) { 241 _conditionalNG_Entries.set(i, _conditionalNG_Entries.get(i - 1)); 242 } 243 _conditionalNG_Entries.set(nextInOrder, temp); 244 } 245 246 /** {@inheritDoc} */ 247 @Override 248 public ConditionalNG getConditionalNG(int order) { 249 try { 250 return _conditionalNG_Entries.get(order)._conditionalNG; 251 } catch (java.lang.IndexOutOfBoundsException ioob) { 252 return null; 253 } 254 } 255 256 /** {@inheritDoc} */ 257 @Override 258 public boolean addConditionalNG(ConditionalNG conditionalNG) { 259 for (ConditionalNG_Entry entry : _conditionalNG_Entries) { 260 if (conditionalNG.getSystemName().equals(entry._systemName)) { 261 if (entry._conditionalNG == null) { 262 // Normally this will be during xml loading 263 entry._conditionalNG = conditionalNG; 264 return true; 265 } else { 266 log.error("ConditionalNG '{}' has already been added to LogixNG '{}'", conditionalNG.getSystemName(), getSystemName()); // NOI18N 267 return false; 268 } 269 } 270 271 } 272 273 ConditionalNG_Entry entry = new ConditionalNG_Entry(conditionalNG, conditionalNG.getSystemName()); 274 _conditionalNG_Entries.add(entry); 275 conditionalNG.setParent(this); 276 return true; 277 } 278 279 /** {@inheritDoc} */ 280 @Override 281 public ConditionalNG getConditionalNG(String systemName) { 282 for (int i = 0; i < getNumConditionalNGs(); i++) { 283 if (systemName.equals(_conditionalNG_Entries.get(i)._systemName)) { 284 return _conditionalNG_Entries.get(i)._conditionalNG; 285 } 286 } 287 return null; 288 } 289 290 /** {@inheritDoc} */ 291 @Override 292 public ConditionalNG getConditionalNGByUserName(String userName) { 293 for (ConditionalNG_Entry entry : _conditionalNG_Entries) { 294 if (userName.equals(entry._conditionalNG.getUserName())) { 295 return entry._conditionalNG; 296 } 297 } 298 return null; 299 } 300 301 /** {@inheritDoc} */ 302 @Override 303 public void deleteConditionalNG(ConditionalNG conditionalNG) { 304 if (_conditionalNG_Entries.size() <= 0) { 305 log.error("attempt to delete ConditionalNG not in LogixNG: {}", conditionalNG.getSystemName()); // NOI18N 306 return; 307 } 308 309 boolean found = false; 310 // Remove Conditional from this logix 311 for (ConditionalNG_Entry entry : _conditionalNG_Entries) { 312 if (conditionalNG == entry._conditionalNG) { 313 _conditionalNG_Entries.remove(entry); 314 found = true; 315 break; 316 } 317 } 318 if (!found) { 319 log.error("attempt to delete ConditionalNG not in LogixNG: {}", conditionalNG.getSystemName()); // NOI18N 320 } 321 } 322 323 /** {@inheritDoc} */ 324 @Override 325 public boolean isActive() { 326 return _enabled && _isActive && _manager.isActive(); 327 } 328 329 /** {@inheritDoc} */ 330 @Override 331 public boolean isActivated() { 332 return _isActive; 333 } 334 335 /** {@inheritDoc} */ 336 @Override 337 public void execute() { 338 for (ConditionalNG_Entry entry : _conditionalNG_Entries) { 339 entry._conditionalNG.execute(); 340 } 341 } 342 343 /** {@inheritDoc} */ 344 @Override 345 public void execute(boolean allowRunDelayed) { 346 execute(allowRunDelayed, false); 347 } 348 349 /** {@inheritDoc} */ 350 @Override 351 public void execute(boolean allowRunDelayed, boolean isStartup) { 352 for (ConditionalNG_Entry entry : _conditionalNG_Entries) { 353 ConditionalNG cng = entry._conditionalNG; 354 if (cng.isEnabled() && (!isStartup || cng.isExecuteAtStartup())) { 355 cng.execute(allowRunDelayed); 356 } 357 } 358 } 359 360 /** {@inheritDoc} */ 361 @Override 362 public ConditionalNG getConditionalNG() { 363 throw new UnsupportedOperationException("Not supported."); 364 } 365 366 /** {@inheritDoc} */ 367 @Override 368 public LogixNG getLogixNG() { 369 return this; 370 } 371 372 /** {@inheritDoc} */ 373 @Override 374 public final Base getRoot() { 375 return this; 376 } 377 378 /** {@inheritDoc} */ 379 @Override 380 public boolean setParentForAllChildren(List<String> errors) { 381 boolean result = true; 382 for (ConditionalNG_Entry entry : _conditionalNG_Entries) { 383 if (entry._conditionalNG != null) { 384 entry._conditionalNG.setParent(this); 385 result = result && entry._conditionalNG.setParentForAllChildren(errors); 386 } 387 } 388 return result; 389 } 390 391 /** {@inheritDoc} */ 392 @Override 393 public void registerListeners() { 394 for (ConditionalNG_Entry entry : _conditionalNG_Entries) { 395 entry._conditionalNG.registerListeners(); 396 } 397 } 398 399 /** {@inheritDoc} */ 400 @Override 401 public void unregisterListeners() { 402 for (ConditionalNG_Entry entry : _conditionalNG_Entries) { 403 entry._conditionalNG.unregisterListeners(); 404 } 405 } 406 407 protected void printTreeRow( 408 PrintTreeSettings settings, 409 Locale locale, 410 PrintWriter writer, 411 String currentIndent, 412 MutableInt lineNumber) { 413 414 if (settings._printLineNumbers) { 415 writer.append(String.format(PRINT_LINE_NUMBERS_FORMAT, lineNumber.addAndGet(1))); 416 } 417 writer.append(currentIndent); 418 writer.append(getLongDescription(locale)); 419 if (isInline()) { 420 writer.append(" ::: ").append(Bundle.getMessage("Inline")); 421 } 422 if (settings._printDisabled && !isEnabled()) { 423 writer.append(" ::: ").append(Bundle.getMessage("Disabled")); 424 } 425 writer.println(); 426 } 427 428 /** {@inheritDoc} */ 429 @Override 430 public void printTree( 431 PrintTreeSettings settings, 432 PrintWriter writer, 433 String indent, 434 MutableInt lineNumber) { 435 436 printTree(settings, Locale.getDefault(), writer, indent, "", lineNumber); 437 } 438 439 /** {@inheritDoc} */ 440 @Override 441 public void printTree( 442 PrintTreeSettings settings, 443 Locale locale, 444 PrintWriter writer, 445 String indent, 446 MutableInt lineNumber) { 447 448 printTree(settings, locale, writer, indent, "", lineNumber); 449 } 450 451 /** {@inheritDoc} */ 452 @Override 453 public void printTree( 454 PrintTreeSettings settings, 455 Locale locale, 456 PrintWriter writer, 457 String indent, 458 String currentIndent, 459 MutableInt lineNumber) { 460 461 printTreeRow(settings, locale, writer, currentIndent, lineNumber); 462 463 for (int i=0; i < this.getNumConditionalNGs(); i++) { 464 getConditionalNG(i).printTree(settings, locale, writer, indent, currentIndent+indent, lineNumber); 465// writer.println(); 466 } 467 } 468 469 @Override 470 public Base getDeepCopy(Map<String, String> systemNames, Map<String, String> userNames) { 471 throw new UnsupportedOperationException("Not supported yet."); 472 } 473 474 @Override 475 public Base deepCopyChildren(Base original, Map<String, String> systemNames, Map<String, String> userNames) throws JmriException { 476 throw new UnsupportedOperationException("Not supported"); 477 } 478 479 private static class ConditionalNG_Entry { 480 private String _systemName; 481 private ConditionalNG _conditionalNG; 482 483 private ConditionalNG_Entry(ConditionalNG conditionalNG, String systemName) { 484 _systemName = systemName; 485 _conditionalNG = conditionalNG; 486 } 487 488 private ConditionalNG_Entry(ConditionalNG conditionalNG) { 489 this._conditionalNG = conditionalNG; 490 } 491 492 private ConditionalNG_Entry(String systemName) { 493 this._systemName = systemName; 494 } 495 496 @Override 497 public String toString() { 498 StringBuilder sb = new StringBuilder("ConditionalNG_Entry: name ="); 499 sb.append(_systemName); 500 sb.append(", cdl = "); 501 sb.append(_conditionalNG == null ? "----" : _conditionalNG.getDisplayName()); 502 return sb.toString(); 503 } 504 } 505 506 /** {@inheritDoc} */ 507 @Override 508 public List<NamedBeanUsageReport> getUsageReport(NamedBean bean) { 509 List<NamedBeanUsageReport> report = new ArrayList<>(); 510 if (bean != null) { 511 getUsageTree(0, bean, report, null); 512 } 513 return report; 514 } 515 516 /** {@inheritDoc} */ 517 @Override 518 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value="SLF4J_SIGN_ONLY_FORMAT", 519 justification="Specific log message format") 520 public void getUsageTree(int level, NamedBean bean, List<jmri.NamedBeanUsageReport> report, NamedBean cdl) { 521 log.debug("** {} :: {}", level, this.getClass().getName()); 522 523 level++; 524 for (int i=0; i < this.getNumConditionalNGs(); i++) { 525 getConditionalNG(i).getUsageTree(level, bean, report, getConditionalNG(i)); 526 } 527 } 528 529 /** {@inheritDoc} */ 530 @Override 531 public void getUsageDetail(int level, NamedBean bean, List<jmri.NamedBeanUsageReport> report, NamedBean cdl) { 532 } 533 534 /** {@inheritDoc} */ 535 @Override 536 public void getListenerRefsIncludingChildren(List<String> list) { 537 list.addAll(getListenerRefs()); 538 for (int i=0; i < getNumConditionalNGs(); i++) { 539 getConditionalNG(i).getListenerRefsIncludingChildren(list); 540 } 541 } 542 543 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DefaultLogixNG.class); 544}