001package jmri.jmrit.symbolicprog;
002
003import java.io.IOException;
004import java.util.HashMap;
005import java.util.List;
006import java.util.Set;
007import jmri.InstanceInitializer;
008import jmri.implementation.AbstractInstanceInitializer;
009import jmri.jmrit.XmlFile;
010import org.jdom2.Element;
011import org.jdom2.JDOMException;
012import org.openide.util.lookup.ServiceProvider;
013import org.slf4j.Logger;
014import org.slf4j.LoggerFactory;
015
016// try to limit the JDOM to this class, so that others can manipulate...
017/**
018 * Represents a set of standard names and aliases in memory.
019 * <p>
020 * This class doesn't provide tools for defining the names and aliases; that's
021 * done manually, or at least not done here, to create the file.
022 * <p>
023 * This automatically initializes from the default file if requested
024 * from the InstanceManager.
025 *
026 * @author Bob Jacobsen Copyright (C) 2001
027 */
028public class NameFile extends XmlFile {
029
030    public Set<String> names() {
031        return _nameHash.keySet();
032    }
033
034    // hold names in a HashMap
035    protected HashMap<String, Element> _nameHash = new HashMap<>();
036
037    public Element elementFromName(String name) {
038        return _nameHash.get(name);
039    }
040
041    /**
042     * Check to see if a name is present in the file.
043     *
044     * @param name the name to check
045     * @return true if present; false otherwise
046     */
047    public boolean checkName(String name) {
048        return (elementFromName(name) != null);
049    }
050
051    /**
052     * Read the contents of a NameFile XML file into this object. Note that this
053     * does not clear any existing entries.
054     * @param name File name to read
055     * @throws JDOMException if the file can't be parsed
056     * @throws IOException from underlying IO operations
057     */
058    void readFile(String name) throws org.jdom2.JDOMException, java.io.IOException {
059        if (log.isDebugEnabled()) {
060            log.debug("readFile {}", name);
061        }
062
063        // read file, find root
064        Element root = rootFromName(name);
065        // decode type, invoke proper processing routine
066        readNames(root);
067    }
068
069    void readNames(Element root) {
070
071        List<Element> l = root.getChildren("definition");
072        if (log.isDebugEnabled()) {
073            log.debug("readNames sees {} direct children", l.size());
074        }
075        for (int i = 0; i < l.size(); i++) {
076            // handle each entry
077            Element el = l.get(i);
078            storeDefinition(el);
079        }
080        // now recurse with "definitiongroup" children
081        l = root.getChildren("definitiongroup");
082        if (log.isDebugEnabled()) {
083            log.debug("readNames sees {} groups", l.size());
084        }
085        for (int i = 0; i < l.size(); i++) {
086            // handle each entry
087            Element el = l.get(i);
088            readNames(el);
089        }
090
091    }
092
093    void storeDefinition(Element el) {
094        String name = el.getAttribute("item").getValue();
095        _nameHash.put(name, el);
096    }
097
098    /**
099     * Get the filename for the default file, including location. This is here
100     * to allow easy override in tests.
101     *
102     * @return the default filename
103     */
104    protected static String defaultNameFilename() {
105        return fileLocation + nameFileName;
106    }
107
108    static String fileLocation = "";
109    static String nameFileName = "names.xml";
110
111    @ServiceProvider(service = InstanceInitializer.class)
112    public static class Initializer extends AbstractInstanceInitializer {
113
114        @Override
115        public <T> Object getDefault(Class<T> type) {
116            if (type.equals(NameFile.class)) {
117                if (log.isDebugEnabled()) {
118                    log.debug("NameFile creating instance");
119                }
120                // create and load
121                NameFile instance = new NameFile();
122                try {
123                    instance.readFile(defaultNameFilename());
124                } catch (IOException | JDOMException e) {
125                    log.error("Exception during name file reading: {}", e.getMessage());
126                }
127                log.debug("NameFile returns instance {}", instance);
128                return instance;
129            }
130            return super.getDefault(type);
131        }
132
133        @Override
134        public Set<Class<?>> getInitalizes() {
135            Set<Class<?>> set = super.getInitalizes();
136            set.add(NameFile.class);
137            return set;
138        }
139
140    }
141    
142    private final static Logger log = LoggerFactory.getLogger(NameFile.class);
143}