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>
|
||||
<version>12.1.0.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</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>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<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;
|
||||
|
||||
import jakarta.xml.bind.JAXBException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
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.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
|
||||
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) {
|
||||
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