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