I have the following code that does some pattern matching and returns a response accordingly:
def handleProvisioningServiceCSRequests(provisioningCsRequest: ProvisioningCSRequest, chargingStationId: String, msgTypeId: Int, msgId: String): Future[OCPPCallResponse] = provisioningCsRequest match {
case bootNotificationRequest: BootNotificationRequest => provisioningService.bootNotification(bootNotificationRequest, chargingStationId).runToFuture.materialize.map {
case Failure(fail) => populateOCPPCallError(msgId, msgTypeId, OCPPCallErrorCode.InternalError(), fail.getMessage)
case Success(response) => OCPPCallResult(
messageTypeId = msgTypeId,
messageId = msgId,
payload = Json.toJson(response)
)
}
case notifyReportRequest: NotifyReportRequest => provisioningService.notifyReport(notifyReportRequest, chargingStationId).runToFuture.materialize.map {
case Failure(fail) => populateOCPPCallError(msgId, msgTypeId, OCPPCallErrorCode.InternalError(), fail.getMessage)
case Success(response) => OCPPCallResult(
messageTypeId = msgTypeId,
messageId = msgId,
payload = Json.toJson(response)
)
}
}
As it can be seen that the preparation off the OCPPCallError or the OCPPCallResult is repetitive and kind of the same. I will have to do 10 other pattern match case statements and that means 10 times repetition.
I tried refactoring it like this below, but it obviously fails compilation as it says it cannot find implicit conversions:
def handleProvisioningServiceCSRequests(provisioningCsRequest: ProvisioningCSRequest, chargingStationId: String, msgTypeId: Int, msgId: String): Future[OCPPCallResponse] = {
val result = provisioningCsRequest match {
case bootNotificationRequest: BootNotificationRequest => provisioningService.bootNotification(bootNotificationRequest, chargingStationId).runToFuture
case notifyReportRequest: NotifyReportRequest => provisioningService.notifyReport(notifyReportRequest, chargingStationId).runToFuture
}
result.materialize.map {
case Failure(fail) => populateOCPPCallError(msgId, msgTypeId, OCPPCallErrorCode.InternalError(), fail.getMessage)
case Success(response) => OCPPCallResult(
messageTypeId = msgTypeId,
messageId = msgId,
payload = Json.toJson(response)) // Fails here saying it cannot find implicits for Writes[Product with Serializable]
}
}
The response in the Success(response) does not add up. How can I cope up for this?
The most obvious fix would be to ensure that result already contains the converted Json by moving the Json-encoding into the upper pattern match:
def handleProvisioningServiceCSRequests(provisioningCsRequest: ProvisioningCSRequest, chargingStationId: String, msgTypeId: Int, msgId: String): Future[OCPPCallResponse] = {
val result = provisioningCsRequest match {
case bootNotificationRequest: BootNotificationRequest =>
provisioningService.bootNotification(bootNotificationRequest, chargingStationId)
.runToFuture.map(response => Json.toJson(response))
case notifyReportRequest: NotifyReportRequest =>
provisioningService.notifyReport(notifyReportRequest, chargingStationId)
.runToFuture.map(response => Json.toJson(response))
}
result.materialize.map {
case Failure(fail) => populateOCPPCallError(msgId, msgTypeId, OCPPCallErrorCode.InternalError(), fail.getMessage)
case Success(json) => OCPPCallResult(
messageTypeId = msgTypeId,
messageId = msgId,
payload = json
}
}
Since you're aiming at reducing redundancies, you might also want to move the runToFuture
down into the shared part of the code:
def handleProvisioningServiceCSRequests(provisioningCsRequest: ProvisioningCSRequest, chargingStationId: String, msgTypeId: Int, msgId: String): Future[OCPPCallResponse] = {
val result = provisioningCsRequest match {
case bootNotificationRequest: BootNotificationRequest =>
provisioningService.bootNotification(bootNotificationRequest, chargingStationId)
.map(response => Json.toJson(response))
case notifyReportRequest: NotifyReportRequest =>
provisioningService.notifyReport(notifyReportRequest, chargingStationId)
.map(response => Json.toJson(response))
}
result.runToFuture.materialize.map {
case Failure(fail) => populateOCPPCallError(msgId, msgTypeId, OCPPCallErrorCode.InternalError(), fail.getMessage)
case Success(json) => OCPPCallResult(
messageTypeId = msgTypeId,
messageId = msgId,
payload = json
}
}
Alternatively, a more involved solution would be to introduce a helper function that abstracts over the type of the result and the availability of an implicit Writes
instance for it (not 100% sure if this will compile like this because I'm making quite a few assumptions about the libraries that are being used (e.g. assuming that your provisioningService
returns monix.eval.Task
s)):
def handleProvisioningServiceCSRequests(provisioningCsRequest: ProvisioningCSRequest, chargingStationId: String, msgTypeId: Int, msgId: String): Future[OCPPCallResponse] = {
def handleResult[T: Writes](result: Task[T]): Future[OCPPCallResponse] =
result.runToFuture.materialize.map {
case Failure(fail) => populateOCPPCallError(msgId, msgTypeId, OCPPCallErrorCode.InternalError(), fail.getMessage)
case Success(json) => OCPPCallResult(
messageTypeId = msgTypeId,
messageId = msgId,
payload = Json.toJson(response)
}
provisioningCsRequest match {
case bootNotificationRequest: BootNotificationRequest =>
handleResult(provisioningService.bootNotification(bootNotificationRequest, chargingStationId))
case notifyReportRequest: NotifyReportRequest =>
handleResult(provisioningService.notifyReport(notifyReportRequest, chargingStationId))
}
}
Edit: if all of your cases are handled in the way that you call a specific method of the provisioningService
that takes the specific request and the chargingStationId
, then you could make this even less redundant (at the price of making it more verbose). Not sure what type the provisioningService
has, so in this example, I name the type ProvisioningService
:
def handleProvisioningServiceCSRequests(provisioningCsRequest: ProvisioningCSRequest, chargingStationId: String, msgTypeId: Int, msgId: String): Future[OCPPCallResponse] = {
def executeRequest[T: Writes](f: ProvisoningService => String => Task[T]): Future[OCPPCallResponse] =
f(provisoningService)(chargingStationId).runToFuture.materialize.map {
case Failure(fail) => populateOCPPCallError(msgId, msgTypeId, OCPPCallErrorCode.InternalError(), fail.getMessage)
case Success(json) => OCPPCallResult(
messageTypeId = msgTypeId,
messageId = msgId,
payload = Json.toJson(response)
}
provisioningCsRequest match {
case bootNotificationRequest: BootNotificationRequest =>
executeRequest(_.bootNotification(bootNotificationRequest, _))
case notifyReportRequest: NotifyReportRequest =>
executeRequest(_.notifyReport(notifyReportRequest, _))
}
}
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments