From 81963c98b0719bc9de31ac0bcfd0ce59ce20865a Mon Sep 17 00:00:00 2001 From: alan10fm Date: Thu, 5 Nov 2020 17:38:35 -0600 Subject: [PATCH] Integrating endpoints to support async methods --- README.md | 57 ++++++- build.gradle.kts | 2 +- .../TransactidLibraryJavaDemoApplication.kt | 18 +- .../controller/TransactIdAsyncController.kt | 160 ++++++++++++++++++ .../controller/TransactIdController.kt | 82 ++++++--- .../controller/UtilController.kt | 49 ++++++ .../model/InvoiceRequestUrl.kt | 5 + .../repo/TransactIdRepository.kt | 39 ++--- .../service/TransactIdService.kt | 81 ++++++++- src/main/resources/application.properties | 2 + 10 files changed, 431 insertions(+), 64 deletions(-) create mode 100755 src/main/java/com/netki/transactidlibraryjavademo/controller/TransactIdAsyncController.kt create mode 100755 src/main/java/com/netki/transactidlibraryjavademo/controller/UtilController.kt create mode 100644 src/main/java/com/netki/transactidlibraryjavademo/model/InvoiceRequestUrl.kt diff --git a/README.md b/README.md index 8e8fb46..2f3046c 100755 --- a/README.md +++ b/README.md @@ -52,6 +52,8 @@ Also you can implement your own clients to connect to the API. ## General Usage +## Synchronous flow + ### Initial invoice request Endpoint: `/initial-invoice-request` @@ -97,7 +99,60 @@ Description: `Send a payment binary to this endpoint and receive a paymentAck bi Verb: `POST` Params: - payment: `Binary containing payment` -Response: `Binary containing paymentAck` +Response: `Binary containing paymentAck` + +## Asynchronous flow + +### Initial invoice request + +Endpoint: `/async/initial-invoice-request` +Description: `If you want to test your full flow with getting an invoiceRequest object at your correct endpoint use the POST as described and it will send the binary object to that URL.` +Verb: `POST` +Params: +- url: `URL to post invoiceRequest` +Response: `HttpStatus 202 or error code` + +If you want to change the notificationUrl for the InvoiceRequest that will be sent, you can do it in `TransactIdService.NOTIFICATION_URL` + +### Initial invoice request Encrypted + +Endpoint: `/async/initial-invoice-request-encrypted` +Verb: `POST` +Description: `If you want to test your full flow with getting an invoiceRequest object at your correct endpoint use the POST as described and it will send the binary object to that URL.` +Params: +- url: `URL to post invoice-request` +Response: `HttpStatus 202 or error code` + +If you want to change the notificationUrl for the InvoiceRequest that will be sent, you can do it in `TransactIdService.NOTIFICATION_URL` + +### Invoice request + +Endpoint: `/async/invoice-request` +Description: `This endpoint receives an invoiceRequest binary and gives a 202 in return. Asynchronously you will receive a PaymentRequest binary in your NotificationUrl defined in your invoiceRequest` +Verb: `POST` +Params: +- invoiceRequest: `Binary containing invoiceRequest` +Response: `HttpStatus 202 or error code` + +If you want to change the paymentUrl for the PaymentRequest that will be sent, you can do it in `TransactIdService.PAYMENT_URL` + +### Payment request + +Endpoint: `/async/payment-request` +Description: `This endpoint receives a paymentRequest binary and gives a 202 in return. Asynchronousluy you will receive a Payment binary in your PaymentUrl defined in your paymentRequest.` +Verb: `POST` +Params: +- paymentRequest: `Binary containing paymentRequest` +Response: `HttpStatus 202 or error code` + +### Payment + +Endpoint: `/async/payment` +Description: `Send a payment binary to this endpoint and receive a paymentAck binary in return.` +Verb: `POST` +Params: +- payment: `Binary containing payment` +Response: `Binary containing paymentAck` ### Encryption You can generate EncryptedMessages to test this functionality. Once you start the service you can fetch a set of ECDSA keys to use in your ProtocolMessages. diff --git a/build.gradle.kts b/build.gradle.kts index 728c484..2517754 100755 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -18,7 +18,7 @@ repositories { } dependencies { - implementation("com.netki:transactid:1.0.0-beta2") + implementation("com.netki:transactid:1.0.1-beta2") implementation("org.springframework.boot:spring-boot-starter-web") implementation("com.fasterxml.jackson.module:jackson-module-kotlin") diff --git a/src/main/java/com/netki/transactidlibraryjavademo/TransactidLibraryJavaDemoApplication.kt b/src/main/java/com/netki/transactidlibraryjavademo/TransactidLibraryJavaDemoApplication.kt index b5bedd1..70d18cd 100755 --- a/src/main/java/com/netki/transactidlibraryjavademo/TransactidLibraryJavaDemoApplication.kt +++ b/src/main/java/com/netki/transactidlibraryjavademo/TransactidLibraryJavaDemoApplication.kt @@ -6,14 +6,15 @@ import com.netki.transactidlibraryjavademo.util.KeyGenerator.Keys.generateKeyPai import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.runApplication import org.springframework.context.annotation.Bean -import java.security.AlgorithmParameters -import java.security.KeyPair -import java.security.KeyPairGenerator -import java.security.SecureRandom -import java.security.spec.ECGenParameterSpec -import java.security.spec.ECParameterSpec +import org.springframework.context.annotation.Configuration +import org.springframework.scheduling.annotation.EnableAsync +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor +import java.util.concurrent.Executor + @SpringBootApplication +@Configuration +@EnableAsync class TransactidLibraryJavaDemoApplication { @Bean @@ -27,6 +28,11 @@ class TransactidLibraryJavaDemoApplication { CryptoModule.objectToPublicKeyPem(recipientKeys.public) ) } + + @Bean(name = ["threadPoolTaskExecutor"]) + fun threadPoolTaskExecutor(): Executor { + return ThreadPoolTaskExecutor() + } } fun main(args: Array) { diff --git a/src/main/java/com/netki/transactidlibraryjavademo/controller/TransactIdAsyncController.kt b/src/main/java/com/netki/transactidlibraryjavademo/controller/TransactIdAsyncController.kt new file mode 100755 index 0000000..c1b9caf --- /dev/null +++ b/src/main/java/com/netki/transactidlibraryjavademo/controller/TransactIdAsyncController.kt @@ -0,0 +1,160 @@ +package com.netki.transactidlibraryjavademo.controller + +import com.netki.transactidlibraryjavademo.model.InvoiceRequestUrl +import com.netki.transactidlibraryjavademo.service.TransactIdService +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.tags.Tag +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.http.HttpStatus +import org.springframework.http.MediaType +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestMethod +import org.springframework.web.bind.annotation.RestController + +@RestController +@Tag(name = "TransactId-Async", description = "The TransactId API async") +@RequestMapping("/async") +class TransactIdAsyncController { + + @Autowired + private lateinit var transactIdService: TransactIdService + + @Operation( + summary = "Send invoiceRequest binary", + description = "Send an invoiceRequest binary to an specific URL" + ) + @ApiResponse( + responseCode = "202", + description = "Indicates that the request has been accepted for processing.", + content = [Content()] + ) + @RequestMapping( + method = [RequestMethod.POST], + value = ["/initial-invoice-request"], + produces = [MediaType.APPLICATION_JSON_VALUE], + consumes = [MediaType.APPLICATION_JSON_VALUE] + ) + fun sendInitialInvoiceRequest( + @Parameter(description = "Url where the InvoiceRequest will be send") + @RequestBody invoiceRequestUrl: InvoiceRequestUrl + ): ResponseEntity { + transactIdService.sendInitialInvoiceRequest(invoiceRequestUrl.url) + return ResponseEntity(HttpStatus.ACCEPTED) + } + + @Operation( + summary = "Send invoiceRequest binary encrypted", + description = "Send an invoiceRequest binary encrypted to an specific URL" + ) + @ApiResponse( + responseCode = "202", + description = "Indicates that the request has been accepted for processing.", + content = [Content()] + ) + @RequestMapping( + method = [RequestMethod.POST], + value = ["/initial-invoice-request-encrypted"], + produces = [MediaType.APPLICATION_JSON_VALUE], + consumes = [MediaType.APPLICATION_JSON_VALUE] + ) + fun sendInitialInvoiceRequestEncrypted( + @Parameter(description = "Url where the InvoiceRequest will be send") + @RequestBody invoiceRequestUrl: InvoiceRequestUrl + ): ResponseEntity { + transactIdService.sendInitialInvoiceRequestEncrypted(invoiceRequestUrl.url) + return ResponseEntity(HttpStatus.ACCEPTED) + } + + @Operation( + summary = "Post an invoiceRequest binary with no sync response", + description = "This endpoint receives an invoiceRequest binary and gives a 202 in return. Asynchronous you will receive a PaymentRequest binary in your NotificationUrl defined in your invoiceRequest." + ) + @ApiResponse( + responseCode = "202", + description = "Indicates that the request has been accepted for processing.", + content = [Content()] + ) + @RequestMapping( + method = [RequestMethod.POST], + value = ["/invoice-request"], + consumes = [MediaType.APPLICATION_OCTET_STREAM_VALUE], + produces = [MediaType.APPLICATION_OCTET_STREAM_VALUE] + ) + fun postInvoiceRequest( + @Parameter(description = "Binary containing invoiceRequest") + @RequestBody invoiceRequest: ByteArray + ): ResponseEntity { + return try { + transactIdService.postInvoiceRequestAsync(invoiceRequest) + ResponseEntity(HttpStatus.ACCEPTED) + } catch (exception: Exception) { + ResponseEntity.status(HttpStatus.BAD_REQUEST).body(exception.message) + } + } + + @Operation( + summary = "Post a paymentRequest binary with no sync response.", + description = "This endpoint receives a paymentRequest binary and gives a 202 in return. Asynchronous you will receive a Payment binary in your PaymentUrl defined in your paymentRequest." + ) + @ApiResponse( + responseCode = "202", + description = "Indicates that the request has been accepted for processing.", + content = [Content()] + ) + @RequestMapping( + method = [RequestMethod.POST], + value = ["/payment-request"], + consumes = [MediaType.APPLICATION_OCTET_STREAM_VALUE], + produces = [MediaType.APPLICATION_OCTET_STREAM_VALUE] + ) + + fun postPaymentRequest( + @Parameter(description = "Binary containing paymentRequest") + @RequestBody paymentRequest: ByteArray + ): ResponseEntity { + return try { + transactIdService.postPaymentRequestAsync(paymentRequest) + ResponseEntity(HttpStatus.ACCEPTED) + } catch (exception: Exception) { + ResponseEntity.status(HttpStatus.BAD_REQUEST).body(exception.message) + } + } + + @Operation( + summary = "Post a payment binary", + description = "This endpoint receives a payment binary and gives a paymentAck binary in return." + ) + @ApiResponse( + responseCode = "200", + description = "PaymentAck binary.", + content = [ + Content( + mediaType = MediaType.APPLICATION_OCTET_STREAM_VALUE, + schema = Schema(implementation = ByteArray::class) + ) + ] + ) + @RequestMapping( + method = [RequestMethod.POST], + value = ["/payment"], + consumes = [MediaType.APPLICATION_OCTET_STREAM_VALUE], + produces = [MediaType.APPLICATION_OCTET_STREAM_VALUE] + ) + fun postPayment( + @Parameter(description = "Binary containing payment") + @RequestBody payment: ByteArray + ): ResponseEntity { + return try { + val paymentAck = transactIdService.postPayment(payment) + ResponseEntity.ok(paymentAck) + } catch (exception: Exception) { + ResponseEntity.status(HttpStatus.BAD_REQUEST).body(exception.message) + } + } +} diff --git a/src/main/java/com/netki/transactidlibraryjavademo/controller/TransactIdController.kt b/src/main/java/com/netki/transactidlibraryjavademo/controller/TransactIdController.kt index a685bd4..b0db6f0 100755 --- a/src/main/java/com/netki/transactidlibraryjavademo/controller/TransactIdController.kt +++ b/src/main/java/com/netki/transactidlibraryjavademo/controller/TransactIdController.kt @@ -1,9 +1,11 @@ package com.netki.transactidlibraryjavademo.controller -import com.netki.transactidlibraryjavademo.model.EncryptionKeys import com.netki.transactidlibraryjavademo.service.TransactIdService import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.responses.ApiResponse import io.swagger.v3.oas.annotations.tags.Tag import org.springframework.beans.factory.annotation.Autowired import org.springframework.http.HttpStatus @@ -21,27 +23,25 @@ class TransactIdController { @Autowired private lateinit var transactIdService: TransactIdService - @Operation( - summary = "Get Encryption keys", - description = "Get the set of keys for the sender/recipient, this is needed if you want to generate encrypted messages" - ) - @RequestMapping( - method = [RequestMethod.GET], - value = ["/encryption/keys"], - produces = [MediaType.APPLICATION_JSON_VALUE] - ) - fun getEncryptionKeys(): ResponseEntity = - ResponseEntity.ok(transactIdService.getEncryptionKeys()) - @Operation( summary = "Get invoiceRequest binary", - description = "Request receive back an invoiceRequest binary so that you can test parsing things" + description = "Returns an invoiceRequest binary so that you can start testing your flow" ) @RequestMapping( method = [RequestMethod.GET], value = ["/initial-invoice-request"], produces = [MediaType.APPLICATION_OCTET_STREAM_VALUE] ) + @ApiResponse( + responseCode = "201", + description = "InvoiceRequest binary.", + content = [ + Content( + mediaType = MediaType.APPLICATION_OCTET_STREAM_VALUE, + schema = Schema(implementation = ByteArray::class) + ) + ] + ) fun getInitialInvoiceRequest() = ResponseEntity( transactIdService.getInitialInvoiceRequest(), HttpStatus.CREATED @@ -49,21 +49,31 @@ class TransactIdController { @Operation( summary = "Get invoiceRequest binary encrypted", - description = "Request receive back an invoiceRequest binary encrypted so that you can test parsing things" + description = "Returns an invoiceRequest binary encrypted so that you can start testing your flow" ) @RequestMapping( method = [RequestMethod.GET], value = ["/initial-invoice-request-encrypted"], produces = [MediaType.APPLICATION_OCTET_STREAM_VALUE] ) + @ApiResponse( + responseCode = "201", + description = "InvoiceRequest binary.", + content = [ + Content( + mediaType = MediaType.APPLICATION_OCTET_STREAM_VALUE, + schema = Schema(implementation = ByteArray::class) + ) + ] + ) fun getInitialInvoiceRequestEncrypted() = ResponseEntity( transactIdService.getInitialInvoiceRequestEncrypted(), HttpStatus.CREATED ) @Operation( - summary = "Post invoiceRequest binary", - description = "Send invoiceRequest binary to this endpoint and receive a paymentRequest binary in return." + summary = "Post an invoiceRequest binary", + description = "This endpoint receives an invoiceRequest binary and gives a paymentRequest binary in return." ) @RequestMapping( method = [RequestMethod.POST], @@ -71,6 +81,16 @@ class TransactIdController { consumes = [MediaType.APPLICATION_OCTET_STREAM_VALUE], produces = [MediaType.APPLICATION_OCTET_STREAM_VALUE] ) + @ApiResponse( + responseCode = "200", + description = "PaymentRequest binary.", + content = [ + Content( + mediaType = MediaType.APPLICATION_OCTET_STREAM_VALUE, + schema = Schema(implementation = ByteArray::class) + ) + ] + ) fun postInvoiceRequest( @Parameter(description = "Binary containing invoiceRequest") @RequestBody invoiceRequest: ByteArray @@ -84,8 +104,8 @@ class TransactIdController { } @Operation( - summary = "Post paymentRequest binary", - description = "Send a paymentRequest binary to this endpoint and receive a payment binary in return." + summary = "Post a paymentRequest binary.", + description = "This endpoint receives a paymentRequest binary and gives a payment binary in return." ) @RequestMapping( method = [RequestMethod.POST], @@ -93,6 +113,16 @@ class TransactIdController { consumes = [MediaType.APPLICATION_OCTET_STREAM_VALUE], produces = [MediaType.APPLICATION_OCTET_STREAM_VALUE] ) + @ApiResponse( + responseCode = "200", + description = "Payment binary.", + content = [ + Content( + mediaType = MediaType.APPLICATION_OCTET_STREAM_VALUE, + schema = Schema(implementation = ByteArray::class) + ) + ] + ) fun postPaymentRequest( @Parameter(description = "Binary containing paymentRequest") @RequestBody paymentRequest: ByteArray @@ -106,8 +136,8 @@ class TransactIdController { } @Operation( - summary = "Post payment binary", - description = "Send a payment binary to this endpoint and receive a paymentAck binary in return." + summary = "Post a payment binary", + description = "This endpoint receives a payment binary and gives a paymentAck binary in return." ) @RequestMapping( method = [RequestMethod.POST], @@ -115,6 +145,16 @@ class TransactIdController { consumes = [MediaType.APPLICATION_OCTET_STREAM_VALUE], produces = [MediaType.APPLICATION_OCTET_STREAM_VALUE] ) + @ApiResponse( + responseCode = "200", + description = "PaymentAck binary.", + content = [ + Content( + mediaType = MediaType.APPLICATION_OCTET_STREAM_VALUE, + schema = Schema(implementation = ByteArray::class) + ) + ] + ) fun postPayment( @Parameter(description = "Binary containing payment") @RequestBody payment: ByteArray diff --git a/src/main/java/com/netki/transactidlibraryjavademo/controller/UtilController.kt b/src/main/java/com/netki/transactidlibraryjavademo/controller/UtilController.kt new file mode 100755 index 0000000..476b53f --- /dev/null +++ b/src/main/java/com/netki/transactidlibraryjavademo/controller/UtilController.kt @@ -0,0 +1,49 @@ +package com.netki.transactidlibraryjavademo.controller + +import com.netki.transactidlibraryjavademo.model.EncryptionKeys +import com.netki.transactidlibraryjavademo.service.TransactIdService +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.tags.Tag +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.http.HttpStatus +import org.springframework.http.MediaType +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestMethod +import org.springframework.web.bind.annotation.RestController + +@RestController +@Tag(name = "Utils", description = "Utilities to test TransactId") +@RequestMapping("/utils") +class UtilController { + + @Autowired + private lateinit var transactIdService: TransactIdService + + @Operation( + summary = "Get Encryption keys", + description = "Get the set of keys for the sender/recipient, this is needed if you want to generate encrypted messages" + ) + @RequestMapping( + method = [RequestMethod.GET], + value = ["/encryption/keys"], + produces = [MediaType.APPLICATION_JSON_VALUE] + ) + @ApiResponse( + responseCode = "200", + description = "Encryption keys.", + content = [ + Content( + mediaType = MediaType.APPLICATION_JSON_VALUE, + schema = Schema(implementation = EncryptionKeys::class) + ) + ] + ) + fun getEncryptionKeys(): ResponseEntity = + ResponseEntity.ok(transactIdService.getEncryptionKeys()) +} diff --git a/src/main/java/com/netki/transactidlibraryjavademo/model/InvoiceRequestUrl.kt b/src/main/java/com/netki/transactidlibraryjavademo/model/InvoiceRequestUrl.kt new file mode 100644 index 0000000..ef817dd --- /dev/null +++ b/src/main/java/com/netki/transactidlibraryjavademo/model/InvoiceRequestUrl.kt @@ -0,0 +1,5 @@ +package com.netki.transactidlibraryjavademo.model + +data class InvoiceRequestUrl( + val url: String +) diff --git a/src/main/java/com/netki/transactidlibraryjavademo/repo/TransactIdRepository.kt b/src/main/java/com/netki/transactidlibraryjavademo/repo/TransactIdRepository.kt index ca3ff5a..283226d 100755 --- a/src/main/java/com/netki/transactidlibraryjavademo/repo/TransactIdRepository.kt +++ b/src/main/java/com/netki/transactidlibraryjavademo/repo/TransactIdRepository.kt @@ -1,6 +1,7 @@ package com.netki.transactidlibraryjavademo.repo import com.netki.transactidlibraryjavademo.util.ClientHttpLoggingInterceptor +import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.web.client.RestTemplateBuilder import org.springframework.http.HttpEntity @@ -10,6 +11,7 @@ import org.springframework.http.MediaType import org.springframework.http.client.BufferingClientHttpRequestFactory import org.springframework.http.client.ClientHttpRequestInterceptor import org.springframework.http.client.SimpleClientHttpRequestFactory +import org.springframework.scheduling.annotation.Async import org.springframework.stereotype.Component import java.time.Duration @@ -18,52 +20,31 @@ class TransactIdRepository { @Autowired private lateinit var restTemplateBuilder: RestTemplateBuilder - private val url = "http://localhost:8081/" - private val token = "e08dca199281279be75c1272b4533898406c93c8" + private val logger = LoggerFactory.getLogger(this.javaClass) private val restTemplate by lazy { val restTemplate = restTemplateBuilder - .rootUri(url) .setConnectTimeout(Duration.ofMillis(5000)) .setReadTimeout(Duration.ofMillis(5000)) .build() val interceptors = ArrayList() interceptors.add(ClientHttpLoggingInterceptor()) restTemplate.interceptors = interceptors - restTemplate.requestFactory = BufferingClientHttpRequestFactory(SimpleClientHttpRequestFactory()) + restTemplate.requestFactory = + BufferingClientHttpRequestFactory(SimpleClientHttpRequestFactory()) restTemplate } - fun postInvoiceRequest(invoiceRequest: ByteArray, url: String) { - sendRequestNoResponse(invoiceRequest, url) - } - - fun sendInvoiceRequest(invoiceRequest: ByteArray, walletAddress: String): ByteArray { - val urlInvoiceRequest = "/bip/$walletAddress/invoice-requests/" - return sendRequest(urlInvoiceRequest, invoiceRequest)!! - } - - fun sendPayment(payment: ByteArray, walletAddress: String): ByteArray { - val urlPayment = "/bip/$walletAddress/record-payment/" - return sendRequest(urlPayment, payment)!! - } - - private fun sendRequest(url: String, message: ByteArray): ByteArray? { - val headers = HttpHeaders() - headers.set("Authorization", token) - headers.contentType = MediaType.APPLICATION_OCTET_STREAM - headers.set("accept", "application/octet-stream") - - return restTemplate.exchange(url, HttpMethod.POST, HttpEntity(message, headers), ByteArray::class.java).body - } - - private fun sendRequestNoResponse(message: ByteArray, url: String) { + @Async("threadPoolTaskExecutor") + fun sendRequestNoResponse(message: ByteArray, url: String) { + Thread.sleep(5000) + logger.info("Sending message to $url") val headers = HttpHeaders() - headers.set("Authorization", token) headers.contentType = MediaType.APPLICATION_OCTET_STREAM headers.set("accept", "application/octet-stream") restTemplate.postForLocation(url, HttpEntity(message, headers)) + logger.info("Message successfully sent") } } diff --git a/src/main/java/com/netki/transactidlibraryjavademo/service/TransactIdService.kt b/src/main/java/com/netki/transactidlibraryjavademo/service/TransactIdService.kt index 5058039..781c125 100755 --- a/src/main/java/com/netki/transactidlibraryjavademo/service/TransactIdService.kt +++ b/src/main/java/com/netki/transactidlibraryjavademo/service/TransactIdService.kt @@ -3,8 +3,8 @@ package com.netki.transactidlibraryjavademo.service import com.netki.TransactId import com.netki.model.* import com.netki.transactidlibraryjavademo.model.EncryptionKeys +import com.netki.transactidlibraryjavademo.repo.TransactIdRepository import com.netki.transactidlibraryjavademo.util.TestData.Attestations.ATTESTATIONS_REQUESTED -import com.netki.transactidlibraryjavademo.util.TestData.Beneficiaries.NO_PRIMARY_BENEFICIARY_PKI_NONE import com.netki.transactidlibraryjavademo.util.TestData.Beneficiaries.NO_PRIMARY_BENEFICIARY_PKI_X509SHA256 import com.netki.transactidlibraryjavademo.util.TestData.Beneficiaries.PRIMARY_BENEFICIARY_PKI_X509SHA256 import com.netki.transactidlibraryjavademo.util.TestData.Originators.NO_PRIMARY_ORIGINATOR_PKI_X509SHA256 @@ -19,11 +19,21 @@ import org.springframework.stereotype.Service import java.sql.Timestamp import javax.annotation.PostConstruct +/** + * Make sure to change this URLs to test the async flow if needed. + */ +const val NOTIFICATION_URL = "http://localhost:8080/async/payment-request" +const val PAYMENT_URL = "http://localhost:8080/async/payment" + @Service class TransactIdService { @Autowired private lateinit var encryptionKeys: EncryptionKeys + + @Autowired + private lateinit var transactIdRepository: TransactIdRepository + private lateinit var recipientParameters: RecipientParameters private lateinit var senderParameters: SenderParameters @@ -54,6 +64,16 @@ class TransactIdService { fun getEncryptionKeys() = encryptionKeys + fun sendInitialInvoiceRequest(url: String) { + val invoiceRequest = getInitialInvoiceRequest() + transactIdRepository.sendRequestNoResponse(invoiceRequest, url) + } + + fun sendInitialInvoiceRequestEncrypted(url: String) { + val invoiceRequestEncrypted = getInitialInvoiceRequestEncrypted() + transactIdRepository.sendRequestNoResponse(invoiceRequestEncrypted, url) + } + fun getInitialInvoiceRequest(): ByteArray { logger.info("Creating InvoiceRequest...") val originators = listOf( @@ -67,7 +87,7 @@ class TransactIdService { val invoiceRequestParameters = InvoiceRequestParameters( amount = 1000, memo = "memo", - notificationUrl = "notificationUrl", + notificationUrl = NOTIFICATION_URL, originatorsAddresses = OUTPUTS, originatorParameters = originators, beneficiaryParameters = beneficiaries, @@ -92,7 +112,7 @@ class TransactIdService { val invoiceRequestParameters = InvoiceRequestParameters( amount = 1000, memo = "memo", - notificationUrl = "notificationUrl", + notificationUrl = NOTIFICATION_URL, originatorsAddresses = OUTPUTS, originatorParameters = originators, beneficiaryParameters = beneficiaries, @@ -118,8 +138,33 @@ class TransactIdService { val invoiceRequestModel = transactId.parseInvoiceRequest(invoiceRequest, recipientParameters) logger.info("InvoiceRequest parsed: $invoiceRequestModel") + return createPaymentRequest(invoiceRequestModel.protocolMessageMetadata.encrypted) + } + + fun postInvoiceRequestAsync(invoiceRequest: ByteArray) { + logger.info("InvoiceRequest received") + logger.info( + "InvoiceRequest valid? ${transactId.isInvoiceRequestValid( + invoiceRequest, + recipientParameters + )}" + ) + val invoiceRequestModel = + transactId.parseInvoiceRequest(invoiceRequest, recipientParameters) + logger.info("InvoiceRequest parsed: $invoiceRequestModel") - return if (invoiceRequestModel.protocolMessageMetadata.encrypted) { + val notificationUrl = invoiceRequestModel.notificationUrl + if (notificationUrl == null || notificationUrl.isNullOrBlank() || notificationUrl.isNullOrEmpty()) { + throw IllegalArgumentException("Missing notificationUrl to send the async response") + } else { + val paymentRequest = + createPaymentRequest(invoiceRequestModel.protocolMessageMetadata.encrypted) + transactIdRepository.sendRequestNoResponse(paymentRequest, notificationUrl) + } + } + + private fun createPaymentRequest(encrypted: Boolean): ByteArray { + return if (encrypted) { logger.info("Creating PaymentRequest Encrypted...") logger.info("Returning PaymentRequest Encrypted...") val beneficiaries = listOf( @@ -132,7 +177,7 @@ class TransactIdService { time = Timestamp(System.currentTimeMillis()), expires = Timestamp(System.currentTimeMillis()), memo = "memo", - paymentUrl = "www.payment.url/test", + paymentUrl = PAYMENT_URL, merchantData = "merchant data", beneficiaryParameters = beneficiaries, senderParameters = senderParameters, @@ -155,7 +200,7 @@ class TransactIdService { time = Timestamp(System.currentTimeMillis()), expires = Timestamp(System.currentTimeMillis()), memo = "memo", - paymentUrl = "www.payment.url/test", + paymentUrl = PAYMENT_URL, merchantData = "merchant data", beneficiaryParameters = beneficiaries, senderParameters = sender, @@ -173,6 +218,30 @@ class TransactIdService { recipientParameters )}" ) + return createPayment(paymentRequest) + } + + fun postPaymentRequestAsync(paymentRequest: ByteArray) { + logger.info("PaymentRequest received") + logger.info( + "PaymentRequest valid? ${transactId.isPaymentRequestValid( + paymentRequest, + recipientParameters + )}" + ) + val paymentRequestModel = + transactId.parsePaymentRequest(paymentRequest, recipientParameters) + + val paymentUrl = paymentRequestModel.paymentUrl + if (paymentUrl == null || paymentUrl.isNullOrBlank() || paymentUrl.isNullOrEmpty()) { + throw IllegalArgumentException("Missing paymentUrl to send the async response") + } else { + val payment = createPayment(paymentRequest) + transactIdRepository.sendRequestNoResponse(payment, paymentUrl) + } + } + + fun createPayment(paymentRequest: ByteArray): ByteArray { val paymentRequestModel = transactId.parsePaymentRequest(paymentRequest, recipientParameters) logger.info("PaymentRequest parsed: $paymentRequestModel") diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index d82ec08..d316f71 100755 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -6,3 +6,5 @@ spring.thymeleaf.suffix=.html springdoc.api-docs.path=/api-docs springdoc.swagger-ui.path=/transact-id-docs.html +springdoc.swagger-ui.operationsSorter=alpha +springdoc.swagger-ui.tagsSorter=alpha