001package jmri.jmrit.logixng.expressions; 002 003import java.util.Locale; 004import java.util.Map; 005 006import jmri.InstanceManager; 007import jmri.JmriException; 008import jmri.jmrit.logixng.Base; 009import jmri.jmrit.logixng.Category; 010import jmri.jmrit.logixng.FemaleSocket; 011import jmri.jmrit.logixng.FemaleSocketListener; 012import jmri.jmrit.logixng.DigitalExpressionManager; 013import jmri.jmrit.logixng.FemaleDigitalExpressionSocket; 014import jmri.jmrit.logixng.MaleSocket; 015import jmri.jmrit.logixng.SocketAlreadyConnectedException; 016 017/** 018 * An Expression that keeps its status even if its child expression doesn't. 019 * 020 * This expression stays False until both the 'hold' expression and the 'trigger' 021 * expression becomes True. It stays true until the 'hold' expression goes to 022 * False. The 'trigger' expression can for example be a push button that stays 023 * True for a short time. 024 * 025 * @author Daniel Bergqvist Copyright 2018 026 */ 027public class Hold extends AbstractDigitalExpression implements FemaleSocketListener { 028 029 private String _triggerExpressionSocketSystemName; 030 private String _holdExpressionSocketSystemName; 031 private final FemaleDigitalExpressionSocket _triggerExpressionSocket; 032 private final FemaleDigitalExpressionSocket _holdExpressionSocket; 033 private boolean _isActive = false; 034 035 public Hold(String sys, String user) 036 throws BadUserNameException, BadSystemNameException { 037 038 super(sys, user); 039 040 _triggerExpressionSocket = InstanceManager.getDefault(DigitalExpressionManager.class) 041 .createFemaleSocket(this, this, Bundle.getMessage("Hold_SocketName_Trigger")); 042 _holdExpressionSocket = InstanceManager.getDefault(DigitalExpressionManager.class) 043 .createFemaleSocket(this, this, Bundle.getMessage("Hold_SocketName_Hold")); 044 } 045 046 @Override 047 public Base getDeepCopy(Map<String, String> systemNames, Map<String, String> userNames) throws JmriException { 048 DigitalExpressionManager manager = InstanceManager.getDefault(DigitalExpressionManager.class); 049 String sysName = systemNames.get(getSystemName()); 050 String userName = userNames.get(getSystemName()); 051 if (sysName == null) sysName = manager.getAutoSystemName(); 052 Hold copy = new Hold(sysName, userName); 053 copy.setComment(getComment()); 054 return manager.registerExpression(copy).deepCopyChildren(this, systemNames, userNames); 055 } 056 057 /** {@inheritDoc} */ 058 @Override 059 public Category getCategory() { 060 return Category.OTHER; 061 } 062 063 /** {@inheritDoc} */ 064 @Override 065 public boolean evaluate() throws JmriException { 066 if (_isActive) { 067 _isActive = _holdExpressionSocket.evaluate() 068 || _triggerExpressionSocket.evaluate(); 069 } else { 070 _isActive = _triggerExpressionSocket.evaluate(); 071 } 072 return _isActive; 073 } 074 075 @Override 076 public FemaleSocket getChild(int index) throws IllegalArgumentException, UnsupportedOperationException { 077 switch (index) { 078 case 0: 079 return _triggerExpressionSocket; 080 081 case 1: 082 return _holdExpressionSocket; 083 084 default: 085 throw new IllegalArgumentException( 086 String.format("index has invalid value: %d", index)); 087 } 088 } 089 090 @Override 091 public int getChildCount() { 092 return 2; 093 } 094 095 @Override 096 public void connected(FemaleSocket socket) { 097 if (socket == _triggerExpressionSocket) { 098 _triggerExpressionSocketSystemName = socket.getConnectedSocket().getSystemName(); 099 } else if (socket == _holdExpressionSocket) { 100 _holdExpressionSocketSystemName = socket.getConnectedSocket().getSystemName(); 101 } else { 102 throw new IllegalArgumentException("unkown socket"); 103 } 104 } 105 106 @Override 107 public void disconnected(FemaleSocket socket) { 108 if (socket == _triggerExpressionSocket) { 109 _triggerExpressionSocketSystemName = null; 110 } else if (socket == _holdExpressionSocket) { 111 _holdExpressionSocketSystemName = null; 112 } else { 113 throw new IllegalArgumentException("unkown socket"); 114 } 115 } 116 117 @Override 118 public String getShortDescription(Locale locale) { 119 return Bundle.getMessage(locale, "Hold_Short"); 120 } 121 122 @Override 123 public String getLongDescription(Locale locale) { 124 return Bundle.getMessage(locale, "Hold_Long", 125 _triggerExpressionSocket.getName(), 126 _holdExpressionSocket.getName()); 127 } 128 129 public String getTriggerExpressionSocketSystemName() { 130 return _triggerExpressionSocketSystemName; 131 } 132 133 public void setTriggerExpressionSocketSystemName(String systemName) { 134 _triggerExpressionSocketSystemName = systemName; 135 } 136 137 public String getHoldActionSocketSystemName() { 138 return _holdExpressionSocketSystemName; 139 } 140 141 public void setHoldActionSocketSystemName(String systemName) { 142 _holdExpressionSocketSystemName = systemName; 143 } 144 145 /** {@inheritDoc} */ 146 @Override 147 public void setup() { 148 try { 149 if ( !_triggerExpressionSocket.isConnected() 150 || !_triggerExpressionSocket.getConnectedSocket().getSystemName() 151 .equals(_triggerExpressionSocketSystemName)) { 152 153 String socketSystemName = _triggerExpressionSocketSystemName; 154 _triggerExpressionSocket.disconnect(); 155 if (socketSystemName != null) { 156 MaleSocket maleSocket = 157 InstanceManager.getDefault(DigitalExpressionManager.class) 158 .getBySystemName(socketSystemName); 159 _triggerExpressionSocket.disconnect(); 160 if (maleSocket != null) { 161 _triggerExpressionSocket.connect(maleSocket); 162 maleSocket.setup(); 163 } else { 164 log.error("cannot load digital expression {}", socketSystemName); 165 } 166 } 167 } else { 168 _triggerExpressionSocket.getConnectedSocket().setup(); 169 } 170 171 if ( !_holdExpressionSocket.isConnected() 172 || !_holdExpressionSocket.getConnectedSocket().getSystemName() 173 .equals(_holdExpressionSocketSystemName)) { 174 175 String socketSystemName = _holdExpressionSocketSystemName; 176 _holdExpressionSocket.disconnect(); 177 if (socketSystemName != null) { 178 MaleSocket maleSocket = 179 InstanceManager.getDefault(DigitalExpressionManager.class) 180 .getBySystemName(socketSystemName); 181 if (maleSocket != null) { 182 _holdExpressionSocket.connect(maleSocket); 183 maleSocket.setup(); 184 } else { 185 log.error("cannot load digital expression {}", socketSystemName); 186 } 187 } 188 } else { 189 _holdExpressionSocket.getConnectedSocket().setup(); 190 } 191 } catch (SocketAlreadyConnectedException ex) { 192 // This shouldn't happen and is a runtime error if it does. 193 throw new RuntimeException("socket is already connected"); 194 } 195 } 196 197 /** {@inheritDoc} */ 198 @Override 199 public void registerListenersForThisClass() { 200 // Do nothing 201 } 202 203 /** {@inheritDoc} */ 204 @Override 205 public void unregisterListenersForThisClass() { 206 // Do nothing 207 } 208 209 /** {@inheritDoc} */ 210 @Override 211 public void disposeMe() { 212 } 213 214 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(Hold.class); 215 216}