001package jmri.jmrit.roster; 002 003import java.beans.PropertyChangeEvent; 004import java.io.File; 005import java.io.FileNotFoundException; 006import java.util.HashMap; 007import java.util.Locale; 008import java.util.Set; 009import java.util.prefs.BackingStoreException; 010import java.util.prefs.Preferences; 011import javax.annotation.CheckForNull; 012import javax.annotation.Nonnull; 013import jmri.implementation.FileLocationsPreferences; 014import jmri.profile.Profile; 015import jmri.profile.ProfileManager; 016import jmri.profile.ProfileUtils; 017import jmri.spi.PreferencesManager; 018import jmri.util.FileUtil; 019import jmri.util.prefs.AbstractPreferencesManager; 020import jmri.util.prefs.InitializationException; 021import org.openide.util.lookup.ServiceProvider; 022import org.slf4j.Logger; 023import org.slf4j.LoggerFactory; 024 025/** 026 * Load and store the Roster configuration. 027 * 028 * This only configures the Roster when initialized so that configuration 029 * changes made by users do not affect the running instance of JMRI, but only 030 * take effect after restarting JMRI. 031 * 032 * @author Randall Wood (C) 2015 033 */ 034@ServiceProvider(service = PreferencesManager.class) 035public class RosterConfigManager extends AbstractPreferencesManager { 036 037 private final HashMap<Profile, String> directories = new HashMap<>(); 038 private final HashMap<Profile, String> defaultOwners = new HashMap<>(); 039 private final HashMap<Profile, Roster> rosters = new HashMap<>(); 040 041 public static final String DIRECTORY = "directory"; 042 public static final String DEFAULT_OWNER = "defaultOwner"; 043 private static final Logger log = LoggerFactory.getLogger(RosterConfigManager.class); 044 045 public RosterConfigManager() { 046 log.debug("Roster is {}", this.directories); 047 FileUtil.getDefault().addPropertyChangeListener(FileUtil.PREFERENCES, (PropertyChangeEvent evt) -> { 048 FileUtil.Property oldValue = (FileUtil.Property) evt.getOldValue(); 049 FileUtil.Property newValue = (FileUtil.Property) evt.getNewValue(); 050 Profile project = oldValue.getKey(); 051 log.debug("UserFiles changed from {} to {}", evt.getOldValue(), evt.getNewValue()); 052 if (RosterConfigManager.this.getDirectory(project).equals(oldValue.getValue())) { 053 RosterConfigManager.this.setDirectory(project, newValue.getValue()); 054 } 055 }); 056 } 057 058 @Override 059 public void initialize(Profile profile) throws InitializationException { 060 if (!this.isInitialized(profile)) { 061 Preferences preferences = ProfileUtils.getPreferences(profile, this.getClass(), true); 062 this.setDefaultOwner(profile, preferences.get(DEFAULT_OWNER, this.getDefaultOwner(profile))); 063 try { 064 this.setDirectory(profile, preferences.get(DIRECTORY, this.getDirectory())); 065 } catch (IllegalArgumentException ex) { 066 this.setInitialized(profile, true); 067 throw new InitializationException( 068 Bundle.getMessage(Locale.ENGLISH, "IllegalRosterLocation", preferences.get(DIRECTORY, this.getDirectory())), 069 ex.getMessage(), 070 ex); 071 } 072 getRoster(profile).setRosterLocation(this.getDirectory()); 073 this.setInitialized(profile, true); 074 } 075 } 076 077 @Override 078 public void savePreferences(Profile profile) { 079 Preferences preferences = ProfileUtils.getPreferences(profile, this.getClass(), true); 080 preferences.put(DIRECTORY, FileUtil.getPortableFilename(this.getDirectory())); 081 preferences.put(DEFAULT_OWNER, this.getDefaultOwner(profile)); 082 try { 083 preferences.sync(); 084 } catch (BackingStoreException ex) { 085 log.error("Unable to save preferences", ex); 086 } 087 } 088 089 @Override 090 @Nonnull 091 public Set<Class<? extends PreferencesManager>> getRequires() { 092 Set<Class<? extends PreferencesManager>> requires = super.getRequires(); 093 requires.add(FileLocationsPreferences.class); 094 return requires; 095 } 096 097 /** 098 * Get the default owner for the active profile. 099 * 100 * @return the default owner 101 */ 102 @Nonnull 103 public String getDefaultOwner() { 104 return getDefaultOwner(ProfileManager.getDefault().getActiveProfile()); 105 } 106 107 /** 108 * Get the default owner for the specified profile. 109 * 110 * @param profile the profile to get the default owner for 111 * @return the default owner 112 */ 113 @Nonnull 114 public String getDefaultOwner(@CheckForNull Profile profile) { 115 String owner = defaultOwners.get(profile); 116 // defaultOwner should never be null, but check anyway to ensure its not 117 if (owner == null) { 118 owner = ""; // NOI18N 119 defaultOwners.put(profile, owner); 120 } 121 return owner; 122 } 123 124 /** 125 * Set the default owner for the specified profile. 126 * 127 * @param profile the profile to set the default owner for 128 * @param defaultOwner the default owner to set 129 */ 130 public void setDefaultOwner(@CheckForNull Profile profile, @CheckForNull String defaultOwner) { 131 if (defaultOwner == null) { 132 defaultOwner = ""; 133 } 134 String oldDefaultOwner = this.defaultOwners.get(profile); 135 this.defaultOwners.put(profile, defaultOwner); 136 firePropertyChange(DEFAULT_OWNER, oldDefaultOwner, defaultOwner); 137 } 138 139 /** 140 * Get the roster directory for the active profile. 141 * 142 * @return the directory 143 */ 144 @Nonnull 145 public String getDirectory() { 146 return getDirectory(ProfileManager.getDefault().getActiveProfile()); 147 } 148 149 /** 150 * Get the roster directory for the specified profile. 151 * 152 * @param profile the profile to get the directory for 153 * @return the directory 154 */ 155 @Nonnull 156 public String getDirectory(@CheckForNull Profile profile) { 157 String directory = directories.get(profile); 158 if (directory == null) { 159 directory = FileUtil.PREFERENCES; 160 } 161 if (FileUtil.PREFERENCES.equals(directory)) { 162 return FileUtil.getUserFilesPath(); 163 } 164 return directory; 165 } 166 167 /** 168 * Set the roster directory for the specified profile. 169 * 170 * @param profile the profile to set the directory for 171 * @param directory the directory to set 172 */ 173 public void setDirectory(@CheckForNull Profile profile, @CheckForNull String directory) { 174 if (directory == null || directory.isEmpty()) { 175 directory = FileUtil.PREFERENCES; 176 } 177 String oldDirectory = this.directories.get(profile); 178 try { 179 if (!FileUtil.getFile(directory).isDirectory()) { 180 throw new IllegalArgumentException(Bundle.getMessage("IllegalRosterLocation", directory)); // NOI18N 181 } 182 } catch (FileNotFoundException ex) { // thrown by getFile() if directory does not exist 183 throw new IllegalArgumentException(Bundle.getMessage("IllegalRosterLocation", directory)); // NOI18N 184 } 185 if (!directory.equals(FileUtil.PREFERENCES)) { 186 directory = FileUtil.getAbsoluteFilename(directory); 187 if (!directory.endsWith(File.separator)) { 188 directory = directory + File.separator; 189 } 190 } 191 this.directories.put(profile, directory); 192 log.debug("Roster changed from {} to {}", oldDirectory, this.directories); 193 firePropertyChange(DIRECTORY, oldDirectory, directory); 194 } 195 196 /** 197 * Get the roster for the profile. 198 * 199 * @param profile the profile to get the roster for 200 * @return the roster for the profile 201 */ 202 @Nonnull 203 public Roster getRoster(@CheckForNull Profile profile) { 204 Roster roster = rosters.get(profile); 205 if (roster == null) { 206 roster = new Roster(); 207 rosters.put(profile, roster); 208 } 209 return roster; 210 } 211 212 /** 213 * Set the roster for the profile. 214 * 215 * @param profile the profile to set the roster for 216 * @param roster the roster for the profile 217 * @return the roster just set, so this method can be used in a chain 218 */ 219 @Nonnull 220 public Roster setRoster(@CheckForNull Profile profile, @Nonnull Roster roster) { 221 rosters.put(profile, roster); 222 return getRoster(profile); 223 } 224}