001package jmri.jmrit.logixng.actions; 002 003import java.util.*; 004 005import jmri.*; 006import jmri.jmrit.logixng.*; 007import jmri.jmrit.roster.Roster; 008import jmri.jmrit.roster.RosterEntry; 009 010/** 011 * Executes an action when the expression is True. 012 * 013 * @author Daniel Bergqvist Copyright 2026 014 */ 015public class ForEachRoster extends AbstractDigitalAction 016 implements FemaleSocketListener { 017 018 private String _variableName = ""; 019 private String _socketSystemName; 020 private final FemaleDigitalActionSocket _socket; 021 022 public ForEachRoster(String sys, String user) { 023 super(sys, user); 024 _socket = InstanceManager.getDefault(DigitalActionManager.class) 025 .createFemaleSocket(this, this, "A"); 026 } 027 028 @Override 029 public Base getDeepCopy(Map<String, String> systemNames, Map<String, String> userNames) throws JmriException { 030 DigitalActionManager manager = InstanceManager.getDefault(DigitalActionManager.class); 031 String sysName = systemNames.get(getSystemName()); 032 String userName = userNames.get(getSystemName()); 033 if (sysName == null) sysName = manager.getAutoSystemName(); 034 ForEachRoster copy = new ForEachRoster(sysName, userName); 035 copy.setComment(getComment()); 036 copy.setLocalVariableName(_variableName); 037 return manager.registerAction(copy).deepCopyChildren(this, systemNames, userNames); 038 } 039 040 /** 041 * Get name of local variable 042 * @return name of local variable 043 */ 044 public String getLocalVariableName() { 045 return _variableName; 046 } 047 048 /** 049 * Set name of local variable 050 * @param localVariableName name of local variable 051 */ 052 public void setLocalVariableName(String localVariableName) { 053 _variableName = localVariableName; 054 } 055 056 /** {@inheritDoc} */ 057 @Override 058 public LogixNG_Category getCategory() { 059 return LogixNG_Category.FLOW_CONTROL; 060 } 061 062 /** {@inheritDoc} */ 063 @Override 064 public void execute() throws JmriException { 065 SymbolTable symbolTable = getConditionalNG().getSymbolTable(); 066 067 var roster = Roster.getDefault(); 068 069 for (RosterEntry rosterEntry : roster.getAllEntries()) { 070 symbolTable.setValue(_variableName, rosterEntry); 071 try { 072 _socket.execute(); 073 } catch (BreakException e) { 074 break; 075 } catch (ContinueException e) { 076 // Do nothing, just catch it. 077 } 078 } 079 } 080 081 @Override 082 public FemaleSocket getChild(int index) throws IllegalArgumentException, UnsupportedOperationException { 083 switch (index) { 084 case 0: 085 return _socket; 086 087 default: 088 throw new IllegalArgumentException( 089 String.format("index has invalid value: %d", index)); 090 } 091 } 092 093 @Override 094 public int getChildCount() { 095 return 1; 096 } 097 098 @Override 099 public void connected(FemaleSocket socket) { 100 if (socket == _socket) { 101 _socketSystemName = socket.getConnectedSocket().getSystemName(); 102 } else { 103 throw new IllegalArgumentException("unkown socket"); 104 } 105 } 106 107 @Override 108 public void disconnected(FemaleSocket socket) { 109 if (socket == _socket) { 110 _socketSystemName = null; 111 } else { 112 throw new IllegalArgumentException("unkown socket"); 113 } 114 } 115 116 @Override 117 public String getShortDescription(Locale locale) { 118 return Bundle.getMessage(locale, "ForEachRoster_Short"); 119 } 120 121 @Override 122 public String getLongDescription(Locale locale) { 123 return Bundle.getMessage(locale, "ForEachRoster_Long", 124 _variableName, _socket.getName()); 125 } 126 127 public FemaleDigitalActionSocket getSocket() { 128 return _socket; 129 } 130 131 public String getSocketSystemName() { 132 return _socketSystemName; 133 } 134 135 public void setSocketSystemName(String systemName) { 136 _socketSystemName = systemName; 137 } 138 139 /** {@inheritDoc} */ 140 @Override 141 public void setup() { 142 try { 143 if ( !_socket.isConnected() 144 || !_socket.getConnectedSocket().getSystemName() 145 .equals(_socketSystemName)) { 146 147 String socketSystemName = _socketSystemName; 148 _socket.disconnect(); 149 if (socketSystemName != null) { 150 MaleSocket maleSocket = 151 InstanceManager.getDefault(DigitalActionManager.class) 152 .getBySystemName(socketSystemName); 153 _socket.disconnect(); 154 if (maleSocket != null) { 155 _socket.connect(maleSocket); 156 maleSocket.setup(); 157 } else { 158 log.error("cannot load digital action {}", socketSystemName); 159 } 160 } 161 } else { 162 _socket.getConnectedSocket().setup(); 163 } 164 } catch (SocketAlreadyConnectedException ex) { 165 // This shouldn't happen and is a runtime error if it does. 166 throw new RuntimeException("socket is already connected"); 167 } 168 } 169 170 171 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ForEachRoster.class); 172 173}