diff options
author | Antoine A <> | 2024-02-13 07:47:46 +0100 |
---|---|---|
committer | Antoine A <> | 2024-02-13 07:47:46 +0100 |
commit | f83a22f243a315fbc4b4086155c2401845cf334c (patch) | |
tree | af264e686c5fc657fba060e210bdfdb3454cbf72 /ebics | |
parent | 7f84324c0712097513becd7c4675e50d4194833a (diff) | |
download | libeufin-f83a22f243a315fbc4b4086155c2401845cf334c.tar.gz libeufin-f83a22f243a315fbc4b4086155c2401845cf334c.tar.bz2 libeufin-f83a22f243a315fbc4b4086155c2401845cf334c.zip |
Optimize memory usage and performance by using ByteArray when possible and improve logging
Diffstat (limited to 'ebics')
-rw-r--r-- | ebics/src/main/kotlin/Ebics.kt | 10 | ||||
-rw-r--r-- | ebics/src/main/kotlin/EbicsOrderUtil.kt | 4 | ||||
-rw-r--r-- | ebics/src/main/kotlin/XMLUtil.kt | 56 | ||||
-rw-r--r-- | ebics/src/main/kotlin/ebics_h004/EbicsRequest.kt | 9 | ||||
-rw-r--r-- | ebics/src/main/kotlin/ebics_h005/Ebics3Request.kt | 7 | ||||
-rw-r--r-- | ebics/src/test/kotlin/EbicsMessagesTest.kt | 50 | ||||
-rw-r--r-- | ebics/src/test/kotlin/EbicsOrderUtilTest.kt | 4 | ||||
-rw-r--r-- | ebics/src/test/kotlin/XmlUtilTest.kt | 22 |
8 files changed, 68 insertions, 94 deletions
diff --git a/ebics/src/main/kotlin/Ebics.kt b/ebics/src/main/kotlin/Ebics.kt index 406da44c..91a41022 100644 --- a/ebics/src/main/kotlin/Ebics.kt +++ b/ebics/src/main/kotlin/Ebics.kt @@ -310,7 +310,7 @@ class HpbResponseData( fun parseEbicsHpbOrder(orderDataRaw: ByteArray): HpbResponseData { val resp = try { - XMLUtil.convertStringToJaxb<HPBResponseOrderData>(orderDataRaw.toString(Charsets.UTF_8)) + XMLUtil.convertBytesToJaxb<HPBResponseOrderData>(orderDataRaw) } catch (e: Exception) { throw EbicsProtocolError(HttpStatusCode.InternalServerError, "Invalid XML (as HPB response) received from bank") } @@ -331,10 +331,10 @@ fun parseEbicsHpbOrder(orderDataRaw: ByteArray): HpbResponseData { ) } -fun ebics3toInternalRepr(response: String): EbicsResponseContent { +fun ebics3toInternalRepr(response: ByteArray): EbicsResponseContent { // logger.debug("Converting bank resp to internal repr.: $response") val resp: JAXBElement<Ebics3Response> = try { - XMLUtil.convertStringToJaxb(response) + XMLUtil.convertBytesToJaxb(response) } catch (e: Exception) { throw EbicsProtocolError( HttpStatusCode.InternalServerError, @@ -368,9 +368,9 @@ fun ebics3toInternalRepr(response: String): EbicsResponseContent { ) } -fun ebics25toInternalRepr(response: String): EbicsResponseContent { +fun ebics25toInternalRepr(response: ByteArray): EbicsResponseContent { val resp: JAXBElement<EbicsResponse> = try { - XMLUtil.convertStringToJaxb(response) + XMLUtil.convertBytesToJaxb(response) } catch (e: Exception) { throw EbicsProtocolError( HttpStatusCode.InternalServerError, diff --git a/ebics/src/main/kotlin/EbicsOrderUtil.kt b/ebics/src/main/kotlin/EbicsOrderUtil.kt index ef7ed1f7..c056ddde 100644 --- a/ebics/src/main/kotlin/EbicsOrderUtil.kt +++ b/ebics/src/main/kotlin/EbicsOrderUtil.kt @@ -39,12 +39,12 @@ object EbicsOrderUtil { inline fun <reified T> decodeOrderDataXml(encodedOrderData: ByteArray): T { return InflaterInputStream(encodedOrderData.inputStream()).use { val bytes = it.readAllBytes() - XMLUtil.convertStringToJaxb<T>(bytes.toString(Charsets.UTF_8)).value + XMLUtil.convertBytesToJaxb<T>(bytes).value } } inline fun <reified T> encodeOrderDataXml(obj: T): ByteArray { - val bytes = XMLUtil.convertJaxbToString(obj).toByteArray() + val bytes = XMLUtil.convertJaxbToBytes(obj) return DeflaterInputStream(bytes.inputStream()).use { it.readAllBytes() } diff --git a/ebics/src/main/kotlin/XMLUtil.kt b/ebics/src/main/kotlin/XMLUtil.kt index 63dbf35b..5947341a 100644 --- a/ebics/src/main/kotlin/XMLUtil.kt +++ b/ebics/src/main/kotlin/XMLUtil.kt @@ -287,17 +287,17 @@ class XMLUtil private constructor() { * @param xmlString XML body, as read from the POST body. * @return InputStream object, as wanted by the validator. */ - fun validateFromString(xmlString: String): Boolean { - val xmlInputStream: InputStream = ByteArrayInputStream(xmlString.toByteArray()) + fun validateFromBytes(xml: ByteArray): Boolean { + val xmlInputStream: InputStream = ByteArrayInputStream(xml) val xmlSource = StreamSource(xmlInputStream) return validate(xmlSource) } - inline fun <reified T> convertJaxbToString( + inline fun <reified T> convertJaxbToBytes( obj: T, withSchemaLocation: String? = null - ): String { - val sw = StringWriter() + ): ByteArray { + val w = ByteArrayOutputStream() val jc = JAXBContext.newInstance(T::class.java) val m = jc.createMarshaller() m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true) @@ -305,8 +305,8 @@ class XMLUtil private constructor() { m.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, withSchemaLocation) } m.setProperty("com.sun.xml.bind.namespacePrefixMapper", DefaultNamespaces()) - m.marshal(obj, sw) - return sw.toString() + m.marshal(obj, w) + return w.toByteArray() } inline fun <reified T> convertJaxbToDocument( @@ -328,37 +328,31 @@ class XMLUtil private constructor() { } /** - * Convert a XML string to the JAXB representation. + * Convert XML bytes to the JAXB representation. * - * @param documentString the string to convert into JAXB. + * @param documentBytes the bytes to convert into JAXB. * @return the JAXB object reflecting the original XML document. */ - inline fun <reified T> convertStringToJaxb(documentString: String): JAXBElement<T> { + inline fun <reified T> convertBytesToJaxb(documentBytes: ByteArray): JAXBElement<T> { val jc = JAXBContext.newInstance(T::class.java) val u = jc.createUnmarshaller() return u.unmarshal( /* Marshalling the object into the document. */ - StreamSource(StringReader(documentString)), + StreamSource(ByteArrayInputStream(documentBytes)), T::class.java ) } - /** - * Extract String from DOM. - * - * @param document the DOM to extract the string from. - * @return the final String, or null if errors occur. - */ - fun convertDomToString(document: Document): String { + fun convertDomToBytes(document: Document): ByteArray { /* Make Transformer. */ val tf = TransformerFactory.newInstance() val t = tf.newTransformer() - /* Make string writer. */ - val sw = StringWriter() + /* Make bytes writer. */ + val w = ByteArrayOutputStream() /* Extract string. */ - t.transform(DOMSource(document), StreamResult(sw)) - return sw.toString() + t.transform(DOMSource(document), StreamResult(w)) + return w.toByteArray() } /** @@ -391,20 +385,6 @@ class XMLUtil private constructor() { return m.unmarshal(document, finalType) // document "went" into Jaxb } - /** - * Parse string into XML DOM. - * @param xmlString the string to parse. - * @return the DOM representing @a xmlString - */ - fun parseStringIntoDom(xmlString: String): Document { - val factory = DocumentBuilderFactory.newInstance().apply { - isNamespaceAware = true - } - val xmlInputStream = ByteArrayInputStream(xmlString.toByteArray()) - val builder = factory.newDocumentBuilder() - return builder.parse(InputSource(xmlInputStream)) - } - /** Parse [xml] into a XML DOM */ fun parseBytesIntoDom(xml: ByteArray): Document { val factory = DocumentBuilderFactory.newInstance().apply { @@ -415,10 +395,10 @@ class XMLUtil private constructor() { return builder.parse(InputSource(xmlInputStream)) } - fun signEbicsResponse(ebicsResponse: EbicsResponse, privateKey: RSAPrivateCrtKey): String { + fun signEbicsResponse(ebicsResponse: EbicsResponse, privateKey: RSAPrivateCrtKey): ByteArray { val doc = convertJaxbToDocument(ebicsResponse) signEbicsDocument(doc, privateKey) - val signedDoc = XMLUtil.convertDomToString(doc) + val signedDoc = XMLUtil.convertDomToBytes(doc) // logger.debug("response: $signedDoc") return signedDoc } diff --git a/ebics/src/main/kotlin/ebics_h004/EbicsRequest.kt b/ebics/src/main/kotlin/ebics_h004/EbicsRequest.kt index 263fb71a..2b89e963 100644 --- a/ebics/src/main/kotlin/ebics_h004/EbicsRequest.kt +++ b/ebics/src/main/kotlin/ebics_h004/EbicsRequest.kt @@ -286,11 +286,10 @@ class EbicsRequest { } companion object { - fun createForDownloadReceiptPhase( - transactionId: String?, - hostId: String - + transactionId: String, + hostId: String, + success: Boolean ): EbicsRequest { return EbicsRequest().apply { header = Header().apply { @@ -310,7 +309,7 @@ class EbicsRequest { body = Body().apply { transferReceipt = TransferReceipt().apply { authenticate = true - receiptCode = 0 // always true at this point. + receiptCode = if (success) 1 else 0 } } } diff --git a/ebics/src/main/kotlin/ebics_h005/Ebics3Request.kt b/ebics/src/main/kotlin/ebics_h005/Ebics3Request.kt index 54987c8b..ab710690 100644 --- a/ebics/src/main/kotlin/ebics_h005/Ebics3Request.kt +++ b/ebics/src/main/kotlin/ebics_h005/Ebics3Request.kt @@ -368,8 +368,9 @@ class Ebics3Request { companion object { fun createForDownloadReceiptPhase( - transactionId: String?, - hostId: String + transactionId: String, + hostId: String, + success: Boolean ): Ebics3Request { return Ebics3Request().apply { header = Header().apply { @@ -389,7 +390,7 @@ class Ebics3Request { body = Body().apply { transferReceipt = TransferReceipt().apply { authenticate = true - receiptCode = 0 // always true at this point. + receiptCode = if (success) 1 else 0 } } } diff --git a/ebics/src/test/kotlin/EbicsMessagesTest.kt b/ebics/src/test/kotlin/EbicsMessagesTest.kt index 5d0f8f5d..2b8d63ca 100644 --- a/ebics/src/test/kotlin/EbicsMessagesTest.kt +++ b/ebics/src/test/kotlin/EbicsMessagesTest.kt @@ -17,8 +17,6 @@ * <http://www.gnu.org/licenses/> */ -package tech.libeufin.sandbox - import junit.framework.TestCase.assertEquals import org.apache.xml.security.binding.xmldsig.SignatureType import org.junit.Test @@ -43,7 +41,7 @@ class EbicsMessagesTest { fun testImportNonRoot() { val classLoader = ClassLoader.getSystemClassLoader() val ini = classLoader.getResource("ebics_ini_inner_key.xml") - val jaxb = XMLUtil.convertStringToJaxb<SignatureTypes.SignaturePubKeyOrderData>(ini.readText()) + val jaxb = XMLUtil.convertBytesToJaxb<SignatureTypes.SignaturePubKeyOrderData>(ini.readBytes()) assertEquals("A006", jaxb.value.signaturePubKeyInfo.signatureVersion) } @@ -54,7 +52,7 @@ class EbicsMessagesTest { fun testStringToJaxb() { val classLoader = ClassLoader.getSystemClassLoader() val ini = classLoader.getResource("ebics_ini_request_sample.xml") - val jaxb = XMLUtil.convertStringToJaxb<EbicsUnsecuredRequest>(ini.readText()) + val jaxb = XMLUtil.convertBytesToJaxb<EbicsUnsecuredRequest>(ini.readBytes()) println("jaxb loaded") assertEquals( "INI", @@ -74,7 +72,7 @@ class EbicsMessagesTest { } this.versionNumber = listOf(HEVResponse.VersionNumber.create("H004", "02.50")) } - XMLUtil.convertJaxbToString(hevResponseJaxb) + XMLUtil.convertJaxbToBytes(hevResponseJaxb) } /** @@ -84,7 +82,7 @@ class EbicsMessagesTest { fun testDomToJaxb() { val classLoader = ClassLoader.getSystemClassLoader() val ini = classLoader.getResource("ebics_ini_request_sample.xml")!! - val iniDom = XMLUtil.parseStringIntoDom(ini.readText()) + val iniDom = XMLUtil.parseBytesIntoDom(ini.readBytes()) XMLUtil.convertDomToJaxb<EbicsUnsecuredRequest>( EbicsUnsecuredRequest::class.java, iniDom @@ -109,22 +107,22 @@ class EbicsMessagesTest { } } } - val text = XMLUtil.convertJaxbToString(responseXml) - assertTrue(text.isNotEmpty()) + val bytes = XMLUtil.convertJaxbToBytes(responseXml) + assertTrue(bytes.isNotEmpty()) } @Test fun testParseHiaRequestOrderData() { val classLoader = ClassLoader.getSystemClassLoader() - val hia = classLoader.getResource("hia_request_order_data.xml")!!.readText() - XMLUtil.convertStringToJaxb<HIARequestOrderData>(hia) + val hia = classLoader.getResource("hia_request_order_data.xml")!!.readBytes() + XMLUtil.convertBytesToJaxb<HIARequestOrderData>(hia) } @Test fun testHiaLoad() { val classLoader = ClassLoader.getSystemClassLoader() val hia = classLoader.getResource("hia_request.xml")!! - val hiaDom = XMLUtil.parseStringIntoDom(hia.readText()) + val hiaDom = XMLUtil.parseBytesIntoDom(hia.readBytes()) val x: Element = hiaDom.getElementsByTagNameNS( "urn:org:ebics:H004", "OrderDetails" @@ -150,7 +148,7 @@ class EbicsMessagesTest { "ebics_ini_inner_key.xml" ) assertNotNull(file) - XMLUtil.convertStringToJaxb<SignatureTypes.SignaturePubKeyOrderData>(file.readText()) + XMLUtil.convertBytesToJaxb<SignatureTypes.SignaturePubKeyOrderData>(file.readBytes()) } val modulus = jaxbKey.value.signaturePubKeyInfo.pubKeyValue.rsaKeyValue.modulus @@ -161,8 +159,8 @@ class EbicsMessagesTest { @Test fun testLoadIniMessage() { val classLoader = ClassLoader.getSystemClassLoader() - val text = classLoader.getResource("ebics_ini_request_sample.xml")!!.readText() - XMLUtil.convertStringToJaxb<EbicsUnsecuredRequest>(text) + val text = classLoader.getResource("ebics_ini_request_sample.xml")!!.readBytes() + XMLUtil.convertBytesToJaxb<EbicsUnsecuredRequest>(text) } @Test @@ -185,14 +183,14 @@ class EbicsMessagesTest { } } } - print(XMLUtil.convertJaxbToString(response)) + print(XMLUtil.convertJaxbToBytes(response).toString()) } @Test fun testLoadHpb() { val classLoader = ClassLoader.getSystemClassLoader() - val text = classLoader.getResource("hpb_request.xml")!!.readText() - XMLUtil.convertStringToJaxb<EbicsNpkdRequest>(text) + val text = classLoader.getResource("hpb_request.xml")!!.readBytes() + XMLUtil.convertBytesToJaxb<EbicsNpkdRequest>(text) } @Test @@ -248,9 +246,8 @@ class EbicsMessagesTest { } } - val str = XMLUtil.convertJaxbToString(htd) - println(str) - assert(XMLUtil.validateFromString(str)) + val bytes = XMLUtil.convertJaxbToBytes(htd) + assert(XMLUtil.validateFromBytes(bytes)) } @@ -308,9 +305,8 @@ class EbicsMessagesTest { }) } - val str = XMLUtil.convertJaxbToString(hkd) - println(str) - assert(XMLUtil.validateFromString(str)) + val bytes = XMLUtil.convertJaxbToBytes(hkd) + assert(XMLUtil.validateFromBytes(bytes)) } @Test @@ -361,11 +357,11 @@ class EbicsMessagesTest { } } - val str = XMLUtil.convertJaxbToString(ebicsRequestObj) - val doc = XMLUtil.parseStringIntoDom(str) + val str = XMLUtil.convertJaxbToBytes(ebicsRequestObj) + val doc = XMLUtil.parseBytesIntoDom(str) val pair = CryptoUtil.generateRsaKeyPair(1024) XMLUtil.signEbicsDocument(doc, pair.private) - val finalStr = XMLUtil.convertDomToString(doc) - assert(XMLUtil.validateFromString(finalStr)) + val bytes = XMLUtil.convertDomToBytes(doc) + assert(XMLUtil.validateFromBytes(bytes)) } }
\ No newline at end of file diff --git a/ebics/src/test/kotlin/EbicsOrderUtilTest.kt b/ebics/src/test/kotlin/EbicsOrderUtilTest.kt index 05f7f72d..c78da738 100644 --- a/ebics/src/test/kotlin/EbicsOrderUtilTest.kt +++ b/ebics/src/test/kotlin/EbicsOrderUtilTest.kt @@ -302,7 +302,7 @@ class EbicsOrderUtilTest { </Permission> </UserInfo> </HTDResponseOrderData> - """.trimIndent() - XMLUtil.convertStringToJaxb<HTDResponseOrderData>(orderDataXml); + """.trimIndent().toByteArray() + XMLUtil.convertBytesToJaxb<HTDResponseOrderData>(orderDataXml); } }
\ No newline at end of file diff --git a/ebics/src/test/kotlin/XmlUtilTest.kt b/ebics/src/test/kotlin/XmlUtilTest.kt index b8639d7a..93ca8bf2 100644 --- a/ebics/src/test/kotlin/XmlUtilTest.kt +++ b/ebics/src/test/kotlin/XmlUtilTest.kt @@ -37,8 +37,7 @@ class XmlUtilTest { @Test fun deserializeConsecutiveLists() { - - val tmp = XMLUtil.convertStringToJaxb<HTDResponseOrderData>(""" + val tmp = XMLUtil.convertBytesToJaxb<HTDResponseOrderData>(""" <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <HTDResponseOrderData xmlns="urn:org:ebics:H004"> <PartnerInfo> @@ -81,7 +80,7 @@ class XmlUtilTest { <OrderTypes>C54 C53 C52 CCC</OrderTypes> </Permission> </UserInfo> - </HTDResponseOrderData>""".trimIndent() + </HTDResponseOrderData>""".trimIndent().toByteArray() ) println(tmp.value.partnerInfo.orderInfoList[0].description) @@ -90,7 +89,7 @@ class XmlUtilTest { @Test fun exceptionOnConversion() { try { - XMLUtil.convertStringToJaxb<EbicsKeyManagementResponse>("<malformed xml>") + XMLUtil.convertBytesToJaxb<EbicsKeyManagementResponse>("<malformed xml>".toByteArray()) } catch (e: javax.xml.bind.UnmarshalException) { // just ensuring this is the exception println("caught") @@ -115,12 +114,12 @@ class XmlUtilTest { @Test fun basicSigningTest() { - val doc = XMLUtil.parseStringIntoDom(""" + val doc = XMLUtil.parseBytesIntoDom(""" <myMessage xmlns:ebics="urn:org:ebics:H004"> <ebics:AuthSignature /> <foo authenticate="true">Hello World</foo> </myMessage> - """.trimIndent()) + """.trimIndent().toByteArray()) val kpg = KeyPairGenerator.getInstance("RSA") kpg.initialize(2048) val pair = kpg.genKeyPair() @@ -155,10 +154,9 @@ class XmlUtilTest { } val signature = signEbicsResponse(response, pair.private) - val signatureJaxb = XMLUtil.convertStringToJaxb<EbicsResponse>(signature) + val signatureJaxb = XMLUtil.convertBytesToJaxb<EbicsResponse>(signature) assertTrue( - XMLUtil.verifyEbicsDocument( XMLUtil.convertJaxbToDocument(signatureJaxb.value), pair.public @@ -168,13 +166,13 @@ class XmlUtilTest { @Test fun multiAuthSigningTest() { - val doc = XMLUtil.parseStringIntoDom(""" + val doc = XMLUtil.parseBytesIntoDom(""" <myMessage xmlns:ebics="urn:org:ebics:H004"> <ebics:AuthSignature /> <foo authenticate="true">Hello World</foo> <bar authenticate="true">Another one!</bar> </myMessage> - """.trimIndent()) + """.trimIndent().toByteArray()) val kpg = KeyPairGenerator.getInstance("RSA") kpg.initialize(2048) val pair = kpg.genKeyPair() @@ -185,8 +183,8 @@ class XmlUtilTest { @Test fun testRefSignature() { val classLoader = ClassLoader.getSystemClassLoader() - val docText = classLoader.getResourceAsStream("signature1/doc.xml")!!.readAllBytes().toString(Charsets.UTF_8) - val doc = XMLUtil.parseStringIntoDom(docText) + val docText = classLoader.getResourceAsStream("signature1/doc.xml")!!.readAllBytes() + val doc = XMLUtil.parseBytesIntoDom(docText) val keyText = classLoader.getResourceAsStream("signature1/public_key.txt")!!.readAllBytes() val keyBytes = Base64.getDecoder().decode(keyText) val key = CryptoUtil.loadRsaPublicKey(keyBytes) |