Removed FailureAnswerGenerator and SuccessAnswerGenerator; Added staxReader for exceptions handling from nbki service; Minor refactoring

This commit is contained in:
Mikhail Trofimov 2025-06-25 17:16:00 +03:00
parent d85f97a025
commit 16bb8eb723
14 changed files with 397 additions and 195 deletions

View file

@ -0,0 +1,23 @@
package ru.nbch.credit_tracker.entities.response.external_errors;
import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlType;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"name",
"description"
})
public class Error {
@XmlElement(name = "name", required = true)
protected String name;
@XmlElement(name = "description", required = true)
protected String description;
}

View file

@ -0,0 +1,21 @@
package ru.nbch.credit_tracker.entities.response.external_errors;
import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlType;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"memberCode",
"packCode"
})
public class InputParams {
@XmlElement(name = "memberCode", required = true)
protected String memberCode;
}

View file

@ -0,0 +1,21 @@
package ru.nbch.credit_tracker.entities.response.external_errors;
import jakarta.xml.bind.annotation.*;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"inputParams",
"error"
})
@XmlRootElement(name = "SgnlReport")
public class SgnlReport {
@XmlElement(name = "InputParams", required = true)
protected InputParams inputParams;
@XmlElement(name = "Error", required = true)
protected Error error;
}

View file

@ -24,8 +24,6 @@ import ru.nbch.credit_tracker.service.SignalService;
import ru.nbch.credit_tracker.service.indic.PhoneService; import ru.nbch.credit_tracker.service.indic.PhoneService;
import ru.nbch.credit_tracker.service.scoring.AuthorizationService; import ru.nbch.credit_tracker.service.scoring.AuthorizationService;
import ru.nbch.credit_tracker.service.signal.SignalRestService; import ru.nbch.credit_tracker.service.signal.SignalRestService;
import ru.nbch.credit_tracker.service.xml.FailureAnswerGenerator;
import ru.nbch.credit_tracker.service.xml.SuccessAnswerGenerator;
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.XmlUtilService; import ru.nbch.credit_tracker.service.xml.jaxb.XmlUtilService;
import ru.nbch.credit_tracker.utils.CTUtil; import ru.nbch.credit_tracker.utils.CTUtil;
@ -48,8 +46,6 @@ public class SignalFacade {
private final AuthorizationService authorizationService; private final AuthorizationService authorizationService;
private final SignalService signalService; private final SignalService signalService;
private final SignalRestService signalRestService; private final SignalRestService signalRestService;
private final FailureAnswerGenerator failureAnswerGenerator;
private final SuccessAnswerGenerator successAnswerGenerator;
private final XmlUtilService xmlUtilService; private final XmlUtilService xmlUtilService;
private final ExecutorService executor; private final ExecutorService executor;
@ -59,16 +55,12 @@ public class SignalFacade {
AuthorizationService authorizationService, AuthorizationService authorizationService,
SignalService signalService, SignalService signalService,
SignalRestService signalRestService, SignalRestService signalRestService,
FailureAnswerGenerator failureAnswerGenerator,
SuccessAnswerGenerator successAnswerGenerator,
XmlUtilService xmlUtilService, XmlUtilService xmlUtilService,
@Qualifier("executorService") ExecutorService executor) { @Qualifier("executorService") ExecutorService executor) {
this.config = config; this.config = config;
this.authorizationService = authorizationService; this.authorizationService = authorizationService;
this.signalService = signalService; this.signalService = signalService;
this.signalRestService = signalRestService; this.signalRestService = signalRestService;
this.failureAnswerGenerator = failureAnswerGenerator;
this.successAnswerGenerator = successAnswerGenerator;
this.xmlUtilService = xmlUtilService; this.xmlUtilService = xmlUtilService;
this.executor = executor; this.executor = executor;
} }
@ -256,15 +248,6 @@ public class SignalFacade {
file.getOriginalFilename() != null && file.getOriginalFilename().toLowerCase().endsWith(".zip"); file.getOriginalFilename() != null && file.getOriginalFilename().toLowerCase().endsWith(".zip");
} }
private ResponseEntity<Resource> getBadResponse(SignalError error, String tag) {
Resource answer = failureAnswerGenerator.generateFailureAnswer(error, tag);
return ResponseEntity.badRequest().body(answer);
}
private ResponseEntity<Resource> getBadResponse(SignalError error) {
return getBadResponse(error, null);
}
public ResponseEntity<MonitoringActivePackagesResponse> findActivePackages(MonitoringActivePackagesRequest activePackagesRequest) { public ResponseEntity<MonitoringActivePackagesResponse> findActivePackages(MonitoringActivePackagesRequest activePackagesRequest) {
try { try {
AuthorizationService.AuthResult authResult = authorizationService.findAuthInfo(activePackagesRequest.getUserId(), activePackagesRequest.getPassword()); AuthorizationService.AuthResult authResult = authorizationService.findAuthInfo(activePackagesRequest.getUserId(), activePackagesRequest.getPassword());

View file

@ -60,6 +60,10 @@ public class MonitoringService {
for (PackageData packageData : packages) { for (PackageData packageData : packages) {
SgnlOnlineReport onlineReports = signalRestService.getReports(packageData.getUserId().substring(0, 6) + "_" + packageData.getPackageName()); SgnlOnlineReport onlineReports = signalRestService.getReports(packageData.getUserId().substring(0, 6) + "_" + packageData.getPackageName());
if (onlineReports == null) {
continue;
}
List<String> fileNames = onlineReports.getOperationReport().getReports().getReports().stream().map(Report::getFilename) List<String> fileNames = onlineReports.getOperationReport().getReports().getReports().stream().map(Report::getFilename)
.filter(fileName -> CTUtil.parseDateFromReportFileName(fileName) != null).toList(); // TODO оптимизировать .filter(fileName -> CTUtil.parseDateFromReportFileName(fileName) != null).toList(); // TODO оптимизировать

View file

@ -11,18 +11,18 @@ import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap; import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings; import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
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.jaxb.XmlUtilService; import ru.nbch.credit_tracker.service.xml.jaxb.XmlUtilService;
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.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;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.GZIPOutputStream; import java.util.zip.GZIPOutputStream;
@Slf4j @Slf4j
@ -64,13 +64,116 @@ public class SignalRestService {
// good response // good response
return true; return true;
} else if (response.getStatusCode().value() == 200 && response.getBody() != null) { } else if (response.getStatusCode().value() == 200 && response.getBody() != null) {
// bad response StaxXmlProcessor staxXmlProcessor = xmlUtilService.staxXmlProcessor();
log.error("Ошибка при постановке пакета на мониторинг в официальный сервис сигналов: {}", response.getBody()); SgnlReport error = staxXmlProcessor.read(response.getBody(), SgnlReport.class);
if (error.getError().getDescription() != null) {
log.error("Ошибка при постановке пакета на мониторинг в официальный сервис сигналов: {}", error.getError().getDescription());
} else {
log.error("неизвестная ошибка при постановке пакета на мониторинг в официальный сервис сигналов: {}", response.getBody());
}
return false; return false;
} }
return false; return false;
} }
public void deletePackage(String username, String packageName) {
String packCode = username.substring(0, 6) + "_" + packageName;
String url = DELETE_URI + "?packCode=" + packCode;
HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth(authToken);
HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(headers);
ResponseEntity<String> response = restTemplate.exchange(
url,
HttpMethod.GET,
requestEntity,
String.class
);
String answer = response.getBody();
StaxXmlProcessor staxXmlProcessor = xmlUtilService.staxXmlProcessor();
SgnlReport error = staxXmlProcessor.read(answer, SgnlReport.class);
if (error.getError().getDescription() != null) {
log.error("Ошибка при удалении пакета из сервиса НБКИ. packCode={}. Описание: {}", packCode, error.getError().getDescription());
}
}
public SgnlOnlineReport getReports(String packCode) {
String url = GET_REPORTS_URI + "?packCode=" + packCode;
HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth(authToken);
HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(headers);
ResponseEntity<String> response = restTemplate.exchange(
url,
HttpMethod.GET,
requestEntity,
String.class
);
String answer = response.getBody();
StaxXmlProcessor staxXmlProcessor = xmlUtilService.staxXmlProcessor();
SgnlReport error = staxXmlProcessor.read(answer, SgnlReport.class);
if (error.getError().getDescription() != null) {
log.error("Ошибка при получении пакета из сервиса НБКИ. packCode={}. Описание: {}", packCode, error.getError().getDescription());
return null;
}
try {
IXmlProcessor processor = xmlUtilService.createJaxbProcessor();
return processor.read(answer, SgnlOnlineReport.class);
} catch (Exception e) {
log.error("Ошибка при получении пакета из сервиса НБКИ. Код ошибки: {} packCode={}", response.getStatusCode().value(), packCode);
return null;
}
}
public byte[] downloadReport(String reportName) {
String url = DOWNLOAD_REPORT_URI + "?fNameReport=" + reportName;
HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth(authToken);
HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(headers);
ResponseEntity<byte[]> response = restTemplate.exchange(
url,
HttpMethod.GET,
requestEntity,
byte[].class
);
byte[] answer = response.getBody();
if (isXmlError(response.getBody())) {
StaxXmlProcessor staxXmlProcessor = xmlUtilService.staxXmlProcessor();
SgnlReport error = staxXmlProcessor.read(answer, SgnlReport.class);
if (error.getError().getDescription() != null) {
log.error("Ошибка при скачивание отчета. fNameReport={}. Описание: {}", reportName, error.getError().getDescription());
return null;
}
log.error("Неизвестная ошибка при скачивание отчета. fNameReport={}", reportName);
return null;
}
return answer;
}
private String buildToken(String signalsToken, String signalsuser) throws Exception {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] messageDigest = md.digest((signalsuser + "|" + signalsToken).getBytes(StandardCharsets.UTF_8));
String hash = DatatypeConverter.printHexBinary(messageDigest).toLowerCase();
Base64.Encoder encoder = Base64.getEncoder();
return encoder.encodeToString((signalsuser + ":" + hash).getBytes(StandardCharsets.UTF_8));
} catch (Exception e) {
log.error("Error building token", e);
throw new Exception("Error building token", e);
}
}
private Resource compressFile(Signals signals) throws Exception { private Resource compressFile(Signals signals) throws Exception {
IXmlProcessor processor = xmlUtilService.createJaxbProcessor(); IXmlProcessor processor = xmlUtilService.createJaxbProcessor();
String requestData = processor.asString(signals, false); String requestData = processor.asString(signals, false);
@ -88,85 +191,9 @@ public class SignalRestService {
}; };
} }
public void deletePackage(String username, String packageName) { private boolean isXmlError(byte[] data) {
String packCode = username.substring(0, 6) + "_" + packageName; if (data == null || data.length < 10) return false;
String url = DELETE_URI + "?packCode=" + packCode; String start = new String(data, 0, 10).trim();
HttpHeaders headers = new HttpHeaders(); return start.startsWith("<?xml");
headers.setBasicAuth(authToken);
HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(headers);
ResponseEntity<String> response = restTemplate.exchange(
url,
HttpMethod.GET,
requestEntity,
String.class
);
String answer = response.getBody();
if (response.getStatusCode().value() == 200 && answer != null && answer.contains("<Error>")) {
if (answer.contains("<description>")) {
Pattern pattern = Pattern.compile("<description>(.*?)</description>");
Matcher matcher = pattern.matcher(answer);
if (matcher.find()) {
String description = matcher.group(1);
log.error("Ошибка при удалении пакета из сервиса НБКИ. packCode={}. Описание: {}", packCode, description);
}
} else {
log.error("Ошибка при удалении пакета из сервиса НБКИ. packCode={}", packCode);
}
} else if (response.getStatusCode().value() != 200) {
log.error("Ошибка при удалении пакета из сервиса НБКИ. Код ошибки: {} packCode={}", response.getStatusCode().value(), packCode);
}
}
public SgnlOnlineReport getReports(String packCode) {
String url = GET_REPORTS_URI + "?packCode=" + packCode;
HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth(authToken);
HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(headers);
ResponseEntity<SgnlOnlineReport> response = restTemplate.exchange(
url,
HttpMethod.GET,
requestEntity,
SgnlOnlineReport.class
);
// TODO обработка ошибок
return response.getBody();
}
public byte[] downloadReport(String reportName) {
String url = DOWNLOAD_REPORT_URI + "?fNameReport=" + reportName;
HttpHeaders headers = new HttpHeaders();
headers.setBasicAuth(authToken);
HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(headers);
ResponseEntity<byte[]> response = restTemplate.exchange(
url,
HttpMethod.GET,
requestEntity,
byte[].class
);
return response.getBody();
}
private String buildToken(String signalsToken, String signalsuser) throws Exception {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] messageDigest = md.digest((signalsuser + "|" + signalsToken).getBytes(StandardCharsets.UTF_8));
String hash = DatatypeConverter.printHexBinary(messageDigest).toLowerCase();
Base64.Encoder encoder = Base64.getEncoder();
return encoder.encodeToString((signalsuser + ":" + hash).getBytes(StandardCharsets.UTF_8));
} catch (Exception e) {
log.error("Error building token", e);
throw new Exception("Error building token", e);
}
} }
} }

View file

@ -1,53 +0,0 @@
package ru.nbch.credit_tracker.service.xml;
import jakarta.xml.bind.JAXBException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import ru.nbch.credit_tracker.entities.response.errors.MonitoringError;
import ru.nbch.credit_tracker.enums.SignalError;
import ru.nbch.credit_tracker.service.xml.jaxb.IXmlProcessor;
import ru.nbch.credit_tracker.service.xml.jaxb.XmlUtilService;
import java.nio.charset.StandardCharsets;
@Slf4j
@Service
public class FailureAnswerGenerator {
private final XmlUtilService xmlUtilService;
public FailureAnswerGenerator(XmlUtilService xmlUtilService) {
this.xmlUtilService = xmlUtilService;
}
public Resource generateFailureAnswer(SignalError error) {
return generateFailureAnswer(error, null);
}
// TODO extend with common errorResponse class
public Resource generateFailureAnswer(SignalError error, String tag) {
try {
IXmlProcessor xmlProcessor = xmlUtilService.createJaxbProcessor();
String errorMessage = xmlProcessor.asString(createErrorMessage(error, tag), false, StandardCharsets.UTF_8.name());
byte[] xmlBytes = errorMessage.getBytes(StandardCharsets.UTF_8);
return new ByteArrayResource(xmlBytes);
} catch (JAXBException e) {
log.error(e.getMessage(), e);
}
return null;
}
private MonitoringError createErrorMessage(SignalError error, String tag) {
MonitoringError errorMessage = new MonitoringError();
errorMessage.setStatus("error");
errorMessage.setErrorCode(error.getCode());
if (tag != null) {
errorMessage.setErrorText(error.getMessage() + " " + tag);
} else {
errorMessage.setErrorText(error.getMessage());
}
return errorMessage;
}
}

View file

@ -1,41 +0,0 @@
package ru.nbch.credit_tracker.service.xml;
import jakarta.xml.bind.JAXBException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import ru.nbch.credit_tracker.entities.response.success.MonitoringResponse;
import ru.nbch.credit_tracker.service.xml.jaxb.IXmlProcessor;
import ru.nbch.credit_tracker.service.xml.jaxb.XmlUtilService;
import java.nio.charset.StandardCharsets;
@Slf4j
@Service
public class SuccessAnswerGenerator {
private final XmlUtilService xmlUtilService;
public SuccessAnswerGenerator(XmlUtilService xmlUtilService) {
this.xmlUtilService = xmlUtilService;
}
// TODO extend with common successResponse class
public Resource generateSuccessAnswer(Class clazz) {
try {
IXmlProcessor xmlProcessor = xmlUtilService.createJaxbProcessor();
String errorMessage = xmlProcessor.asString(createSuccessMessage(), false, StandardCharsets.UTF_8.name());
byte[] xmlBytes = errorMessage.getBytes(StandardCharsets.UTF_8);
return new ByteArrayResource(xmlBytes);
} catch (JAXBException e) {
log.error(e.getMessage(), e);
}
return null;
}
private MonitoringResponse createSuccessMessage() {
return new MonitoringResponse();
}
}

View file

@ -7,8 +7,13 @@ import ru.nbch.credit_tracker.entities.request.monitoring_request.MonitoringRequ
import ru.nbch.credit_tracker.entities.response.errors.MonitoringError; import ru.nbch.credit_tracker.entities.response.errors.MonitoringError;
import ru.nbch.credit_tracker.entities.response.monitoring_signal_response.MonitoringSignalResponse; import ru.nbch.credit_tracker.entities.response.monitoring_signal_response.MonitoringSignalResponse;
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.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.entities.signal_package.Signals;
import ru.nbch.credit_tracker.service.xml.stax.SgnlReportStatusStaxReader;
import ru.nbch.credit_tracker.service.xml.stax.StaxReader;
import ru.nbch.credit_tracker.service.xml.stax.StaxXmlProcessor;
import ru.nbch.credit_tracker.service.xml.stax.XmlProcessorStaxImpl;
import javax.xml.XMLConstants; import javax.xml.XMLConstants;
import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLInputFactory;
@ -22,6 +27,8 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import static javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI; import static javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI;
@ -33,6 +40,7 @@ public class XmlUtilService {
// unmarshalling classes // unmarshalling classes
MonitoringRequest.class, MonitoringRequest.class,
OnlineDownloadReport.class, OnlineDownloadReport.class,
SgnlOnlineReport.class,
// marshalling classes // marshalling classes
Signals.class, Signals.class,
MonitoringError.class, MonitoringError.class,
@ -40,6 +48,12 @@ public class XmlUtilService {
MonitoringSignalResponse.class); MonitoringSignalResponse.class);
} }
public StaxXmlProcessor staxXmlProcessor() {
List<StaxReader<?>> staxReader = new ArrayList<>();
staxReader.add(new SgnlReportStatusStaxReader());
return new XmlProcessorStaxImpl(staxReader);
}
public void validateXMLByXSD(InputStream xmlStream, String xsdPath) throws IOException, XMLStreamException, SAXException { public void validateXMLByXSD(InputStream xmlStream, String xsdPath) throws IOException, XMLStreamException, SAXException {
SchemaFactory sf = SchemaFactory.newInstance(W3C_XML_SCHEMA_NS_URI); SchemaFactory sf = SchemaFactory.newInstance(W3C_XML_SCHEMA_NS_URI);
Schema schema = sf.newSchema(new File(xsdPath)); Schema schema = sf.newSchema(new File(xsdPath));

View file

@ -0,0 +1,77 @@
package ru.nbch.credit_tracker.service.xml.stax;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Iterator;
public abstract class BaseStaxReader<T> implements StaxReader<T> {
private final Deque<String> stack = new ArrayDeque<>();
protected final StringBuilder buffer = new StringBuilder();
protected abstract T createObject();
@Override
public T read(XMLStreamReader reader) throws XMLStreamException {
T obj = createObject();
while (reader.hasNext()) {
boolean breakExecution = false;
int ev = reader.next();
switch (ev) {
case XMLStreamConstants.START_ELEMENT -> {
buffer.setLength(0);
startElement(reader.getLocalName());
}
case XMLStreamConstants.CHARACTERS -> {
String text = reader.getText().trim();
if (!text.isEmpty()) buffer.append(text);
}
case XMLStreamConstants.END_ELEMENT -> {
breakExecution = innerProcess(reader, obj);
endElement();
}
default -> {}
}
if (breakExecution) break;
}
return obj;
}
protected abstract boolean innerProcess(XMLStreamReader reader, T obj) throws XMLStreamException;
public void startElement(String localName) {
localName = substringAfterColon(localName);
stack.push(localName);
}
public void endElement() {
if (!stack.isEmpty()) {
stack.pop();
}
}
public String getPath() {
StringBuilder sb = new StringBuilder();
for (Iterator<String> it = stack.descendingIterator(); it.hasNext(); ) {
String name = it.next();
sb.append('/').append(name);
}
return sb.toString();
}
public static String substringAfterColon(String input) {
if (input == null) {
return null;
}
int idx = input.indexOf(':');
if (idx == -1) {
return input;
}
if (idx == input.length() - 1) {
return "";
}
return input.substring(idx + 1);
}
}

View file

@ -0,0 +1,42 @@
package ru.nbch.credit_tracker.service.xml.stax;
import org.springframework.stereotype.Component;
import ru.nbch.credit_tracker.entities.response.external_errors.Error;
import ru.nbch.credit_tracker.entities.response.external_errors.InputParams;
import ru.nbch.credit_tracker.entities.response.external_errors.SgnlReport;
import javax.xml.stream.XMLStreamReader;
@Component
public class SgnlReportStatusStaxReader extends BaseStaxReader<SgnlReport> {
@Override
public Class<SgnlReport> type() {
return SgnlReport.class;
}
@Override
protected SgnlReport createObject() {
SgnlReport report = new SgnlReport();
InputParams inputParams = new InputParams();
report.setInputParams(inputParams);
Error error = new Error();
report.setError(error);
return report;
}
@Override
protected boolean innerProcess(XMLStreamReader reader, SgnlReport obj) {
String text = buffer.toString();
String currPath = getPath();
switch (currPath) {
case "/SgnlReport/InputParams/memberCode" ->
obj.getInputParams().setMemberCode(text);
case "/SgnlReport/Error/name" ->
obj.getError().setName(text);
case "/SgnlReport/Error/description" ->
obj.getError().setDescription(text);
}
return false;
}
}

View file

@ -0,0 +1,9 @@
package ru.nbch.credit_tracker.service.xml.stax;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
public interface StaxReader<T> {
Class<T> type();
T read(XMLStreamReader xmlStreamReader) throws XMLStreamException;
}

View file

@ -0,0 +1,6 @@
package ru.nbch.credit_tracker.service.xml.stax;
public interface StaxXmlProcessor {
<Z> Z read(String xml, Class<Z> clazz);
<Z> Z read(byte[] xml, Class<Z> clazz);
}

View file

@ -0,0 +1,69 @@
package ru.nbch.credit_tracker.service.xml.stax;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import java.io.ByteArrayInputStream;
import java.io.StringReader;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class XmlProcessorStaxImpl implements StaxXmlProcessor {
private final Logger log = LoggerFactory.getLogger(getClass());
protected XMLInputFactory xmlInputFactory;
protected Map<Class<?>, StaxReader<?>> staxReaders = new HashMap<>();
public XmlProcessorStaxImpl(List<StaxReader<?>> staxReaders) {
this.xmlInputFactory = XMLInputFactory.newInstance();
this.xmlInputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, false); // полностью выключить DOCTYPE Declaration
// или выключить особо опасные возможности (менее строгое ограничение XXE, но достаточное):
this.xmlInputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
this.xmlInputFactory.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, false);
this.xmlInputFactory.setXMLResolver((publicID, systemID, baseURI, namespace) -> {
throw new XMLStreamException("External entities are disabled");
});
staxReaders.forEach(reader -> this.staxReaders.put(reader.type(), reader));
}
public XmlProcessorStaxImpl(StaxReader<?>... staxReaders) {
this(Arrays.asList(staxReaders));
}
@Override
public <Z> Z read(String xml, Class<Z> clazz) {
try {
XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(new StringReader(xml));
@SuppressWarnings("unchecked")
StaxReader<Z> staxProcessor = (StaxReader<Z>) staxReaders.get(clazz);
if (staxProcessor != null) {
return staxProcessor.read(xmlStreamReader);
}
throw new IllegalStateException("no stax reader registered for " + clazz);
} catch (Exception e) {
log.error(ExceptionUtils.getStackTrace(e));
throw new RuntimeException(e);
}
}
@Override
public <Z> Z read(byte[] xml, Class<Z> clazz) {
try {
XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(xml));
@SuppressWarnings("unchecked")
StaxReader<Z> staxProcessor = (StaxReader<Z>) staxReaders.get(clazz);
if (staxProcessor != null) {
return staxProcessor.read(xmlStreamReader);
}
throw new IllegalStateException("no stax reader registered for " + clazz);
} catch (Exception e) {
log.error(ExceptionUtils.getStackTrace(e));
throw new RuntimeException(e);
}
}
}