001package jmri.jmrit.logixng.implementation; 002 003import java.beans.*; 004import java.io.File; 005import java.io.IOException; 006import java.io.PrintWriter; 007import java.text.DecimalFormat; 008import java.util.Locale; 009 010import javax.annotation.*; 011 012import jmri.*; 013import jmri.jmrit.logixng.*; 014import jmri.managers.AbstractManager; 015import jmri.util.*; 016 017/** 018 * Class providing the basic logic of the NamedTable_Manager interface. 019 * 020 * @author Dave Duchamp Copyright (C) 2007 021 * @author Daniel Bergqvist Copyright (C) 2020 022 */ 023public class DefaultNamedTableManager extends AbstractManager<NamedTable> 024 implements NamedTableManager { 025 026 DecimalFormat paddedNumber = new DecimalFormat("0000"); 027 028 029 /** 030 * {@inheritDoc} 031 */ 032 @Override 033 public int getXMLOrder() { 034 return LOGIXNG_TABLES; 035 } 036 037 /** 038 * {@inheritDoc} 039 */ 040 @Override 041 public char typeLetter() { 042 return 'Q'; 043 } 044 045 /** 046 * {@inheritDoc} 047 */ 048 @Override 049 public NameValidity validSystemNameFormat(String systemName) { 050 return LogixNG_Manager.validSystemNameFormat( 051 getSubSystemNamePrefix(), systemName); 052// if (systemName.matches(getSubSystemNamePrefix()+"(:AUTO:)?\\d+")) { 053// return NameValidity.VALID; 054// } else { 055// return NameValidity.INVALID; 056// } 057 } 058 059 060 /** 061 * {@inheritDoc} 062 */ 063 @Override 064 public NamedTable newCSVTable(String systemName, String userName, String fileName) 065 throws IllegalArgumentException { 066 return newCSVTable(systemName, userName, fileName, Table.CsvType.TABBED); 067 } 068 069 /** 070 * {@inheritDoc} 071 */ 072 @Override 073 public NamedTable newCSVTable(String systemName, String userName, String fileName, Table.CsvType csvType) 074 throws IllegalArgumentException { 075 076 // Check that NamedTable does not already exist 077 NamedTable x; 078 if (userName != null && !userName.equals("")) { 079 x = getByUserName(userName); 080 if (x != null) { 081 return null; 082 } 083 } 084 x = getBySystemName(systemName); 085 if (x != null) { 086 return null; 087 } 088 // Check if system name is valid 089 if (this.validSystemNameFormat(systemName) != NameValidity.VALID) { 090 throw new IllegalArgumentException("SystemName " + systemName + " is not in the correct format"); 091 } 092 try { 093 log.debug("about to load file {}", fileName ); 094 // NamedTable does not exist, create a new NamedTable 095 x = AbstractNamedTable.loadTableFromCSV_File(systemName, userName, fileName, true, csvType); 096 } catch (IOException ex) { 097// Exceptions.printStackTrace(ex); 098 log.error("Cannot load table due to I/O error", ex); 099 return null; 100 } 101 // save in the maps 102 register(x); 103 104 // Keep track of the last created auto system name 105 updateAutoNumber(systemName); 106 107 return x; 108 } 109 110 /** 111 * {@inheritDoc} 112 */ 113 @Override 114 public NamedTable newInternalTable(String systemName, String userName, int numRows, int numColumns) 115 throws IllegalArgumentException { 116 117 // Check that NamedTable does not already exist 118 NamedTable x; 119 if (userName != null && !userName.equals("")) { 120 x = getByUserName(userName); 121 if (x != null) { 122 return null; 123 } 124 } 125 x = getBySystemName(systemName); 126 if (x != null) { 127 return null; 128 } 129 // Check if system name is valid 130 if (this.validSystemNameFormat(systemName) != NameValidity.VALID) { 131 throw new IllegalArgumentException("SystemName " + systemName + " is not in the correct format"); 132 } 133 // Table does not exist, create a new NamedTable 134 x = new DefaultInternalNamedTable(systemName, userName, numRows, numColumns); 135 // save in the maps 136 register(x); 137 138 // Keep track of the last created auto system name 139 updateAutoNumber(systemName); 140 141 return x; 142 } 143 144 /** 145 * {@inheritDoc} 146 */ 147 @Override 148 public AnonymousTable newAnonymousTable(int numRows, int numColumns) 149 throws IllegalArgumentException { 150 151 // Check that NamedTable does not already exist 152 // NamedTable does not exist, create a new NamedTable 153 return new DefaultAnonymousTable(numRows, numColumns); 154 } 155 156 /** 157 * {@inheritDoc} 158 */ 159 @Override 160 public NamedTable loadTableFromCSVData( 161 @Nonnull String sys, @CheckForNull String user, @Nonnull String text) 162 throws NamedBean.BadUserNameException, 163 NamedBean.BadSystemNameException, 164 IOException { 165 return AbstractNamedTable.loadTableFromCSV_Text(sys, user, text, true, Table.CsvType.TABBED); 166 } 167 168 /** 169 * {@inheritDoc} 170 */ 171 @Override 172 public NamedTable loadTableFromCSV( 173 @Nonnull String sys, @CheckForNull String user, 174 @Nonnull String fileName) 175 throws NamedBean.BadUserNameException, NamedBean.BadSystemNameException, IOException { 176 return AbstractNamedTable.loadTableFromCSV_File(sys, user, fileName, true, Table.CsvType.TABBED); 177 } 178 179 /** 180 * {@inheritDoc} 181 */ 182 @Override 183 public NamedTable loadTableFromCSV( 184 @Nonnull String sys, @CheckForNull String user, 185 @Nonnull File file) 186 throws NamedBean.BadUserNameException, NamedBean.BadSystemNameException, IOException { 187 return AbstractNamedTable.loadTableFromCSV_File(sys, user, file, true, Table.CsvType.TABBED); 188 } 189 190 /** 191 * {@inheritDoc} 192 */ 193 @Override 194 public NamedTable getNamedTable(String name) { 195 NamedTable x = getByUserName(name); 196 if (x != null) { 197 return x; 198 } 199 return getBySystemName(name); 200 } 201 202 /** 203 * {@inheritDoc} 204 */ 205 @Override 206 public NamedTable getByUserName(String name) { 207 return _tuser.get(name); 208 } 209 210 /** 211 * {@inheritDoc} 212 */ 213 @Override 214 public NamedTable getBySystemName(String name) { 215 return _tsys.get(name); 216 } 217 218 /** 219 * {@inheritDoc} 220 */ 221 @Override 222 public String getBeanTypeHandled(boolean plural) { 223 return Bundle.getMessage(plural ? "BeanNameNamedTables" : "BeanNameNamedTable"); 224 } 225 226 /** 227 * {@inheritDoc} 228 */ 229 @Override 230 public void deleteNamedTable(NamedTable x) { 231 // delete the NamedTable 232 deregister(x); 233 x.dispose(); 234 } 235 236 /** {@inheritDoc} */ 237 @Override 238 public void printTree(PrintWriter writer, String indent) { 239 printTree(Locale.getDefault(), writer, indent); 240 } 241 242 /** {@inheritDoc} */ 243 @Override 244 public void printTree(Locale locale, PrintWriter writer, String indent) { 245 for (NamedTable namedTable : getNamedBeanSet()) { 246 if (namedTable instanceof DefaultCsvNamedTable) { 247 DefaultCsvNamedTable csvTable = (DefaultCsvNamedTable)namedTable; 248 writer.append(String.format( 249 "Named table: System name: %s, User name: %s, File name: %s, Num rows: %d, Num columns: %d", 250 csvTable.getSystemName(), csvTable.getUserName(), 251 csvTable.getFileName(), csvTable.numRows(), csvTable.numColumns())); 252 } else if (namedTable != null) { 253 writer.append(String.format( 254 "Named table: System name: %s, User name: %s, Num rows: %d, Num columns: %d", 255 namedTable.getSystemName(), namedTable.getUserName(), 256 namedTable.numRows(), namedTable.numColumns())); 257 } else { 258 throw new NullPointerException("namedTable is null"); 259 } 260 writer.println(); 261 } 262 writer.println(); 263 } 264 265 static volatile DefaultNamedTableManager _instance = null; 266 267 @InvokeOnGuiThread // this method is not thread safe 268 static public DefaultNamedTableManager instance() { 269 if (!ThreadingUtil.isGUIThread()) { 270 LoggingUtil.warnOnce(log, "instance() called on wrong thread"); 271 } 272 273 if (_instance == null) { 274 _instance = new DefaultNamedTableManager(); 275 } 276 return (_instance); 277 } 278 279 /** 280 * {@inheritDoc} 281 */ 282 @Override 283 public Class<NamedTable> getNamedBeanClass() { 284 return NamedTable.class; 285 } 286 287 /** 288 * Inform all registered listeners of a vetoable change.If the propertyName 289 * is "CanDelete" ALL listeners with an interest in the bean will throw an 290 * exception, which is recorded returned back to the invoking method, so 291 * that it can be presented back to the user.However if a listener decides 292 * that the bean can not be deleted then it should throw an exception with 293 * a property name of "DoNotDelete", this is thrown back up to the user and 294 * the delete process should be aborted. 295 * 296 * @param p The programmatic name of the property that is to be changed. 297 * "CanDelete" will inquire with all listeners if the item can 298 * be deleted. "DoDelete" tells the listener to delete the item. 299 * @param old The old value of the property. 300 * @throws java.beans.PropertyVetoException If the recipients wishes the 301 * delete to be aborted (see above) 302 */ 303 @OverridingMethodsMustInvokeSuper 304 public void fireVetoableChange(String p, Object old) throws PropertyVetoException { 305 PropertyChangeEvent evt = new PropertyChangeEvent(this, p, old, null); 306 for (VetoableChangeListener vc : vetoableChangeSupport.getVetoableChangeListeners()) { 307 vc.vetoableChange(evt); 308 } 309 } 310 311 /** {@inheritDoc} */ 312 @Override 313// @OverridingMethodsMustInvokeSuper 314 public final void deleteBean(@Nonnull NamedTable namedTable, @Nonnull String property) throws PropertyVetoException { 315 // throws PropertyVetoException if vetoed 316 fireVetoableChange(property, namedTable); 317 if (property.equals("DoDelete")) { // NOI18N 318 deregister(namedTable); 319 namedTable.dispose(); 320 } 321 } 322 323 324 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DefaultNamedTableManager.class); 325 326}