001package jmri.jmrix.openlcb.configurexml; 002 003import org.jdom2.Element; 004import org.slf4j.Logger; 005import org.slf4j.LoggerFactory; 006 007import java.util.Map; 008 009import jmri.jmrix.PortAdapter; 010import jmri.jmrix.can.CanSystemConnectionMemo; 011import jmri.jmrix.can.ConfigurationManager; 012 013/** 014 * This class encapsulates common code for reading and writing per-connection information from/to 015 * the XML of the connection profile. It is intended to be called by all conforming Adapter 016 * implementations that are the possible choices for an OpenLCB connection. 017 * <p> 018 * (C) Balazs Racz, 2018. 019 */ 020 021public class ConnectionConfigXml { 022 /** 023 * Checks if we are loading an OpenLCB protocol adapter. If no, returns without doing 024 * anything. If yes, loads the protocol settings from the XML elements. 025 * 026 * Must be called after loadOptions is done. 027 * 028 * @param shared The <connection> element in the shared profile configuration. 029 * @param perNode The <connection> element in the per-node profile configuration. 030 * @param adapter The adapter that's in the process of initializing this connection. 031 */ 032 public static void maybeLoadOlcbProfileSettings(Element shared, Element perNode, PortAdapter 033 adapter) { 034 CanSystemConnectionMemo sc = isOpenLCBProtocol(adapter); 035 if (sc == null) return; 036 loadSettingsElement(sc, shared); 037 loadSettingsElement(sc, perNode); 038 } 039 040 private static void loadSettingsElement(CanSystemConnectionMemo sc, Element xmlNode) { 041 for (Element n : xmlNode.getChildren("node")) { 042 String protocol = n.getAttributeValue("name"); 043 for (Element p : n.getChildren("parameter")) { 044 String optionName = p.getAttributeValue("name"); 045 String value = p.getTextTrim(); 046 sc.setProtocolOption(protocol, optionName, value); 047 } 048 } 049 } 050 051 /** 052 * Checks if we are saving an OpenLCB protocol connection. If no, does nothing. If yes, saves 053 * the protocol options from the SystemConnectionMemo into the XML element. 054 * This function needs to be called from the extendElement(Element e) override in a 055 * ConnectionConfigXml of an adaptor. 056 * 057 * @param element <connection> XML node 058 * @param adapter Adaptor object that we are trying to save; used to access the system 059 * connection memo. 060 */ 061 public static void maybeSaveOlcbProfileSettings(Element element, PortAdapter adapter) { 062 CanSystemConnectionMemo sc = isOpenLCBProtocol(adapter); 063 if (sc == null) return; 064 065 for (String protocol : sc.getProtocolsWithOptions()) { 066 Element n = new Element("node"); 067 n.setAttribute("name", protocol); 068 element.addContent(n); 069 070 Map<String, String> params = sc.getProtocolAllOptions(protocol); 071 for (Map.Entry<String, String> entry : params.entrySet()) { 072 Element p = new Element("parameter"); 073 p.setAttribute("name", entry.getKey()); 074 p.addContent(entry.getValue()); 075 n.addContent(p); 076 } 077 } 078 } 079 080 /** 081 * Tests whether a CAN adapter is set to openLCB protocol or not. 082 * 083 * @param adapter CAN adapter 9may be serial, loopback or network). 084 * @return null for non-OpenLCB connections; for OpenLCB the connection-associated the 085 * CanSystemConnectionMemo. 086 */ 087 public static CanSystemConnectionMemo isOpenLCBProtocol(PortAdapter adapter) { 088 CanSystemConnectionMemo sc = (CanSystemConnectionMemo) adapter.getSystemConnectionMemo(); 089 if (sc == null) { 090 log.error("Adapter is expected to have a CanSystemConnectionMemo to be used for " + 091 "OpenLCB protocol."); 092 return null; 093 } 094 if (!ConfigurationManager.OPENLCB.equals(adapter.getOptionState("Protocol"))) { 095 log.debug("Skipping OpenLCB protocol properties action, because protocol is not " + 096 "OpenLCB, but {}", adapter.getOptionState("Protocol")); 097 return null; 098 } 099 return sc; 100 } 101 102 private static final Logger log = LoggerFactory.getLogger(ConnectionConfigXml.class); 103}