Skip to content
Permalink
Browse files

fix: Exporting a profile no longer throws an NPE

Exporting a Profile no longer throws an NPE, although some older Profiles, never used with JMRI 4.12 or newer, may not export correctly.

This is involved because the way this was fixed was not to re-implement how Profiles are read, but to rely on the multi-profile design of the PreferencesManager to allow preferences from any Profile to be loaded. That decision led to fixing two PrefencesManager implementations to be multi-profile, which led to making FileUtil multi-profile capable.
  • Loading branch information...
rhwood committed Aug 6, 2019
1 parent 19efcff commit 87e18dc499e14da3b50a3e303b140b421a8a0331
@@ -129,11 +129,11 @@ public String getPreferencesTooltip() {
@Override
public void savePreferences() {
if (!FileUtil.getUserFilesPath().equals(this.userLocation.getText())) {
FileUtil.setUserFilesPath(this.userLocation.getText());
FileUtil.setUserFilesPath(ProfileManager.getDefault().getActiveProfile(), this.userLocation.getText());
this.restartRequired = true;
}
if (!FileUtil.getScriptsPath().equals(this.scriptLocation.getText())) {
FileUtil.setScriptsPath(this.scriptLocation.getText());
FileUtil.setScriptsPath(ProfileManager.getDefault().getActiveProfile(), this.scriptLocation.getText());
this.restartRequired = true;
}
Profile profile = ProfileManager.getDefault().getActiveProfile();
@@ -3,6 +3,7 @@
import apps.FileLocationPane;
import java.util.List;
import jmri.ConfigureManager;
import jmri.profile.ProfileManager;
import jmri.util.FileUtil;
import org.jdom2.Element;
import org.slf4j.Logger;
@@ -59,11 +60,11 @@ public boolean load(Element shared, Element perNode) {
FileUtil.setUserFilesPath(userLocation.getValue());*/
String value = loadUserLocations(shared, "defaultUserLocation");
if (value != null) {
FileUtil.setUserFilesPath(value);
FileUtil.setUserFilesPath(ProfileManager.getDefault().getActiveProfile(), value);
}
value = loadUserLocations(shared, "defaultScriptLocation");
if (value != null) {
FileUtil.setScriptsPath(value);
FileUtil.setScriptsPath(ProfileManager.getDefault().getActiveProfile(), value);
}
ConfigureManager cm = jmri.InstanceManager.getNullableDefault(jmri.ConfigureManager.class);
if (cm != null) {
@@ -286,7 +286,7 @@ public void run() {
}
}
Profile project = ProfileManager.getDefault().getActiveProfile();
InstanceManager.getDefault(RosterConfigManager.class).setDefaultOwner(owner.getText());
InstanceManager.getDefault(RosterConfigManager.class).setDefaultOwner(project, owner.getText());
InstanceManager.getDefault(GuiLafPreferencesManager.class).setLocale(Locale.getDefault());
InstanceManager.getDefault(RosterConfigManager.class).savePreferences(project);
InstanceManager.getDefault(GuiLafPreferencesManager.class).savePreferences(project);
@@ -32,33 +32,33 @@ public void initialize(Profile profile) throws InitializationException {
if (!userFiles.startsWith(FileUtil.PROFILE)) {
userFiles = perNode.get(USER_FILES, userFiles);
}
FileUtil.setUserFilesPath(FileUtil.getAbsoluteFilename(userFiles));
FileUtil.setUserFilesPath(profile, FileUtil.getAbsoluteFilename(profile, userFiles));
String scripts = shared.get(SCRIPTS, FileUtil.PROFILE);
if (!scripts.startsWith(FileUtil.PROFILE) && !scripts.startsWith(FileUtil.PROGRAM)) {
scripts = perNode.get(SCRIPTS, scripts);
}
FileUtil.setScriptsPath(FileUtil.getAbsoluteFilename(scripts));
FileUtil.setScriptsPath(profile, FileUtil.getAbsoluteFilename(profile, scripts));
this.setInitialized(profile, true);
try {
if (!FileUtil.getFile(userFiles).isDirectory()) {
if (!FileUtil.getFile(profile, userFiles).isDirectory()) {
String message = "UserFilesIsNotDir"; // NOI18N
userFiles = FileUtil.getAbsoluteFilename(userFiles);
userFiles = FileUtil.getAbsoluteFilename(profile, userFiles);
throw new InitializationException(Bundle.getMessage(Locale.ENGLISH, message, userFiles), Bundle.getMessage(message, userFiles));
}
} catch (FileNotFoundException ex) {
String message = "UserFilesDoesNotExist"; // NOI18N
userFiles = FileUtil.getAbsoluteFilename(userFiles);
userFiles = FileUtil.getAbsoluteFilename(profile, userFiles);
throw new InitializationException(Bundle.getMessage(Locale.ENGLISH, message, userFiles), Bundle.getMessage(message, userFiles));
}
try {
if (!FileUtil.getFile(scripts).isDirectory()) {
if (!FileUtil.getFile(profile, scripts).isDirectory()) {
String message = "ScriptsIsNotDir"; // NOI18N
scripts = FileUtil.getAbsoluteFilename(scripts);
scripts = FileUtil.getAbsoluteFilename(profile, scripts);
throw new InitializationException(Bundle.getMessage(Locale.ENGLISH, message, scripts), Bundle.getMessage(message, scripts));
}
} catch (FileNotFoundException ex) {
String message = "ScriptsDoesNotExist"; // NOI18N
scripts = FileUtil.getAbsoluteFilename(scripts);
scripts = FileUtil.getAbsoluteFilename(profile, scripts);
throw new InitializationException(Bundle.getMessage(Locale.ENGLISH, message, scripts), Bundle.getMessage(message, scripts));
}
}
@@ -73,10 +73,10 @@ public void initialize(Profile profile) throws InitializationException {
public void savePreferences(Profile profile) {
Preferences shared = ProfileUtils.getPreferences(profile, this.getClass(), true);
Preferences perNode = ProfileUtils.getPreferences(profile, this.getClass(), false);
shared.put(USER_FILES, FileUtil.getPortableFilename(FileUtil.getUserFilesPath(), true, false));
shared.put(SCRIPTS, FileUtil.getPortableFilename(FileUtil.getScriptsPath()));
perNode.put(USER_FILES, FileUtil.getPortableFilename(FileUtil.getUserFilesPath(), true, false));
perNode.put(SCRIPTS, FileUtil.getPortableFilename(FileUtil.getScriptsPath()));
shared.put(USER_FILES, FileUtil.getPortableFilename(profile, FileUtil.getUserFilesPath(profile), true, false));
shared.put(SCRIPTS, FileUtil.getPortableFilename(profile, FileUtil.getScriptsPath(profile)));
perNode.put(USER_FILES, FileUtil.getPortableFilename(profile, FileUtil.getUserFilesPath(profile), true, false));
perNode.put(SCRIPTS, FileUtil.getPortableFilename(profile, FileUtil.getScriptsPath(profile)));
}

}
@@ -13,6 +13,8 @@
import java.util.Locale;
import java.util.Set;
import java.util.TreeSet;

import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import javax.swing.JOptionPane;
import jmri.InstanceManager;
@@ -22,6 +24,8 @@
import jmri.jmrit.roster.rostergroup.RosterGroup;
import jmri.jmrit.roster.rostergroup.RosterGroupSelector;
import jmri.jmrit.symbolicprog.SymbolicProgBundle;
import jmri.profile.Profile;
import jmri.profile.ProfileManager;
import jmri.util.FileUtil;
import jmri.util.FileUtilSupport;
import org.jdom2.Document;
@@ -179,16 +183,22 @@ public Roster(String rosterFilename) {
}

/**
* Get the default Roster instance, creating it as required.
* Get the roster for the profile returned by {@link ProfileManager#getActiveProfile()}.
*
* @return The default Roster object
* @return the roster for the active profile
*/
public static synchronized Roster getDefault() {
return InstanceManager.getOptionalDefault(Roster.class).orElseGet(() -> {
log.debug("Creating Roster default instance.");
// Pass null to use defaults.
return InstanceManager.setDefault(Roster.class, new Roster(null));
});
return getRoster(ProfileManager.getDefault().getActiveProfile());
}

/**
* Get the roster for the specified profile.
*
* @param profile the Profile to get the roster for
* @return the roster for the profile
*/
public static synchronized @Nonnull Roster getRoster(@CheckForNull Profile profile) {
return InstanceManager.getDefault(RosterConfigManager.class).getRoster(profile);
}

/**
@@ -618,12 +628,13 @@ public boolean checkEntry(RosterEntry r, String roadName, String roadNumber, Str
* to perform the actual work.
*
* @param name Filename for new file, including path info as needed.
* @throws java.io.FileNotFoundException if file does not exist
* @throws java.io.IOException if unable to write file
*/
void writeFile(String name) throws java.io.FileNotFoundException, java.io.IOException {
if (log.isDebugEnabled()) {
log.debug("writeFile " + name);
}
// This is taken in large part from "Java and XML" page 368
File file = findFile(name);
if (file == null) {
file = new File(name);
@@ -637,7 +648,8 @@ void writeFile(String name) throws java.io.FileNotFoundException, java.io.IOExce
* has to be done separately. See writeRosterFile() for a public function
* that finds the default location, does a backup and then calls this.
*
* @param file an op
* @param file the file to write to
* @throws java.io.IOException if unable to write file
*/
void writeFile(File file) throws java.io.IOException {
// create root element
@@ -805,6 +817,8 @@ static public String makeValidFilename(String entry) {
* Note that this does not clear any existing entries.
*
* @param name filename of roster file
* @throws org.jdom2.JDOMException if file is invalid XML
* @throws java.io.IOException if unable to read file
*/
void readFile(String name) throws org.jdom2.JDOMException, java.io.IOException {
// roster exists?
@@ -1269,7 +1283,9 @@ public void setDefaultRosterGroup(String defaultRosterGroup) {

/**
* Get an array of all the RosterEntry-containing files in the target
* directory
* directory.
*
* @return the list of file names for entries in this roster
*/
static String[] getAllFileNames() {
// ensure preferences will be found for read
@@ -3,13 +3,17 @@
import java.beans.PropertyChangeEvent;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.HashMap;
import java.util.Locale;
import java.util.Set;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;

import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import jmri.implementation.FileLocationsPreferences;
import jmri.profile.Profile;
import jmri.profile.ProfileManager;
import jmri.profile.ProfileUtils;
import jmri.spi.PreferencesManager;
import jmri.util.FileUtil;
@@ -32,8 +36,9 @@
@ServiceProvider(service = PreferencesManager.class)
public class RosterConfigManager extends AbstractPreferencesManager {

private String directory = FileUtil.PREFERENCES;
private String defaultOwner = "";
private final HashMap<Profile, String> directory = new HashMap<>();
private final HashMap<Profile, String> defaultOwner = new HashMap<>();
private final HashMap<Profile, Roster> rosters = new HashMap<>();

public static final String DIRECTORY = "directory";
public static final String DEFAULT_OWNER = "defaultOwner";
@@ -43,8 +48,9 @@ public RosterConfigManager() {
log.debug("Roster is {}", this.directory);
FileUtilSupport.getDefault().addPropertyChangeListener(FileUtil.PREFERENCES, (PropertyChangeEvent evt) -> {
log.debug("UserFiles changed from {} to {}", evt.getOldValue(), evt.getNewValue());
if (RosterConfigManager.this.getDirectory().equals(evt.getOldValue())) {
RosterConfigManager.this.setDirectory(FileUtil.PREFERENCES);
Profile project = ProfileManager.getDefault().getActiveProfile();
if (RosterConfigManager.this.getDirectory(project).equals(evt.getOldValue())) {
RosterConfigManager.this.setDirectory(project, FileUtil.PREFERENCES);
}
});
}
@@ -53,17 +59,17 @@ public RosterConfigManager() {
public void initialize(Profile profile) throws InitializationException {
if (!this.isInitialized(profile)) {
Preferences preferences = ProfileUtils.getPreferences(profile, this.getClass(), true);
this.setDefaultOwner(preferences.get(DEFAULT_OWNER, this.getDefaultOwner()));
this.setDefaultOwner(profile, preferences.get(DEFAULT_OWNER, this.getDefaultOwner(profile)));
try {
this.setDirectory(preferences.get(DIRECTORY, this.getDirectory()));
this.setDirectory(profile, preferences.get(DIRECTORY, this.getDirectory()));
} catch (IllegalArgumentException ex) {
this.setInitialized(profile, true);
throw new InitializationException(
Bundle.getMessage(Locale.ENGLISH, "IllegalRosterLocation", preferences.get(DIRECTORY, this.getDirectory())),
ex.getMessage(),
ex);
}
Roster.getDefault().setRosterLocation(this.getDirectory());
getRoster(profile).setRosterLocation(this.getDirectory());
this.setInitialized(profile, true);
}
}
@@ -72,7 +78,7 @@ public void initialize(Profile profile) throws InitializationException {
public void savePreferences(Profile profile) {
Preferences preferences = ProfileUtils.getPreferences(profile, this.getClass(), true);
preferences.put(DIRECTORY, FileUtil.getPortableFilename(this.getDirectory()));
preferences.put(DEFAULT_OWNER, this.getDefaultOwner());
preferences.put(DEFAULT_OWNER, this.getDefaultOwner(profile));
try {
preferences.sync();
} catch (BackingStoreException ex) {
@@ -88,47 +94,86 @@ public void savePreferences(Profile profile) {
}

/**
* @return the defaultOwner
* Get the default owner for the active profile.
*
* @return the default owner
*/
@Nonnull
public String getDefaultOwner() {
return getDefaultOwner(ProfileManager.getDefault().getActiveProfile());
}

/**
* Get the default owner for the specified profile.
*
* @param profile the profile to get the default owner for
* @return the default owner
*/
@Nonnull public
String getDefaultOwner() {
@Nonnull
public String getDefaultOwner(@CheckForNull Profile profile) {
String owner = defaultOwner.get(profile);
// defaultOwner should never be null, but check anyway to ensure its not
if (defaultOwner == null) {
defaultOwner = "";
if (owner == null) {
owner = ""; // NOI18N
defaultOwner.put(profile, owner);
}
return defaultOwner;
return owner;
}

/**
* @param defaultOwner the defaultOwner to set
* Set the default owner for the specified profile.
*
* @param profile the profile to set the default owner for
* @param defaultOwner the default owner to set
*/
public void setDefaultOwner(String defaultOwner) {
public void setDefaultOwner(@CheckForNull Profile profile, @CheckForNull String defaultOwner) {
if (defaultOwner == null) {
defaultOwner = "";
}
String oldDefaultOwner = this.defaultOwner;
this.defaultOwner = defaultOwner;
String oldDefaultOwner = this.defaultOwner.get(profile);
this.defaultOwner.put(profile, defaultOwner);
firePropertyChange(DEFAULT_OWNER, oldDefaultOwner, defaultOwner);
}

/**
* Get the roster directory for the active profile.
*
* @return the directory
*/
@Nonnull
public String getDirectory() {
if (FileUtil.PREFERENCES.equals(this.directory)) {
return getDirectory(ProfileManager.getDefault().getActiveProfile());
}

/**
* Get the roster directory for the specified profile.
*
* @param profile the profile to get the directory for
* @return the directory
*/
@Nonnull
public String getDirectory(@CheckForNull Profile profile) {
String directory = this.directory.get(profile);
if (directory == null) {
directory = FileUtil.PREFERENCES;
}
if (FileUtil.PREFERENCES.equals(directory)) {
return FileUtil.getUserFilesPath();
}
return this.directory;
return directory;
}

/**
* Set the roster directory for the specified profile.
*
* @param profile the profile to set the directory for
* @param directory the directory to set
*/
public void setDirectory(String directory) {
public void setDirectory(@CheckForNull Profile profile, @CheckForNull String directory) {
if (directory == null || directory.isEmpty()) {
directory = FileUtil.PREFERENCES;
}
String oldDirectory = this.directory;
String oldDirectory = this.directory.get(profile);
try {
if (!FileUtil.getFile(directory).isDirectory()) {
throw new IllegalArgumentException(Bundle.getMessage("IllegalRosterLocation", directory)); // NOI18N
@@ -142,9 +187,25 @@ public void setDirectory(String directory) {
directory = directory + File.separator;
}
}
this.directory = directory;
this.directory.put(profile, directory);
log.debug("Roster changed from {} to {}", oldDirectory, this.directory);
firePropertyChange(DIRECTORY, oldDirectory, directory);
}

/**
* Get the roster for the profile.
*
* @param profile the profile to get the roster for
* @return the roster for the profile
*/
@Nonnull
public Roster getRoster(@CheckForNull Profile profile) {
Roster roster = rosters.get(profile);
if (roster == null) {
roster = new Roster();
rosters.put(profile, roster);
}
return roster;
}

}

0 comments on commit 87e18dc

Please sign in to comment.
You can’t perform that action at this time.