Skip to content

Commit 98a0d0b

Browse files
committed
System Touch
1 parent 7c76ee6 commit 98a0d0b

2 files changed

Lines changed: 160 additions & 0 deletions

File tree

source/Main.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ public Main()
103103

104104
NITRO.BRIDGE.MYSQL_COMPONENT.print(this);
105105

106+
db.N21XmlFallback.replayFallback();
107+
106108
NITRO.BRIDGE.start();
107109
}
108110
}

source/db/N21XmlFallback.java

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@
44
import java.io.FileWriter;
55
import java.time.LocalDate;
66
import java.time.Instant;
7+
import java.util.ArrayList;
8+
import java.util.HashMap;
9+
import java.util.List;
10+
import java.util.Map;
11+
import javax.xml.parsers.DocumentBuilderFactory;
12+
import org.w3c.dom.Element;
13+
import org.w3c.dom.NodeList;
714

815
/**
916
* XML fallback store — appends records to db/fallback/YYYY-MM-DD/N21.xml
@@ -58,4 +65,155 @@ private static String esc(String s)
5865
if (s == null) return "";
5966
return s.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;").replace("\"", "&quot;");
6067
}
68+
69+
// ── Replay on reboot ──────────────────────────────────────────────────────
70+
71+
/**
72+
* Called at startup. Scans every XML fallback file under db/fallback/,
73+
* replays any table=national_finance_ids records into MySQL, then removes
74+
* successfully replayed records from the XML so they are not re-sent.
75+
*/
76+
public static void replayFallback()
77+
{
78+
File root = new File("db/fallback");
79+
if (!root.exists()) return;
80+
81+
for (File dayDir : listDirs(root))
82+
{
83+
File xml = new File(dayDir, "N21.xml");
84+
if (!xml.exists() || xml.length() == 0) continue;
85+
86+
// Close the XML so it is well-formed for parsing
87+
ensureClosed(xml);
88+
89+
List<Element> replayed = new ArrayList<>();
90+
List<Element> remaining = new ArrayList<>();
91+
92+
try
93+
{
94+
org.w3c.dom.Document doc = DocumentBuilderFactory.newInstance()
95+
.newDocumentBuilder().parse(xml);
96+
97+
NodeList records = doc.getElementsByTagName("record");
98+
99+
for (int i = 0; i < records.getLength(); i++)
100+
{
101+
Element rec = (Element) records.item(i);
102+
String table = rec.getAttribute("table");
103+
104+
if ("national_finance_ids".equals(table))
105+
{
106+
national.NationalFinanceID n = fromElement(rec);
107+
boolean ok = tryStore(n);
108+
if (ok) replayed.add(rec); else remaining.add(rec);
109+
}
110+
else
111+
{
112+
remaining.add(rec);
113+
}
114+
}
115+
}
116+
catch (Exception e)
117+
{
118+
System.err.println("[N21XmlFallback] replay parse error: " + e.getMessage());
119+
continue;
120+
}
121+
122+
if (replayed.isEmpty()) continue;
123+
124+
// Rewrite the file keeping only un-replayed records
125+
rewrite(xml, remaining);
126+
127+
System.out.println("[N21XmlFallback] replayed " + replayed.size()
128+
+ " national_finance_ids record(s) from " + xml.getPath());
129+
}
130+
}
131+
132+
// ── replay helpers ────────────────────────────────────────────────────────
133+
134+
private static boolean tryStore(national.NationalFinanceID n)
135+
{
136+
try
137+
{
138+
N21Store.storeNationalFinanceID(n);
139+
// storeNationalFinanceID only falls through to XML on failure;
140+
// if it threw, the catch below will return false.
141+
return true;
142+
}
143+
catch (Exception e)
144+
{
145+
System.err.println("[N21XmlFallback] replay store failed for national_id="
146+
+ n.nationalId + ": " + e.getMessage());
147+
return false;
148+
}
149+
}
150+
151+
private static national.NationalFinanceID fromElement(Element rec)
152+
{
153+
national.NationalFinanceID n = new national.NationalFinanceID();
154+
n.nationalId = parseLong(child(rec, "national_id"));
155+
n.remoteAddress = child(rec, "remote_address");
156+
n.iq = parseInt(child(rec, "iq"));
157+
n.educationLevel = child(rec, "education_level");
158+
n.socialSkills = parseInt(child(rec, "social_skills"));
159+
n.equipment = child(rec, "equipment");
160+
n.trustLevel = parseInt(child(rec, "trust_level"));
161+
n.parentOne = child(rec, "parent_one");
162+
n.parentTwo = child(rec, "parent_two");
163+
n.suspects = child(rec, "suspects");
164+
n.socialSpotting = child(rec, "social_spotting");
165+
n.promissoryNote = parseDouble(child(rec, "promissory_note"));
166+
return n;
167+
}
168+
169+
private static void rewrite(File xml, List<Element> keep)
170+
{
171+
try (FileWriter fw = new FileWriter(xml, false))
172+
{
173+
fw.write("<N21>\n");
174+
for (Element rec : keep)
175+
{
176+
fw.write(" <record table=\"" + rec.getAttribute("table")
177+
+ "\" ts=\"" + rec.getAttribute("ts") + "\">\n");
178+
NodeList children = rec.getChildNodes();
179+
for (int i = 0; i < children.getLength(); i++)
180+
{
181+
if (children.item(i) instanceof Element child)
182+
fw.write(" <" + child.getTagName() + ">"
183+
+ child.getTextContent()
184+
+ "</" + child.getTagName() + ">\n");
185+
}
186+
fw.write(" </record>\n");
187+
}
188+
}
189+
catch (Exception e)
190+
{
191+
System.err.println("[N21XmlFallback] rewrite failed: " + e.getMessage());
192+
}
193+
}
194+
195+
/** Appends </N21> if missing so the file is parseable. */
196+
private static void ensureClosed(File xml)
197+
{
198+
try
199+
{
200+
String content = new String(java.nio.file.Files.readAllBytes(xml.toPath()));
201+
if (!content.trim().endsWith("</N21>"))
202+
{
203+
try (FileWriter fw = new FileWriter(xml, true)) { fw.write("</N21>\n"); }
204+
}
205+
}
206+
catch (Exception ignored) {}
207+
}
208+
209+
private static File[] listDirs(File root)
210+
{
211+
File[] dirs = root.listFiles(File::isDirectory);
212+
return dirs != null ? dirs : new File[0];
213+
}
214+
215+
private static String child(Element e, String tag) { NodeList nl = e.getElementsByTagName(tag); return nl.getLength() > 0 ? nl.item(0).getTextContent().trim() : ""; }
216+
private static long parseLong(String s) { try { return Long.parseLong(s); } catch (Exception e) { return 0L; } }
217+
private static int parseInt(String s) { try { return Integer.parseInt(s); } catch (Exception e) { return 0; } }
218+
private static double parseDouble(String s) { try { return Double.parseDouble(s); } catch (Exception e) { return 0.0; } }
61219
}

0 commit comments

Comments
 (0)