001package jmri.jmrit.logixng.implementation; 002 003import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 004 005import java.beans.*; 006import java.io.PrintWriter; 007import java.util.*; 008 009import javax.annotation.Nonnull; 010import javax.annotation.OverridingMethodsMustInvokeSuper; 011 012import jmri.*; 013import jmri.jmrit.logixng.*; 014import jmri.managers.AbstractManager; 015import jmri.util.LoggingUtil; 016import jmri.util.ThreadingUtil; 017 018/** 019 * Class providing the basic logic of the GlobalVariable_Manager interface. 020 * 021 * @author Dave Duchamp Copyright (C) 2007 022 * @author Daniel Bergqvist Copyright (C) 2022 023 */ 024public class DefaultGlobalVariableManager extends AbstractManager<GlobalVariable> 025 implements GlobalVariableManager { 026 027 028 public DefaultGlobalVariableManager() { 029 // The GlobalVariablePreferences class may load plugins so we must ensure 030 // it's loaded here. 031 InstanceManager.getDefault(LogixNGPreferences.class); 032 } 033 034 @Override 035 public int getXMLOrder() { 036 return LOGIXNG_GLOBAL_VARIABLES; 037 } 038 039 @Override 040 public char typeLetter() { 041 return 'Q'; 042 } 043 044 /** 045 * Test if parameter is a properly formatted system name. 046 * 047 * @param systemName the system name 048 * @return enum indicating current validity, which might be just as a prefix 049 */ 050 @Override 051 public NameValidity validSystemNameFormat(String systemName) { 052 return LogixNG_Manager.validSystemNameFormat( 053 getSubSystemNamePrefix(), systemName); 054 } 055 056 /** 057 * Method to create a new GlobalVariable if the GlobalVariable does not exist. 058 * <p> 059 * Returns null if a GlobalVariable with the same systemName or userName 060 * already exists, or if there is trouble creating a new GlobalVariable. 061 */ 062 @Override 063 public GlobalVariable createGlobalVariable(String systemName, String userName) 064 throws IllegalArgumentException { 065 066 // Check that GlobalVariable does not already exist 067 GlobalVariable x; 068 if (userName != null && !userName.isEmpty()) { 069 x = getByUserName(userName); 070 if (x != null) { 071 return null; 072 } 073 } 074 x = getBySystemName(systemName); 075 if (x != null) { 076 return null; 077 } 078 // Check if system name is valid 079 if (this.validSystemNameFormat(systemName) != NameValidity.VALID) { 080 throw new IllegalArgumentException("SystemName " + systemName + " is not in the correct format"); 081 } 082 // GlobalVariable does not exist, create a new GlobalVariable 083 x = new DefaultGlobalVariable(systemName, userName); 084 // save in the maps 085 register(x); 086 087 // Keep track of the last created auto system name 088 updateAutoNumber(systemName); 089 090 return x; 091 } 092 093 @Override 094 public GlobalVariable createGlobalVariable(String userName) throws IllegalArgumentException { 095 return createGlobalVariable(getAutoSystemName(), userName); 096 } 097 098 @Override 099 public GlobalVariable getGlobalVariable(String name) { 100 GlobalVariable x = getByUserName(name); 101 if (x != null) { 102 return x; 103 } 104 return getBySystemName(name); 105 } 106 107 @Override 108 public GlobalVariable getByUserName(String name) { 109 return _tuser.get(name); 110 } 111 112 @Override 113 public GlobalVariable getBySystemName(String name) { 114 return _tsys.get(name); 115 } 116 117 /** {@inheritDoc} */ 118 @Override 119 public String getBeanTypeHandled(boolean plural) { 120 return Bundle.getMessage(plural ? "BeanNameGlobalVariables" : "BeanNameGlobalVariable"); 121 } 122 123 /** {@inheritDoc} */ 124 @Override 125 public void deleteGlobalVariable(GlobalVariable x) { 126 // delete the GlobalVariable 127 deregister(x); 128 x.dispose(); 129 } 130 131 /** {@inheritDoc} */ 132 @Override 133 public void printTree(Locale locale, PrintWriter writer, String indent) { 134 for (GlobalVariable globalVariable : getNamedBeanSet()) { 135 writer.append(String.format( 136 "Global variable: System name: %s, User name: %s, Initial value type: %s, Initial value data: %s", 137 globalVariable.getSystemName(), globalVariable.getUserName(), 138 globalVariable.getInitialValueType().toString(), globalVariable.getInitialValueData())); 139 writer.println(); 140 } 141 writer.println(); 142 } 143 144 static volatile DefaultGlobalVariableManager _instance = null; 145 146 @InvokeOnGuiThread // this method is not thread safe 147 public static DefaultGlobalVariableManager instance() { 148 if (!ThreadingUtil.isGUIThread()) { 149 LoggingUtil.warnOnce(log, "instance() called on wrong thread"); 150 } 151 152 if (_instance == null) { 153 _instance = new DefaultGlobalVariableManager(); 154 } 155 return (_instance); 156 } 157 158 /** {@inheritDoc} */ 159 @Override 160 public Class<GlobalVariable> getNamedBeanClass() { 161 return GlobalVariable.class; 162 } 163 164 /** 165 * Inform all registered listeners of a vetoable change.If the propertyName 166 * is "CanDelete" ALL listeners with an interest in the bean will throw an 167 * exception, which is recorded returned back to the invoking method, so 168 * that it can be presented back to the user.However if a listener decides 169 * that the bean can not be deleted then it should throw an exception with 170 * a property name of "DoNotDelete", this is thrown back up to the user and 171 * the delete process should be aborted. 172 * 173 * @param p The programmatic name of the property that is to be changed. 174 * "CanDelete" will inquire with all listeners if the item can 175 * be deleted. "DoDelete" tells the listener to delete the item. 176 * @param old The old value of the property. 177 * @throws java.beans.PropertyVetoException If the recipients wishes the 178 * delete to be aborted (see above) 179 */ 180 @OverridingMethodsMustInvokeSuper 181 public void fireVetoableChange(String p, Object old) throws PropertyVetoException { 182 PropertyChangeEvent evt = new PropertyChangeEvent(this, p, old, null); 183 for (VetoableChangeListener vc : vetoableChangeSupport.getVetoableChangeListeners()) { 184 vc.vetoableChange(evt); 185 } 186 } 187 188 /** {@inheritDoc} */ 189 @Override 190 @SuppressFBWarnings(value = "OVERRIDING_METHODS_MUST_INVOKE_SUPER", 191 justification = "Further investigation is needed to handle this correctly") 192 public final void deleteBean(@Nonnull GlobalVariable globalVariable, @Nonnull String property) throws PropertyVetoException { 193 // throws PropertyVetoException if vetoed 194 fireVetoableChange(property, globalVariable); 195 if ( PROPERTY_DO_DELETE.equals(property)) { 196 deregister(globalVariable); 197 globalVariable.dispose(); 198 } 199 } 200 201 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DefaultGlobalVariableManager.class); 202 203}