001package jmri.managers.configurexml;
002
003import java.io.File;
004import java.io.FileNotFoundException;
005import java.io.IOException;
006import java.util.List;
007
008import org.jdom2.Document;
009import org.jdom2.Element;
010import org.jdom2.JDOMException;
011import org.jdom2.ProcessingInstruction;
012import org.slf4j.Logger;
013import org.slf4j.LoggerFactory;
014
015import jmri.Application;
016import jmri.IdTag;
017import jmri.IdTagManager;
018import jmri.jmrit.XmlFile;
019import jmri.util.FileUtil;
020
021/**
022 * Concrete implementation of abstract {@link jmri.jmrit.XmlFile} for
023 * the {@link jmri.managers.DefaultIdTagManager}.
024 *
025 * @author Bob Jacobsen Copyright (C) 2010
026 * @author Matthew Harris Copyright (C) 2011
027 * @since 2.11.4
028 */
029public class DefaultIdTagManagerXml extends XmlFile {
030
031    private final IdTagManager manager;
032
033    public DefaultIdTagManagerXml(IdTagManager tagMan, String baseFileName){
034        manager = tagMan;
035        IDTAG_BASE_FILENAME = baseFileName;
036    }
037
038    public void store() throws java.io.IOException {
039        log.debug("Storing...");
040        log.debug("Using file: {}", getDefaultIdTagFileName());
041        createFile(getDefaultIdTagFileName(), true);
042        try {
043            writeFile(getDefaultIdTagFileName());
044        } catch (FileNotFoundException ex) {
045            log.error("File not found while writing IdTag file, may not be complete", ex);
046        }
047    }
048
049    public void load() {
050        log.debug("Loading...");
051        try {
052            readFile(getDefaultIdTagFileName());
053        } catch (JDOMException | IOException ex) {
054            log.error("Exception during IdTag file reading", ex);
055        }
056    }
057
058    private File createFile(String fileName, boolean backup) {
059        if (backup) {
060            makeBackupFile(fileName);
061        }
062
063        File file = null;
064        try {
065            if (!checkFile(fileName)) {
066                // The file does not exist, create it before writing
067                file = new File(fileName);
068                File parentDir = file.getParentFile();
069                if (!parentDir.exists()) {
070                    if (!parentDir.mkdir()) {
071                        log.error("Directory wasn't created");
072                    }
073                }
074                if (file.createNewFile()) {
075                    log.debug("New file created");
076                }
077           } else {
078              file = new File(fileName);
079           }
080       } catch (java.io.IOException ex) {
081          log.error("Exception while creating IdTag file, may not be complete", (Object) ex);
082       }
083       return file;
084   }
085
086   private void writeFile(String fileName) throws FileNotFoundException, java.io.IOException {
087        log.debug("writeFile {}", fileName);
088        // This is taken in large part from "Java and XML" page 368
089        File file = findFile(fileName);
090        if (file == null) {
091           file = new File(fileName);
092        }
093        // Create root element
094        Element root = new Element("idtagtable");              // NOI18N
095        root.setAttribute("noNamespaceSchemaLocation", // NOI18N
096        "http://jmri.org/xml/schema/idtags.xsd", // NOI18N
097        org.jdom2.Namespace.getNamespace("xsi", // NOI18N
098        "http://www.w3.org/2001/XMLSchema-instance")); // NOI18N
099        Document doc = newDocument(root);
100
101        // add XSLT processing instruction
102        java.util.Map<String, String> m = new java.util.HashMap<>();
103        m.put("type", "text/xsl"); // NOI18N
104        m.put("href", xsltLocation + "idtags.xsl"); // NOI18N
105        ProcessingInstruction p = new ProcessingInstruction("xml-stylesheet", m); // NOI18N
106        doc.addContent(0, p);
107
108        Element values;
109
110        // Store configuration
111        root.addContent(values = new Element("configuration"));                                              // NOI18N
112        values.addContent(new Element("storeState").addContent(manager.isStateStored() ? "yes" : "no"));     // NOI18N
113        values.addContent(new Element("useFastClock").addContent(manager.isFastClockUsed() ? "yes" : "no")); // NOI18N
114
115        // Loop through RfidTags
116        root.addContent(values = new Element("idtags")); // NOI18N
117        for (IdTag t : manager.getNamedBeanSet()) {
118           log.debug("Writing IdTag: {}", t.getSystemName());
119           values.addContent(t.store(manager.isStateStored()));
120        }
121        writeXML(file, doc);
122    }
123
124    private void readFile(String fileName) throws org.jdom2.JDOMException, java.io.IOException, IllegalArgumentException {
125        // Check file exists
126        if (findFile(fileName) == null) {
127            log.debug("{} file could not be found", fileName);
128            return;
129        }
130
131        // Find root
132        Element root = rootFromName(fileName);
133        if (root == null) {
134            log.debug("{} file could not be read", fileName);
135            return;
136        }
137
138        // First read configuration
139        if (root.getChild("configuration") != null) { // NOI18N
140            List<Element> l = root.getChild("configuration").getChildren(); // NOI18N
141            log.debug("readFile sees {} configurations", l.size());
142            for (Element e : l) {
143                log.debug("Configuration {} value {}", e.getName(), e.getValue());
144                if (e.getName().equals("storeState")) { // NOI18N
145                    manager.setStateStored(e.getValue().equals("yes")); // NOI18N
146                }
147                if (e.getName().equals("useFastClock")) { // NOI18N
148                    manager.setFastClockUsed(e.getValue().equals("yes")); // NOI18N
149                }
150            }
151        }
152
153        // Now read tag information
154        if (root.getChild("idtags") != null) { // NOI18N
155            List<Element> l = root.getChild("idtags").getChildren("idtag"); // NOI18N
156            log.debug("readFile sees {} idtags", l.size());
157            for (Element e : l) {
158                String systemName = e.getChild("systemName").getText(); // NOI18N
159                try {
160                    IdTag t = manager.provideIdTag(systemName);
161                    t.load(e);
162                } catch (jmri.NamedBean.BadSystemNameException ex) {
163                    log.error("Could not create tag from ({}) during loading, ignored", systemName);
164                }
165            }
166        }
167    }
168
169    public String getDefaultIdTagFileName() {
170        return getFileLocation() + getIdTagDirectoryName() + File.separator + getIdTagFileName();
171    }
172
173    private static final String IDTAG_DIRECTORY_NAME = "idtags"; // NOI18N
174
175    public String getIdTagDirectoryName() {
176        return IDTAG_DIRECTORY_NAME;
177    }
178
179    private String IDTAG_BASE_FILENAME = "IdTags.xml"; // NOI18N
180
181    public String getIdTagFileName() {
182        String appName = Application.getApplicationName();
183        if (appName.equals("LccPro")) appName = "PanelPro";
184        String retval = appName + IDTAG_BASE_FILENAME;
185        // as a special case, the LccPro application uses
186        // the PanelPro id tag files
187        jmri.util.LoggingUtil.infoOnce(log, "Using "+retval+" for tag storage");
188        return retval;
189    }
190
191    /**
192     * Absolute path to location of IdTag files.
193     *
194     * @return path to location
195     */
196    public String getFileLocation() {
197        return FILE_LOCATION;
198    }
199
200    private final String FILE_LOCATION = FileUtil.getUserFilesPath();
201
202    private final Logger log = LoggerFactory.getLogger(DefaultIdTagManagerXml.class);
203
204}