我正在开发一个应用程序,该应用程序读取XML文件并根据XML中的详细信息创建哈希ID。截至目前,一切工作正常,能够获得List<String>
。
我想使用Smallrye Mutiny
将此应用程序转换为Reactive Streams
,所以我浏览了一些文档,但不清楚如何将此应用软件转换为Reactive Streams
,这样我就不必等待所有XML文件完成才能返回List<String>
。相反,我可以在生成Multi<String>
时开始返回它。
以下是我正在使用SAX Parser创建Hash ID:读取的简单XML
<customerList>
<customer>
<name>Batman</name>
<age>25</age>
</customer>
<customer>
<name>Superman</name>
<age>28</age>
</customer>
</customerList>
以下是将调用SaxHandler
:的主应用程序
public Multi<String> xmlEventHashGenerator(final InputStream xmlStream) throws SAXException, ParserConfigurationException, IOException {
final SAXParserFactory factory = SAXParserFactory.newInstance();
final SaxHandler saxHandler = new SaxHandler();
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
factory.newSAXParser().parse(xmlStream, saxHandler);
return Multi.createFrom().emitter(em ->{
saxHandler.getRootNodes().forEach(contextNode -> {
final String preHashString = contextNode.toString();
try {
final StringBuilder hashId = new StringBuilder();
MessageDigest.getInstance("SHA-256").digest(preHashString.getBytes(StandardCharsets.UTF_8));
hashId.append(DatatypeConverter.printHexBinary(digest).toLowerCase());
em.emit(hashId.toString());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
});
em.complete();
});
}
以下是SaxHandler
,它将读取XML并创建HashID:
public class SaxHandler extends DefaultHandler {
@Getter
private final List<String> eventHashIds = new ArrayList<>();
@Getter
private final List<ContextNode> rootNodes = new ArrayList<>();
private final HashMap<String, String> contextHeader = new HashMap<>();
private final String hashAlgorithm;
private ContextNode currentNode = null;
private ContextNode rootNode = null;
private final StringBuilder currentValue = new StringBuilder();
public SaxHandler(final String hashAlgorithm) {
this.hashAlgorithm = hashAlgorithm;
}
@Override
public void startElement(final String uri, final String localName, final String qName, final Attributes attributes) {
if (rootNode == null && qName.equals("customer")) {
rootNode = new ContextNode(contextHeader);
currentNode = rootNode;
rootNode.children.add(new ContextNode(rootNode, "type", qName));
}else if (currentNode != null) {
ContextNode n = new ContextNode(currentNode, qName, (String) null);
currentNode.children.add(n);
currentNode = n;
}
}
@Override
public void characters(char[] ch, int start, int length) {
currentValue.append(ch, start, length);
}
@Override
public void endElement(final String uri, final String localName, final String qName) {
if (rootNode != null && !qName.equals("customer")) {
final String value = !currentValue.toString().trim().equals("") ? currentValue.toString().trim() : null;
currentNode.children.add(new ContextNode(currentNode, qName, value));
}
if (qName.equals("customer")) {
rootNodes.add(rootNode);
rootNode = null;
}
currentValue.setLength(0);
}
}
以下是Test
:
@Test
public void xmlTest() throws Exception {
final HashGenerator eventHashGenerator = new HashGenerator();
final InputStream xmlStream = getClass().getResourceAsStream("/customer.xml");
final List<String> eventHashIds = eventHashGenerator.xmlHashGenerator(xmlStream, "sha3-256");
System.out.println("nGenerated Event Hash Ids : n" + eventHashIds);
}
有人能给我举一些例子,或者提供一些如何将这个应用程序转换为基于SmallRye Mutinty Multi<String>
的应用程序的想法吗?
我认为您可以将xmlEventHashGenerator
重构为
public Multi<String> xmlEventHashGenerator(final InputStream xmlStream) throws SAXException, ParserConfigurationException, IOException {
final SAXParserFactory factory = SAXParserFactory.newInstance();
final SaxHandler saxHandler = new SaxHandler();
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
factory.newSAXParser().parse(xmlStream, saxHandler);
return Multi.createFrom()
.iterable( saxHandler.getRootNodes() )
.map( RootNode::toString )
.map( this::convertDatatype );
}
private String convertDatatype(String preHashString) {
try {
// I think we could create the MessageDigest instance only once
byte[] digest = MessageDigest.getInstance( "SHA-256" )
.digest( preHashString.getBytes( StandardCharsets.UTF_8 ) );
return DatatypeConverter.printHexBinary( digest ).toLowerCase();
}
catch (NoSuchAlgorithmException e) {
throw new IllegalArgumentException( e );
}
}
测试方法看起来像:
@Test
public void xmlTest() throws Exception {
final HashGenerator eventHashGenerator = new HashGenerator();
final InputStream xmlStream = getClass().getResourceAsStream("/customer.xml");
System.out.println("Generated Event Hash Ids: ");
eventHashGenerator
.xmlHashGenerator(xmlStream)
// Print all the hash codes
.invoke( hash -> System.out.println( hash )
.await().indefinitely();
}
但如果你想连接所有的散列码,你可以这样做:
@Test
public void xmlTest() throws Exception {
final HashGenerator eventHashGenerator = new HashGenerator();
final InputStream xmlStream = getClass()
.getResourceAsStream("/customer.xml");
String hash = eventHashGenerator
.xmlHashGenerator(xmlStream)
// Concatenate all the results
.collect().with( Collectors.joining() );
// Print the hashcode
.invoke( hashcode -> System.out.println("nGenerated Event Hash Ids : n" + hashcode) )
.await().indefinitely();
}