001package jmri.managers; 002 003import java.lang.reflect.InvocationTargetException; 004import java.util.ArrayList; 005import java.util.List; 006import java.util.Objects; 007 008import javax.annotation.CheckForNull; 009import javax.annotation.Nonnull; 010 011import jmri.*; 012import jmri.implementation.*; 013import jmri.jmrix.internal.InternalSystemConnectionMemo; 014import jmri.util.StringUtil; 015 016/** 017 * Default implementation of a SignalMastManager. 018 * <p> 019 * Note that this does not enforce any particular system naming convention at 020 * the present time. They're just names... 021 * 022 * @author Bob Jacobsen Copyright (C) 2009, 2020 023 */ 024public class DefaultSignalMastManager extends AbstractManager<SignalMast> 025 implements SignalMastManager { 026 027 public DefaultSignalMastManager(InternalSystemConnectionMemo memo) { 028 super(memo); 029 repeaterList = new ArrayList<>(); 030 addListeners(); 031 } 032 033 final void addListeners(){ 034 InstanceManager.getDefault(SignalHeadManager.class).addVetoableChangeListener(this); 035 InstanceManager.getDefault(TurnoutManager.class).addVetoableChangeListener(this); 036 } 037 038 /** {@inheritDoc} */ 039 @Override 040 public int getXMLOrder() { 041 return Manager.SIGNALMASTS; 042 } 043 044 /** {@inheritDoc} */ 045 @Override 046 public char typeLetter() { 047 return 'F'; 048 } 049 050 /** 051 * {@inheritDoc} 052 * Searches by UserName then SystemName. 053 */ 054 @Override 055 @CheckForNull 056 public SignalMast getSignalMast(@Nonnull String name) { 057 if (Objects.isNull(name) || name.length() == 0) { 058 return null; 059 } 060 SignalMast t = getByUserName(name); 061 return ( t != null ? t : getBySystemName(name)); 062 } 063 064 /** {@inheritDoc} */ 065 @Override 066 @Nonnull 067 public SignalMast provideSignalMast(@Nonnull String prefix, // nominally IF$shsm 068 @Nonnull String signalSystem, 069 @Nonnull String mastName, 070 @Nonnull String[] heads) throws JmriException { 071 StringBuilder name = new StringBuilder(prefix); 072 name.append(":"); 073 name.append(signalSystem); 074 name.append(":"); 075 name.append(mastName); 076 for (String s : heads) { 077 name.append("("); 078 name.append(StringUtil.parenQuote(s)); 079 name.append(")"); 080 } 081 return provideSignalMast(new String(name)); 082 } 083 084 /** {@inheritDoc} */ 085 @Override 086 @Nonnull 087 public SignalMast provideSignalMast(@Nonnull String name) throws IllegalArgumentException { 088 SignalMast m = getSignalMast(name); 089 if (m == null) { 090 // this should be replaced by a Service based approach, 091 // perhaps along the lines of SignalMastAddPane, but 092 // for now we manually check types 093 if (name.startsWith("IF$shsm")) { 094 m = new SignalHeadSignalMast(name); 095 } else if (name.startsWith("IF$dsm")) { 096 m = new DccSignalMast(name); 097 } else if (name.startsWith("IF$vsm")) { 098 m = new VirtualSignalMast(name); 099 } else { 100 // didn't recognize name, so trying to make it virtual 101 log.warn("building stand-in VirtualSignalMast for {}", name); 102 m = new VirtualSignalMast(name); 103 } 104 register(m); 105 } 106 return m; 107 } 108 109 /** {@inheritDoc} */ 110 @Nonnull 111 @Override 112 public SignalMast provideCustomSignalMast(@Nonnull String systemName, Class<? extends 113 SignalMast> mastClass) throws JmriException { 114 SignalMast m = getBySystemName(systemName); 115 if (m != null) { 116 if (!mastClass.isInstance(m)) { 117 throw new JmriException("Could not create signal mast " + systemName + ", because" + 118 " the system name is already used by a different kind of mast. Expected " 119 + mastClass.getSimpleName() + ", actual " + m.getClass().getSimpleName() 120 + "."); 121 } 122 return m; 123 } 124 try { 125 m = mastClass.getConstructor(String.class).newInstance(systemName); 126 } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | 127 InvocationTargetException e) { 128 throw new JmriException(e); 129 } 130 register(m); 131 return m; 132 } 133 134 /** {@inheritDoc} */ 135 @Override 136 @CheckForNull 137 public SignalMast getBySystemName(@Nonnull String key) { 138 return _tsys.get(key); 139 } 140 141 /** {@inheritDoc} */ 142 @Override 143 @CheckForNull 144 public SignalMast getByUserName(@Nonnull String key) { 145 return _tuser.get(key); 146 } 147 148 @Override 149 @Nonnull 150 public String getBeanTypeHandled(boolean plural) { 151 return Bundle.getMessage(plural ? "BeanNameSignalMasts" : "BeanNameSignalMast"); 152 } 153 154 /** 155 * {@inheritDoc} 156 */ 157 @Override 158 public Class<SignalMast> getNamedBeanClass() { 159 return SignalMast.class; 160 } 161 162 private final ArrayList<SignalMastRepeater> repeaterList; 163 164 /** 165 * Creates or retrieves a signal mast repeater. 166 * @param master the mast for the master of the repeater. 167 * @param slave the mast for the slave of the repeater. 168 * @return newly created (and registered) or existing signal mast repeater. 169 * @throws JmriException if the repeater already exists but the other direction. 170 */ 171 public @Nonnull SignalMastRepeater provideRepeater(@Nonnull SignalMast master, @Nonnull SignalMast 172 slave) throws JmriException { 173 SignalMastRepeater rp = null; 174 for (SignalMastRepeater currentRepeater : repeaterList) { 175 if (currentRepeater.getMasterMast() == master && currentRepeater.getSlaveMast() == slave) { 176 rp = currentRepeater; 177 } else if (currentRepeater.getMasterMast() == slave 178 && currentRepeater.getSlaveMast() == master) { 179 log.error("Signal repeater {}:{} already exists the wrong way", master, slave); 180 throw new JmriException("Signal mast repeater already exists the wrong way"); 181 } 182 } 183 if (rp == null) { 184 rp = new SignalMastRepeater(master, slave); 185 repeaterList.add(rp); 186 } 187 firePropertyChange("repeaterlength", null, null); 188 return rp; 189 } 190 191 public void addRepeater(SignalMastRepeater rp) throws JmriException { 192 for (SignalMastRepeater rpeat : repeaterList) { 193 if (rpeat.getMasterMast() == rp.getMasterMast() 194 && rpeat.getSlaveMast() == rp.getSlaveMast()) { 195 log.error("Signal repeater already Exists"); 196 throw new JmriException("Signal mast Repeater already exists"); 197 } else if (rpeat.getMasterMast() == rp.getSlaveMast() 198 && rpeat.getSlaveMast() == rp.getMasterMast()) { 199 log.error("Signal repeater already Exists"); 200 throw new JmriException("Signal mast Repeater already exists"); 201 } 202 } 203 repeaterList.add(rp); 204 firePropertyChange("repeaterlength", null, null); 205 } 206 207 public void removeRepeater(SignalMastRepeater rp) { 208 rp.dispose(); 209 repeaterList.remove(rp); 210 firePropertyChange("repeaterlength", null, null); 211 } 212 213 public List<SignalMastRepeater> getRepeaterList() { 214 return repeaterList; 215 } 216 217 public void initialiseRepeaters() { 218 for (SignalMastRepeater smr : repeaterList) { 219 smr.initialise(); 220 } 221 } 222 223 /** {@inheritDoc} */ 224 @Nonnull 225 @Override 226 public SignalMast provide(String name) throws IllegalArgumentException { 227 return provideSignalMast(name); 228 } 229 230 /** {@inheritDoc} */ 231 @Override 232 public void dispose(){ 233 InstanceManager.getDefault(SignalHeadManager.class).removeVetoableChangeListener(this); 234 InstanceManager.getDefault(TurnoutManager.class).removeVetoableChangeListener(this); 235 super.dispose(); 236 } 237 238 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DefaultSignalMastManager.class); 239}