NhrXMLReader.java
package nl.b3p.brmo.loader.xml;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import nl.b3p.brmo.loader.BrmoFramework;
import nl.b3p.brmo.loader.entity.Bericht;
import nl.b3p.brmo.loader.entity.NhrBericht;
import nl.b3p.brmo.loader.entity.NhrBerichten;
import nl.b3p.brmo.loader.util.BrmoLeegBestandException;
import org.apache.commons.io.input.TeeInputStream;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
* Deze reader splitst een nHR soap response in berichten.
*
* @author Matthijs Laan
* @author mprins
*/
public class NhrXMLReader extends BrmoXMLReader {
public static final String PREFIX_BSN = "nhr.bsn.natPers.";
public static final String PREFIX_NAAM = "nhr.naam.natPers.";
private static final Log LOG = LogFactory.getLog(NhrXMLReader.class);
private static Templates splitTemplates;
private static Transformer t;
private Iterator<NhrBericht> iterator;
private int volgorde = 0;
private String brOrigXML = null;
public NhrXMLReader(InputStream in) throws Exception {
initTemplates();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
in = new TeeInputStream(in, bos, true);
// Split input naar multiple berichten
DOMResult r = new DOMResult();
splitTemplates.newTransformer().transform(new StreamSource(in), r);
JAXBContext jc = JAXBContext.newInstance(NhrBerichten.class, NhrBericht.class, Bericht.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
NhrBerichten b = (NhrBerichten) unmarshaller.unmarshal(new DOMSource(r.getNode()));
if (b == null || b.berichten == null) {
throw new BrmoLeegBestandException("Geen BRMO berichten gevonden in NHR XML");
}
if (!b.berichten.isEmpty()) {
setBestandsDatum(b.berichten.get(0).getDatum());
}
iterator = b.berichten.iterator();
brOrigXML = bos.toString(StandardCharsets.UTF_8);
LOG.debug("Originele nHR xml is: \n" + brOrigXML);
init();
}
private synchronized void initTemplates() throws Exception {
if (splitTemplates == null) {
LOG.info("Initializing NHR split XSL templates...");
Source xsl =
new StreamSource(NhrXMLReader.class.getResourceAsStream("/xsl/nhr-split-3.0.xsl"));
TransformerFactory tf = TransformerFactory.newInstance();
tf.setURIResolver(
(href, base) -> new StreamSource(NhrXMLReader.class.getResourceAsStream("/xsl/" + href)));
NhrXMLReader.splitTemplates = tf.newTemplates(xsl);
t = TransformerFactory.newInstance().newTransformer();
}
}
@Override
public void init() throws Exception {
soort = BrmoFramework.BR_NHR;
}
@Override
public boolean hasNext() throws Exception {
return iterator.hasNext();
}
@Override
public NhrBericht next() throws Exception {
NhrBericht b = iterator.next();
StringWriter sw = new StringWriter();
t.transform(new DOMSource(b.getNode().getFirstChild()), new StreamResult(sw));
// opzoeklijst van bsn en/of volledige naam en hash toevoegen
StringBuilder xml = new StringBuilder(sw.toString());
String bsns = getXML(extractBSN(xml.toString()));
LOG.trace("gevonden bsn en naam sleutels: " + bsns);
// insert bsnhashes voor de laatste node
xml.insert(xml.lastIndexOf("</"), bsns);
b.setBrXml(xml.toString());
// we willen alleen bij het eerst geparsede nhr bericht de originele soap hebben
if (volgorde == 0) {
b.setBrOrgineelXml(brOrigXML);
}
b.setVolgordeNummer(volgorde++);
return b;
}
/**
* maakt een map met bsn,bsnhash.
*
* @param brXml string
* @return hashmap met bsn/naamzonderspaties,bsnhash
*/
public Map<String, String> extractBSN(String brXml) {
Map<String, String> bsnHashes = new HashMap<>();
// LOG.trace("deel bericht xml: "+brXml);
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new InputSource(new StringReader(brXml)));
NodeList nodeList = doc.getElementsByTagNameNS("*", "bsn");
for (int i = 0; i < nodeList.getLength(); i++) {
LOG.debug(
"BSN: "
+ i
+ ": "
+ nodeList.item(i).getNodeName()
+ " - "
+ nodeList.item(i).getTextContent());
bsnHashes.put(
nodeList.item(i).getTextContent(), getHash(nodeList.item(i).getTextContent()));
}
nodeList = doc.getElementsByTagNameNS("*", "volledigeNaam");
String _cleanName;
for (int i = 0; i < nodeList.getLength(); i++) {
if (nodeList.item(i).getParentNode().getLocalName().equals("natuurlijkPersoon")
|| nodeList.item(i).getParentNode().getLocalName().equals("buitenlandseVennootschap")) {
LOG.debug(
"NAAM: "
+ i
+ ": "
+ nodeList.item(i).getNodeName()
+ " - "
+ nodeList.item(i).getTextContent());
_cleanName =
nodeList
.item(i)
.getTextContent()
.replace(" ", "")
.replace("'", "")
.replace(".", "")
.replace(",", "")
// komt in bedrijfsnaam voor 'A/S'
.replace("/", "")
// komt in bedrijfsnaam voor '(Nederland)'
.replace("(", "")
.replace(")", "")
// komt in bedrijfsnaam voor '& Co'
.replace("&", "");
bsnHashes.put(_cleanName, getHash(_cleanName));
}
}
} catch (ParserConfigurationException | SAXException | IOException e) {
LOG.error("Fout tijdens toevoegen bsn hashes", e);
}
return bsnHashes;
}
public String getXML(Map<String, String> map) {
StringBuilder root = new StringBuilder();
if (!map.isEmpty()) {
root.append(
"<cat:bsnhashes xmlns:cat=\"http://schemas.kvk.nl/schemas/hrip/catalogus/2015/02\">");
String type;
for (Map.Entry<String, String> entry : map.entrySet()) {
if (!entry.getKey().isEmpty() && !entry.getValue().isEmpty()) {
root.append("<cat:");
// NB BSN's kunnen met een 0 beginnen, dus niet NumberUtils#isCreatable
// gebruiken
if (NumberUtils.isParsable(entry.getKey())) {
type = PREFIX_BSN;
} else {
type = PREFIX_NAAM;
}
root.append(type)
.append(entry.getKey())
.append(">")
.append(entry.getValue())
.append("</cat:")
.append(type)
.append(entry.getKey())
.append(">");
}
}
root.append("</cat:bsnhashes>");
}
return root.toString();
}
}