Class Roster

  • All Implemented Interfaces:
    java.beans.PropertyChangeListener, java.util.EventListener, PropertyChangeProvider, RosterGroupSelector

    public class Roster
    extends XmlFile
    implements RosterGroupSelector, PropertyChangeProvider, java.beans.PropertyChangeListener
    Roster manages and manipulates a roster of locomotives.

    It works with the "roster-config" XML schema to load and store its information.

    This is an in-memory representation of the roster xml file (see below for constants defining name and location). As such, this class is also responsible for the "dirty bit" handling to ensure it gets written. As a temporary reliability enhancement, all changes to this structure are now being written to a backup file, and a copy is made when the file is opened.

    Multiple Roster objects don't make sense, so we use an "instance" member to navigate to a single one.

    The only bound property is the list of RosterEntrys; a PropertyChangedEvent is fired every time that changes.

    The entries are stored in an ArrayList, sorted alphabetically. That sort is done manually each time an entry is added.

    The roster is stored in a "Roster Index", which can be read or written. Each individual entry (once stored) contains a filename which can be used to retrieve the locomotive information for that roster entry. Note that the RosterEntry information is duplicated in both the Roster (stored in the roster.xml file) and in the specific file for the entry.

    Originally, JMRI managed just one global roster, held in a global Roster object. With the rise of more complicated layouts, code has been added to address multiple rosters, with the primary one now held in Roster.default(). We're moving references to Roster.default() out to the using code, so that eventually we can make those explicit references to other Roster objects as/when needed.

    See Also:
    RosterEntry
    • Constructor Detail

      • Roster

        public Roster()
        Create a roster with default contents.
      • Roster

        public Roster​(java.lang.String rosterFilename)
    • Method Detail

      • getRoster

        @Nonnull
        public static Roster getRoster​(@CheckForNull
                                       Profile profile)
        Get the roster for the specified profile.
        Parameters:
        profile - the Profile to get the roster for
        Returns:
        the roster for the profile
      • addEntry

        public void addEntry​(RosterEntry e)
        Add a RosterEntry object to the in-memory Roster. This method notifies the UI of changes so should not be used when adding or reloading many roster entries at once.
        Parameters:
        e - Entry to add
      • removeEntry

        public void removeEntry​(RosterEntry e)
        Remove a RosterEntry object from the in-memory Roster. This does not delete the file for the RosterEntry!
        Parameters:
        e - Entry to remove
      • numEntries

        public int numEntries()
        Returns:
        number of entries in the roster
      • numGroupEntries

        public int numGroupEntries​(java.lang.String group)
        Parameters:
        group - The group being queried or null for all entries in the roster.
        Returns:
        The Number of roster entries in the specified group or 0 if the group does not exist.
      • entryFromTitle

        public RosterEntry entryFromTitle​(java.lang.String title)
        Return RosterEntry from a "title" string, ala selection in matchingComboBox.
        Parameters:
        title - The title for the RosterEntry.
        Returns:
        The matching RosterEntry or null
      • getEntryForId

        public RosterEntry getEntryForId​(java.lang.String id)
        Return RosterEntry from a "id" string.
        Parameters:
        id - The id for the RosterEntry.
        Returns:
        The matching RosterEntry or null
      • getEntriesByDccAddress

        @Nonnull
        public java.util.List<RosterEntrygetEntriesByDccAddress​(java.lang.String a)
        Return a list of RosterEntry which have a particular DCC address.
        Parameters:
        a - The address.
        Returns:
        a List of matching entries, empty if there are not matches.
      • getEntry

        @Nonnull
        public RosterEntry getEntry​(int i)
        Return a specific entry by index
        Parameters:
        i - The RosterEntry at position i in the roster.
        Returns:
        The matching RosterEntry
      • getAllEntries

        @Nonnull
        public java.util.List<RosterEntrygetAllEntries()
        Get all roster entries.
        Returns:
        a list of roster entries; the list is empty if the roster is empty
      • getGroupEntry

        public RosterEntry getGroupEntry​(java.lang.String group,
                                         int i)
        Get the Nth RosterEntry in the group
        Parameters:
        group - The group being queried.
        i - The index within the group of the requested entry.
        Returns:
        The specified entry in the group or null if i is larger than the group, or the group does not exist.
      • fileFromTitle

        public java.lang.String fileFromTitle​(java.lang.String title)
        Return filename from a "title" string, ala selection in matchingComboBox.
        Parameters:
        title - The title for the entry.
        Returns:
        The filename for the RosterEntry matching title, or null if no such RosterEntry exists.
      • getEntriesMatchingCriteria

        @Nonnull
        public java.util.List<RosterEntrygetEntriesMatchingCriteria​(java.lang.String roadName,
                                                                      java.lang.String roadNumber,
                                                                      java.lang.String dccAddress,
                                                                      java.lang.String mfg,
                                                                      java.lang.String decoderModel,
                                                                      java.lang.String decoderFamily,
                                                                      java.lang.String id,
                                                                      java.lang.String group,
                                                                      java.lang.String developerID,
                                                                      java.lang.String manufacturerID,
                                                                      java.lang.String productID)
        Get a List of RosterEntry objects in Roster matching some information. The list will be empty if there are no matches.
        Parameters:
        roadName - road name of entry or null for any road name
        roadNumber - road number of entry of null for any number
        dccAddress - address of entry or null for any address
        mfg - manufacturer of entry or null for any manufacturer
        decoderModel - decoder model of entry or null for any model
        decoderFamily - decoder family of entry or null for any family
        id - id of entry or null for any id
        group - group entry is member of or null for any group
        developerID - developerID of entry, or null for any developerID
        manufacturerID - manufacturerID of entry, or null for any manufacturerID
        productID - productID of entry, or null for any productID
        Returns:
        List of matching RosterEntries or an empty List
      • getEntriesMatchingCriteria

        @Nonnull
        public java.util.List<RosterEntrygetEntriesMatchingCriteria​(java.lang.String roadName,
                                                                      java.lang.String roadNumber,
                                                                      java.lang.String dccAddress,
                                                                      java.lang.String mfg,
                                                                      java.lang.String decoderModel,
                                                                      java.lang.String decoderFamily,
                                                                      java.lang.String id,
                                                                      java.lang.String group)
        Get a List of RosterEntry objects in Roster matching some information. The list will be empty if there are no matches.
        Parameters:
        roadName - road name of entry or null for any road name
        roadNumber - road number of entry of null for any number
        dccAddress - address of entry or null for any address
        mfg - manufacturer of entry or null for any manufacturer
        decoderModel - decoder model of entry or null for any model
        decoderFamily - decoder family of entry or null for any family
        id - id of entry or null for any id
        group - group entry is member of or null for any group
        Returns:
        List of matching RosterEntries or an empty List
      • checkEntry

        public boolean checkEntry​(int i,
                                  java.lang.String roadName,
                                  java.lang.String roadNumber,
                                  java.lang.String dccAddress,
                                  java.lang.String mfg,
                                  java.lang.String decoderModel,
                                  java.lang.String decoderFamily,
                                  java.lang.String id,
                                  java.lang.String group)
        Check if an entry is consistent with specific properties.

        A null String argument always matches. Strings are used for convenience in GUI building.

        Parameters:
        i - index in the roster for the RosterEntry
        roadName - road name of entry or null for any road name
        roadNumber - road number of entry of null for any number
        dccAddress - address of entry or null for any address
        mfg - manufacturer of entry or null for any manufacturer
        decoderModel - decoder model of entry or null for any model
        decoderFamily - decoder family of entry or null for any family
        id - id of entry or null for any id
        group - group entry is member of or null for any group
        Returns:
        true if the entry matches
      • checkEntry

        public boolean checkEntry​(java.util.List<RosterEntry> list,
                                  int i,
                                  java.lang.String roadName,
                                  java.lang.String roadNumber,
                                  java.lang.String dccAddress,
                                  java.lang.String mfg,
                                  java.lang.String decoderModel,
                                  java.lang.String decoderFamily,
                                  java.lang.String id,
                                  java.lang.String group)
        Check if an entry is consistent with specific properties.

        A null String argument always matches. Strings are used for convenience in GUI building.

        Parameters:
        list - the list of RosterEntrys being searched
        i - the index of the roster entry in the list
        roadName - road name of entry or null for any road name
        roadNumber - road number of entry of null for any number
        dccAddress - address of entry or null for any address
        mfg - manufacturer of entry or null for any manufacturer
        decoderModel - decoder model of entry or null for any model
        decoderFamily - decoder family of entry or null for any family
        id - id of entry or null for any id
        group - group entry is member of or null for any group
        Returns:
        True if the entry matches
      • checkEntry

        public boolean checkEntry​(RosterEntry r,
                                  java.lang.String roadName,
                                  java.lang.String roadNumber,
                                  java.lang.String dccAddress,
                                  java.lang.String mfg,
                                  java.lang.String decoderModel,
                                  java.lang.String decoderFamily,
                                  java.lang.String id,
                                  java.lang.String group,
                                  java.lang.String developerID,
                                  java.lang.String manufacturerID,
                                  java.lang.String productID)
        Check if an entry is consistent with specific properties.

        A null String argument always matches. Strings are used for convenience in GUI building.

        Parameters:
        r - the roster entry being checked
        roadName - road name of entry or null for any road name
        roadNumber - road number of entry of null for any number
        dccAddress - address of entry or null for any address
        mfg - manufacturer of entry or null for any manufacturer
        decoderModel - decoder model of entry or null for any model
        decoderFamily - decoder family of entry or null for any family
        id - id of entry or null for any id
        group - group entry is member of or null for any group
        developerID - developerID of entry, or null for any developerID
        manufacturerID - manufacturerID of entry, or null for any manufacturerID
        productID - productID of entry, or null for any productID
        Returns:
        True if the entry matches
      • writeFile

        void writeFile​(java.lang.String name)
                throws java.io.FileNotFoundException,
                       java.io.IOException
        Write the entire roster to a file.

        Creates a new file with the given name, and then calls writeFile (File) to perform the actual work.

        Parameters:
        name - Filename for new file, including path info as needed.
        Throws:
        java.io.FileNotFoundException - if file does not exist
        java.io.IOException - if unable to write file
      • writeFile

        void writeFile​(java.io.File file)
                throws java.io.IOException
        Write the entire roster to a file object. This does not do backup; that has to be done separately. See writeRosterFile() for a public function that finds the default location, does a backup and then calls this.
        Parameters:
        file - the file to write to
        Throws:
        java.io.IOException - if unable to write file
      • makeValidFilename

        public static java.lang.String makeValidFilename​(java.lang.String entry)
        Name a valid roster entry filename from an entry name.
        • Replaces all problematic characters with "_".
        • Append .xml suffix
        Does not check for duplicates.
        Parameters:
        entry - the getId() entry name from the RosterEntry
        Returns:
        Filename for RosterEntry
        Throws:
        java.lang.IllegalArgumentException - if called with null or empty entry name
        Since:
        2.1.5
        See Also:
        RosterEntry.ensureFilenameExists()
      • readFile

        void readFile​(java.lang.String name)
               throws JDOMException,
                      java.io.IOException
        Read the contents of a roster XML file into this object.

        Note that this does not clear any existing entries.

        Parameters:
        name - filename of roster file
        Throws:
        JDOMException - if file is invalid XML
        java.io.IOException - if unable to read file
      • setDirty

        void setDirty​(boolean b)
      • writeRoster

        public void writeRoster()
        Store the roster in the default place, including making a backup if needed.

        Uses writeFile(String), a protected method that can write to a specific location.

      • reindex

        public void reindex()
        Rebuild the Roster index and store it.
      • reloadRosterFile

        public void reloadRosterFile()
        Update the in-memory Roster to be consistent with the current roster file. This removes any existing roster entries!
      • setRosterLocation

        public void setRosterLocation​(java.lang.String f)
        Set the default location for the Roster file, and all individual locomotive files.
        Parameters:
        f - Absolute pathname to use. A null or "" argument flags a return to the original default in the user's files directory. This parameter must be a potentially valid path on the system.
      • firePropertyChange

        protected void firePropertyChange​(java.lang.String p,
                                          java.lang.Object old,
                                          java.lang.Object n)
      • entryIdChanged

        public void entryIdChanged​(RosterEntry r)
        Notify that the ID of an entry has changed. This doesn't actually change the roster contents, but triggers a reordering of the roster contents.
        Parameters:
        r - the entry with a changed Id
      • getRosterGroupName

        public static java.lang.String getRosterGroupName​(java.lang.String rosterGroup)
      • getRosterGroupProperty

        public static java.lang.String getRosterGroupProperty​(java.lang.String name)
        Get the string for a RosterGroup property in a RosterEntry
        Parameters:
        name - The name of the rosterGroup
        Returns:
        The full property string
      • addRosterGroup

        public void addRosterGroup​(RosterGroup rg)
        Add a roster group, notifying all listeners of the change.

        This method fires the property change notification "RosterGroupAdded".

        Parameters:
        rg - The group to be added
      • addRosterGroups

        public void addRosterGroups​(java.util.List<RosterGroup> groups)
        Add a list of RosterGroup. RosterGroups that are already known to the Roster are ignored.
        Parameters:
        groups - RosterGroups to add to the roster. RosterGroups already in the roster will not be added again.
      • delRosterGroupList

        public void delRosterGroupList​(java.lang.String rg)
        Delete a roster group, notifying all listeners of the change.

        This method fires the property change notification ""RosterGroupRemoved"".

        Parameters:
        rg - The group to be deleted
      • copyRosterGroupList

        public void copyRosterGroupList​(java.lang.String oldName,
                                        java.lang.String newName)
        Copy a roster group, adding every entry in the roster group to the new group.

        If a roster group with the target name already exists, this method silently fails to rename the roster group. The GUI method CopyRosterGroupAction.performAction() catches this error and informs the user. This method fires the property change ""RosterGroupAdded"".

        Parameters:
        oldName - Name of the roster group to be copied
        newName - Name of the new roster group
        See Also:
        RenameRosterGroupAction
      • rosterGroupRenamed

        public void rosterGroupRenamed​(java.lang.String oldName,
                                       java.lang.String newName)
      • renameRosterGroupList

        public void renameRosterGroupList​(java.lang.String oldName,
                                          java.lang.String newName)
        Rename a roster group, while keeping every entry in the roster group.

        If a roster group with the target name already exists, this method silently fails to rename the roster group. The GUI method RenameRosterGroupAction.performAction() catches this error and informs the user. This method fires the property change ""RosterGroupRenamed"".

        Parameters:
        oldName - Name of the roster group to be renamed
        newName - New name for the roster group
        See Also:
        RenameRosterGroupAction
      • getRosterGroupList

        public java.util.ArrayList<java.lang.String> getRosterGroupList()
        Get a list of the user defined roster group names.

        Strings are immutable, so deleting an item from the copy should not affect the system-wide list of roster groups.

        Returns:
        A list of the roster group names.
      • allEntries

        public static java.lang.String allEntries​(java.util.Locale locale)
        Get the identifier for all entries in the roster.
        Parameters:
        locale - The desired locale
        Returns:
        "All Entries" in the specified locale
      • getDefaultRosterGroup

        public java.lang.String getDefaultRosterGroup()
        Returns:
        the defaultRosterGroup
      • setDefaultRosterGroup

        public void setDefaultRosterGroup​(java.lang.String defaultRosterGroup)
        Parameters:
        defaultRosterGroup - the defaultRosterGroup to set
      • getAllFileNames

        static java.lang.String[] getAllFileNames()
        Get an array of all the RosterEntry-containing files in the target directory.
        Returns:
        the list of file names for entries in this roster
      • getRosterGroups

        @Nonnull
        public java.util.HashMap<java.lang.String,​RosterGroupgetRosterGroups()
        Get the groups known to the roster itself. Note that changes to the returned Map will not be reflected in the Roster.
        Returns:
        the rosterGroups
      • remapRosterGroup

        public void remapRosterGroup​(RosterGroup group,
                                     java.lang.String newKey)
        Changes the key used to lookup a RosterGroup by name. This is a helper method that does not fire a notification to any propertyChangeListeners.

        To rename a RosterGroup, use RosterGroup.setName(java.lang.String).

        Parameters:
        group - The group being associated with newKey and will be disassociated with the key matching RosterGroup.getName().
        newKey - The new key by which group can be found in the map of RosterGroups. This should match the intended new name of group.
      • propertyChange

        public void propertyChange​(java.beans.PropertyChangeEvent evt)
        Specified by:
        propertyChange in interface java.beans.PropertyChangeListener