Skip to content

Commit

Permalink
CU-86b35ftpj_PW-2113--parsing comments and extracting MT from multi-f…
Browse files Browse the repository at this point in the history
…ormat message (#135)

* CU-86b35ftpj_PW-2113--A-way-to-parse-the-MT-value-from-a-ISO-20022-multi-format-message

* rabbit enhancements

* javadoc enhancements

---------

Co-authored-by: zubri <[email protected]>
  • Loading branch information
ptorres-prowide and zubri authored Dec 19, 2024
1 parent 89fb355 commit 1cfa0a4
Show file tree
Hide file tree
Showing 3 changed files with 450 additions and 36 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Prowide ISO 20022 - CHANGELOG

#### 9.4.8 - SNAPSHOT
* (PW-2113) Added API in the `MxParseUtils` to extract comments from XML string
* (PW-2113) Added API in the `MxParseUtils` to extract the enclosed MT from a multi-format MX message

#### 9.4.7 - August 2024
* (PW-1958) Fixed the `DefaultMxMetadataStrategy` NPE issue when the amount values are null

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,22 @@
import com.prowidesoftware.ProwideException;
import com.prowidesoftware.swift.model.DistinguishedName;
import com.prowidesoftware.swift.model.MxId;
import com.prowidesoftware.swift.model.mt.AbstractMT;
import com.prowidesoftware.swift.utils.SafeXmlUtils;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import javax.xml.bind.*;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.sax.SAXSource;
Expand Down Expand Up @@ -241,4 +249,120 @@ private static Optional<MxId> enrichBusinessService(MxId mxId, final String xml)
public static String makeXmlLenient(String xml) {
return xml != null ? xml.replaceFirst("(?i)<\\?XML", "<?xml") : null;
}

/**
* Parses all comments from the given XML document.
*
* <p>This method uses an {@link XMLStreamReader} to parse the provided XML string
* and extract all comments present in the document. Comments are identified as
* XML elements of type {@link XMLStreamConstants#COMMENT}.
* <p>
* All extracted comments are trimmed before being added to the result list. Meaning they will not contain any
* leading or trailing whitespace.
*
* @param xml the XML document as a {@link String} to parse
* @return a {@link List} of comments extracted from the XML document
* @throws NullPointerException if the {@code xml} is null
* @throws IllegalArgumentException if the {@code xml} is blank or empty
*
* @since 9.4.8
*/
public static List<String> parseComments(final String xml) {
Objects.requireNonNull(xml, "XML to parse must not be null");
Validate.notBlank(xml, "XML to parse must not be a blank string");

List<String> result = new ArrayList<>();

final XMLInputFactory factory = SafeXmlUtils.inputFactory();
try {
XMLStreamReader reader = factory.createXMLStreamReader(new StringReader(MxParseUtils.makeXmlLenient(xml)));

while (reader.hasNext()) {
int event = reader.next();
if (event == XMLStreamConstants.COMMENT) {
String comment = reader.getText();
if (comment != null) {
result.add(comment.trim());
}
}
}
reader.close();
} catch (XMLStreamException e) {
log.log(Level.WARNING, "Error parsing XML comments", e);
}
return result;
}

/**
* Parses comments from the given XML document that start with a specific prefix.
*
* <p>This method uses {@link #parseComments(String)} to extract all comments
* from the XML, filters the comments to include only those that start with the
* specified prefix.
*
* @param xml the XML document as a {@link String} to parse
* @param startWith the prefix to filter comments by, leading whitespaces are ignored
* @return a {@link List} of filtered and cropped comments that start with the given prefix
* @throws NullPointerException if the {@code xml} is null
* @throws IllegalArgumentException if the {@code xml} is blank or empty
*
* @since 9.4.8
*/
public static List<String> parseCommentsStartsWith(final String xml, final String startWith) {
return parseComments(xml).stream()
.filter(c -> c.startsWith(startWith)) // Filter comments that start with the given prefix
.collect(Collectors.toList());
}

/**
* Parses comments from the given XML document that contains a specific string.
*
* <p>This method uses {@link #parseComments(String)} to extract all comments
* from the XML, filters the comments to include only those that contains a specific string.
*
* @param xml the XML document as a {@link String} to parse
* @param contains the content to filter comments by
* @return a {@link List} of filtered and cropped comments that start with the given prefix
* @throws NullPointerException if the {@code xml} is null
* @throws IllegalArgumentException if the {@code xml} is blank or empty
*
* @since 9.4.8
*/
public static List<String> parseCommentsContains(final String xml, final String contains) {
return parseComments(xml).stream()
.filter(c -> c.contains(contains)) // Filter comments that start with the given prefix
.collect(Collectors.toList());
}

/**
* Parses an {@link AbstractMT} message from a multi-format XML message.
*
* <p>This method searches for MT (Message Type) content within the comments
* of the provided XML document. Specifically, it extracts comments that start
* with the prefix "{1:F0", which indicates the presence of an MT message, and
* attempts to parse the first matching comment into an {@link AbstractMT} object.</p>
*
* <p>If an error occurs during parsing or no matching comments are found, the method
* returns an empty {@link Optional}.</p>
*
* @param xml the XML document as a {@link String} containing the multi-format message
* @return an {@link Optional} containing the parsed {@link AbstractMT} if successful;
* otherwise, an empty {@link Optional}
* @throws NullPointerException if the {@code xml} is null
*
* @since 9.4.8
*/
public static Optional<AbstractMT> parseMtFromMultiformatMessage(final String xml) {
List<String> MTs = MxParseUtils.parseCommentsStartsWith(xml, "{1:F0");
if (!MTs.isEmpty()) {
String s = MTs.get(0).replace("^~", "\n");

try {
return Optional.of(AbstractMT.parse(s));
} catch (IOException e) {
log.log(Level.WARNING, "Error extracting AbstractMT from Mx", e);
}
}
return Optional.empty();
}
}
Loading

0 comments on commit 1cfa0a4

Please sign in to comment.