001package jmri.web.server; 002 003import java.util.ArrayList; 004import java.util.Arrays; 005import java.util.prefs.BackingStoreException; 006import java.util.prefs.Preferences; 007 008import jmri.InstanceManagerAutoDefault; 009import jmri.beans.PreferencesBean; 010import jmri.profile.ProfileManager; 011import jmri.profile.ProfileUtils; 012import org.slf4j.Logger; 013import org.slf4j.LoggerFactory; 014 015/** 016 * @author Randall Wood Copyright (C) 2012, 2017 017 */ 018public class WebServerPreferences extends PreferencesBean implements InstanceManagerAutoDefault { 019 020 // preferences elements 021 public static final String DISALLOWED_FRAMES = "disallowedFrames"; // NOI18N 022 public static final String WEB_SERVER_PREFERENCES = "WebServerPreferences"; // NOI18N 023 public static final String FRAME = "frame"; // NOI18N 024 public static final String PORT = "port"; // NOI18N 025 public static final String CLICK_DELAY = "clickDelay"; // NOI18N 026 public static final String REFRESH_DELAY = "refreshDelay"; // NOI18N 027 public static final String USE_AJAX = "useAjax"; // NOI18N 028 public static final String SIMPLE = "simple"; // NOI18N 029 public static final String RAILROAD_NAME = "railroadName"; // NOI18N 030 public static final String ALLOW_REMOTE_CONFIG = "allowRemoteConfig"; // NOI18N 031 public static final String READONLY_POWER = "readonlyPower"; // NOI18N 032 public static final String DISABLE_FRAME_SERVER = "disableFrames"; // NOI18N 033 public static final String REDIRECT_FRAMES = "redirectFramesToPanels"; // NOI18N 034 public static final String USE_ZERO_CONF = "useZeroConf"; // NOI18N 035 private static final String DEFAULT_RAILROAD_NAME = "DefaultRailroadName"; // NOI18N 036 037 // initial defaults if preferences not found 038 private int clickDelay = 1; 039 private int refreshDelay = 5; 040 private boolean useAjax = true; 041 private boolean simple = false; 042 private final ArrayList<String> disallowedFrames = 043 new ArrayList<>(Arrays.asList(Bundle.getMessage("DefaultDisallowedFrames").split(";"))); 044 private String railroadName = Bundle.getMessage(DEFAULT_RAILROAD_NAME); 045 private boolean allowRemoteConfig = false; 046 private boolean readonlyPower = true; 047 private int port = 12080; 048 private boolean disableFrames = true; 049 private boolean redirectFramesToPanels = true; 050 private static final Logger log = LoggerFactory.getLogger(WebServerPreferences.class); 051 private boolean useZeroConf = true; 052 053 public WebServerPreferences() { 054 super(ProfileManager.getDefault().getActiveProfile()); 055 Preferences sharedPreferences = ProfileUtils.getPreferences(super.getProfile(), this.getClass(), true); 056 this.readPreferences(sharedPreferences); 057 } 058 059 private void readPreferences(Preferences sharedPreferences) { 060 this.allowRemoteConfig = sharedPreferences.getBoolean(ALLOW_REMOTE_CONFIG, this.allowRemoteConfig); 061 this.clickDelay = sharedPreferences.getInt(CLICK_DELAY, this.clickDelay); 062 this.simple = sharedPreferences.getBoolean(SIMPLE, this.simple); 063 this.railroadName = sharedPreferences.get(RAILROAD_NAME, this.railroadName); 064 this.readonlyPower = sharedPreferences.getBoolean(READONLY_POWER, this.readonlyPower); 065 this.refreshDelay = sharedPreferences.getInt(REFRESH_DELAY, this.refreshDelay); 066 this.useAjax = sharedPreferences.getBoolean(USE_AJAX, this.useAjax); 067 this.disableFrames = sharedPreferences.getBoolean(DISABLE_FRAME_SERVER, this.disableFrames); 068 this.redirectFramesToPanels = sharedPreferences.getBoolean(REDIRECT_FRAMES, this.redirectFramesToPanels); 069 try { 070 Preferences frames = sharedPreferences.node(DISALLOWED_FRAMES); 071 if (frames.keys().length != 0) { 072 this.disallowedFrames.clear(); 073 for (String key : frames.keys()) { // throws 074 // BackingStoreException 075 String frame = frames.get(key, null); 076 if (frame != null && !frame.trim().isEmpty()) { 077 this.disallowedFrames.add(frame); 078 } 079 } 080 } 081 } catch (BackingStoreException ex) { 082 // this is expected if sharedPreferences have not been written 083 // previously, so do nothing. 084 } 085 this.port = sharedPreferences.getInt(PORT, this.port); 086 this.useZeroConf = sharedPreferences.getBoolean(USE_ZERO_CONF, this.useZeroConf); 087 this.setIsDirty(false); 088 } 089 090 public void save() { 091 Preferences sharedPreferences = ProfileUtils.getPreferences(this.getProfile(), this.getClass(), true); 092 sharedPreferences.putInt(PORT, this.getPort()); 093 sharedPreferences.putBoolean(USE_ZERO_CONF, this.isUseZeroConf()); 094 sharedPreferences.putInt(CLICK_DELAY, this.getClickDelay()); 095 sharedPreferences.putInt(REFRESH_DELAY, this.getRefreshDelay()); 096 sharedPreferences.putBoolean(USE_AJAX, this.isUseAjax()); 097 sharedPreferences.putBoolean(SIMPLE, this.isSimple()); 098 sharedPreferences.putBoolean(ALLOW_REMOTE_CONFIG, this.allowRemoteConfig()); 099 sharedPreferences.putBoolean(READONLY_POWER, this.isReadonlyPower()); 100 sharedPreferences.put(RAILROAD_NAME, getRailroadName()); 101 sharedPreferences.putBoolean(DISABLE_FRAME_SERVER, this.isDisableFrames()); 102 sharedPreferences.putBoolean(REDIRECT_FRAMES, this.redirectFramesToPanels); 103 try { 104 Preferences node = sharedPreferences.node(DISALLOWED_FRAMES); 105 this.disallowedFrames.stream() 106 .forEach(frame -> node.put(Integer.toString(this.disallowedFrames.indexOf(frame)), frame)); 107 if (this.disallowedFrames.size() < node.keys().length) { 108 for (int i = node.keys().length - 1; i >= this.disallowedFrames.size(); i--) { 109 node.remove(Integer.toString(i)); 110 } 111 } 112 sharedPreferences.sync(); 113 setIsDirty(false); // Resets only when stored 114 } catch (BackingStoreException ex) { 115 log.error("Exception while saving web server preferences", ex); 116 } 117 } 118 119 public int getClickDelay() { 120 return clickDelay; 121 } 122 123 public void setClickDelay(int value) { 124 int old = this.clickDelay; 125 if (old != value) { 126 this.clickDelay = value; 127 this.firePropertyChange(CLICK_DELAY, old, value); 128 } 129 } 130 131 public int getRefreshDelay() { 132 return refreshDelay; 133 } 134 135 public void setRefreshDelay(int value) { 136 int old = this.refreshDelay; 137 if (old != value) { 138 this.refreshDelay = value; 139 this.firePropertyChange(REFRESH_DELAY, old, value); 140 } 141 } 142 143 public String[] getDisallowedFrames() { 144 return this.disallowedFrames.toArray(new String[this.disallowedFrames.size()]); 145 } 146 147 public boolean isUseAjax() { 148 return useAjax; 149 } 150 151 public void setUseAjax(boolean useAjax) { 152 boolean old = this.useAjax; 153 if (old != useAjax) { 154 this.useAjax = useAjax; 155 this.firePropertyChange(USE_AJAX, old, useAjax); 156 } 157 } 158 159 public boolean isSimple() { 160 return simple; 161 } 162 163 public void setSimple(boolean value) { 164 boolean old = this.simple; 165 if (old != value) { 166 this.simple = value; 167 this.firePropertyChange(SIMPLE, old, value); 168 } 169 } 170 171 public boolean isUseZeroConf() { 172 return useZeroConf; 173 } 174 175 public void setUseZeroConf(boolean value) { 176 boolean old = this.useZeroConf; 177 if (old != value) { 178 this.useZeroConf = value; 179 this.firePropertyChange(USE_ZERO_CONF, old, value); 180 } 181 } 182 183 public boolean allowRemoteConfig() { 184 return this.allowRemoteConfig; 185 } 186 187 public void setAllowRemoteConfig(boolean value) { 188 boolean old = this.allowRemoteConfig; 189 if (old != value) { 190 this.allowRemoteConfig = value; 191 this.firePropertyChange(ALLOW_REMOTE_CONFIG, old, value); 192 } 193 } 194 195 /** 196 * Can the power state be set from web clients? 197 * 198 * @return true if web clients are barred from setting power state; false if 199 * allowed 200 */ 201 public boolean isReadonlyPower() { 202 return readonlyPower; 203 } 204 205 /** 206 * Set if the power state can be set from web clients. 207 * 208 * @param readonlyPower true to bar setting power from web clients; false to 209 * allow 210 */ 211 public void setReadonlyPower(boolean readonlyPower) { 212 this.readonlyPower = readonlyPower; 213 } 214 215 public void setDisallowedFrames(String[] disallowedFrames) { 216 String[] old = this.getDisallowedFrames(); 217 if (!Arrays.equals(old, disallowedFrames)) { 218 this.disallowedFrames.clear(); 219 this.disallowedFrames.addAll(Arrays.asList(disallowedFrames)); 220 this.firePropertyChange(DISALLOWED_FRAMES, old, disallowedFrames); 221 } 222 } 223 224 public int getPort() { 225 return port; 226 } 227 228 public void setPort(int value) { 229 int old = this.port; 230 if (old != value) { 231 this.port = value; 232 this.firePropertyChange(PORT, old, value); 233 this.setRestartRequired(); 234 } 235 } 236 237 /** 238 * Get the name of the railroad. 239 * 240 * @return the railroad name 241 */ 242 public String getRailroadName() { 243 return railroadName; 244 } 245 246 /** 247 * Set the railroad name. 248 * 249 * @param railroadName the railroadName to set 250 */ 251 public void setRailroadName(String railroadName) { 252 String old = this.railroadName; 253 if ((old != null && !old.equals(railroadName)) || railroadName != null) { 254 if (railroadName != null) { 255 this.railroadName = railroadName; 256 } else { 257 this.railroadName = Bundle.getMessage(DEFAULT_RAILROAD_NAME); 258 } 259 this.firePropertyChange(RAILROAD_NAME, old, this.railroadName); 260 } 261 } 262 263 /** 264 * Test if the railroad name has been set by user. 265 * 266 * @return true if user has not set the railroad name. 267 */ 268 public boolean isDefaultRailroadName() { 269 return this.getRailroadName().equals(Bundle.getMessage(DEFAULT_RAILROAD_NAME)); 270 } 271 272 /** 273 * Get the default railroad name. This method exists solely to support unit 274 * testing. 275 * 276 * @return The default railroad name 277 */ 278 public String getDefaultRailroadName() { 279 return Bundle.getMessage(DEFAULT_RAILROAD_NAME); 280 } 281 282 /** 283 * @return true if displaying frames in web pages is disabled, false 284 * otherwise 285 */ 286 public boolean isDisableFrames() { 287 return disableFrames; 288 } 289 290 /** 291 * Set whether or not frames are returned when requests for frames are made 292 * from web pages. 293 * 294 * @param disableFrames true to prevent frames from being displayed in web 295 * pages 296 */ 297 public void setDisableFrames(boolean disableFrames) { 298 boolean old = this.disableFrames; 299 if (old != disableFrames) { 300 this.disableFrames = disableFrames; 301 this.firePropertyChange(DISABLE_FRAME_SERVER, old, disableFrames); 302 } 303 } 304 305 /** 306 * Are requests for frames redirected to panels when frames are disabled? 307 * 308 * @return true if frames should be redirected to panels, false otherwise 309 */ 310 public boolean isRedirectFramesToPanels() { 311 return redirectFramesToPanels; 312 } 313 314 /** 315 * Set whether or not requests for frames should be redirected to panels 316 * when frames are disabled. 317 * 318 * @param redirectFramesToPanels true if frames should be redirected to 319 * panels, false otherwise 320 */ 321 public void setRedirectFramesToPanels(boolean redirectFramesToPanels) { 322 boolean old = this.redirectFramesToPanels; 323 if (old != redirectFramesToPanels) { 324 this.redirectFramesToPanels = redirectFramesToPanels; 325 this.firePropertyChange(REDIRECT_FRAMES, old, this.redirectFramesToPanels); 326 } 327 } 328}