Added JAXB; Added XmlProcessor; Added FailureAnswerGenerator functionality
This commit is contained in:
parent
62e60dd909
commit
590baeba97
10 changed files with 377 additions and 3 deletions
29
pom.xml
29
pom.xml
|
|
@ -37,12 +37,39 @@
|
||||||
<artifactId>jcc</artifactId>
|
<artifactId>jcc</artifactId>
|
||||||
<version>12.1.0.0</version>
|
<version>12.1.0.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.projectlombok</groupId>
|
<groupId>org.projectlombok</groupId>
|
||||||
<artifactId>lombok</artifactId>
|
<artifactId>lombok</artifactId>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.commons</groupId>
|
||||||
|
<artifactId>commons-lang3</artifactId>
|
||||||
|
<version>3.17.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-io</groupId>
|
||||||
|
<artifactId>commons-io</artifactId>
|
||||||
|
<version>2.18.0</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- JAXB API -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>jakarta.xml.bind</groupId>
|
||||||
|
<artifactId>jakarta.xml.bind-api</artifactId>
|
||||||
|
<version>4.0.2</version>
|
||||||
|
</dependency>
|
||||||
|
<!--JAXB runtime implementation: eclipse moxy-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.persistence</groupId>
|
||||||
|
<artifactId>org.eclipse.persistence.moxy</artifactId>
|
||||||
|
<version>4.0.2</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- Activation dependency needed for JAXB -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.sun.activation</groupId>
|
||||||
|
<artifactId>jakarta.activation</artifactId>
|
||||||
|
<version>2.0.1</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-test</artifactId>
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
package ru.nbch.credit_tracker.entities.response.errors;
|
||||||
|
|
||||||
|
import jakarta.xml.bind.annotation.*;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@XmlAccessorType(XmlAccessType.FIELD)
|
||||||
|
@XmlType(name = "MonitoringErrorResponse", propOrder = {
|
||||||
|
"status",
|
||||||
|
"errorCode",
|
||||||
|
"errorText"
|
||||||
|
})
|
||||||
|
@XmlRootElement(name = "MonitoringErrorResponse")
|
||||||
|
public class MonitoringError {
|
||||||
|
|
||||||
|
@XmlElement(name = "Status", required = true)
|
||||||
|
protected String status;
|
||||||
|
@XmlElement(name = "ErrorCode",required = true)
|
||||||
|
protected String errorCode;
|
||||||
|
@XmlElement(name = "ErrorText",required = true)
|
||||||
|
protected String errorText;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,13 +1,55 @@
|
||||||
package ru.nbch.credit_tracker.service;
|
package ru.nbch.credit_tracker.service;
|
||||||
|
|
||||||
|
import jakarta.xml.bind.JAXBException;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
import org.springframework.stereotype.Service;
|
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.enums.SignalError;
|
||||||
|
import ru.nbch.credit_tracker.service.xml.IXmlProcessor;
|
||||||
|
import ru.nbch.credit_tracker.service.xml.XmlUtilService;
|
||||||
|
|
||||||
// TODO generate xml error file (mb return path ?)
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
public class FailureAnswerGenerator {
|
public class FailureAnswerGenerator {
|
||||||
|
private static final String ANSWER_PATH = "temp_failure_response";
|
||||||
|
private final XmlUtilService xmlUtilService;
|
||||||
|
|
||||||
|
public FailureAnswerGenerator(XmlUtilService xmlUtilService) {
|
||||||
|
this.xmlUtilService = xmlUtilService;
|
||||||
|
}
|
||||||
|
|
||||||
public String generateFailureAnswer(SignalError error) {
|
public String generateFailureAnswer(SignalError error) {
|
||||||
return error.getCode() + ": " + error.getMessage();
|
try {
|
||||||
|
File tempFolder = new File(ANSWER_PATH);
|
||||||
|
if (!tempFolder.exists()) {
|
||||||
|
tempFolder.mkdir();
|
||||||
|
}
|
||||||
|
String answerPath = ANSWER_PATH + File.separator + UUID.randomUUID() + File.separator + "error_reply.xml";
|
||||||
|
|
||||||
|
IXmlProcessor xmlProcessor = xmlUtilService.createJaxbProcessor();
|
||||||
|
String errorMessage = xmlProcessor.asString(createErrorMessage(error), false);
|
||||||
|
FileUtils.writeStringToFile(new File(answerPath), errorMessage, Charset.forName("windows-1251"));
|
||||||
|
|
||||||
|
return answerPath;
|
||||||
|
} catch (IOException | JAXBException e) {
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO think about common error class
|
||||||
|
private MonitoringError createErrorMessage(SignalError error) {
|
||||||
|
MonitoringError errorMessage = new MonitoringError();
|
||||||
|
errorMessage.setStatus("error");
|
||||||
|
errorMessage.setErrorCode(error.getCode());
|
||||||
|
errorMessage.setErrorText(error.getMessage());
|
||||||
|
return errorMessage;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
package ru.nbch.credit_tracker.service.xml;
|
||||||
|
|
||||||
|
public interface IXmlProcessor {
|
||||||
|
String asString(Object xmlObj, boolean useStandalone);
|
||||||
|
|
||||||
|
void write(String path, Object xmlObj, boolean useStandalone);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
package ru.nbch.credit_tracker.service.xml;
|
||||||
|
|
||||||
|
import jakarta.xml.bind.JAXBContext;
|
||||||
|
import jakarta.xml.bind.JAXBException;
|
||||||
|
import org.eclipse.persistence.jaxb.JAXBContextFactory;
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
public class XmlProcessorImplAnyClasses extends XmlProcessorImplBase {
|
||||||
|
private final JAXBContext context;
|
||||||
|
|
||||||
|
public XmlProcessorImplAnyClasses(Charset charset, Class<?>... classes) throws JAXBException {
|
||||||
|
super(charset.name());
|
||||||
|
this.context = JAXBContextFactory.createContext(classes, new HashMap<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected JAXBContext getContextByClass(Class<?> clazz) throws JAXBException {
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,76 @@
|
||||||
|
package ru.nbch.credit_tracker.service.xml;
|
||||||
|
|
||||||
|
import jakarta.xml.bind.JAXBContext;
|
||||||
|
import jakarta.xml.bind.JAXBException;
|
||||||
|
import jakarta.xml.bind.Marshaller;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.eclipse.persistence.jaxb.MarshallerProperties;
|
||||||
|
import ru.nbch.credit_tracker.utils.EscapeHandlerUtil;
|
||||||
|
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public abstract class XmlProcessorImplBase implements IXmlProcessor {
|
||||||
|
protected String charsetName;
|
||||||
|
|
||||||
|
public XmlProcessorImplBase() {
|
||||||
|
this.charsetName = "windows-1251";
|
||||||
|
}
|
||||||
|
|
||||||
|
public XmlProcessorImplBase(String charsetName) {
|
||||||
|
this();
|
||||||
|
this.charsetName = charsetName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String asString(Object xmlObj, boolean useStandalone) {
|
||||||
|
try {
|
||||||
|
StringWriter strWriter = new StringWriter();
|
||||||
|
if (useStandalone) {
|
||||||
|
strWriter.write("<?xml version=\"1.0\" encoding=\"%s\" standalone=\"yes\"?>\n".formatted(charsetName));
|
||||||
|
}
|
||||||
|
genMarshaller(xmlObj, useStandalone).marshal(xmlObj, strWriter);
|
||||||
|
return strWriter.toString();
|
||||||
|
} catch (Throwable e) {
|
||||||
|
log.error("Error serializing object to XML string: {}", e.getMessage());
|
||||||
|
throw new IllegalStateException("cannot serialize object to XML");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(String path, Object xmlObj, boolean useStandalone) {
|
||||||
|
try (OutputStream os = new FileOutputStream(path)) {
|
||||||
|
if (useStandalone) {
|
||||||
|
os.write("<?xml version=\"1.0\" encoding=\"%s\" standalone=\"yes\"?>\n".formatted(charsetName).getBytes(charsetName));
|
||||||
|
}
|
||||||
|
genMarshaller(xmlObj, useStandalone).marshal(xmlObj, os);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
log.error("Error serializing object to XML string: {}", e.getMessage(), e);
|
||||||
|
throw new IllegalStateException("cannot serialize object to XML");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Marshaller genMarshaller(Object obj, boolean useStandalone) throws JAXBException {
|
||||||
|
Marshaller marshaller = getContextByObject(obj).createMarshaller();
|
||||||
|
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
|
||||||
|
marshaller.setProperty(Marshaller.JAXB_ENCODING, charsetName);
|
||||||
|
if (useStandalone) {
|
||||||
|
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
|
||||||
|
} else {
|
||||||
|
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.FALSE);
|
||||||
|
}
|
||||||
|
marshaller.setProperty(MarshallerProperties.CHARACTER_ESCAPE_HANDLER, EscapeHandlerUtil.createEscapeHandler(marshaller));
|
||||||
|
marshaller.setProperty(MarshallerProperties.INDENT_STRING, " ");
|
||||||
|
return marshaller;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected JAXBContext getContextByObject(Object obj) throws JAXBException {
|
||||||
|
Class<?> aClass = obj.getClass();
|
||||||
|
return getContextByClass(aClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract JAXBContext getContextByClass(Class<?> clazz) throws JAXBException;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
package ru.nbch.credit_tracker.service.xml;
|
||||||
|
|
||||||
|
import jakarta.xml.bind.JAXBException;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import ru.nbch.credit_tracker.entities.response.errors.MonitoringError;
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class XmlUtilService {
|
||||||
|
|
||||||
|
public IXmlProcessor createJaxbProcessor() throws JAXBException {
|
||||||
|
return new XmlProcessorImplAnyClasses(Charset.forName("windows-1251"),
|
||||||
|
MonitoringError.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
package ru.nbch.credit_tracker.utils;
|
||||||
|
|
||||||
|
import org.eclipse.persistence.oxm.CharacterEscapeHandler;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Writer;
|
||||||
|
|
||||||
|
public class DumbEscapeHandler implements CharacterEscapeHandler {
|
||||||
|
public static final CharacterEscapeHandler theInstance = new DumbEscapeHandler();
|
||||||
|
|
||||||
|
private DumbEscapeHandler() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void escape(char[] ch, int start, int length, boolean isAttVal, Writer out) throws IOException {
|
||||||
|
int limit = start + length;
|
||||||
|
|
||||||
|
for (int i = start; i < limit; ++i) {
|
||||||
|
switch (ch[i]) {
|
||||||
|
case '"':
|
||||||
|
if (isAttVal) {
|
||||||
|
out.write(""");
|
||||||
|
} else {
|
||||||
|
out.write(34);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '&':
|
||||||
|
out.write("&");
|
||||||
|
break;
|
||||||
|
case '<':
|
||||||
|
out.write("<");
|
||||||
|
break;
|
||||||
|
case '>':
|
||||||
|
out.write(">");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (ch[i] > 127) {
|
||||||
|
out.write("&#");
|
||||||
|
out.write(Integer.toString(ch[i]));
|
||||||
|
out.write(59);
|
||||||
|
} else {
|
||||||
|
out.write(ch[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
package ru.nbch.credit_tracker.utils;
|
||||||
|
|
||||||
|
|
||||||
|
import jakarta.xml.bind.Marshaller;
|
||||||
|
import jakarta.xml.bind.PropertyException;
|
||||||
|
import org.eclipse.persistence.internal.oxm.record.CharacterEscapeHandlerWrapper;
|
||||||
|
import org.eclipse.persistence.jaxb.MarshallerProperties;
|
||||||
|
import org.eclipse.persistence.oxm.CharacterEscapeHandler;
|
||||||
|
//!!! was in <artifactId>eclipselink</artifactId> dependency
|
||||||
|
//import org.glassfish.jaxb.core.marshaller.DumbEscapeHandler;
|
||||||
|
//import org.glassfish.jaxb.core.marshaller.MinimumEscapeHandler;
|
||||||
|
|
||||||
|
public class EscapeHandlerUtil {
|
||||||
|
public static CharacterEscapeHandler createEscapeHandler(Marshaller marshaller) throws PropertyException {
|
||||||
|
org.eclipse.persistence.internal.oxm.CharacterEscapeHandler handler = null;
|
||||||
|
String encoding = (String) marshaller.getProperty(Marshaller.JAXB_ENCODING);
|
||||||
|
Object escapeHandler = marshaller.getProperty(MarshallerProperties.CHARACTER_ESCAPE_HANDLER);
|
||||||
|
if (encoding == null) encoding = "UTF-8";
|
||||||
|
try {
|
||||||
|
if (escapeHandler != null) {
|
||||||
|
try {
|
||||||
|
handler = (CharacterEscapeHandler) escapeHandler;
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
handler = new CharacterEscapeHandlerWrapper(escapeHandler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
handler = new NioEscapeHandler(encoding);
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
handler = DumbEscapeHandler.theInstance;
|
||||||
|
}
|
||||||
|
var finalHandler = handler;
|
||||||
|
return (ch, start, length, isAttVal, out) -> {
|
||||||
|
int limit = start + length;
|
||||||
|
int startToWrite = start;
|
||||||
|
int endToWrite;
|
||||||
|
for (int i = start; i < limit; ++i) {
|
||||||
|
if (ch[i] == '<' || ch[i] == '>') {
|
||||||
|
if (i > start) {
|
||||||
|
endToWrite = i;//1;
|
||||||
|
finalHandler.escape(ch, startToWrite, endToWrite - startToWrite, isAttVal, out);
|
||||||
|
startToWrite = i + 1;
|
||||||
|
} else {
|
||||||
|
startToWrite++;
|
||||||
|
}
|
||||||
|
out.write(ch[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (startToWrite < limit) {
|
||||||
|
endToWrite = limit - startToWrite;
|
||||||
|
finalHandler.escape(ch, startToWrite, endToWrite, isAttVal, out);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
package ru.nbch.credit_tracker.utils;
|
||||||
|
|
||||||
|
import org.eclipse.persistence.internal.oxm.CharacterEscapeHandler;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.charset.CharsetEncoder;
|
||||||
|
|
||||||
|
public class NioEscapeHandler implements CharacterEscapeHandler {
|
||||||
|
private final CharsetEncoder encoder;
|
||||||
|
|
||||||
|
public NioEscapeHandler(String charsetName) {
|
||||||
|
this.encoder = Charset.forName(charsetName).newEncoder();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void escape(char[] ch, int start, int length, boolean isAttVal, Writer out) throws IOException {
|
||||||
|
int limit = start + length;
|
||||||
|
|
||||||
|
for(int i = start; i < limit; ++i) {
|
||||||
|
switch (ch[i]) {
|
||||||
|
case '"':
|
||||||
|
if (isAttVal) {
|
||||||
|
out.write(""");
|
||||||
|
} else {
|
||||||
|
out.write(34);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '&':
|
||||||
|
out.write("&");
|
||||||
|
break;
|
||||||
|
case '<':
|
||||||
|
out.write("<");
|
||||||
|
break;
|
||||||
|
case '>':
|
||||||
|
out.write(">");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (this.encoder.canEncode(ch[i])) {
|
||||||
|
out.write(ch[i]);
|
||||||
|
} else {
|
||||||
|
out.write("&#");
|
||||||
|
out.write(Integer.toString(ch[i]));
|
||||||
|
out.write(59);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Loading…
Add table
Reference in a new issue