Skip to content

Commit 9c75314

Browse files
authored
Merge pull request #90 from Julius278/feature/633
SDC-633, adjusted check for xml parser
2 parents 50b0732 + ac9eb17 commit 9c75314

File tree

2 files changed

+136
-87
lines changed

2 files changed

+136
-87
lines changed

src/main/java/net/finmath/smartcontract/product/xml/SDCXMLParser.java

Lines changed: 107 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -28,100 +28,120 @@
2828
*/
2929
public class SDCXMLParser {
3030

31-
private static final Logger logger = LoggerFactory.getLogger(SDCXMLParser.class);
31+
private static final Logger logger = LoggerFactory.getLogger(SDCXMLParser.class);
3232

33-
private SDCXMLParser() {
34-
}
33+
private SDCXMLParser() {
34+
}
3535

36-
public static SmartDerivativeContractDescriptor parse(String sdcxml) throws ParserConfigurationException, IOException, SAXException {
36+
public static SmartDerivativeContractDescriptor parse(String sdcxml) throws ParserConfigurationException, IOException, SAXException {
3737

38-
Smartderivativecontract sdc = unmarshalXml(sdcxml, Smartderivativecontract.class);
38+
Smartderivativecontract sdc = unmarshalXml(sdcxml, Smartderivativecontract.class);
3939

40-
LocalDateTime settlementDateInitial = LocalDateTime.parse(sdc.getSettlement().settlementDateInitial.trim());
40+
LocalDateTime settlementDateInitial = LocalDateTime.parse(sdc.getSettlement().settlementDateInitial.trim());
4141

42-
String uniqueTradeIdentifier = sdc.getUniqueTradeIdentifier().trim();
43-
String dltAddress = sdc.getDltAddress() == null ? "" : sdc.getDltAddress().trim();
44-
String dltTradeId = sdc.getDltTradeId() == null ? "" : sdc.getDltTradeId().trim();
42+
String uniqueTradeIdentifier = sdc.getUniqueTradeIdentifier().trim();
43+
String dltAddress = sdc.getDltAddress() == null ? "" : sdc.getDltAddress().trim();
44+
String dltTradeId = sdc.getDltTradeId() == null ? "" : sdc.getDltTradeId().trim();
4545

4646
/*
4747
Market Data
4848
*/
49-
List<CalibrationDataItem.Spec> marketdataItems = new ArrayList<>();
50-
for(Smartderivativecontract.Settlement.Marketdata.Marketdataitems.Item item : sdc.getSettlement().getMarketdata().getMarketdataitems().getItem()){
51-
String symbol = item.getSymbol().get(0).trim();
52-
String curve = item.getCurve().get(0).trim();
53-
String type = item.getType().get(0).trim();
54-
String tenor = item.getTenor().get(0).trim();
55-
CalibrationDataItem.Spec spec = new CalibrationDataItem.Spec(symbol, curve, type, tenor);
56-
marketdataItems.add(spec);
57-
}
58-
59-
/*
60-
* Counterparties
61-
*/
62-
List<SmartDerivativeContractDescriptor.Party> parties = new ArrayList<>();
63-
Map<String, Double> marginAccountInitialByPartyID = new HashMap<>();
64-
Map<String, Double> penaltyFeeInitialByPartyID = new HashMap<>();
65-
66-
for(Smartderivativecontract.Parties.Party p : sdc.getParties().getParty()){
67-
SmartDerivativeContractDescriptor.Party party = new SmartDerivativeContractDescriptor.Party(
68-
p.getId().trim(),
69-
p.getName().trim(),
70-
null,
71-
p.getAddress().trim()
72-
);
73-
parties.add(party);
74-
marginAccountInitialByPartyID.put(party.getId(), p.getMarginAccount().getValue());
75-
penaltyFeeInitialByPartyID.put(party.getId(), p.getPenaltyFee().getValue());
76-
}
77-
78-
// Receiver party ID
79-
String receiverPartyID = sdc.getReceiverPartyID().trim();
80-
81-
// TODO The parser needs to check that the field receiverPartyID of the SDC matched the field <receiverPartyReference href="party2"/> in the FPML
82-
83-
// TODO Support multiple underlyings
84-
85-
Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new ByteArrayInputStream(sdcxml.getBytes(StandardCharsets.UTF_8)));
86-
document.getDocumentElement().normalize();
87-
88-
Node underlying = document
89-
.getElementsByTagName("underlying")
90-
.item(0)
91-
.getFirstChild();
92-
if (!underlying.getNodeName().equals("dataDocument")) {
93-
underlying = underlying.getNextSibling();
94-
}
95-
Swap swap = (Swap) sdc.getUnderlyings().getUnderlying().getDataDocument().getTrade().get(0).getProduct().getValue();
96-
String currency = swap.getSwapStream().get(0).getCalculationPeriodAmount().getCalculation().getNotionalSchedule().getNotionalStepSchedule().getCurrency().getValue().trim();
97-
98-
String marketDataProvider = sdc.getSettlement().getMarketdata().getProvider().trim();
99-
100-
return new SmartDerivativeContractDescriptor(dltTradeId, dltAddress, uniqueTradeIdentifier, settlementDateInitial, parties, marginAccountInitialByPartyID, penaltyFeeInitialByPartyID, receiverPartyID, underlying, marketdataItems, currency, marketDataProvider);
101-
}
102-
103-
public static <T> T unmarshalXml(String xml, Class<T> t) {
104-
try {
105-
StringReader reader = new StringReader(xml);
106-
JAXBContext jaxbContext = JAXBContext.newInstance(t);
107-
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
108-
return (T) unmarshaller.unmarshal(reader);
109-
} catch (JAXBException e) {
110-
logger.error("unmarshalXml: jaxb error, ", e);
111-
throw new SDCException(ExceptionId.SDC_JAXB_ERROR, e.getMessage(), 400);
112-
}
113-
}
114-
115-
public static <T> String marshalClassToXMLString(T t) {
116-
try {
117-
JAXBContext jaxbContextSettlement = JAXBContext.newInstance(t.getClass());
118-
Marshaller jaxbMarshaller = jaxbContextSettlement.createMarshaller();
119-
StringWriter writer = new StringWriter();
120-
jaxbMarshaller.marshal(t, writer);
121-
return writer.toString();
122-
} catch (JAXBException e) {
123-
logger.error("marshalClassToXMLString: jaxb error, ", e);
124-
throw new SDCException(ExceptionId.SDC_JAXB_ERROR, e.getMessage(), 400);
125-
}
126-
}
49+
List<CalibrationDataItem.Spec> marketdataItems = new ArrayList<>();
50+
for (Smartderivativecontract.Settlement.Marketdata.Marketdataitems.Item item : sdc.getSettlement().getMarketdata().getMarketdataitems().getItem()) {
51+
String symbol = item.getSymbol().get(0).trim();
52+
String curve = item.getCurve().get(0).trim();
53+
String type = item.getType().get(0).trim();
54+
String tenor = item.getTenor().get(0).trim();
55+
CalibrationDataItem.Spec spec = new CalibrationDataItem.Spec(symbol, curve, type, tenor);
56+
marketdataItems.add(spec);
57+
}
58+
59+
/*
60+
* Counterparties
61+
*/
62+
List<SmartDerivativeContractDescriptor.Party> parties = new ArrayList<>();
63+
Map<String, Double> marginAccountInitialByPartyID = new HashMap<>();
64+
Map<String, Double> penaltyFeeInitialByPartyID = new HashMap<>();
65+
66+
for (Smartderivativecontract.Parties.Party p : sdc.getParties().getParty()) {
67+
SmartDerivativeContractDescriptor.Party party = new SmartDerivativeContractDescriptor.Party(
68+
p.getId().trim(),
69+
p.getName().trim(),
70+
null,
71+
p.getAddress().trim()
72+
);
73+
parties.add(party);
74+
marginAccountInitialByPartyID.put(party.getId(), p.getMarginAccount().getValue());
75+
penaltyFeeInitialByPartyID.put(party.getId(), p.getPenaltyFee().getValue());
76+
}
77+
78+
// Receiver party ID
79+
String receiverPartyID = sdc.getReceiverPartyID().trim();
80+
81+
// TODO The parser needs to check that the field receiverPartyID of the SDC matched the field <receiverPartyReference href="party2"/> in the FPML
82+
83+
// TODO Support multiple underlyings
84+
85+
Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new ByteArrayInputStream(sdcxml.getBytes(StandardCharsets.UTF_8)));
86+
document.getDocumentElement().normalize();
87+
88+
Node underlying = document
89+
.getElementsByTagName("underlying")
90+
.item(0)
91+
.getFirstChild();
92+
if (!underlying.getNodeName().contains("dataDocument")) {
93+
underlying = underlying.getNextSibling();
94+
}
95+
Swap swap = (Swap) sdc.getUnderlyings().getUnderlying().getDataDocument().getTrade().get(0).getProduct().getValue();
96+
String currency = swap.getSwapStream().get(0).getCalculationPeriodAmount().getCalculation().getNotionalSchedule().getNotionalStepSchedule().getCurrency().getValue().trim();
97+
98+
String marketDataProvider = sdc.getSettlement().getMarketdata().getProvider().trim();
99+
100+
return new SmartDerivativeContractDescriptor(dltTradeId, dltAddress, uniqueTradeIdentifier, settlementDateInitial, parties, marginAccountInitialByPartyID, penaltyFeeInitialByPartyID, receiverPartyID, underlying, marketdataItems, currency, marketDataProvider);
101+
}
102+
103+
public static <T> T unmarshalXml(String xml, Class<T> t) {
104+
try {
105+
StringReader reader = new StringReader(xml);
106+
JAXBContext jaxbContext = JAXBContext.newInstance(t);
107+
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
108+
return (T) unmarshaller.unmarshal(reader);
109+
} catch (JAXBException e) {
110+
logger.error("unmarshalXml: jaxb error, ", e);
111+
throw new SDCException(ExceptionId.SDC_JAXB_ERROR, e.getMessage(), 400);
112+
}
113+
}
114+
115+
/**
116+
* Generic object-to-XML-string converter for all annotated classes
117+
* @param t object to be converted to an XML string
118+
* @return XML formatted String
119+
* @param <T> generic Type, which has the correct XML bind annotations
120+
*/
121+
public static <T> String marshalClassToXMLString(T t) {
122+
try {
123+
JAXBContext jaxbContextSettlement = JAXBContext.newInstance(t.getClass());
124+
Marshaller jaxbMarshaller = jaxbContextSettlement.createMarshaller();
125+
if (t instanceof Smartderivativecontract)
126+
jaxbMarshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, "uri:sdc smartderivativecontract.xsd");
127+
StringWriter writer = new StringWriter();
128+
jaxbMarshaller.marshal(t, writer);
129+
return writer.toString();
130+
} catch (JAXBException e) {
131+
logger.error("marshalClassToXMLString: jaxb error, ", e);
132+
throw new SDCException(ExceptionId.SDC_JAXB_ERROR, e.getMessage(), 400);
133+
}
134+
}
135+
136+
/**
137+
* this version of an SDC-object-to-XML-string conversion includes text replacements to get rid of XML namespace tags like "fpml:dataDocument"
138+
* @param smartderivativecontract SDC product data object which will be transformed into an XML string
139+
* @return formatted xml string
140+
*/
141+
public static String marshalSDCToXMLString(Smartderivativecontract smartderivativecontract) {
142+
//TODO took over an old implementation, please review
143+
return marshalClassToXMLString(smartderivativecontract)
144+
.replaceAll("<fpml:dataDocument fpmlVersion=\"5-9\">", "<dataDocument fpmlVersion=\"5-9\" xmlns=\"http://www.fpml.org/FpML-5/confirmation\">")
145+
.replaceAll("fpml:", "");
146+
}
127147
}

src/test/java/net/finmath/smartcontract/product/xml/SDCXMLParserTest.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import net.finmath.smartcontract.settlement.Settlement;
1010
import net.finmath.smartcontract.valuation.client.ValuationClient;
1111
import net.finmath.smartcontract.valuation.marketdata.data.MarketDataPoint;
12+
import org.apache.commons.lang3.StringUtils;
1213
import org.junit.jupiter.api.Assertions;
1314
import org.junit.jupiter.api.Test;
1415
import org.w3c.dom.Node;
@@ -115,4 +116,32 @@ void marshalClassToXMLString() {
115116
Assertions.assertTrue(xmlString.contains("</marketData>"));
116117
}
117118

119+
@Test
120+
void marshalSDCToXMLString() throws IOException, ParserConfigurationException, SAXException {
121+
//given
122+
String fpml = new String(SDCXMLParserTest.class.getClassLoader().getResourceAsStream("net.finmath.smartcontract.product.xml/smartderivativecontract.xml").readAllBytes(), StandardCharsets.UTF_8);
123+
Smartderivativecontract sdc = SDCXMLParser.unmarshalXml(fpml, Smartderivativecontract.class);
124+
125+
//when
126+
String xmlString = SDCXMLParser.marshalSDCToXMLString(sdc);
127+
String xmlStringNameSpaceTags = SDCXMLParser.marshalClassToXMLString(sdc);
128+
SmartDerivativeContractDescriptor sdcDescriptor = SDCXMLParser.parse(xmlString);
129+
130+
//then
131+
//xml based
132+
Assertions.assertTrue(xmlStringNameSpaceTags.contains("<fpml:dataDocument fpmlVersion=\"5-9\">"));
133+
Assertions.assertEquals(1, StringUtils.countMatches(xmlStringNameSpaceTags,"<fpml:dataDocument fpmlVersion=\"5-9\">"));
134+
Assertions.assertFalse(xmlString.contains("<fpml:dataDocument fpmlVersion=\"5-9\">"));
135+
Assertions.assertTrue(xmlString.contains("<dataDocument fpmlVersion=\"5-9\" xmlns=\"http://www.fpml.org/FpML-5/confirmation\">"));
136+
Assertions.assertTrue(xmlStringNameSpaceTags.contains("</fpml:"));
137+
Assertions.assertFalse(xmlString.contains("</fpml:"));
138+
139+
//parsed back
140+
Assertions.assertEquals("UTI12345", sdcDescriptor.getUniqueTradeIdentifier());
141+
Assertions.assertEquals("ID-Test123", sdcDescriptor.getDltTradeId());
142+
Assertions.assertEquals("0x000000001", sdcDescriptor.getDltAddress());
143+
Assertions.assertEquals("EUR", sdcDescriptor.getCurrency());
144+
Assertions.assertEquals("internal", sdcDescriptor.getMarketDataProvider());
145+
}
146+
118147
}

0 commit comments

Comments
 (0)