Added SignalsStaxXmlWriter; Write Signals using stax;

This commit is contained in:
Mikhail Trofimov 2025-07-04 18:01:06 +03:00
parent adfd2d4d28
commit ba317986b0
6 changed files with 493 additions and 5 deletions

View file

@ -8,7 +8,6 @@ import ru.nbch.credit_tracker.entities.response.monitoring_signal_response.Monit
import ru.nbch.credit_tracker.entities.response.online_download.OnlineDownloadReport; import ru.nbch.credit_tracker.entities.response.online_download.OnlineDownloadReport;
import ru.nbch.credit_tracker.entities.response.online_report.SgnlOnlineReport; import ru.nbch.credit_tracker.entities.response.online_report.SgnlOnlineReport;
import ru.nbch.credit_tracker.entities.response.success.MonitoringResponse; import ru.nbch.credit_tracker.entities.response.success.MonitoringResponse;
import ru.nbch.credit_tracker.entities.signal_package.Signals;
import ru.nbch.credit_tracker.service.xml.jaxb.IXmlProcessor; import ru.nbch.credit_tracker.service.xml.jaxb.IXmlProcessor;
import ru.nbch.credit_tracker.service.xml.jaxb.XmlProcessorImplAnyClasses; import ru.nbch.credit_tracker.service.xml.jaxb.XmlProcessorImplAnyClasses;
import ru.nbch.credit_tracker.service.xml.stax.*; import ru.nbch.credit_tracker.service.xml.stax.*;
@ -27,7 +26,6 @@ public class XmlConfig {
OnlineDownloadReport.class, OnlineDownloadReport.class,
SgnlOnlineReport.class, SgnlOnlineReport.class,
// marshalling classes // marshalling classes
Signals.class,
MonitoringError.class, MonitoringError.class,
MonitoringResponse.class, MonitoringResponse.class,
MonitoringSignalResponse.class); MonitoringSignalResponse.class);

View file

@ -15,10 +15,10 @@ import ru.nbch.credit_tracker.entities.response.external_errors.SgnlReport;
import ru.nbch.credit_tracker.entities.response.online_report.SgnlOnlineReport; import ru.nbch.credit_tracker.entities.response.online_report.SgnlOnlineReport;
import ru.nbch.credit_tracker.entities.signal_package.Signals; import ru.nbch.credit_tracker.entities.signal_package.Signals;
import ru.nbch.credit_tracker.service.xml.jaxb.IXmlProcessor; import ru.nbch.credit_tracker.service.xml.jaxb.IXmlProcessor;
import ru.nbch.credit_tracker.service.xml.stax.SignalsStaxXmlWriter;
import ru.nbch.credit_tracker.service.xml.stax.StaxXmlProcessor; import ru.nbch.credit_tracker.service.xml.stax.StaxXmlProcessor;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.util.Base64; import java.util.Base64;
@ -172,11 +172,11 @@ public class SignalRestService {
} }
private Resource compressFile(Signals signals) throws Exception { private Resource compressFile(Signals signals) throws Exception {
String requestData = xmlProcessor.asString(signals, false); SignalsStaxXmlWriter signalsStaxXmlWriter = new SignalsStaxXmlWriter("windows-1251");
ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
try (GZIPOutputStream gzipStream = new GZIPOutputStream(byteStream)) { try (GZIPOutputStream gzipStream = new GZIPOutputStream(byteStream)) {
gzipStream.write(requestData.getBytes(Charset.forName("windows-1251"))); signalsStaxXmlWriter.writeWithStax(gzipStream, signals, false);
} }
return new ByteArrayResource(byteStream.toByteArray()) { return new ByteArrayResource(byteStream.toByteArray()) {

View file

@ -0,0 +1,255 @@
package ru.nbch.credit_tracker.service.xml.stax;
import javax.xml.namespace.NamespaceContext;
import javax.xml.namespace.QName;
import javax.xml.stream.Location;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Characters;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import java.io.IOException;
import java.io.Writer;
public class IndentingXMLEventWriter implements XMLEventWriter {
private final XMLEventWriter core;
private String indent = " ";
private final Characters indentEvent = new CharactersImpl() {
public String getData() {
return IndentingXMLEventWriter.this.indent;
}
};
private String newLine;
private final Characters newLineEvent = new CharactersImpl() {
public String getData() {
return IndentingXMLEventWriter.this.newLine;
}
};
private int depth = 0;
private boolean hasText;
private boolean hasEndTag;
public IndentingXMLEventWriter(XMLEventWriter core) {
if (core == null) {
throw new IllegalArgumentException();
} else {
this.core = core;
try {
this.newLine = System.getProperty("line.separator");
} catch (SecurityException var3) {
this.newLine = "\n";
}
}
}
public String getIndent() {
return this.indent;
}
public void setIndent(String indent) {
if (indent == null) {
throw new IllegalArgumentException();
} else {
this.indent = indent;
}
}
public String getNewLine() {
return this.newLine;
}
public void setNewLine(String newLine) {
if (newLine == null) {
throw new IllegalArgumentException();
} else {
this.newLine = newLine;
}
}
public void add(XMLEvent event) throws XMLStreamException {
switch (event.getEventType()) {
case 1:
this.newLine();
this.core.add(event);
this.hasText = false;
this.hasEndTag = false;
++this.depth;
return;
case 2:
--this.depth;
if (!this.hasText && this.hasEndTag) {
this.newLine();
}
this.core.add(event);
this.hasText = false;
this.hasEndTag = true;
return;
case 3:
case 5:
case 11:
if (!this.hasText) {
this.newLine();
}
this.core.add(event);
return;
case 4:
case 6:
case 12:
if (event.asCharacters().isWhiteSpace()) {
return;
}
this.hasText = true;
this.core.add(event);
return;
case 7:
case 9:
case 10:
default:
this.core.add(event);
return;
case 8:
this.core.add(event);
this.flush();
}
}
private void newLine() throws XMLStreamException {
this.core.add(this.newLineEvent);
for (int i = 0; i < this.depth; ++i) {
this.core.add(this.indentEvent);
}
}
public void add(XMLEventReader reader) throws XMLStreamException {
if (reader == null) {
throw new IllegalArgumentException();
} else {
while (reader.hasNext()) {
this.add(reader.nextEvent());
}
}
}
public void close() throws XMLStreamException {
this.core.close();
}
public void flush() throws XMLStreamException {
this.core.flush();
}
public NamespaceContext getNamespaceContext() {
return this.core.getNamespaceContext();
}
public void setNamespaceContext(NamespaceContext context) throws XMLStreamException {
this.core.setNamespaceContext(context);
}
public String getPrefix(String uri) throws XMLStreamException {
return this.core.getPrefix(uri);
}
public void setDefaultNamespace(String uri) throws XMLStreamException {
this.core.setDefaultNamespace(uri);
}
public void setPrefix(String prefix, String uri) throws XMLStreamException {
this.core.setPrefix(prefix, uri);
}
private abstract static class CharactersImpl implements Characters {
private CharactersImpl() {
}
public boolean isWhiteSpace() {
return true;
}
public boolean isCData() {
return false;
}
public boolean isIgnorableWhiteSpace() {
return true;
}
public int getEventType() {
return 4;
}
public Location getLocation() {
return null;
}
public boolean isStartElement() {
return false;
}
public boolean isAttribute() {
return false;
}
public boolean isNamespace() {
return false;
}
public boolean isEndElement() {
return false;
}
public boolean isEntityReference() {
return false;
}
public boolean isProcessingInstruction() {
return false;
}
public boolean isCharacters() {
return true;
}
public boolean isStartDocument() {
return false;
}
public boolean isEndDocument() {
return false;
}
public StartElement asStartElement() {
return null;
}
public EndElement asEndElement() {
return null;
}
public Characters asCharacters() {
return this;
}
public QName getSchemaType() {
return null;
}
public void writeAsEncodedUnicode(Writer writer) throws XMLStreamException {
try {
writer.write(this.getData());
} catch (IOException var3) {
throw new XMLStreamException(var3);
}
}
}
}

View file

@ -0,0 +1,110 @@
package ru.nbch.credit_tracker.service.xml.stax;
import lombok.extern.slf4j.Slf4j;
import ru.nbch.credit_tracker.entities.signal_package.*;
import javax.xml.stream.XMLEventFactory;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLOutputFactory;
import java.io.BufferedOutputStream;
import java.io.OutputStream;
@Slf4j
public class SignalsStaxXmlWriter extends StaxXmlWriter<Signals>{
public SignalsStaxXmlWriter(String charsetName) {
super(charsetName);
}
public void writeWithStax(OutputStream outputStream, Signals signals, boolean useStandalone) {
try (BufferedOutputStream bos = new BufferedOutputStream(outputStream, 4 * 1024 * 1024)) {
XMLOutputFactory output = XMLOutputFactory.newInstance();
XMLEventFactory xmlEventFactory = XMLEventFactory.newInstance();
XMLEventWriter writer = output.createXMLEventWriter(bos, charsetName);
writer = new IndentingXMLEventWriter(writer);
writerWrapper = new WriterWrapper(xmlEventFactory, writer);
if (useStandalone) {
bos.write("<?xml version=\"1.0\" encoding=\"%s\" standalone=\"yes\"?>".formatted(charsetName).getBytes(charsetName));
bos.flush();
} else {
writerWrapper.addStartDocument(charsetName);
}
writerWrapper.addStartElement("Signals");
writerWrapper.addAttribute("online", signals.getOnline());
writerWrapper.addSimplelement("Id", signals.getId());
writeAuth(signals.getAuth());
writeConditions(signals.getConditions());
writerWrapper.addEndElement("Signals");
if (!useStandalone) {
writerWrapper.addEndDocument();
}
writerWrapper.flush();
System.gc();
} catch (Throwable e) {
log.error("Error serializing object to XML string: {}", e.getMessage(), e);
throw new IllegalStateException("cannot serialize object to XML");
}
}
private void writeAuth(Auth auth) throws Exception {
writerWrapper.addStartElement("Auth");
writerWrapper.addSimplelement("User", auth.getUser());
writerWrapper.addEndElement("Auth");
}
private void writeConditions(Conditions conditions) throws Exception {
writerWrapper.addStartElement("Conditions");
writePersons(conditions.getPersons());
writerWrapper.addEndElement("Conditions");
}
private void writePersons(Persons persons) throws Exception {
writerWrapper.addStartElement("Persons");
writerWrapper.writeCollection("p", persons.getPerson(), this::writePerson);
writerWrapper.addEndElement("Persons");
}
private void writePerson(Person person, String name) throws Exception {
if (person == null) {
return;
}
writerWrapper.addStartElement(name);
writerWrapper.addAttribute("uid", person.getUid());
writerWrapper.addAttribute("oksm", person.getOksm());
writerWrapper.addAttribute("s", person.getS());
writerWrapper.addAttribute("n", person.getN());
writerWrapper.addAttribute("m", person.getM());
writerWrapper.addAttribute("d", person.getD());
writerWrapper.addAttribute("pn", person.getPn());
writerWrapper.addAttribute("pd", person.getPd());
writerWrapper.addAttribute("dt", person.getDt());
writerWrapper.addAttribute("ip", person.getIp());
writerWrapper.addAttribute("consentDate", person.getConsentDate());
writerWrapper.addAttribute("consentPurpose", person.getConsentPurpose());
writerWrapper.addAttribute("reportUser", person.getReportUser());
writerWrapper.addAttribute("liability", person.getLiability());
writerWrapper.addAttribute("consentPeriod", person.getConsentPeriod());
writerWrapper.addAttribute("agrDate", person.getAgrDate());
writerWrapper.addAttribute("reportUserRegNum", person.getReportUserRegNum());
writerWrapper.addAttribute("reportUserTaxID", person.getReportUserTaxID());
writerWrapper.addAttribute("consentHash", person.getConsentHash());
writerWrapper.addAttribute("cS", person.getCs());
writerWrapper.addAttribute("consentN", person.getConsentN());
writerWrapper.addAttribute("consentM", person.getConsentM());
writerWrapper.addAttribute("consentBd", person.getConsentBd());
writerWrapper.addAttribute("consentPn", person.getConsentPn());
writerWrapper.addAttribute("consentPd", person.getConsentPd());
writerWrapper.addAttribute("consentDivCode", person.getConsentDivCode());
writerWrapper.addAttribute("consentDt", person.getConsentDt());
writerWrapper.addAttribute("inqPurpose", person.getInqPurpose());
writerWrapper.addEndElement(name);
}
}

View file

@ -0,0 +1,16 @@
package ru.nbch.credit_tracker.service.xml.stax;
import java.io.OutputStream;
public abstract class StaxXmlWriter<T> {
protected final String charsetName;
protected WriterWrapper writerWrapper;
public StaxXmlWriter(String charsetName) {
this.charsetName = charsetName;
}
public abstract void writeWithStax(OutputStream outputStream, T xmlObj, boolean useStandalone);
}

View file

@ -0,0 +1,109 @@
package ru.nbch.credit_tracker.service.xml.stax;
import javax.xml.stream.XMLEventFactory;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.events.XMLEvent;
import java.util.List;
public class WriterWrapper {
private final XMLEventFactory xmlEventFactory;
private final XMLEventWriter writer;
private final int batchSize = 2500;
public WriterWrapper(XMLEventFactory xmlEventFactory, XMLEventWriter writer) {
this.xmlEventFactory = xmlEventFactory;
this.writer = writer;
}
public void flush() throws Exception {
writer.flush();
}
public void addStartDocument(String charsetName, String version, boolean standalone) throws Exception {
writer.add(xmlEventFactory.createStartDocument(charsetName, version, standalone));
}
public void addStartDocument(String charsetName) throws Exception {
writer.add(xmlEventFactory.createStartDocument(charsetName));
}
public void addDTD(String value) throws Exception {
writer.add(xmlEventFactory.createDTD(value));
}
public void addEndDocument() throws Exception {
writer.add(xmlEventFactory.createEndDocument());
}
public void addStartElement(String name) throws Exception {
writer.add(createStartElement(name));
}
public void addEndElement(String name) throws Exception {
writer.add(createEndElement(name));
}
public void addAttribute(String name, String value) throws Exception {
if(value != null) {
writer.add(createAttribute(name, value));
}
}
public void addSimplelement(String name, String value) throws Exception {
if (value == null) {
return;
}
writer.add(createStartElement(name));
writer.add(createCharacters(value));
writer.add(createEndElement(name));
}
public void addCharacters(String value) throws Exception {
if (value == null) {
return;
}
writer.add(createCharacters(value));
}
public <T> void writeCollection(String name, List<T> collection, ObjectWriterAction<T> action) throws Exception {
if (collection == null || collection.isEmpty()) {
return;
}
for (int i = 0; i < collection.size(); i++) {
T obj = collection.get(i);
if (obj != null) {
action.write(obj, name);
}
if (i % batchSize == 0) {
writer.flush();
}
}
}
public void add(XMLEvent event) throws Exception {
writer.add(event);
}
private XMLEvent createCharacters(String text) {
return xmlEventFactory.createCharacters(text);
}
public XMLEvent createStartElement(String name) {
return xmlEventFactory.createStartElement("", "", name);
}
public XMLEvent createEndElement(String name) {
return xmlEventFactory.createEndElement("", "", name);
}
private XMLEvent createAttribute(String name, String value) {
return xmlEventFactory.createAttribute(name, value);
}
public interface ObjectWriterAction<T> {
void write(T obj, String name) throws Exception;
}
}