Skip to content

Commit 116700a

Browse files
authored
Backup and restore network (#1439)
* Implement full network backup / restore functionality Signed-off-by: Chris Jackson <[email protected]> * Update to set IEEE address in Ember NCP Signed-off-by: Chris Jackson <[email protected]> * Update following testing Signed-off-by: Chris Jackson <[email protected]> * Fix log statement Signed-off-by: Chris Jackson <[email protected]> * Minor updates following comments --------- Signed-off-by: Chris Jackson <[email protected]>
1 parent 5774fca commit 116700a

File tree

19 files changed

+953
-357
lines changed

19 files changed

+953
-357
lines changed

com.zsmartsystems.zigbee.console.main/src/main/java/com/zsmartsystems/zigbee/console/main/ZigBeeDataStore.java

+84-12
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import java.io.OutputStreamWriter;
1717
import java.util.HashSet;
1818
import java.util.Set;
19+
import java.util.UUID;
1920

2021
import org.slf4j.Logger;
2122
import org.slf4j.LoggerFactory;
@@ -27,6 +28,7 @@
2728
import com.zsmartsystems.zigbee.database.ZclAttributeDao;
2829
import com.zsmartsystems.zigbee.database.ZclClusterDao;
2930
import com.zsmartsystems.zigbee.database.ZigBeeEndpointDao;
31+
import com.zsmartsystems.zigbee.database.ZigBeeNetworkBackupDao;
3032
import com.zsmartsystems.zigbee.database.ZigBeeNetworkDataStore;
3133
import com.zsmartsystems.zigbee.database.ZigBeeNodeDao;
3234
import com.zsmartsystems.zigbee.security.ZigBeeKey;
@@ -47,19 +49,25 @@ public class ZigBeeDataStore implements ZigBeeNetworkDataStore {
4749
*/
4850
private final static Logger logger = LoggerFactory.getLogger(ZigBeeDataStore.class);
4951

52+
private final static String CHARSET = "UTF-8";
53+
private final static String DATABASE = "database/";
5054
private final static String KEYSTORE = "keystore";
55+
private final static String BACKUP = "backup";
5156

5257
private final String networkId;
5358

5459
public ZigBeeDataStore(String networkId) {
55-
this.networkId = "database/" + networkId + "/";
56-
File file = new File(this.networkId + "/" + KEYSTORE);
57-
if (file.exists()) {
58-
return;
59-
}
60-
if (!file.mkdirs()) {
60+
this.networkId = DATABASE + networkId + "/";
61+
File file;
62+
63+
file = new File(this.networkId + "/" + KEYSTORE);
64+
if (!file.exists() && !file.mkdirs()) {
6165
logger.error("Error creating network database folder {}", file);
6266
}
67+
file = new File(DATABASE + BACKUP);
68+
if (!file.exists() && !file.mkdirs()) {
69+
logger.error("Error creating network backup folder {}", file);
70+
}
6371
}
6472

6573
private XStream openStream() {
@@ -99,6 +107,10 @@ private File getFile(IeeeAddress address) {
99107
return new File(networkId + address + ".xml");
100108
}
101109

110+
private File getFile(UUID uuid) {
111+
return new File(DATABASE + BACKUP + "/" + uuid + ".xml");
112+
}
113+
102114
private File getFile(String key) {
103115
return new File(networkId + KEYSTORE + "/" + key + ".xml");
104116
}
@@ -135,10 +147,9 @@ public ZigBeeNodeDao readNode(IeeeAddress address) {
135147
File file = getFile(address);
136148

137149
ZigBeeNodeDao node = null;
138-
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"))) {
150+
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), CHARSET))) {
139151
node = (ZigBeeNodeDao) stream.fromXML(reader);
140152
reader.close();
141-
logger.info("{}: ZigBee reading network state complete.", address);
142153
} catch (Exception e) {
143154
logger.error("{}: Error reading network state: ", address, e);
144155
}
@@ -151,10 +162,9 @@ public void writeNode(ZigBeeNodeDao node) {
151162
XStream stream = openStream();
152163
File file = getFile(node.getIeeeAddress());
153164

154-
try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8"))) {
165+
try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), CHARSET))) {
155166
stream.marshal(node, new PrettyPrintWriter(writer));
156167
writer.close();
157-
logger.info("{}: ZigBee saving network state complete.", node.getIeeeAddress());
158168
} catch (Exception e) {
159169
logger.error("{}: Error writing network state: ", node.getIeeeAddress(), e);
160170
}
@@ -173,10 +183,9 @@ public void writeObject(String key, Object object) {
173183
XStream stream = openStream();
174184
File file = getFile(key);
175185

176-
try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8"))) {
186+
try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), CHARSET))) {
177187
stream.marshal(object, new PrettyPrintWriter(writer));
178188
writer.close();
179-
logger.info("{}: ZigBee saving key complete.", key);
180189
} catch (Exception e) {
181190
logger.error("{}: Error writing key: ", key, e);
182191
}
@@ -187,4 +196,67 @@ public Object readObject(String key) {
187196
return null;
188197
}
189198

199+
@Override
200+
public boolean writeBackup(ZigBeeNetworkBackupDao backup) {
201+
XStream stream = openStream();
202+
File file = getFile(backup.getUuid());
203+
204+
try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), CHARSET))) {
205+
stream.marshal(backup, new PrettyPrintWriter(writer));
206+
writer.close();
207+
} catch (Exception e) {
208+
logger.error("{}: Error writing network backup: ", backup.getUuid(), e);
209+
return false;
210+
}
211+
212+
return true;
213+
}
214+
215+
@Override
216+
public ZigBeeNetworkBackupDao readBackup(UUID uuid) {
217+
XStream stream = openStream();
218+
File file = getFile(uuid);
219+
220+
ZigBeeNetworkBackupDao backup = null;
221+
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), CHARSET))) {
222+
backup = (ZigBeeNetworkBackupDao) stream.fromXML(reader);
223+
reader.close();
224+
} catch (Exception e) {
225+
logger.error("{}: Error reading network backup: ", uuid, e);
226+
}
227+
228+
return backup;
229+
}
230+
231+
@Override
232+
public Set<ZigBeeNetworkBackupDao> listBackups() {
233+
Set<ZigBeeNetworkBackupDao> backups = new HashSet<>();
234+
File dir = new File(DATABASE + BACKUP);
235+
File[] files = dir.listFiles();
236+
237+
if (files == null) {
238+
return backups;
239+
}
240+
241+
for (File file : files) {
242+
if (!file.getName().toLowerCase().endsWith(".xml")) {
243+
continue;
244+
}
245+
246+
try {
247+
String filename = file.getName();
248+
UUID uuid = UUID.fromString(filename.substring(0, filename.length() - 4));
249+
ZigBeeNetworkBackupDao backup = readBackup(uuid);
250+
for (ZigBeeNodeDao node : backup.getNodes()) {
251+
node.setEndpoints(null);
252+
node.setBindingTable(null);
253+
}
254+
backups.add(backup);
255+
} catch (IllegalArgumentException e) {
256+
logger.error("Error parsing database filename: {}", file.getName());
257+
}
258+
}
259+
260+
return backups;
261+
}
190262
}

com.zsmartsystems.zigbee.console/src/main/java/com/zsmartsystems/zigbee/console/ZigBeeConsoleLinkKeyCommand.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public String getCommand() {
2828

2929
@Override
3030
public String getDescription() {
31-
return "Sets the link key int the dongle, optionally computing the MMO Hash from the join code";
31+
return "Sets the link key in the dongle, optionally computing the MMO Hash from the join code";
3232
}
3333

3434
@Override

0 commit comments

Comments
 (0)