001package jmri.jmrix.openlcb.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; 012 013import org.openlcb.NodeID; 014 015import jmri.Application; 016import jmri.jmrit.XmlFile; 017import jmri.jmrix.openlcb.OlcbNodeGroupStore; 018import jmri.util.FileUtil; 019 020/** 021 * Concrete implementation of abstract {@link jmri.jmrit.XmlFile} for 022 * the {@link jmri.jmrix.openlcb.OlcbNodeGroupStore}. 023 * 024 * @author Bob Jacobsen Copyright (C) 2024 025 * @since 5.11.1 026 */ 027public class OlcbNodeGroupStoreXml extends XmlFile { 028 029 OlcbNodeGroupStore store; 030 031 public OlcbNodeGroupStoreXml(OlcbNodeGroupStore store, String baseFileName){ 032 this.store = store; 033 BASE_FILENAME = baseFileName; 034 } 035 036 public void store() throws java.io.IOException { 037 log.debug("Storing using file: {}", getDefaultFileName()); 038 createFile(getDefaultFileName(), true); 039 try { 040 log.debug("about to call writeFile"); 041 writeFile(getDefaultFileName()); 042 } catch (FileNotFoundException ex) { 043 log.error("File not found while writing node group file, may not be complete", ex); 044 } 045 } 046 047 public void load() { 048 log.debug("Loading..."); 049 try { 050 readFile(getDefaultFileName()); 051 } catch (JDOMException | IOException ex) { 052 log.error("Exception during node group file reading", ex); 053 } 054 log.debug("load complete..."); 055 } 056 057 private File createFile(String fileName, boolean backup) { 058 if (backup) { 059 makeBackupFile(fileName); 060 } 061 062 File file = null; 063 try { 064 if (!checkFile(fileName)) { 065 log.debug("file check done"); 066 // The file does not exist, create it before writing 067 file = new File(fileName); 068 File parentDir = file.getParentFile(); 069 log.debug("before exists {}", parentDir); 070 if (!parentDir.exists()) { 071 if (!parentDir.mkdir()) { 072 log.error("Directory wasn't created"); 073 } 074 } 075 if (file.createNewFile()) { 076 log.debug("New file created"); 077 } 078 } else { 079 file = new File(fileName); 080 } 081 } catch (java.io.IOException ex) { 082 log.error("Exception while creating IdTag file, may not be complete", (Object) ex); 083 } 084 return file; 085 } 086 087 private void writeFile(String fileName) throws FileNotFoundException, java.io.IOException { 088 log.debug("writeFile {}", fileName); 089 // This is taken in large part from "Java and XML" page 368 090 File file = findFile(fileName); 091 if (file == null) { 092 file = new File(fileName); 093 } 094 // Create root element 095 Element root = new Element("nodegroupassociations"); // NOI18N 096 root.setAttribute("noNamespaceSchemaLocation", // NOI18N 097 "http://jmri.org/xml/schema/nodegroupassociations.xsd", // NOI18N 098 org.jdom2.Namespace.getNamespace("xsi", // NOI18N 099 "http://www.w3.org/2001/XMLSchema-instance")); // NOI18N 100 Document doc = newDocument(root); 101 102 // add XSLT processing instruction 103 java.util.Map<String, String> m = new java.util.HashMap<>(); 104 m.put("type", "text/xsl"); // NOI18N 105 m.put("href", xsltLocation + "nodegroupassociations.xsl"); // NOI18N 106 ProcessingInstruction p = new ProcessingInstruction("xml-stylesheet", m); // NOI18N 107 doc.addContent(0, p); 108 109 Element values; 110 111 // Loop through associations 112 for (String group : store.getGroupNames()) { 113 for (NodeID node : store.getGroupNodes(group)) { 114 root.addContent(values = new Element("association")); // NOI18N 115 values.addContent(new Element("node").addContent(node.toString()) ); // NOI18N 116 values.addContent(new Element("group").addContent(group)); // NOI18N 117 } 118 } 119 log.debug("write to {}", file); 120 writeXML(file, doc); 121 } 122 123 private void readFile(String fileName) throws org.jdom2.JDOMException, java.io.IOException, IllegalArgumentException { 124 // Check file exists 125 if (findFile(fileName) == null) { 126 log.warn("{} file could not be found", fileName); 127 return; 128 } 129 130 // Find root 131 Element root = rootFromName(fileName); 132 if (root == null) { 133 log.warn("{} file could not be read", fileName); 134 return; 135 } 136 137 // Node association information 138 List<Element> l = root.getChildren("association"); // NOI18N 139 for (Element e : l) { 140 NodeID node = new NodeID(e.getChild("node").getText()); // NOI18N 141 String group = e.getChild("group").getText(); // NOI18N 142 log.trace("load entry {} {}", node, group); 143 store.addNodeToGroup(node, group); 144 } 145 } 146 147 public String getDefaultFileName() { 148 return getFileLocation() + getDirectoryName() + File.separator + getFileName(); 149 } 150 151 private static final String DIRECTORY_NAME = "idtags"; // NOI18N 152 153 public String getDirectoryName() { 154 return DIRECTORY_NAME; 155 } 156 157 private String BASE_FILENAME = "NodeGroupAssociations.xml"; // NOI18N 158 159 public String getFileName() { 160 String appName = Application.getApplicationName(); 161 if (appName.equals("LccPro")) appName = "PanelPro"; 162 String retval = appName + BASE_FILENAME; 163 // as a special case, the LccPro application uses 164 // the PanelPro file 165 jmri.util.LoggingUtil.infoOnce(log, "Using "+retval+" for LCC node group storage"); 166 return retval; 167 } 168 169 /** 170 * Absolute path to location of IdTag files. 171 * 172 * @return path to location 173 */ 174 public String getFileLocation() { 175 return FILE_LOCATION; 176 } 177 178 private final String FILE_LOCATION = FileUtil.getUserFilesPath(); 179 180 private final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(OlcbNodeGroupStoreXml.class); 181 182}