001package jmri.managers; 002 003import java.util.*; 004 005import javax.annotation.Nonnull; 006import javax.annotation.CheckForNull; 007 008import jmri.AddressedProgrammer; 009import jmri.AddressedProgrammerManager; 010import jmri.GlobalProgrammerManager; 011import jmri.Programmer; 012import jmri.ProgrammingMode; 013import jmri.beans.PropertyChangeSupport; 014import jmri.implementation.PermissionProgrammer; 015import jmri.implementation.PermissionAddressedProgrammer; 016 017import org.slf4j.Logger; 018import org.slf4j.LoggerFactory; 019 020/** 021 * Provides a very basic implementation of a programmer manager by providing a 022 * union of the AddressedProgrammerManager and GlobalProgrammerManager 023 * interfaces. 024 * <p> 025 * This implementation requires a service-mode Programmer at construction time 026 * and returns that Programmer for all global programming mode requests. This 027 * implementation of AddressedProgrammerManager always returns null for Op Mode, 028 * or addressed programmer requests, indicating there is no programmer of that 029 * type. 030 * 031 * @see jmri.AddressedProgrammerManager 032 * @see jmri.GlobalProgrammerManager 033 * @author Bob Jacobsen Copyright (C) 2001, 2015, 2016 034 */ 035public class DefaultProgrammerManager extends PropertyChangeSupport implements AddressedProgrammerManager, GlobalProgrammerManager { 036 037 // For the record, these were the original numerical definitions: 038 // public static final ProgrammingMode NONE = new ProgrammingMode("NONE", 0); 039 // public static final ProgrammingMode REGISTERMODE = new ProgrammingMode("REGISTERMODE", 11); 040 // public static final ProgrammingMode PAGEMODE = new ProgrammingMode("PAGEMODE", 21); 041 // public static final ProgrammingMode DIRECTBITMODE = new ProgrammingMode("DIRECTBITMODE", 31); 042 // public static final ProgrammingMode DIRECTBYTEMODE = new ProgrammingMode("DIRECTBYTEMODE", 32); 043 // public static final ProgrammingMode ADDRESSMODE = new ProgrammingMode("ADDRESSMODE", 41); 044 // public static final ProgrammingMode OPSBYTEMODE = new ProgrammingMode("OPSBYTEMODE", 101); 045 // public static final ProgrammingMode OPSBITMODE = new ProgrammingMode("OPSBITMODE", 102); 046 // public static final ProgrammingMode OPSACCBYTEMODE = new ProgrammingMode("OPSACCBYTEMODE", 111); 047 // public static final ProgrammingMode OPSACCBITMODE = new ProgrammingMode("OPSACCBITMODE", 112); 048 // public static final ProgrammingMode OPSACCEXTBYTEMODE = new ProgrammingMode("OPSACCEXTBYTEMODE", 121); 049 // public static final ProgrammingMode OPSACCEXTBITMODE = new ProgrammingMode("OPSACCEXTBITMODE", 122); 050 private Programmer programmer; 051 Map<Programmer, PermissionProgrammer> permissionProgrammers = new HashMap<>(); 052 Map<AddressedProgrammer, PermissionAddressedProgrammer> permissionAddressedProgrammers = new HashMap<>(); 053 054 /** 055 * Constructor when no global programmer is available. 056 */ 057 public DefaultProgrammerManager() { 058 this(null); // indicates not present 059 } 060 061 /** 062 * Constructor with a programmer. 063 * 064 * @param programmer the programmer to use; if null, acts as if no 065 * programmer is available 066 */ 067 public DefaultProgrammerManager(@CheckForNull Programmer programmer) { 068 this.programmer = programmer; 069 } 070 071 /** 072 * Constructor with a programmer and associated connection. 073 * 074 * @param programmer the programmer to use; if null, acts as if no 075 * programmer is available 076 * @param memo the associated connection 077 */ 078 public DefaultProgrammerManager(@CheckForNull Programmer programmer, @Nonnull jmri.SystemConnectionMemo memo) { 079 this(programmer); 080 this.userName = memo.getUserName(); 081 } 082 083 private String userName = "<Default>"; 084 085 /** 086 * Provides the human-readable representation for including 087 * ProgrammerManagers directly in user interface components, so it should 088 * return a user-provided name for this particular one. 089 */ 090 @Override 091 public String getUserName() { 092 return userName; 093 } 094 095 /** 096 * Provides the human-readable representation for including 097 * ProgrammerManagers directly in user interface components, so it should 098 * return a user-provided name for this particular one. 099 */ 100 @Override 101 public String toString() { 102 return getUserName(); 103 } 104 105 @Override 106 public final Programmer getGlobalProgrammer() { 107 Programmer p = getConcreteGlobalProgrammer(); 108 if (p != null) { 109 return permissionProgrammers.computeIfAbsent(p, 110 v -> new PermissionProgrammer(v)); 111 } else { 112 return null; 113 } 114 } 115 116 /** 117 * Gain access to the Global Mode Programmer without reservation. 118 * 119 * @return null only if there isn't a Global Mode Programmer available via 120 * this Manager. 121 */ 122 @CheckForNull 123 protected Programmer getConcreteGlobalProgrammer() { 124 log.debug("return default service-mode programmer of type {}", (programmer != null ? programmer.getClass() : "(null)")); 125 return programmer; 126 } 127 128 @Override 129 public final AddressedProgrammer getAddressedProgrammer(boolean pLongAddress, int pAddress) { 130 AddressedProgrammer p = getConcreteAddressedProgrammer(pLongAddress, pAddress); 131 if (p != null) { 132 return permissionAddressedProgrammers.computeIfAbsent(p, 133 v -> new PermissionAddressedProgrammer(v)); 134 } else { 135 return null; 136 } 137 } 138 139 /** 140 * Gain access to a Addressed Mode Programmer without reservation. 141 * 142 * @param pLongAddress true if this is a long (14 bit) address, else false 143 * @param pAddress specific decoder address to use 144 * @return null only if there isn't an Ops Mode Programmer in the system 145 */ 146 @CheckForNull 147 protected AddressedProgrammer getConcreteAddressedProgrammer(boolean pLongAddress, int pAddress) { 148 return null; 149 } 150 151 @Override 152 public final Programmer reserveGlobalProgrammer() { 153 Programmer p = reserveConcreteGlobalProgrammer(); 154 if (p != null) { 155 return permissionProgrammers.computeIfAbsent(p, 156 v -> new PermissionProgrammer(v)); 157 } else { 158 return null; 159 } 160 } 161 162 /** 163 * Gain access to the Global Mode Programmer, in the process reserving it 164 * for yourself. 165 * 166 * @return null if the existing Global Mode programmer is in use 167 */ 168 protected Programmer reserveConcreteGlobalProgrammer() { 169 return programmer; 170 } 171 172 @Override 173 public void releaseGlobalProgrammer(@Nonnull Programmer p) { 174 } 175 176 @Override 177 public final AddressedProgrammer reserveAddressedProgrammer(boolean pLongAddress, int pAddress) { 178 AddressedProgrammer p = reserveConcreteAddressedProgrammer(pLongAddress, pAddress); 179 if (p != null) { 180 return permissionAddressedProgrammers.computeIfAbsent(p, 181 v -> new PermissionAddressedProgrammer(v)); 182 } else { 183 return null; 184 } 185 } 186 187 /** 188 * Gain access to a (the) Addressed Mode Programmer, in the process 189 * reserving it for yourself. 190 * 191 * @param pLongAddress true if this is a long (14 bit) address, else false 192 * @param pAddress Specific decoder address to use 193 * @return null if the address is in use by a reserved programmer 194 */ 195 @CheckForNull 196 protected AddressedProgrammer reserveConcreteAddressedProgrammer(boolean pLongAddress, int pAddress) { 197 return null; 198 } 199 200 @Override 201 public void releaseAddressedProgrammer(@Nonnull AddressedProgrammer p) { 202 } 203 204 /** 205 * {@inheritDoc} 206 * 207 * @return always false in this implementation 208 */ 209 @Override 210 public boolean isAddressedModePossible() { 211 return false; 212 } 213 214 /** 215 * {@inheritDoc} 216 * 217 * @return always false in this implementation 218 */ 219 @Override 220 public boolean isAddressedModePossible(@Nonnull jmri.LocoAddress l) { 221 return isAddressedModePossible(); 222 } 223 224 /** 225 * {@inheritDoc} 226 * 227 * @return always false in this implementation 228 */ 229 @Override 230 public boolean isGlobalProgrammerAvailable() { 231 return true; 232 } 233 234 /** 235 * {@inheritDoc} 236 * 237 * @return a default list of programming modes that most 238 * {@link jmri.AddressedProgrammer}s make available 239 */ 240 @Override 241 public List<ProgrammingMode> getDefaultModes() { 242 List<ProgrammingMode> retval = new java.util.ArrayList<>(); 243 retval.add(ProgrammingMode.OPSBYTEMODE); 244 return retval; 245 } 246 247 public void dispose() { 248 if (programmer != null) { 249 programmer.dispose(); 250 } 251 } 252 253 private final static Logger log = LoggerFactory.getLogger(DefaultProgrammerManager.class); 254}