001package jmri.jmrix.ieee802154.xbee.configurexml; 002 003import com.digi.xbee.api.RemoteXBeeDevice; 004import com.digi.xbee.api.exceptions.TimeoutException; 005import com.digi.xbee.api.exceptions.XBeeException; 006import com.digi.xbee.api.models.XBee16BitAddress; 007import com.digi.xbee.api.models.XBee64BitAddress; 008import java.util.List; 009import jmri.configurexml.ConfigXmlManager; 010import jmri.configurexml.XmlAdapter; 011import jmri.jmrix.AbstractStreamPortController; 012import jmri.jmrix.AbstractStreamConnectionConfig; 013import jmri.jmrix.configurexml.AbstractSerialConnectionConfigXml; 014import jmri.jmrix.ieee802154.xbee.ConnectionConfig; 015import jmri.jmrix.ieee802154.xbee.XBeeAdapter; 016import jmri.jmrix.ieee802154.xbee.XBeeConnectionMemo; 017import jmri.jmrix.ieee802154.xbee.XBeeNode; 018import jmri.jmrix.ieee802154.xbee.XBeeTrafficController; 019import org.jdom2.Element; 020import org.slf4j.Logger; 021import org.slf4j.LoggerFactory; 022 023/** 024 * Handle XML persistance of layout connections by persisting the XBeeAdapter 025 * (and connections). Note this is named as the XML version of a 026 * ConnectionConfig object, but it's actually persisting the XBeeAdapter. 027 * <p> 028 * This class is invoked from jmrix.JmrixConfigPaneXml on write, as that class 029 * is the one actually registered. Reads are brought here directly via the class 030 * attribute in the XML. 031 * 032 * @author Bob Jacobsen Copyright: Copyright (c) 2003, 2006, 2007, 2008 033 */ 034public class ConnectionConfigXml extends AbstractSerialConnectionConfigXml { 035 036 public ConnectionConfigXml() { 037 super(); 038 } 039 040 /** 041 * Write out the SerialNode objects too 042 * 043 * @param e Element being extended 044 */ 045 @Override 046 protected void extendElement(Element e) { 047 XBeeConnectionMemo xcm; 048 XBeeTrafficController xtc; 049 try { 050 xcm = (XBeeConnectionMemo) adapter.getSystemConnectionMemo(); 051 xtc = (XBeeTrafficController) xcm.getTrafficController(); 052 } catch (NullPointerException npe) { 053 // The adapter doesn't have a memo, so no nodes can be defined. 054 if (log.isDebugEnabled()) { 055 log.debug("No memo defined; no nodes to save."); 056 } 057 return; 058 } 059 try { 060 XBeeNode node = (XBeeNode) xtc.getNode(0); 061 int index = 1; 062 while (node != null) { 063 // add node as an element 064 Element n = new Element("node"); 065 n.setAttribute("name", Integer.toString(node.getNodeAddress())); 066 e.addContent(n); 067 // add parameters to the node as needed 068 n.addContent(makeParameter("address", 069 jmri.util.StringUtil.hexStringFromBytes(node.getUserAddress()))); 070 n.addContent(makeParameter("PAN", 071 jmri.util.StringUtil.hexStringFromBytes(node.getPANAddress()))); 072 n.addContent(makeParameter("GUID", 073 jmri.util.StringUtil.hexStringFromBytes(node.getGlobalAddress()))); 074 n.addContent(makeParameter("name", node.getIdentifier())); 075 n.addContent(makeParameter("polled", node.getPoll() ? "yes" : "no")); 076 077 jmri.jmrix.AbstractStreamPortController pc = null; 078 if ((pc = node.getPortController()) != null) { 079 n.addContent(makeParameter("StreamController", 080 pc.getClass().getName())); 081 } 082 083 jmri.jmrix.AbstractStreamConnectionConfig cf = null; 084 if ((cf = node.getConnectionConfig()) != null) { 085 n.addContent(makeParameter("StreamConfig", 086 cf.getClass().getName())); 087 String adapter = ConfigXmlManager.adapterName(cf); 088 log.debug("forward to {}", adapter); 089 try { 090 XmlAdapter x = (XmlAdapter) Class.forName(adapter).getDeclaredConstructor().newInstance(); 091 n.addContent(x.store(cf)); 092 } catch (ClassNotFoundException | IllegalAccessException 093 | InstantiationException | NoSuchMethodException | java.lang.reflect.InvocationTargetException ex) { 094 log.error("Exception: ", ex); 095 } 096 } 097 098 // look for the next node 099 node = (XBeeNode) xtc.getNode(index); 100 index++; 101 } 102 } catch (java.lang.NullPointerException npe2) { 103 // no nodes defined. 104 } 105 } 106 107 protected Element makeParameter(String name, String value) { 108 Element p = new Element("parameter"); 109 p.setAttribute("name", name); 110 p.addContent(value); 111 return p; 112 } 113 114 @Override 115 protected void getInstance() { 116 adapter = new XBeeAdapter(); 117 } 118 119 @Override 120 protected void getInstance(Object object) { 121 adapter = ((ConnectionConfig) object).getAdapter(); 122 } 123 124 @Override 125 protected void unpackElement(Element shared, Element perNode) { 126 List<Element> l = shared.getChildren("node"); 127 // Trigger initialization of this Node to reflect these parameters 128 XBeeConnectionMemo xcm = (XBeeConnectionMemo) adapter.getSystemConnectionMemo(); 129 XBeeTrafficController xtc = (XBeeTrafficController) xcm.getTrafficController(); 130 for (Element n : l) { 131 byte[] GUID = jmri.util.StringUtil.bytesFromHexString(findParmValue(n, "GUID")); 132 XBee64BitAddress guid = new XBee64BitAddress(GUID); 133 byte[] addr = jmri.util.StringUtil.bytesFromHexString(findParmValue(n, "address")); 134 XBee16BitAddress address = new XBee16BitAddress(addr); 135 String Identifier = findParmValue(n, "name"); 136 // create the RemoteXBeeDevice for the node. 137 RemoteXBeeDevice remoteDevice = new RemoteXBeeDevice(xtc.getXBee(), guid, address, Identifier); 138 // Check to see if the node is a duplicate, if it is, move 139 // to the next one. 140 // get a XBeeNode corresponding to this node address if one exists 141 XBeeNode curNode = (XBeeNode) xtc.getNodeFromXBeeDevice(remoteDevice); 142 if (curNode != null) { 143 log.info("Read duplicate node {} from file", remoteDevice); 144 continue; 145 } 146 147 try { 148 // and then add it to the network 149 xtc.getXBee().getNetwork().addRemoteDevice(remoteDevice); 150 // create node (they register themselves) 151 XBeeNode node = new XBeeNode(remoteDevice); 152 153 String polled = findParmValue(n, "polled"); 154 node.setPoll(polled.equals("yes")); 155 156 xtc.registerNode(node); 157 158 // if there is a stream port controller stored for this 159 // node, we need to load that after the node starts running. 160 // otherwise, the IOStream associated with the node has not 161 // been configured. 162 String streamController = findParmValue(n, "StreamController"); 163 String streamConfig = findParmValue(n, "StreamConfig"); 164 AbstractStreamPortController connectedController = null; 165 AbstractStreamConnectionConfig connectedConfig = null; 166 167 Element connect; 168 try { 169 connect = n.getChildren("connection").get(0); // there should only be one connection child. 170 } catch (IndexOutOfBoundsException ioobe) { 171 connect = null; 172 } 173 174 // configure the controller. 175 if (streamController != null) { 176 try { 177 @SuppressWarnings("unchecked") // Class.forName cast is unchecked at this point 178 Class<AbstractStreamPortController> T = (Class<AbstractStreamPortController>) Class.forName(streamController); 179 java.lang.reflect.Constructor<?> ctor = T.getConstructor(java.io.DataInputStream.class, java.io.DataOutputStream.class, String.class); 180 connectedController = (AbstractStreamPortController) ctor.newInstance(node.getIOStream().getInputStream(), node.getIOStream().getOutputStream(), "XBee Node " + node.getPreferedName()); 181 } catch (ClassNotFoundException cnfe) { 182 log.error("Unable to find class for stream controller : {}", streamController); 183 } catch (InstantiationException | NoSuchMethodException | IllegalAccessException | 184 java.lang.reflect.InvocationTargetException ex) { 185 log.error("Unable to construct Stream Port Controller for node.", ex); 186 } 187 } 188 // if streamConfig is available, set up connectedConfig. 189 if (streamConfig != null && connectedController != null) { 190 try { 191 @SuppressWarnings("unchecked") // Class.forName cast is unchecked at this point 192 Class<AbstractStreamConnectionConfig> T = (Class<AbstractStreamConnectionConfig>) Class.forName(streamConfig); 193 java.lang.reflect.Constructor<?> ctor = T.getConstructor(AbstractStreamPortController.class); 194 connectedConfig = (AbstractStreamConnectionConfig) ctor.newInstance(connectedController); 195 } catch (ClassNotFoundException cnfe) { 196 log.error("Unable to find class for stream config: {}", streamConfig); 197 } catch (InstantiationException | NoSuchMethodException | IllegalAccessException | 198 java.lang.reflect.InvocationTargetException ex) { 199 log.error("Unable to construct Stream Port Configuration for node.", ex); 200 } 201 } 202 // load information from the xml file. 203 if (connect != null && connectedConfig != null) { 204 String className = connect.getAttributeValue("class"); 205 206 try { 207 XmlAdapter adapter = (XmlAdapter) Class.forName(className).getDeclaredConstructor().newInstance(); 208 adapter.load(connect, connectedConfig); 209 } catch (ClassNotFoundException | InstantiationException | NoSuchMethodException | 210 java.lang.reflect.InvocationTargetException | IllegalAccessException ex) { 211 log.error("Unable to create {} for {}", className, shared, ex); 212 } catch (RuntimeException | jmri.configurexml.JmriConfigureXmlException ex) { 213 log.error("Unable to load {} into {}", shared, className, ex); 214 } 215 } 216 217 // after loading either config or controller, connect them. 218 if (connectedConfig != null) { 219 node.connectPortController(connectedConfig); 220 } else if (connectedController != null) { 221 // fallback for connections created with a script 222 node.connectPortController(connectedController); 223 } 224 if (node.getConnectionConfig() != null) { 225 // connection config is optional. don't assume it loaded from the file. 226 log.info("loaded {} onto node {}", node.getConnectionConfig(), node); 227 log.info("manuf {} userName {} ", node.getConnectionConfig().getManufacturer(), node.getConnectionConfig().name()); 228 } 229 } catch (TimeoutException toe) { 230 log.error("Timeout adding node {} from configuration file.", remoteDevice); 231 } catch (XBeeException xbe) { 232 log.error("Exception adding node {} from configuration file.", remoteDevice); 233 } 234 } 235 236 } 237 238 @Override 239 protected void register() { 240 this.register(new ConnectionConfig(adapter)); 241 } 242 243 // initialize logging 244 private final static Logger log = LoggerFactory.getLogger(ConnectionConfigXml.class); 245 246}