Skip to content

Commit

Permalink
APIS-6702 Mongo lib upgrades 0.74.0 to 1.7.0 (#77)
Browse files Browse the repository at this point in the history
* APIS-6702 Mongo lib upgrades 0.74.0 to 1.7.0

* APIS-6702 Remove enumerations

* APIS-6702 Remove enumerations

* APIS-6702 Add tests

* APIS-6702 PR bot actions
  • Loading branch information
petekirby-ee authored Jan 24, 2024
1 parent 5d6fbf2 commit a9c3a12
Show file tree
Hide file tree
Showing 13 changed files with 327 additions and 135 deletions.
10 changes: 5 additions & 5 deletions app/uk/gov/hmrc/apiplatformoutboundsoap/models/JsonFormats.scala
Original file line number Diff line number Diff line change
Expand Up @@ -69,23 +69,23 @@ object JsonFormats {
implicit val outboundSoapMessageWrites: OWrites[OutboundSoapMessage] = {
case r @ RetryingOutboundSoapMessage(_, _, _, _, _, _, _, _, _, _, _, _) =>
retryingSoapMessageFormatter.writes(r) ++ Json.obj(
"status" -> SendingStatus.RETRYING.entryName
"status" -> SendingStatus.RETRYING.toString()
)
case f @ FailedOutboundSoapMessage(_, _, _, _, _, _, _, _, _, _, _) =>
failedSoapMessageFormatter.writes(f) ++ Json.obj(
"status" -> SendingStatus.FAILED.entryName
"status" -> SendingStatus.FAILED.toString()
)
case s @ SentOutboundSoapMessage(_, _, _, _, _, _, _, _, _, _, _) =>
sentSoapMessageFormatter.writes(s) ++ Json.obj(
"status" -> SendingStatus.SENT.entryName
"status" -> SendingStatus.SENT.toString()
)
case cod @ CodSoapMessage(_, _, _, _, _, _, _, _, _, _, _) =>
codSoapMessageFormatter.writes(cod) ++ Json.obj(
"status" -> DeliveryStatus.COD.entryName
"status" -> DeliveryStatus.COD.toString()
)
case coe @ CoeSoapMessage(_, _, _, _, _, _, _, _, _, _, _) =>
coeSoapMessageFormatter.writes(coe) ++ Json.obj(
"status" -> DeliveryStatus.COE.entryName
"status" -> DeliveryStatus.COE.toString()
)
}
implicit val outboundSoapMessageFormatter: OFormat[OutboundSoapMessage] = OFormat(Json.reads[OutboundSoapMessage], outboundSoapMessageWrites)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,9 @@ package uk.gov.hmrc.apiplatformoutboundsoap.models

import java.time.Instant
import java.util.UUID
import scala.collection.immutable
import scala.reflect.classTag

import enumeratum.{Enum, EnumEntry, PlayJsonEnum}
import play.api.libs.json.Format

sealed trait OutboundSoapMessage {
val globalId: UUID
Expand Down Expand Up @@ -143,38 +142,49 @@ case class RetryingOutboundSoapMessage(
def toSent = SentOutboundSoapMessage(globalId, messageId, soapMessage, destinationUrl, createDateTime, ccnHttpStatus, notificationUrl, codMessage, coeMessage, Some(Instant.now))
}

sealed abstract class StatusType extends EnumEntry
sealed abstract trait StatusType

object StatusType extends Enum[StatusType] with PlayJsonEnum[StatusType] {
val values: immutable.IndexedSeq[StatusType] = findValues
object StatusType {
val values: Set[StatusType] = DeliveryStatus.values ++ SendingStatus.values

def apply(text: String): Option[StatusType] = StatusType.values.find(_.toString() == text.toUpperCase)

implicit val format: Format[StatusType] = SealedTraitJsonFormatting.createFormatFor[StatusType]("Status Type", apply)
}

sealed abstract class DeliveryStatus(override val entryName: String) extends StatusType
sealed trait DeliveryStatus extends StatusType

object DeliveryStatus {
case object COE extends DeliveryStatus
case object COD extends DeliveryStatus
val values: Set[DeliveryStatus] = Set(COE, COD)

object DeliveryStatus extends Enum[DeliveryStatus] with PlayJsonEnum[DeliveryStatus] {
def apply(text: String): Option[DeliveryStatus] = DeliveryStatus.values.find(_.toString() == text.toUpperCase)

def fromAction(action: String): DeliveryStatus = {
def unsafeApply(text: String): DeliveryStatus = apply(text).getOrElse(throw new RuntimeException(s"$text is not a valid Delivery Status"))

def fromAction(action: String): DeliveryStatus = {
action match {
case "CCN2.Service.Platform.AcknowledgementService/CoE" => DeliveryStatus.COE
case "CCN2.Service.Platform.AcknowledgementService/CoD" => DeliveryStatus.COD
case _ => throw new IllegalArgumentException(s"${action} is not a valid DeliveryStatus")
case _ => throw new IllegalArgumentException(s"${action} is not a valid Delivery Status")
}
}
val values: immutable.IndexedSeq[DeliveryStatus] = findValues

case object COE extends DeliveryStatus("COE")

case object COD extends DeliveryStatus("COD")
implicit val format: Format[DeliveryStatus] = SealedTraitJsonFormatting.createFormatFor[DeliveryStatus]("Delivery Status", apply)
}

sealed abstract class SendingStatus(override val entryName: String) extends StatusType
sealed trait SendingStatus extends StatusType

object SendingStatus extends Enum[SendingStatus] with PlayJsonEnum[SendingStatus] {
val values: immutable.IndexedSeq[SendingStatus] = findValues
object SendingStatus {
case object SENT extends SendingStatus
case object FAILED extends SendingStatus
case object RETRYING extends SendingStatus
val values: Set[SendingStatus] = Set(SENT, FAILED, RETRYING)

case object SENT extends SendingStatus("SENT")
def apply(text: String): Option[SendingStatus] = SendingStatus.values.find(_.toString() == text.toUpperCase)

case object FAILED extends SendingStatus("FAILED")
def unsafeApply(text: String): SendingStatus = apply(text).getOrElse(throw new RuntimeException(s"$text is not a valid Sending Status"))

case object RETRYING extends SendingStatus("RETRYING")
implicit val format: Format[SendingStatus] = SealedTraitJsonFormatting.createFormatFor[SendingStatus]("Sending Status", apply)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright 2024 HM Revenue & Customs
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package uk.gov.hmrc.apiplatformoutboundsoap.models

object SealedTraitJsonFormatting {
import play.api.libs.json._

def createFormatFor[T](name: String, read: String => Option[T], write: T => String = (t: T) => t.toString) = new Format[T] {

def reads(json: JsValue): JsResult[T] = json match {
case JsString(text) => read(text).fold[JsResult[T]] { JsError(s"$text is not a valid $name") }(JsSuccess(_))
case e => JsError(s"Cannot parse $name from '$e'")
}

def writes(foo: T): JsValue = {
JsString(write(foo))
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ private[repositories] object MongoFormatter extends MongoJavatimeFormats.Implici
implicit val cfg: Aux[Json.MacroOptions] = JsonConfiguration(
discriminator = "status",
typeNaming = JsonNaming { fullName =>
OutboundSoapMessage.typeToStatus(fullName).entryName
OutboundSoapMessage.typeToStatus(fullName).toString()
}
)
implicit val privateHeaderReads: Reads[PrivateHeader] = Json.reads[PrivateHeader]
Expand All @@ -40,7 +40,7 @@ private[repositories] object MongoFormatter extends MongoJavatimeFormats.Implici
Json.reads[RetryingOutboundSoapMessage]

implicit val retryingMessageWrites: OWrites[RetryingOutboundSoapMessage] =
Json.writes[RetryingOutboundSoapMessage].transform(_ ++ Json.obj("status" -> SendingStatus.RETRYING.entryName))
Json.writes[RetryingOutboundSoapMessage].transform(_ ++ Json.obj("status" -> SendingStatus.RETRYING.toString()))

implicit val retryingSoapMessageFormatter: OFormat[RetryingOutboundSoapMessage] =
OFormat(retryingMessageReads, retryingMessageWrites)
Expand All @@ -49,7 +49,7 @@ private[repositories] object MongoFormatter extends MongoJavatimeFormats.Implici
Json.reads[SentOutboundSoapMessage]

implicit val sentMessageWrites: OWrites[SentOutboundSoapMessage] =
Json.writes[SentOutboundSoapMessage].transform(_ ++ Json.obj("status" -> SendingStatus.SENT.entryName))
Json.writes[SentOutboundSoapMessage].transform(_ ++ Json.obj("status" -> SendingStatus.SENT.toString()))

implicit val sentSoapMessageFormatter: OFormat[SentOutboundSoapMessage] =
OFormat(sentMessageReads, sentMessageWrites)
Expand All @@ -58,7 +58,7 @@ private[repositories] object MongoFormatter extends MongoJavatimeFormats.Implici
Json.reads[FailedOutboundSoapMessage]

implicit val failedMessageWrites: OWrites[FailedOutboundSoapMessage] =
Json.writes[FailedOutboundSoapMessage].transform(_ ++ Json.obj("status" -> SendingStatus.FAILED.entryName))
Json.writes[FailedOutboundSoapMessage].transform(_ ++ Json.obj("status" -> SendingStatus.FAILED.toString()))

implicit val failedSoapMessageFormatter: OFormat[FailedOutboundSoapMessage] =
OFormat(failedMessageReads, failedMessageWrites)
Expand All @@ -67,7 +67,7 @@ private[repositories] object MongoFormatter extends MongoJavatimeFormats.Implici
Json.reads[CodSoapMessage]

implicit val codMessageWrites: OWrites[CodSoapMessage] =
Json.writes[CodSoapMessage].transform(_ ++ Json.obj("status" -> DeliveryStatus.COD.entryName))
Json.writes[CodSoapMessage].transform(_ ++ Json.obj("status" -> DeliveryStatus.COD.toString()))

implicit val codSoapMessageFormatter: OFormat[CodSoapMessage] =
OFormat(codMessageReads, codMessageWrites)
Expand All @@ -76,22 +76,22 @@ private[repositories] object MongoFormatter extends MongoJavatimeFormats.Implici
Json.reads[CoeSoapMessage]

implicit val coeMessageWrites: OWrites[CoeSoapMessage] =
Json.writes[CoeSoapMessage].transform(_ ++ Json.obj("status" -> DeliveryStatus.COE.entryName))
Json.writes[CoeSoapMessage].transform(_ ++ Json.obj("status" -> DeliveryStatus.COE.toString()))

implicit val coeSoapMessageFormatter: OFormat[CoeSoapMessage] =
OFormat(coeMessageReads, coeMessageWrites)

implicit val outboundSoapMessageReads: Reads[OutboundSoapMessage] =
(JsPath \ "status").read[String].flatMap {
case SendingStatus.RETRYING.entryName =>
case "RETRYING" =>
retryingSoapMessageFormatter.widen[OutboundSoapMessage]
case SendingStatus.SENT.entryName =>
case "SENT" =>
sentSoapMessageFormatter.widen[OutboundSoapMessage]
case SendingStatus.FAILED.entryName =>
case "FAILED" =>
failedSoapMessageFormatter.widen[OutboundSoapMessage]
case DeliveryStatus.COD.entryName =>
case "COD" =>
codSoapMessageFormatter.widen[OutboundSoapMessage]
case DeliveryStatus.COE.entryName =>
case "COE" =>
coeSoapMessageFormatter.widen[OutboundSoapMessage]
}

Expand All @@ -100,23 +100,23 @@ private[repositories] object MongoFormatter extends MongoJavatimeFormats.Implici
override def writes(soapMessage: OutboundSoapMessage): JsObject = soapMessage match {
case r @ RetryingOutboundSoapMessage(_, _, _, _, _, _, _, _, _, _, _, _) =>
retryingSoapMessageFormatter.writes(r) ++ Json.obj(
"status" -> SendingStatus.RETRYING.entryName
"status" -> SendingStatus.RETRYING.toString()
)
case f @ FailedOutboundSoapMessage(_, _, _, _, _, _, _, _, _, _, _) =>
failedSoapMessageFormatter.writes(f) ++ Json.obj(
"status" -> SendingStatus.FAILED.entryName
"status" -> SendingStatus.FAILED.toString()
)
case s @ SentOutboundSoapMessage(_, _, _, _, _, _, _, _, _, _, _) =>
sentSoapMessageFormatter.writes(s) ++ Json.obj(
"status" -> SendingStatus.SENT.entryName
"status" -> SendingStatus.SENT.toString()
)
case cod @ CodSoapMessage(_, _, _, _, _, _, _, _, _, _, _) =>
codSoapMessageFormatter.writes(cod) ++ Json.obj(
"status" -> DeliveryStatus.COD.entryName
"status" -> DeliveryStatus.COD.toString()
)
case coe @ CoeSoapMessage(_, _, _, _, _, _, _, _, _, _, _) =>
coeSoapMessageFormatter.writes(coe) ++ Json.obj(
"status" -> DeliveryStatus.COE.entryName
"status" -> DeliveryStatus.COE.toString()
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,9 @@ class OutboundMessageRepository @Inject() (mongoComponent: MongoComponent, appCo
Codecs.playFormatCodec(MongoFormatter.sentSoapMessageFormatter),
Codecs.playFormatCodec(MongoFormatter.codSoapMessageFormatter),
Codecs.playFormatCodec(MongoFormatter.coeSoapMessageFormatter),
Codecs.playFormatCodec(StatusType.jsonFormat),
Codecs.playFormatCodec(DeliveryStatus.jsonFormat),
Codecs.playFormatCodec(SendingStatus.jsonFormat)
Codecs.playFormatCodec(StatusType.format),
Codecs.playFormatCodec(DeliveryStatus.format),
Codecs.playFormatCodec(SendingStatus.format)
),
MongoClient.DEFAULT_CODEC_REGISTRY
)
Expand All @@ -89,7 +89,7 @@ class OutboundMessageRepository @Inject() (mongoComponent: MongoComponent, appCo

def retrieveMessagesForRetry: Source[RetryingOutboundSoapMessage, NotUsed] = {
MongoSource(collection.withReadPreference(primaryPreferred())
.find(filter = and(equal("status", SendingStatus.RETRYING.entryName), and(lte("retryDateTime", Codecs.toBson(Instant.now)))))
.find(filter = and(equal("status", SendingStatus.RETRYING.toString()), and(lte("retryDateTime", Codecs.toBson(Instant.now)))))
.sort(ascending("retryDateTime"))
.map(_.asInstanceOf[RetryingOutboundSoapMessage]))
}
Expand All @@ -107,7 +107,7 @@ class OutboundMessageRepository @Inject() (mongoComponent: MongoComponent, appCo
collection.withReadPreference(primaryPreferred())
.findOneAndUpdate(
filter = equal("globalId", Codecs.toBson(globalId)),
update = set("status", Codecs.toBson(newStatus.entryName)),
update = set("status", Codecs.toBson(newStatus.toString())),
options = FindOneAndUpdateOptions().upsert(true).returnDocument(ReturnDocument.AFTER)
).toFutureOption()
}
Expand All @@ -118,7 +118,7 @@ class OutboundMessageRepository @Inject() (mongoComponent: MongoComponent, appCo
filter = equal("globalId", Codecs.toBson(globalId)),
update = combine(
set("sentDateTime", Codecs.toBson(sentInstant)),
set("status", Codecs.toBson(SendingStatus.SENT.entryName))
set("status", Codecs.toBson(SendingStatus.SENT.toString()))
),
options = FindOneAndUpdateOptions().upsert(true).returnDocument(ReturnDocument.AFTER)
).toFutureOption()
Expand All @@ -132,7 +132,7 @@ class OutboundMessageRepository @Inject() (mongoComponent: MongoComponent, appCo

for {
_ <- collection.bulkWrite(
List(UpdateManyModel(Document("messageId" -> messageId), combine(set("status", Codecs.toBson(newStatus.entryName)), set(field, confirmationMsg)))),
List(UpdateManyModel(Document("messageId" -> messageId), combine(set("status", Codecs.toBson(newStatus.toString())), set(field, confirmationMsg)))),
BulkWriteOptions().ordered(false)
).toFuture()
findUpdated <- findById(messageId)
Expand Down
38 changes: 26 additions & 12 deletions app/uk/gov/hmrc/apiplatformoutboundsoap/responses.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,38 @@ package uk.gov.hmrc.apiplatformoutboundsoap
import play.api.libs.json.Json.JsValueWrapper
import play.api.libs.json.{JsObject, Json}

object ErrorCode extends Enumeration {
type ErrorCode = Value
val NOT_FOUND = Value("NOT_FOUND")
val BAD_REQUEST = Value("BAD_REQUEST")
val INTERNAL_SERVER_ERROR = Value("INTERNAL_SERVER_ERROR")
sealed trait ErrorCode

object ErrorCode {
case object NOT_FOUND extends ErrorCode
case object BAD_REQUEST extends ErrorCode
case object INTERNAL_SERVER_ERROR extends ErrorCode

val values: Set[ErrorCode] = Set(NOT_FOUND, BAD_REQUEST, INTERNAL_SERVER_ERROR)

def apply(text: String): Option[ErrorCode] = ErrorCode.values.find(_.toString() == text.toUpperCase)

def unsafeApply(text: String): ErrorCode = apply(text).getOrElse(throw new RuntimeException(s"$text is not a valid Error Code"))
}

object CcnRequestResult extends Enumeration {
type CcnRequestResult = Value
val UNEXPECTED_SUCCESS = Value("UNEXPECTED_SUCCESS")
val SUCCESS = Value("SUCCESS")
val FAIL_ERROR = Value("FAIL_ERROR")
val RETRYABLE_ERROR = Value("RETRYABLE_ERROR")
sealed trait CcnRequestResult

object CcnRequestResult {
case object UNEXPECTED_SUCCESS extends CcnRequestResult
case object SUCCESS extends CcnRequestResult
case object FAIL_ERROR extends CcnRequestResult
case object RETRYABLE_ERROR extends CcnRequestResult

val values: Set[CcnRequestResult] = Set(UNEXPECTED_SUCCESS, SUCCESS, FAIL_ERROR, RETRYABLE_ERROR)

def apply(text: String): Option[CcnRequestResult] = CcnRequestResult.values.find(_.toString() == text.toUpperCase)

def unsafeApply(text: String): CcnRequestResult = apply(text).getOrElse(throw new RuntimeException(s"$text is not a valid CCN Request Result"))
}

object JsErrorResponse {

def apply(errorCode: ErrorCode.Value, message: JsValueWrapper): JsObject =
def apply(errorCode: ErrorCode, message: JsValueWrapper): JsObject =
Json.obj(
"code" -> errorCode.toString,
"message" -> message
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ class OutboundService @Inject() (
envelope.getBody.addChild(payload)
}

private def mapHttpStatusCode(httpStatusCode: Int): CcnRequestResult.Value = {
private def mapHttpStatusCode(httpStatusCode: Int): CcnRequestResult = {
if (isSuccessful(httpStatusCode)) {
httpStatusCode match {
case ACCEPTED => SUCCESS
Expand Down
Loading

0 comments on commit a9c3a12

Please sign in to comment.