001package jmri.jmrit.logixng.implementation; 002 003import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 004 005import java.beans.*; 006 007import javax.annotation.Nonnull; 008import javax.annotation.OverridingMethodsMustInvokeSuper; 009 010import jmri.InstanceManager; 011import jmri.InvokeOnGuiThread; 012import jmri.jmrit.logixng.*; 013import jmri.jmrit.logixng.util.LogixNG_Thread; 014import jmri.managers.AbstractManager; 015import jmri.util.*; 016 017/** 018 * Class providing the basic logic of the ConditionalNG_Manager interface. 019 * 020 * @author Dave Duchamp Copyright (C) 2007 021 * @author Daniel Bergqvist Copyright (C) 2018 022 * @author Dave Sand Copyright (C) 2021 023 */ 024public class DefaultConditionalNGManager extends AbstractManager<ConditionalNG> 025 implements ConditionalNG_Manager { 026 027 028 public DefaultConditionalNGManager() { 029 // LogixNGPreferences class may load plugins so we must ensure 030 // it's loaded here. 031 InstanceManager.getDefault(LogixNGPreferences.class); 032 } 033 034 /** {@inheritDoc} */ 035 @Override 036 public int getXMLOrder() { 037 return LOGIXNG_CONDITIONALNGS; 038 } 039 040 /** {@inheritDoc} */ 041 @Override 042 public char typeLetter() { 043 return 'Q'; 044 } 045 046 /** {@inheritDoc} */ 047 @Override 048 public NameValidity validSystemNameFormat(String systemName) { 049 return LogixNG_Manager.validSystemNameFormat( 050 getSubSystemNamePrefix(), systemName); 051 } 052 053 /** {@inheritDoc} */ 054 @Override 055 public ConditionalNG createConditionalNG(LogixNG logixNG, String systemName, String userName) 056 throws IllegalArgumentException { 057 058 return createConditionalNG(logixNG, systemName, userName, LogixNG_Thread.DEFAULT_LOGIXNG_THREAD); 059 } 060 061 /** {@inheritDoc} */ 062 @Override 063 public ConditionalNG createConditionalNG( 064 LogixNG logixNG, String systemName, String userName, int threadID) 065 throws IllegalArgumentException { 066 067 // Check that ConditionalNG does not already exist 068 ConditionalNG x; 069 if (userName != null && !userName.isEmpty()) { 070 x = getByUserName(logixNG, userName); 071 if (x != null) { 072 log.error("username '{}' already exists, conditionalNG is '{}'", userName, x.getDisplayName()); 073 return null; 074 } 075 } 076 077 x = getBySystemName(systemName); 078 if (x != null) { 079 log.error("systemname '{}' already exists, conditionalNG is '{}'", systemName, x.getDisplayName()); 080 return null; 081 } 082 083 // Check if system name is valid 084 if (this.validSystemNameFormat(systemName) != NameValidity.VALID) { 085 throw new IllegalArgumentException("SystemName '" + systemName + "' is not in the correct format"); 086 } 087 088 // ConditionalNG does not exist, create a new ConditionalNG 089 x = new DefaultConditionalNG(systemName, userName, threadID); 090 091 // Add the conditional to the LogixNG map 092 logixNG.addConditionalNG(x); 093 094 // Keep track of the last created auto system name 095 updateAutoNumber(systemName); 096 097 return x; 098 } 099 100 /** {@inheritDoc} */ 101 @Override 102 public ConditionalNG createConditionalNG(LogixNG logixNG, String userName) throws IllegalArgumentException { 103 return createConditionalNG(logixNG, getAutoSystemName(), userName); 104 } 105 106 /** {@inheritDoc} */ 107 @Override 108 public ConditionalNG createConditionalNG(LogixNG logixNG, String userName, int threadID) throws IllegalArgumentException { 109 return createConditionalNG(logixNG, getAutoSystemName(), userName, threadID); 110 } 111 112 /** {@inheritDoc} */ 113 @Override 114 public ConditionalNG getConditionalNG(LogixNG logixNG, String name) { 115 if (logixNG != null) { 116 ConditionalNG x = getByUserName(logixNG, name); 117 if (x != null) { 118 return x; 119 } 120 } 121 return getBySystemName(name); 122 } 123 124 /** {@inheritDoc} */ 125 @Override 126 public LogixNG getParentLogixNG(String systemName) { 127 if (systemName == null || systemName.isEmpty()) { 128 return null; 129 } 130 131 for (LogixNG logixNG : InstanceManager.getDefault(LogixNG_Manager.class).getNamedBeanSet()) { 132 for (int i = 0; i < logixNG.getNumConditionalNGs(); i++) { 133 if (systemName.equals(logixNG.getConditionalNG_SystemName(i))) { 134 return logixNG; 135 } 136 } 137 } 138 return null; 139 } 140 141 /** {@inheritDoc} */ 142 @Override 143 public ConditionalNG getByUserName(LogixNG logixNG, String name) { 144 if (logixNG != null && name != null && !name.isEmpty()) { 145 for (int i = 0; i < logixNG.getNumConditionalNGs(); i++) { 146 ConditionalNG conditionalNG = logixNG.getConditionalNG(i); 147 if (conditionalNG != null) { 148 if (name.equals(conditionalNG.getUserName())) { 149 return conditionalNG; 150 } 151 } 152 } 153 } 154 return null; 155 } 156 157 /** {@inheritDoc} */ 158 @Override 159 public ConditionalNG getBySystemName(String name) { 160 LogixNG logixNG = getParentLogixNG(name); 161 if (logixNG != null) { 162 for (int i = 0; i < logixNG.getNumConditionalNGs(); i++) { 163 if (name.equals(logixNG.getConditionalNG_SystemName(i))) { 164 return logixNG.getConditionalNG(i); 165 } 166 } 167 } 168 return null; 169 } 170 171 /** {@inheritDoc} */ 172 @Override 173 public String getBeanTypeHandled(boolean plural) { 174 return Bundle.getMessage(plural ? "BeanNameConditionalNGs" : "BeanNameConditionalNG"); 175 } 176 177 /** {@inheritDoc} */ 178 @Override 179 public void deleteConditionalNG(ConditionalNG x) { 180 // delete the ConditionalNG 181 deregister(x); 182 x.dispose(); 183 } 184 185 /** {@inheritDoc} */ 186 @Override 187 public void setLoadDisabled(boolean s) { 188 throw new UnsupportedOperationException("Not supported yet."); 189 } 190 191 /** {@inheritDoc} */ 192 @Override 193 public void setRunOnGUIDelayed(boolean value) { 194 InstanceManager.getDefault(LogixNG_Manager.class).getNamedBeanSet().forEach(logixNG -> { 195 for (int i = 0; i < logixNG.getNumConditionalNGs(); i++) { 196 if (logixNG.getConditionalNG(i) != null) { 197 logixNG.getConditionalNG(i).setRunDelayed(false); 198 } 199 } 200 }); 201 } 202 203 static volatile DefaultConditionalNGManager _instance = null; 204 205 @InvokeOnGuiThread // this method is not thread safe 206 static public DefaultConditionalNGManager instance() { 207 if (!ThreadingUtil.isGUIThread()) { 208 LoggingUtil.warnOnce(log, "instance() called on wrong thread"); 209 } 210 211 if (_instance == null) { 212 _instance = new DefaultConditionalNGManager(); 213 } 214 return (_instance); 215 } 216 217 /** {@inheritDoc} */ 218 @Override 219 public Class<ConditionalNG> getNamedBeanClass() { 220 return ConditionalNG.class; 221 } 222 223 /** 224 * Inform all registered listeners of a vetoable change.If the propertyName 225 * is "CanDelete" ALL listeners with an interest in the bean will throw an 226 * exception, which is recorded returned back to the invoking method, so 227 * that it can be presented back to the user.However if a listener decides 228 * that the bean can not be deleted then it should throw an exception with 229 * a property name of "DoNotDelete", this is thrown back up to the user and 230 * the delete process should be aborted. 231 * 232 * @param p The programmatic name of the property that is to be changed. 233 * "CanDelete" will inquire with all listeners if the item can 234 * be deleted. "DoDelete" tells the listener to delete the item. 235 * @param old The old value of the property. 236 * @throws java.beans.PropertyVetoException If the recipients wishes the 237 * delete to be aborted (see above) 238 */ 239 @OverridingMethodsMustInvokeSuper 240 public void fireVetoableChange(String p, Object old) throws PropertyVetoException { 241 PropertyChangeEvent evt = new PropertyChangeEvent(this, p, old, null); 242 for (VetoableChangeListener vc : vetoableChangeSupport.getVetoableChangeListeners()) { 243 vc.vetoableChange(evt); 244 } 245 } 246 247 /** {@inheritDoc} */ 248 @Override 249 @SuppressFBWarnings(value = "OVERRIDING_METHODS_MUST_INVOKE_SUPER", 250 justification = "LogixNG is a tree that must be deleted recursively") 251 public final void deleteBean(@Nonnull ConditionalNG conditionalNG, @Nonnull String property) throws PropertyVetoException { 252 FemaleSocket child = conditionalNG.getFemaleSocket(); 253 if (child.isConnected()) { 254 MaleSocket maleSocket = child.getConnectedSocket(); 255 maleSocket.getManager().deleteBean(maleSocket, property); 256 } 257 258 // throws PropertyVetoException if vetoed 259 fireVetoableChange(property, conditionalNG); 260 if (property.equals("DoDelete")) { // NOI18N 261 if (conditionalNG.getLogixNG() != null) { 262 conditionalNG.getLogixNG().deleteConditionalNG(conditionalNG); 263 } 264 conditionalNG.dispose(); 265 } 266 } 267 268 269 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DefaultConditionalNGManager.class); 270}