001package jmri.jmrit.logixng.implementation; 002 003import java.beans.*; 004import java.io.PrintWriter; 005import java.util.*; 006 007import javax.annotation.Nonnull; 008 009import jmri.*; 010import jmri.jmrit.logixng.*; 011import jmri.jmrit.logixng.Module; 012import jmri.jmrit.logixng.SymbolTable.VariableData; 013import jmri.jmrit.logixng.actions.*; 014import jmri.jmrit.logixng.implementation.swing.ErrorHandlingDialog; 015import jmri.jmrit.logixng.implementation.swing.ErrorHandlingDialog_MultiLine; 016import jmri.jmrit.logixng.util.LogixNG_Thread; 017import jmri.util.LoggingUtil; 018import jmri.util.ThreadingUtil; 019 020import org.apache.commons.lang3.mutable.MutableInt; 021import org.slf4j.Logger; 022 023/** 024 * The abstract class that is the base class for all LogixNG classes that 025 * implements the Base interface. 026 * 027 * @author Daniel Bergqvist 2020 028 */ 029public abstract class AbstractMaleSocket implements MaleSocket { 030 031 private final Base _object; 032 private boolean _locked = false; 033 private boolean _system = false; 034 protected final List<VariableData> _localVariables = new ArrayList<>(); 035 private final BaseManager<? extends NamedBean> _manager; 036 private Base _parent; 037 private ErrorHandlingType _errorHandlingType = ErrorHandlingType.Default; 038 private boolean _catchAbortExecution; 039 private boolean _listen = true; // By default, actions and expressions listen 040 041 042 private static class ErrorHandlingModuleClass { 043 044 private static final ErrorHandlingModuleClass INSTANCE = new ErrorHandlingModuleClass(); 045 046 private final LogixNG errorHandlingLogixNG; 047 private final ConditionalNG errorHandlingConditionalNG; 048 private final Module errorHandlingModule; 049 private final Map<String, Object> _variablesWithValues; 050 051 private ErrorHandlingModuleClass() { 052 errorHandlingLogixNG = new DefaultLogixNG("IQ:JMRI:ErrorHandlingLogixNG", null); 053 errorHandlingConditionalNG = new DefaultConditionalNG("IQC:JMRI:ErrorHandlingCondtionalNG", null, LogixNG_Thread.ERROR_HANDLING_LOGIXNG_THREAD); 054 errorHandlingLogixNG.addConditionalNG(errorHandlingConditionalNG); 055 056 Module tempErrorHandlingModule = InstanceManager.getDefault(ModuleManager.class).getBySystemName(LogixNG_Manager.ERROR_HANDLING_MODULE_NAME); 057 if (tempErrorHandlingModule != null) { 058 errorHandlingModule = tempErrorHandlingModule; 059 } else { 060 FemaleSocketManager.SocketType socketType = InstanceManager.getDefault( 061 FemaleSocketManager.class).getSocketTypeByType("DefaultFemaleDigitalActionSocket"); 062 errorHandlingModule = new DefaultModule(LogixNG_Manager.ERROR_HANDLING_MODULE_NAME, null, socketType, false, false); 063 InstanceManager.getDefault(ModuleManager.class).register(errorHandlingModule); 064 } 065 066 067 DigitalMany many = new DigitalMany("IQDA:JMRI:ErrorHandlingAction", null); 068 MaleSocket maleSocketMany = new DefaultMaleDigitalActionSocket( 069 InstanceManager.getDefault(DigitalActionManager.class), many); 070 many.setParent(maleSocketMany); 071 072 maleSocketMany.addLocalVariable("logixng", SymbolTable.InitialValueType.String, null); 073 maleSocketMany.addLocalVariable("conditionalng", SymbolTable.InitialValueType.String, null); 074 maleSocketMany.addLocalVariable("module", SymbolTable.InitialValueType.String, null); 075 maleSocketMany.addLocalVariable("item", SymbolTable.InitialValueType.String, null); 076 maleSocketMany.addLocalVariable("message", SymbolTable.InitialValueType.String, null); 077 maleSocketMany.addLocalVariable("messageList", SymbolTable.InitialValueType.String, null); 078 maleSocketMany.addLocalVariable("exception", SymbolTable.InitialValueType.String, null); 079 080 try { 081 errorHandlingConditionalNG.getFemaleSocket().connect(maleSocketMany); 082 } catch (SocketAlreadyConnectedException e) { 083 log.error("Exception when creating error handling LogixNG: ", e); 084 } 085 086 SetLocalVariables setLocalVariables = new SetLocalVariables("IQDA:JMRI:ErrorHandlingAction", null); 087 MaleSocket maleSocketSetLocalVariables = new DefaultMaleDigitalActionSocket( 088 InstanceManager.getDefault(DigitalActionManager.class), setLocalVariables); 089 setLocalVariables.setParent(maleSocketSetLocalVariables); 090 _variablesWithValues = setLocalVariables.getMap(); 091 092 try { 093 maleSocketMany.getChild(maleSocketMany.getChildCount()-1).connect(maleSocketSetLocalVariables); 094 } catch (SocketAlreadyConnectedException e) { 095 log.error("Exception when creating error handling LogixNG: ", e); 096 } 097 098 DigitalCallModule action = new DigitalCallModule("IQDA:JMRI:ErrorHandlingAction", null); 099 action.getSelectNamedBean().setNamedBean(errorHandlingModule); 100 action.addParameter("__logixng__", SymbolTable.InitialValueType.LocalVariable, "logixng", Module.ReturnValueType.None, null); 101 action.addParameter("__conditionalng__", SymbolTable.InitialValueType.LocalVariable, "conditionalng", Module.ReturnValueType.None, null); 102 action.addParameter("__module__", SymbolTable.InitialValueType.LocalVariable, "module", Module.ReturnValueType.None, null); 103 action.addParameter("__item__", SymbolTable.InitialValueType.LocalVariable, "item", Module.ReturnValueType.None, null); 104 action.addParameter("__message__", SymbolTable.InitialValueType.LocalVariable, "message", Module.ReturnValueType.None, null); 105 action.addParameter("__messageList__", SymbolTable.InitialValueType.LocalVariable, "messageList", Module.ReturnValueType.None, null); 106 action.addParameter("__exception__", SymbolTable.InitialValueType.LocalVariable, "exception", Module.ReturnValueType.None, null); 107 MaleSocket maleSocket = new DefaultMaleDigitalActionSocket(InstanceManager.getDefault(DigitalActionManager.class), action); 108 action.setParent(maleSocket); 109 try { 110 maleSocketMany.getChild(maleSocketMany.getChildCount()-1).connect(maleSocket); 111 } catch (SocketAlreadyConnectedException e) { 112 log.error("Exception when creating error handling LogixNG: ", e); 113 } 114 List<String> errors = new ArrayList<>(); 115 errorHandlingLogixNG.setParentForAllChildren(errors); 116 if (!errors.isEmpty()) { 117 for (String s : errors) { 118 log.error("Error: {}", s); 119 } 120 } 121 } 122 } 123 124 125 public AbstractMaleSocket(BaseManager<? extends NamedBean> manager, Base object) { 126 _manager = manager; 127 _object = object; 128 } 129 130 public static FemaleSocket getErrorHandlingModuleSocket() { 131 return ErrorHandlingModuleClass.INSTANCE.errorHandlingModule.getRootSocket(); 132 } 133 134 public static boolean isErrorHandlingModuleEnabled() { 135 // Does the error handling module exist? 136 Module errorHandlingModule = InstanceManager.getDefault(ModuleManager.class) 137 .getBySystemName(LogixNG_Manager.ERROR_HANDLING_MODULE_NAME); 138 if (errorHandlingModule == null) { 139 return false; 140 } 141 return errorHandlingModule.getRootSocket().isConnected(); 142 } 143 144 /** {@inheritDoc} */ 145 @Override 146 public final Base getObject() { 147 return _object; 148 } 149 150 /** {@inheritDoc} */ 151 @Override 152 public final Base getRoot() { 153 return _object.getRoot(); 154 } 155 156 /** {@inheritDoc} */ 157 @Override 158 public boolean isLocked() { 159 if (_object instanceof MaleSocket) { 160 return ((MaleSocket)_object).isLocked(); 161 } 162 return _locked; 163 } 164 165 /** {@inheritDoc} */ 166 @Override 167 public void setLocked(boolean locked) { 168 if (_object instanceof MaleSocket) { 169 ((MaleSocket)_object).setLocked(locked); 170 } 171 _locked = locked; 172 } 173 174 /** {@inheritDoc} */ 175 @Override 176 public boolean isSystem() { 177 if (_object instanceof MaleSocket) { 178 return ((MaleSocket)_object).isSystem(); 179 } 180 return _system; 181 } 182 183 /** {@inheritDoc} */ 184 @Override 185 public void setSystem(boolean system) { 186 if (_object instanceof MaleSocket) { 187 ((MaleSocket)_object).setSystem(system); 188 } 189 _system = system; 190 } 191 192 /** {@inheritDoc} */ 193 @Override 194 public final Category getCategory() { 195 return _object.getCategory(); 196 } 197 198 @Override 199 public final FemaleSocket getChild(int index) throws IllegalArgumentException, UnsupportedOperationException { 200 return _object.getChild(index); 201 } 202 203 @Override 204 public final int getChildCount() { 205 return _object.getChildCount(); 206 } 207 208 @Override 209 public final String getShortDescription(Locale locale) { 210 return _object.getShortDescription(locale); 211 } 212 213 @Override 214 public final String getLongDescription(Locale locale) { 215 String s = _object.getLongDescription(locale); 216 // Only the innermost male socket should add "::: Listen" 217 if (!_listen && !(getObject() instanceof MaleSocket)) { 218 s += " ::: " + Base.getNoListenString(); 219 } 220 return s; 221 } 222 223 @Override 224 public final String getUserName() { 225 return _object.getUserName(); 226 } 227 228 @Override 229 public final void setUserName(String s) throws NamedBean.BadUserNameException { 230 _object.setUserName(s); 231 } 232 233 @Override 234 public final String getSystemName() { 235 return _object.getSystemName(); 236 } 237 238 @Override 239 public final void addPropertyChangeListener(PropertyChangeListener l, String name, String listenerRef) { 240 _object.addPropertyChangeListener(l, name, listenerRef); 241 } 242 243 @Override 244 public final void addPropertyChangeListener(String propertyName, PropertyChangeListener l, String name, String listenerRef) { 245 _object.addPropertyChangeListener(propertyName, l, name, listenerRef); 246 } 247 248 @Override 249 public final void addPropertyChangeListener(PropertyChangeListener l) { 250 _object.addPropertyChangeListener(l); 251 } 252 253 @Override 254 public final void addPropertyChangeListener(String propertyName, PropertyChangeListener l) { 255 _object.addPropertyChangeListener(propertyName, l); 256 } 257 258 @Override 259 public final void removePropertyChangeListener(PropertyChangeListener l) { 260 _object.removePropertyChangeListener(l); 261 } 262 263 @Override 264 public final void removePropertyChangeListener(String propertyName, PropertyChangeListener l) { 265 _object.removePropertyChangeListener(propertyName, l); 266 } 267 268 @Override 269 public final void updateListenerRef(PropertyChangeListener l, String newName) { 270 _object.updateListenerRef(l, newName); 271 } 272 273 @Override 274 public final void vetoableChange(PropertyChangeEvent evt) throws PropertyVetoException { 275 _object.vetoableChange(evt); 276 } 277 278 @Override 279 public final String getListenerRef(PropertyChangeListener l) { 280 return _object.getListenerRef(l); 281 } 282 283 @Override 284 public final ArrayList<String> getListenerRefs() { 285 return _object.getListenerRefs(); 286 } 287 288 @Override 289 public final int getNumPropertyChangeListeners() { 290 return _object.getNumPropertyChangeListeners(); 291 } 292 293 @Override 294 public final synchronized PropertyChangeListener[] getPropertyChangeListeners() { 295 return _object.getPropertyChangeListeners(); 296 } 297 298 @Override 299 public final synchronized PropertyChangeListener[] getPropertyChangeListeners(String propertyName) { 300 return _object.getPropertyChangeListeners(propertyName); 301 } 302 303 @Override 304 public final PropertyChangeListener[] getPropertyChangeListenersByReference(String name) { 305 return _object.getPropertyChangeListenersByReference(name); 306 } 307 308 @Override 309 public String getComment() { 310 return _object.getComment(); 311 } 312 313 @Override 314 public void setComment(String comment) { 315 _object.setComment(comment); 316 } 317 318 @Override 319 public boolean getListen() { 320 if (getObject() instanceof MaleSocket) { 321 return ((MaleSocket)getObject()).getListen(); 322 } 323 return _listen; 324 } 325 326 @Override 327 public void setListen(boolean listen) 328 { 329 if (getObject() instanceof MaleSocket) { 330 ((MaleSocket)getObject()).setListen(listen); 331 } 332 _listen = listen; 333 } 334 335 @Override 336 public boolean getCatchAbortExecution() { 337 return _catchAbortExecution; 338 } 339 340 @Override 341 public void setCatchAbortExecution(boolean catchAbortExecution) 342 { 343 _catchAbortExecution = catchAbortExecution; 344 } 345 346 @Override 347 public void addLocalVariable( 348 String name, 349 SymbolTable.InitialValueType initialValueType, 350 String initialValueData) { 351 352 if (getObject() instanceof MaleSocket) { 353 ((MaleSocket)getObject()).addLocalVariable(name, initialValueType, initialValueData); 354 } else { 355 _localVariables.add(new VariableData(name, initialValueType, initialValueData)); 356 } 357 } 358 359 @Override 360 public void addLocalVariable(VariableData variableData) { 361 362 if (getObject() instanceof MaleSocket) { 363 ((MaleSocket)getObject()).addLocalVariable(variableData); 364 } else { 365 _localVariables.add(variableData); 366 } 367 } 368 369 @Override 370 public void clearLocalVariables() { 371 if (getObject() instanceof MaleSocket) { 372 ((MaleSocket)getObject()).clearLocalVariables(); 373 } else { 374 _localVariables.clear(); 375 } 376 } 377 378 @Override 379 public List<VariableData> getLocalVariables() { 380 if (getObject() instanceof MaleSocket) { 381 return ((MaleSocket)getObject()).getLocalVariables(); 382 } else { 383 return _localVariables; 384 } 385 } 386 387 @Override 388 public Base getParent() { 389 return _parent; 390 } 391 392 @Override 393 public void setParent(Base parent) { 394 _parent = parent; 395 } 396 397 @Override 398 public final ConditionalNG getConditionalNG() { 399 if (getParent() == null) return null; 400 return getParent().getConditionalNG(); 401 } 402 403 @Override 404 public final LogixNG getLogixNG() { 405 if (getParent() == null) return null; 406 return getParent().getLogixNG(); 407 } 408 409 /** {@inheritDoc} */ 410 @Override 411 public final boolean setParentForAllChildren(List<String> errors) { 412 boolean result = true; 413 for (int i=0; i < getChildCount(); i++) { 414 FemaleSocket femaleSocket = getChild(i); 415 if (femaleSocket.isConnected()) { 416 MaleSocket connectedSocket = femaleSocket.getConnectedSocket(); 417 connectedSocket.setParent(femaleSocket); 418 result = result && connectedSocket.setParentForAllChildren(errors); 419 } 420 } 421 return result; 422 } 423 424 /** 425 * Register listeners if this object needs that. 426 * <P> 427 * Important: This method may be called more than once. Methods overriding 428 * this method must ensure that listeners are not registered more than once. 429 */ 430 abstract protected void registerListenersForThisClass(); 431 432 /** 433 * Unregister listeners if this object needs that. 434 * <P> 435 * Important: This method may be called more than once. Methods overriding 436 * this method must ensure that listeners are not unregistered more than once. 437 */ 438 abstract protected void unregisterListenersForThisClass(); 439 440 /** {@inheritDoc} */ 441 @Override 442 public final void registerListeners() { 443 if (getObject() instanceof MaleSocket) { 444 getObject().registerListeners(); 445 } else { 446 if (_listen) { 447 registerListenersForThisClass(); 448 for (int i=0; i < getChildCount(); i++) { 449 getChild(i).registerListeners(); 450 } 451 } 452 } 453 } 454 455 /** {@inheritDoc} */ 456 @Override 457 public final void unregisterListeners() { 458 if (getObject() instanceof MaleSocket) { 459 getObject().unregisterListeners(); 460 } else { 461 unregisterListenersForThisClass(); 462 for (int i=0; i < getChildCount(); i++) { 463 getChild(i).unregisterListeners(); 464 } 465 } 466 } 467 468 /** {@inheritDoc} */ 469 @Override 470 public final boolean isActive() { 471 return isEnabled() && ((getParent() == null) || getParent().isActive()); 472 } 473 474 /** 475 * Print this row. 476 * If getObject() doesn't return an AbstractMaleSocket, print this row. 477 * <P> 478 * If a male socket that extends AbstractMaleSocket wants to print 479 * something here, it needs to override this method. 480 * <P> 481 * The reason this method doesn't print if getObject() returns an 482 * AbstractMaleSocket is to protect so it doesn't print itself twice if 483 * it's embedding an other AbstractMaleSocket. An example of this is the 484 * AbstractDebuggerMaleSocket which embeds other male sockets. 485 * 486 * @param settings settings for what to print 487 * @param locale The locale to be used 488 * @param writer the stream to print the tree to 489 * @param currentIndent the current indentation 490 * @param lineNumber the line number 491 */ 492 protected void printTreeRow( 493 PrintTreeSettings settings, 494 Locale locale, 495 PrintWriter writer, 496 String currentIndent, 497 MutableInt lineNumber) { 498 499 if (!(getObject() instanceof AbstractMaleSocket)) { 500 String comment = getComment(); 501 if (comment != null) { 502 comment = comment.replaceAll("\\r\\n", "\\n"); 503 comment = comment.replaceAll("\\r", "\\n"); 504 for (String s : comment.split("\\n", 0)) { 505 if (settings._printLineNumbers) { 506 writer.append(String.format(PRINT_LINE_NUMBERS_FORMAT, lineNumber.addAndGet(1))); 507 } 508 writer.append(currentIndent); 509 writer.append("// "); 510 writer.append(s); 511 writer.println(); 512 } 513 } 514 if (settings._printLineNumbers) { 515 writer.append(String.format(PRINT_LINE_NUMBERS_FORMAT, lineNumber.addAndGet(1))); 516 } 517 writer.append(currentIndent); 518 writer.append(getLongDescription(locale)); 519 if (settings._printSystemNames) { 520 writer.append(" ::: "); 521 writer.append(this.getSystemName()); 522 } 523 if (settings._printDisplayName) { 524 writer.append(" ::: "); 525 writer.append(Bundle.getMessage("LabelDisplayName")); 526 writer.append(" "); 527 writer.append(((NamedBean)this).getDisplayName( 528 NamedBean.DisplayOptions.USERNAME_SYSTEMNAME)); 529 } else if (!settings._hideUserName && getUserName() != null) { 530 writer.append(" ::: "); 531 writer.append(Bundle.getMessage("LabelUserName")); 532 writer.append(" "); 533 writer.append(getUserName()); 534 } 535 536 if (settings._printErrorHandling) { 537 writer.append(" ::: "); 538 writer.append(getErrorHandlingType().toString()); 539 } 540 if (!isEnabled()) { 541 writer.append(" ::: "); 542 writer.append(Bundle.getMessage("AbstractMaleSocket_Disabled")); 543 } 544 if (isLocked()) { 545 writer.append(" ::: "); 546 writer.append(Bundle.getMessage("AbstractMaleSocket_Locked")); 547 } 548 if (isSystem()) { 549 writer.append(" ::: "); 550 writer.append(Bundle.getMessage("AbstractMaleSocket_System")); 551 } 552 writer.println(); 553 } 554 } 555 556 protected void printLocalVariable( 557 PrintTreeSettings settings, 558 Locale locale, 559 PrintWriter writer, 560 String currentIndent, 561 MutableInt lineNumber, 562 VariableData localVariable) { 563 564 if (settings._printLineNumbers) { 565 writer.append(String.format(PRINT_LINE_NUMBERS_FORMAT, lineNumber.addAndGet(1))); 566 } 567 writer.append(currentIndent); 568 writer.append(" ::: "); 569 writer.append(Bundle.getMessage( 570 locale, 571 "PrintLocalVariable", 572 localVariable._name, 573 localVariable._initialValueType.toString(), 574 localVariable._initialValueData)); 575 writer.println(); 576 } 577 578 /** {@inheritDoc} */ 579 @Override 580 public void printTree( 581 PrintTreeSettings settings, 582 PrintWriter writer, 583 String indent, 584 MutableInt lineNumber) { 585 printTree(settings, Locale.getDefault(), writer, indent, "", lineNumber); 586 } 587 588 /** {@inheritDoc} */ 589 @Override 590 public void printTree( 591 PrintTreeSettings settings, 592 Locale locale, 593 PrintWriter writer, 594 String indent, 595 MutableInt lineNumber) { 596 printTree(settings, locale, writer, indent, "", lineNumber); 597 } 598 599 /** {@inheritDoc} */ 600 @Override 601 public void printTree( 602 PrintTreeSettings settings, 603 Locale locale, 604 PrintWriter writer, 605 String indent, 606 String currentIndent, 607 MutableInt lineNumber) { 608 609 printTreeRow(settings, locale, writer, currentIndent, lineNumber); 610 611 if (settings._printLocalVariables) { 612 for (VariableData localVariable : _localVariables) { 613 printLocalVariable(settings, locale, writer, currentIndent, lineNumber, localVariable); 614 } 615 } 616 617 if (getObject() instanceof MaleSocket) { 618 getObject().printTree(settings, locale, writer, indent, currentIndent, lineNumber); 619 } else { 620 for (int i=0; i < getChildCount(); i++) { 621 getChild(i).printTree(settings, locale, writer, indent, currentIndent+indent, lineNumber); 622 } 623 } 624 } 625 626 /** {@inheritDoc} */ 627 @Override 628 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value="SLF4J_SIGN_ONLY_FORMAT", 629 justification="Specific log message format") 630 public void getUsageTree(int level, NamedBean bean, List<NamedBeanUsageReport> report, NamedBean cdl) { 631 if (!(getObject() instanceof AbstractMaleSocket)) { 632 log.debug("*@ {} :: {}", level, this.getLongDescription()); 633 _object.getUsageDetail(level, bean, report, cdl); 634 } 635 636 if (getObject() instanceof MaleSocket) { 637 getObject().getUsageTree(level, bean, report, cdl); 638 } else { 639 level++; 640 for (int i=0; i < getChildCount(); i++) { 641 getChild(i).getUsageTree(level, bean, report, cdl); 642 } 643 } 644 } 645 646 /** {@inheritDoc} */ 647 @Override 648 public void getUsageDetail(int level, NamedBean bean, List<jmri.NamedBeanUsageReport> report, NamedBean cdl) { 649 } 650 651 @Override 652 public BaseManager<? extends NamedBean> getManager() { 653 return _manager; 654 } 655 656 @Override 657 public final Base getDeepCopy(Map<String, String> systemNames, Map<String, String> userNames) 658 throws JmriException { 659 660 MaleSocket maleSocket = (MaleSocket)getObject().getDeepCopy(systemNames, userNames); 661 662 maleSocket.setComment(this.getComment()); 663 if (maleSocket.getDebugConfig() != null) { 664 maleSocket.setDebugConfig(maleSocket.getDebugConfig().getCopy()); 665 } 666 maleSocket.setEnabledFlag(isEnabled()); 667 maleSocket.setListen(getListen()); 668 maleSocket.setErrorHandlingType(getErrorHandlingType()); 669 maleSocket.setLocked(isLocked()); 670 maleSocket.setSystem(false); // If a system item is copied, the new item is not treated as system 671 maleSocket.setCatchAbortExecution(getCatchAbortExecution()); 672 673 for (VariableData data : _localVariables) { 674 maleSocket.addLocalVariable(data._name, data._initialValueType, data._initialValueData); 675 } 676 677 return maleSocket; 678 } 679 680 @Override 681 public final Base deepCopyChildren(Base original, Map<String, String> systemNames, Map<String, String> userNames) throws JmriException { 682 getObject().deepCopyChildren(original, systemNames, userNames); 683 return this; 684 } 685 686 /** 687 * Disposes this object. 688 * This must remove _all_ connections! 689 */ 690 abstract protected void disposeMe(); 691 692 /** {@inheritDoc} */ 693 @Override 694 public final void dispose() { 695 for (int i=0; i < getChildCount(); i++) { 696 getChild(i).dispose(); 697 } 698 disposeMe(); 699 } 700 701 @Override 702 public ErrorHandlingType getErrorHandlingType() { 703 if (getObject() instanceof MaleSocket) { 704 return ((MaleSocket)getObject()).getErrorHandlingType(); 705 } else { 706 return _errorHandlingType; 707 } 708 } 709 710 @Override 711 public void setErrorHandlingType(ErrorHandlingType errorHandlingType) 712 { 713 if (getObject() instanceof MaleSocket) { 714 ((MaleSocket)getObject()).setErrorHandlingType(errorHandlingType); 715 } else { 716 _errorHandlingType = errorHandlingType; 717 } 718 } 719 720 /** 721 * Executes the error handling module. 722 * @param item the item that had the error 723 * @param message the error message 724 * @param messageList a list of error messages 725 * @param e the exception that has happened 726 */ 727 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings({"SLF4J_SIGN_ONLY_FORMAT"}) 728 // justification="The message is on several lines") 729 public void executeErrorHandlingModule( 730 Base item, 731 String message, 732 List<String> messageList, 733 Exception e) { 734 735 // Don't call the error handling module if it doesnt exist. 736 Module errorHandlingModule = InstanceManager.getDefault(ModuleManager.class) 737 .getBySystemName(LogixNG_Manager.ERROR_HANDLING_MODULE_NAME); 738 if (errorHandlingModule == null) { 739 return; 740 } 741 742 // Don't call the error handling module if it hasn't any children. 743 if (!ErrorHandlingModuleClass.INSTANCE.errorHandlingModule.getRootSocket().isConnected()) { 744 return; 745 } 746 747 // Don't call the error handling module recursively. It would happen 748 // if there is an error in the error handling module. 749 if (item.getModule() == ErrorHandlingModuleClass.INSTANCE.errorHandlingModule) { 750 log.warn("Exception in LogixNG error handling module. Can't execute error handling module recursively."); 751 if (messageList != null) { 752 for (String s : messageList) { 753 log.warn(" {}", s); 754 } 755 } else { 756 log.warn(" {}", message); 757 } 758 log.warn("Exception: ", e); 759 } 760 761 ErrorHandlingModuleClass.INSTANCE._variablesWithValues.put("logixng", item.getLogixNG()); 762 ErrorHandlingModuleClass.INSTANCE._variablesWithValues.put("conditionalng", item.getConditionalNG()); 763 ErrorHandlingModuleClass.INSTANCE._variablesWithValues.put("module", item.getModule()); 764 ErrorHandlingModuleClass.INSTANCE._variablesWithValues.put("item", item); 765 ErrorHandlingModuleClass.INSTANCE._variablesWithValues.put("message", message); 766 ErrorHandlingModuleClass.INSTANCE._variablesWithValues.put("messageList", messageList); 767 ErrorHandlingModuleClass.INSTANCE._variablesWithValues.put("exception", e); 768 ErrorHandlingModuleClass.INSTANCE.errorHandlingConditionalNG.execute(); 769 } 770 771 @Override 772 public void handleError(Base item, String message, JmriException e, Logger log) throws JmriException { 773 774 // Always throw AbortConditionalNGExecutionException exceptions 775 if (!_catchAbortExecution && (e instanceof AbortConditionalNGExecutionException)) throw e; 776 777 ErrorHandlingType errorHandlingType = getErrorHandlingType(); 778 if (errorHandlingType == ErrorHandlingType.Default) { 779 errorHandlingType = InstanceManager.getDefault(LogixNGPreferences.class) 780 .getErrorHandlingType(); 781 } 782 783 executeErrorHandlingModule(item, message, null, e); 784 785 switch (errorHandlingType) { 786 case ShowDialogBox: 787 boolean abort = ThreadingUtil.runOnGUIwithReturn(() -> { 788 ErrorHandlingDialog dialog = new ErrorHandlingDialog(); 789 return dialog.showDialog(item, message); 790 }); 791 if (abort) throw new AbortConditionalNGExecutionException(this, e); 792 break; 793 794 case LogError: 795 log.error("item {}, {} thrown an exception: {}", item.toString(), getObject().toString(), e, e); 796 break; 797 798 case LogErrorOnce: 799 LoggingUtil.warnOnce(log, "item {}, {} thrown an exception: {}", item.toString(), getObject().toString(), e, e); 800 break; 801 802 case ThrowException: 803 throw e; 804 805 case AbortExecution: 806 log.error("item {}, {} thrown an exception: {}", item.toString(), getObject().toString(), e, e); 807 throw new AbortConditionalNGExecutionException(this, e); 808 809 case AbortWithoutError: 810 throw new AbortConditionalNG_IgnoreException(this, e); 811 812 default: 813 throw e; 814 } 815 } 816 817 @Override 818 public void handleError( 819 Base item, 820 String message, 821 List<String> messageList, 822 JmriException e, 823 Logger log) 824 throws JmriException { 825 826 ErrorHandlingType errorHandlingType = getErrorHandlingType(); 827 if (errorHandlingType == ErrorHandlingType.Default) { 828 errorHandlingType = InstanceManager.getDefault(LogixNGPreferences.class) 829 .getErrorHandlingType(); 830 } 831 832 executeErrorHandlingModule(item, message, messageList, e); 833 834 switch (errorHandlingType) { 835 case ShowDialogBox: 836 boolean abort = ThreadingUtil.runOnGUIwithReturn(() -> { 837 ErrorHandlingDialog_MultiLine dialog = new ErrorHandlingDialog_MultiLine(); 838 return dialog.showDialog(item, message, messageList); 839 }); 840 if (abort) throw new AbortConditionalNGExecutionException(this, e); 841 break; 842 843 case LogError: 844 log.error("item {}, {} thrown an exception: {}", item.toString(), getObject().toString(), e, e); 845 break; 846 847 case LogErrorOnce: 848 LoggingUtil.warnOnce(log, "item {}, {} thrown an exception: {}", item.toString(), getObject().toString(), e, e); 849 break; 850 851 case ThrowException: 852 throw e; 853 854 case AbortExecution: 855 log.error("item {}, {} thrown an exception: {}", item.toString(), getObject().toString(), e, e); 856 throw new AbortConditionalNGExecutionException(this, e); 857 858 case AbortWithoutError: 859 throw new AbortConditionalNG_IgnoreException(this, e); 860 861 default: 862 throw e; 863 } 864 } 865 866 @Override 867 public void handleError(Base item, String message, RuntimeException e, Logger log) throws JmriException { 868 869 ErrorHandlingType errorHandlingType = getErrorHandlingType(); 870 if (errorHandlingType == ErrorHandlingType.Default) { 871 errorHandlingType = InstanceManager.getDefault(LogixNGPreferences.class) 872 .getErrorHandlingType(); 873 } 874 875 executeErrorHandlingModule(item, message, null, e); 876 877 switch (errorHandlingType) { 878 case ShowDialogBox: 879 boolean abort = ThreadingUtil.runOnGUIwithReturn(() -> { 880 ErrorHandlingDialog dialog = new ErrorHandlingDialog(); 881 return dialog.showDialog(item, message); 882 }); 883 if (abort) throw new AbortConditionalNGExecutionException(this, e); 884 break; 885 886 case LogError: 887// e.printStackTrace(); 888 log.error("item {}, {} thrown an exception: {}", item.toString(), getObject().toString(), e, e); 889 break; 890 891 case LogErrorOnce: 892// e.printStackTrace(); 893 LoggingUtil.warnOnce(log, "item {}, {} thrown an exception: {}", item.toString(), getObject().toString(), e, e); 894 break; 895 896 case ThrowException: 897 throw e; 898 899 case AbortExecution: 900 throw new AbortConditionalNGExecutionException(this, e); 901 902 case AbortWithoutError: 903 throw new AbortConditionalNG_IgnoreException(this, e); 904 905 default: 906 throw e; 907 } 908 } 909 910 /** {@inheritDoc} */ 911 @Override 912 public void getListenerRefsIncludingChildren(List<String> list) { 913 list.addAll(getListenerRefs()); 914 for (int i=0; i < getChildCount(); i++) { 915 getChild(i).getListenerRefsIncludingChildren(list); 916 } 917 } 918 919 @Override 920 public boolean hasChild(@Nonnull Base b) { 921 return getObject() == b; 922 } 923 924 /** {@inheritDoc} */ 925 @Override 926 public String toString() { 927 return getObject().toString(); 928 } 929 930 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(AbstractMaleSocket.class); 931}