feature/add_required_field_annotation : all required field validation put at startConnector, at this single place.

This commit is contained in:
shuang 2020-01-28 20:16:32 +08:00
parent 97d45e07a9
commit 9fdc819968
11 changed files with 191 additions and 124 deletions

View File

@ -2128,7 +2128,7 @@ Returns a string showed to the developer
* @param box Some boxed type
* @return Boxed value or throw some exception
*/
def fullBoxOrException[T](box: Box[T])(implicit m: Manifest[T]) : Box[T]= {
def fullBoxOrException[T](box: Box[T]) : Box[T]= {
box match {
case Full(v) => // Just forwarding
Full(v)

View File

@ -4,7 +4,7 @@ import java.util.Date
import java.util.UUID.randomUUID
import code.accountholders.{AccountHolders, MapperAccountHolders}
import code.api.ApiVersionHolder
import code.api.{APIFailure, APIFailureNewStyle}
import code.api.cache.Caching
import code.api.util.APIUtil.{OBPReturnType, _}
import code.api.util.ApiRole._
@ -38,7 +38,7 @@ import code.views.Views
import com.openbankproject.commons.model.enums.{AccountAttributeType, CardAttributeType, DynamicEntityOperation, ProductAttributeType}
import com.openbankproject.commons.model.{AccountApplication, Bank, CounterpartyTrait, CustomerAddress, Product, ProductCollection, ProductCollectionItem, TaxResidence, TransactionRequestStatus, UserAuthContext, UserAuthContextUpdate, _}
import com.tesobe.CacheKeyFromArguments
import net.liftweb.common.{Box, Empty, Failure, Full}
import net.liftweb.common.{Box, Empty, EmptyBox, Failure, Full, ParamFailure}
import net.liftweb.json.{Formats, JObject, JValue}
import net.liftweb.mapper.By
import net.liftweb.util.Helpers.tryo
@ -47,7 +47,7 @@ import net.liftweb.util.SimpleInjector
import scala.collection.immutable.{List, Nil}
import scala.collection.mutable.ArrayBuffer
import com.openbankproject.commons.ExecutionContext.Implicits.global
import com.openbankproject.commons.util.ApiVersion
import net.liftweb.json
import scala.concurrent.Future
import scala.concurrent.duration._
@ -96,6 +96,29 @@ object Connector extends SimpleInjector {
}
def extractAdapterResponse[T: Manifest](responseJson: String): Box[T] = {
val clazz = manifest[T].runtimeClass
val boxJValue: Box[Box[JValue]] = tryo {
val jValue = json.parse(responseJson)
if (ErrorMessage.isErrorMessage(jValue)) {
val ErrorMessage(code, message) = jValue.extract[ErrorMessage]
ParamFailure(message, Empty, Empty, APIFailure(message, code))
} else {
Box !! jValue
}
} ~> APIFailureNewStyle(s"INTERNAL-$InvalidJsonFormat The Json body should be the ${clazz.getName} ", 400)
boxJValue match {
case Full(Full(jValue)) =>
tryo {
jValue.extract[T](CustomJsonFormats.nullTolerateFormats, manifest[T])
} ~> APIFailureNewStyle(s"INTERNAL-$InvalidJsonFormat The Json body should be the ${clazz.getName} ", 400)
case Full(failure) => failure.asInstanceOf[Box[T]]
case empty: EmptyBox => empty
}
}
}
trait Connector extends MdcLoggable {
@ -129,8 +152,6 @@ trait Connector extends MdcLoggable {
protected val statusOfCreditcardOrders = getSecondsCache("getStatusOfCreditCardOrderFuture")
protected val bankAccountsBalancesTTL = getSecondsCache("getBankAccountsBalances")
protected def apiVersion: ApiVersion = ApiVersionHolder.getApiVersion
/**
* convert original return type future to OBPReturnType
*
@ -1922,4 +1943,4 @@ trait Connector extends MdcLoggable {
callContext: Option[CallContext]): OBPReturnType[Box[StandingOrderTrait]] = Future {
(Failure(setUnimplementedError), callContext)
}
}
}

View File

@ -2,7 +2,8 @@ package code
import java.lang.reflect.Method
import code.api.util.NewStyle
import code.api.{APIFailure, APIFailureNewStyle, ApiVersionHolder}
import code.api.util.{CallContext, NewStyle}
import code.bankconnectors.akka.AkkaConnector_vDec2018
import code.bankconnectors.rest.RestConnector_vMar2019
import code.bankconnectors.storedprocedure.StoredProcedureConnector_vDec2019
@ -11,14 +12,26 @@ import code.bankconnectors.vMar2017.KafkaMappedConnector_vMar2017
import code.bankconnectors.vMay2019.KafkaMappedConnector_vMay2019
import code.bankconnectors.vSept2018.KafkaMappedConnector_vSept2018
import code.methodrouting.MethodRouting
import code.util.Helper
import code.util.Helper.MdcLoggable
import com.openbankproject.commons.model.BankId
import com.openbankproject.commons.util.ReflectUtils.{findMethodByArgs, getConstructorArgs}
import net.liftweb.common.{Box, EmptyBox}
import com.openbankproject.commons.ExecutionContext.Implicits.global
import net.liftweb.common.{Box, Empty, EmptyBox, Full, ParamFailure}
import net.sf.cglib.proxy.{Enhancer, MethodInterceptor, MethodProxy}
import scala.reflect.runtime.universe.{Type, typeOf}
import scala.collection.mutable.ArrayBuffer
import scala.reflect.runtime.universe.{MethodSymbol, Type, typeOf}
import code.api.util.ErrorMessages.InvalidConnectorResponseForMissingRequiredValues
import code.api.util.APIUtil.{fullBoxOrException, unboxFull}
import com.openbankproject.commons.util.ApiVersion
import com.openbankproject.commons.util.ReflectUtils._
import com.openbankproject.commons.util.Functions.RichCollection
package object bankconnectors {
import scala.collection.GenTraversableOnce
import scala.concurrent.Future
package object bankconnectors extends MdcLoggable {
/**
* a star connector object, usage:
@ -44,8 +57,11 @@ package object bankconnectors {
if(method.getName.contains("$default$")) {
method.invoke(StubConnector, args:_*)
} else {
val objToCall = getConnectorObject(method, args)
method.invoke(objToCall, args:_*)
val (objToCall, methodSymbol) = getConnectorObject(method, args)
val connectorMethodResult = method.invoke(objToCall, args: _*)
logger.debug(s"do required field validation for ${methodSymbol.typeSignature}")
val apiVersion = ApiVersionHolder.getApiVersion
validatRequiredFields(connectorMethodResult, methodSymbol.returnType, apiVersion)
}
}
val enhancer: Enhancer = new Enhancer()
@ -60,9 +76,10 @@ package object bankconnectors {
* @param args passed arguments
* @return connector Object
*/
private[this]def getConnectorObject(method: Method, args: Seq[Any]): Connector = {
private[this]def getConnectorObject(method: Method, args: Seq[Any]): (Connector, MethodSymbol) = {
val methodName = method.getName
val methodSymbol = findMethodByArgs(typeOf[Connector], methodName, args:_*).getOrElse(sys.error(s"not found matched method, method name: ${methodName}, params: ${args.mkString(",")}"))
val tpe = typeOf[Connector]
val methodSymbol: MethodSymbol = findMethodByArgs(tpe, methodName, args:_*).getOrElse(sys.error(s"not found matched method, method name: ${methodName}, params: ${args.mkString(",")}"))
val paramList = methodSymbol.paramLists.headOption.getOrElse(Nil)
val paramNameToType: Map[String, Type] = paramList.map(param => (param.name.toString, param.info)).toMap
val paramNameToValue: Map[String, Any] = paramList.zip(args).map(pair =>(pair._1.name.toString, pair._2)).toMap
@ -101,7 +118,7 @@ package object bankconnectors {
}
}
connectorName.getOrElse("mapped") match {
val connector = connectorName.getOrElse("mapped") match {
case "mapped" => LocalMappedConnector
case "akka_vDec2018" => AkkaConnector_vDec2018
case "kafka" => KafkaMappedConnector
@ -114,6 +131,7 @@ package object bankconnectors {
case "stored_procedure_vDec2019" => StoredProcedureConnector_vDec2019
case _ => throw new IllegalStateException(s"config of connector.start.methodName.${methodName} have wrong value, not exists connector of name ${connectorName.get}")
}
(connector, methodSymbol)
}
@ -177,4 +195,104 @@ package object bankconnectors {
}
}
private def validatRequiredFields(value: AnyRef, returnType: Type, apiVersion: ApiVersion): AnyRef = {
value match {
case Unit => value
case coll @(_:Array[_] | _: ArrayBuffer[_] | _: GenTraversableOnce[_]) =>
val elementTpe = returnType.typeArgs.head
validate(value, elementTpe, coll, apiVersion, None, false)
case Full((coll: GenTraversableOnce[_], cc: Option[_]))
if coll.nonEmpty && getNestTypeArg(returnType, 0, 1, 0) =:= typeOf[CallContext] =>
val elementTpe = getNestTypeArg(returnType, 0, 0, 0)
val callContext = cc.asInstanceOf[Option[CallContext]]
validate(value, elementTpe, coll, apiVersion, callContext)
case Full((v, cc: Option[_]))
if getNestTypeArg(returnType, 0, 1, 0) =:= typeOf[CallContext] =>
val elementTpe = getNestTypeArg(returnType, 0, 0)
val callContext = cc.asInstanceOf[Option[CallContext]]
validate(value, elementTpe, v, apiVersion, callContext)
case Full((v1, v2)) =>
val tpe1 = getNestTypeArg(returnType, 0, 0)
val tpe2 = getNestTypeArg(returnType, 0, 1)
validateMultiple(value, apiVersion)(v1 -> tpe1, v2 -> tpe2)
// return type is: Box[List[(ProductCollectionItem, Product, List[ProductAttribute])]]
case Full(coll: Traversable[_])
if coll.nonEmpty &&
getNestTypeArg(returnType, 0, 0) <:< typeOf[(_, _, GenTraversableOnce[_])] =>
val tpe1 = getNestTypeArg(returnType, 0, 0, 0)
val tpe2 = getNestTypeArg(returnType, 0, 0, 1)
val tpe3 = getNestTypeArg(returnType, 0, 0, 2, 0)
val collTuple = coll.asInstanceOf[Traversable[(_, _, _)]]
val v1 = collTuple.map(_._1)
val v2 = collTuple.map(_._2)
val v3 = collTuple.map(_._3)
validateMultiple(value, apiVersion)(v1 -> tpe1, v2 -> tpe2, v3 -> tpe3)
case Full(coll: GenTraversableOnce[_]) if coll.nonEmpty =>
val elementTpe = getNestTypeArg(returnType, 0, 0)
validate(value, elementTpe, coll, apiVersion)
case Full(v) =>
val elementTpe = returnType.typeArgs.head
validate(value, elementTpe, v, apiVersion)
case (f @Full(v), cc: Option[_])
if getNestTypeArg(returnType, 1, 0) =:= typeOf[CallContext] =>
val elementTpe = getNestTypeArg(returnType, 0, 0)
val callContext = cc.asInstanceOf[Option[CallContext]]
val result = validate(f, elementTpe, v, apiVersion, callContext)
(result, cc)
case (v, cc: Option[_])
if getNestTypeArg(returnType, 1, 0) =:= typeOf[CallContext] =>
val elementTpe = returnType.typeArgs.head
val callContext = cc.asInstanceOf[Option[CallContext]]
validate(value, elementTpe, v, apiVersion, callContext, false)
case future: Future[_] =>
val futureType = returnType.typeArgs.head
future.map(v => validatRequiredFields(v.asInstanceOf[AnyRef], futureType, apiVersion))
case _ => validate(value, returnType, value, apiVersion, None, false)
}
}
private def validate[T: Manifest](originValue: AnyRef,
validateType: Type,
any: Any,
apiVersion: ApiVersion,
cc: Option[CallContext] = None,
resultIsBox: Boolean = true): AnyRef =
validateMultiple[T](originValue, apiVersion, cc, resultIsBox)(any -> validateType)
private def validateMultiple[T: Manifest](originValue: AnyRef,
apiVersion: ApiVersion,
cc: Option[CallContext] = None,
resultIsBox: Boolean = true)(valueAndType: (Any, Type)*): AnyRef = {
val (lefts, _) = valueAndType
.map(it => Helper.getRequiredFieldInfo(it._2).validate(it._1, apiVersion))
.classify(_.isLeft)
if(lefts.isEmpty) { // all validation passed
originValue
} else {
val missingFields = lefts.flatMap(_.left.get)
val value = missingFieldsToFailure(missingFields, cc)
if(resultIsBox) value else fullBoxOrException(value)
}
}
private def missingFieldsToFailure(missingFields: Seq[String], cc: Option[CallContext] = None): ParamFailure[APIFailureNewStyle] = {
val message = missingFields.map(it => s"data.$it")
.mkString(s"INTERNAL-$InvalidConnectorResponseForMissingRequiredValues The missing fields: [", ", ", "]")
logger.error(message)
ParamFailure(message, Empty, Empty, APIFailureNewStyle(message, 400, cc.map(_.toLight)))
}
}

View File

@ -9458,26 +9458,10 @@ trait RestConnector_vMar2019 extends Connector with KafkaHelper with MdcLoggable
}
private[this] def extractEntity[T: TypeTag: Manifest](responseEntity: ResponseEntity): Future[Box[T]] = {
val tp = typeTag[T].tpe
this.extractBody(responseEntity)
.map({
case null => Empty
case str => {
val box: Box[Box[T]] = tryo {
implicit val formats: Formats = CustomJsonFormats.nullTolerateFormats
val jValue = parse(str)
val extractResult: Either[List[String], T] = Helper.getRequiredFieldInfo(tp).validateAndExtract[T](jValue, apiVersion)
extractResult match {
case Left(missingFields) =>
val message = missingFields.mkString(s"INTERNAL-$InvalidConnectorResponseForMissingRequiredValues The missing fields: [", ", ", "]")
logger.error(message)
ParamFailure(message, Empty, Empty, APIFailure(message, 400))
case Right(entity) => Full(entity)
}
} ~> APIFailureNewStyle(s"$InvalidJsonFormat The Json body should be the ${tp.typeSymbol.fullName} ", 400)
box.flatten
}
case str => Connector.extractAdapterResponse[T](str)
})
}

View File

@ -13016,34 +13016,8 @@ trait StoredProcedureConnector_vDec2019 extends Connector with MdcLoggable {
private[this] def sendRequest[T <: InBoundTrait[_]: TypeTag : Manifest](procedureName: String, outBound: TopicTrait, callContext: Option[CallContext]): Future[Box[T]] = {
//transfer accountId to accountReference and customerId to customerReference in outBound
this.convertToReference(outBound)
val apiVersion = ApiVersionHolder.getApiVersion
val tp = typeTag[T].tpe
Future{
val jValue = StoredProcedureUtils.callProcedure(procedureName, outBound)
val box: Box[T] = jValue match {
case v if ErrorMessage.isErrorMessage(v) =>
val ErrorMessage(code, message) = v.extract[ErrorMessage]
ParamFailure(message, Empty, Empty, APIFailure(message, code))
case _ => {
val boxBox: Box[Box[T]] = tryo {
implicit val formats: Formats = CustomJsonFormats.nullTolerateFormats
val extractResult: Either[List[String], T] = Helper.getRequiredFieldInfo(tp).validateAndExtract[T](jValue, apiVersion)
extractResult match {
case Left(missingFields) =>
val message = missingFields.mkString(s"INTERNAL-$InvalidConnectorResponseForMissingRequiredValues The missing fields: [", ", ", "]")
logger.error(message)
ParamFailure(message, Empty, Empty, APIFailure(message, 400))
case Right(entity) => Full(entity)
}
} ~> APIFailureNewStyle(s"INTERNAL-$InvalidJsonFormat The Json body should be the ${tp.typeSymbol.fullName} ", 400)
boxBox match {
case Full(v) => v
case e: EmptyBox => e
}
}
}
box
StoredProcedureUtils.callProcedure[T](procedureName, outBound)
}.map(convertToId(_)) recoverWith {
case e: Exception => Future.failed(new Exception(s"$AdapterUnknownError Please Check Adapter Side! Details: ${e.getMessage}", e))
}

View File

@ -3,9 +3,9 @@ package code.bankconnectors.storedprocedure
import java.sql.Connection
import code.api.util.APIUtil
import code.bankconnectors.Connector
import com.openbankproject.commons.model.TopicTrait
import net.liftweb.json
import net.liftweb.json.JValue
import net.liftweb.common.Box
import net.liftweb.json.Serialization.write
import scalikejdbc.{DB, _}
@ -16,6 +16,8 @@ import scalikejdbc.{DB, _}
*/
object StoredProcedureUtils {
private implicit val formats = code.api.util.CustomJsonFormats.nullTolerateFormats
// lazy initial DB connection
{
val driver = APIUtil.getPropsValue("stored_procedure_connector.driver").openOrThrowException("mandatory property stored_procedure_connector.driver is missing!")
@ -42,8 +44,7 @@ object StoredProcedureUtils {
}
def callProcedure(procedureName: String, outBound: TopicTrait): JValue = {
implicit val formats = code.api.util.CustomJsonFormats.formats
def callProcedure[T: Manifest](procedureName: String, outBound: TopicTrait): Box[T] = {
val procedureParam: String = write(outBound) // convert OutBound to json string
val responseJson: String =
@ -72,8 +73,6 @@ object StoredProcedureUtils {
callableStatement.getString(2)
}
}
json.parse(responseJson)
Connector.extractAdapterResponse[T](responseJson)
}
}

View File

@ -158,7 +158,7 @@ class CommonGenerator(val methodName: String, tp: Type) {
|
| val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).get ${params})
| logger.debug(s"Kafka ${methodName} Req is: $$req")
| processRequest[InBound](req) map(validateRequiredFields(apiVersion)) map (convertToTuple(callContext))
| processRequest[InBound](req) map (convertToTuple(callContext))
| }
""".stripMargin

View File

@ -158,7 +158,7 @@ trait KafkaMappedConnector_vMay2019 extends Connector with KafkaHelper with MdcL
val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).get )
logger.debug(s"Kafka getAdapterInfo Req is: $req")
processRequest[InBound](req) map(validateRequiredFields(apiVersion)) map (convertToTuple(callContext))
processRequest[InBound](req) map (convertToTuple(callContext))
}
}
@ -236,7 +236,7 @@ trait KafkaMappedConnector_vMay2019 extends Connector with KafkaHelper with MdcL
val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).get , bankId)
logger.debug(s"Kafka getBank Req is: $req")
processRequest[InBound](req) map(validateRequiredFields(apiVersion)) map (convertToTuple(callContext))
processRequest[InBound](req) map (convertToTuple(callContext))
}
}
@ -313,7 +313,7 @@ trait KafkaMappedConnector_vMay2019 extends Connector with KafkaHelper with MdcL
val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).get )
logger.debug(s"Kafka getBanks Req is: $req")
processRequest[InBound](req) map(validateRequiredFields(apiVersion)) map (convertToTuple(callContext))
processRequest[InBound](req) map (convertToTuple(callContext))
}
}
@ -393,7 +393,7 @@ trait KafkaMappedConnector_vMay2019 extends Connector with KafkaHelper with MdcL
val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).get , bankIdAccountIds)
logger.debug(s"Kafka getBankAccountsBalances Req is: $req")
processRequest[InBound](req) map(validateRequiredFields(apiVersion)) map (convertToTuple(callContext))
processRequest[InBound](req) map (convertToTuple(callContext))
}
}
@ -520,7 +520,7 @@ trait KafkaMappedConnector_vMay2019 extends Connector with KafkaHelper with MdcL
val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).get , bankId, branchId)
logger.debug(s"Kafka getBranch Req is: $req")
processRequest[InBound](req) map(validateRequiredFields(apiVersion)) map (convertToTuple(callContext))
processRequest[InBound](req) map (convertToTuple(callContext))
}
}
@ -650,7 +650,7 @@ trait KafkaMappedConnector_vMay2019 extends Connector with KafkaHelper with MdcL
val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).get , bankId, OBPQueryParam.getLimit(queryParams), OBPQueryParam.getOffset(queryParams), OBPQueryParam.getFromDate(queryParams), OBPQueryParam.getToDate(queryParams))
logger.debug(s"Kafka getBranches Req is: $req")
processRequest[InBound](req) map(validateRequiredFields(apiVersion)) map (convertToTuple(callContext))
processRequest[InBound](req) map (convertToTuple(callContext))
}
}
@ -757,7 +757,7 @@ trait KafkaMappedConnector_vMay2019 extends Connector with KafkaHelper with MdcL
val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).get , bankId, atmId)
logger.debug(s"Kafka getAtm Req is: $req")
processRequest[InBound](req) map(validateRequiredFields(apiVersion)) map (convertToTuple(callContext))
processRequest[InBound](req) map (convertToTuple(callContext))
}
}
@ -867,7 +867,7 @@ trait KafkaMappedConnector_vMay2019 extends Connector with KafkaHelper with MdcL
val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).get , bankId, OBPQueryParam.getLimit(queryParams), OBPQueryParam.getOffset(queryParams), OBPQueryParam.getFromDate(queryParams), OBPQueryParam.getToDate(queryParams))
logger.debug(s"Kafka getAtms Req is: $req")
processRequest[InBound](req) map(validateRequiredFields(apiVersion)) map (convertToTuple(callContext))
processRequest[InBound](req) map (convertToTuple(callContext))
}
}
@ -959,7 +959,7 @@ trait KafkaMappedConnector_vMay2019 extends Connector with KafkaHelper with MdcL
val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).get , userId)
logger.debug(s"Kafka getCustomersByUserId Req is: $req")
processRequest[InBound](req) map(validateRequiredFields(apiVersion)) map (convertToTuple(callContext))
processRequest[InBound](req) map (convertToTuple(callContext))
}
}
@ -1051,7 +1051,7 @@ trait KafkaMappedConnector_vMay2019 extends Connector with KafkaHelper with MdcL
val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).get , customerId)
logger.debug(s"Kafka getCustomerByCustomerId Req is: $req")
processRequest[InBound](req) map(validateRequiredFields(apiVersion)) map (convertToTuple(callContext))
processRequest[InBound](req) map (convertToTuple(callContext))
}
}
@ -1144,7 +1144,7 @@ trait KafkaMappedConnector_vMay2019 extends Connector with KafkaHelper with MdcL
val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).get , customerNumber, bankId)
logger.debug(s"Kafka getCustomerByCustomerNumber Req is: $req")
processRequest[InBound](req) map(validateRequiredFields(apiVersion)) map (convertToTuple(callContext))
processRequest[InBound](req) map (convertToTuple(callContext))
}
}
@ -1152,21 +1152,6 @@ trait KafkaMappedConnector_vMay2019 extends Connector with KafkaHelper with MdcL
//---------------- dynamic end ---------------------please don't modify this line
private[this] def validateRequiredFields[T: TypeTag: Manifest](version: ApiVersion)(box: Box[T]): Box[T] =
box match {
case Full(entity) => {
val value: Either[List[String], T] = RequiredFieldValidation.getRequiredInfo(typeTag[T].tpe).validate(entity, version)
value match {
case Left(missingFields) =>
val message = missingFields.mkString(s"INTERNAL-$InvalidConnectorResponseForMissingRequiredValues The missing fields: [", ", ", "]")
logger.error(message)
ParamFailure(message, Empty, Empty, APIFailure(message, 400))
case _ => box
}
}
case _ => box
}
//-----helper methods

View File

@ -204,7 +204,7 @@ class CommonGenerator(val methodName: String, typeSignature: Type) {
|
| val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).get ${parametersNamesString})
| logger.debug(s"Kafka ${methodName} Req is: $$req")
| processRequest[InBound](req) map(validateRequiredFields(apiVersion)) map (convertToTuple(callContext))
| processRequest[InBound](req) map (convertToTuple(callContext))
| }
""".stripMargin

View File

@ -3160,7 +3160,7 @@ trait KafkaMappedConnector_vSept2018 extends Connector with KafkaHelper with Mdc
val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).get , bankId, accountId, accountType, accountLabel, currency, initialBalance, accountHolderName, branchId, accountRoutingScheme, accountRoutingAddress)
logger.debug(s"Kafka createBankAccount Req is: $req")
processRequest[InBound](req) map(validateRequiredFields(apiVersion)) map (convertToTuple(callContext))
processRequest[InBound](req) map (convertToTuple(callContext))
}
@ -3260,7 +3260,7 @@ trait KafkaMappedConnector_vSept2018 extends Connector with KafkaHelper with Mdc
val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).get , bankId, legalName, mobileNumber, email, faceImage, dateOfBirth, relationshipStatus, dependents, dobOfDependents, highestEducationAttained, employmentStatus, kycStatus, lastOkDate, creditRating, creditLimit, title, branchId, nameSuffix)
logger.debug(s"Kafka createCustomer Req is: $req")
processRequest[InBound](req) map(validateRequiredFields(apiVersion)) map (convertToTuple(callContext))
processRequest[InBound](req) map (convertToTuple(callContext))
}
@ -3336,7 +3336,7 @@ trait KafkaMappedConnector_vSept2018 extends Connector with KafkaHelper with Mdc
val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).get , bankId, customerId, id, customerNumber, date, how, staffUserId, mStaffName, mSatisfied, comments)
logger.debug(s"Kafka createOrUpdateKycCheck Req is: $req")
processRequest[InBound](req) map(validateRequiredFields(apiVersion)) map (convertToTuple(callContext))
processRequest[InBound](req) map (convertToTuple(callContext))
}
@ -3410,7 +3410,7 @@ trait KafkaMappedConnector_vSept2018 extends Connector with KafkaHelper with Mdc
val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).get , bankId, customerId, id, customerNumber, `type`, number, issueDate, issuePlace, expiryDate)
logger.debug(s"Kafka createOrUpdateKycDocument Req is: $req")
processRequest[InBound](req) map(validateRequiredFields(apiVersion)) map (convertToTuple(callContext))
processRequest[InBound](req) map (convertToTuple(callContext))
}
@ -3484,7 +3484,7 @@ trait KafkaMappedConnector_vSept2018 extends Connector with KafkaHelper with Mdc
val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).get , bankId, customerId, id, customerNumber, `type`, url, date, relatesToKycDocumentId, relatesToKycCheckId)
logger.debug(s"Kafka createOrUpdateKycMedia Req is: $req")
processRequest[InBound](req) map(validateRequiredFields(apiVersion)) map (convertToTuple(callContext))
processRequest[InBound](req) map (convertToTuple(callContext))
}
@ -3550,7 +3550,7 @@ trait KafkaMappedConnector_vSept2018 extends Connector with KafkaHelper with Mdc
val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).get , bankId, customerId, customerNumber, ok, date)
logger.debug(s"Kafka createOrUpdateKycStatus Req is: $req")
processRequest[InBound](req) map(validateRequiredFields(apiVersion)) map (convertToTuple(callContext))
processRequest[InBound](req) map (convertToTuple(callContext))
}
@ -3626,7 +3626,7 @@ trait KafkaMappedConnector_vSept2018 extends Connector with KafkaHelper with Mdc
val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).get , customerId)
logger.debug(s"Kafka getKycChecks Req is: $req")
processRequest[InBound](req) map(validateRequiredFields(apiVersion)) map (convertToTuple(callContext))
processRequest[InBound](req) map (convertToTuple(callContext))
}
}
@ -3704,7 +3704,7 @@ trait KafkaMappedConnector_vSept2018 extends Connector with KafkaHelper with Mdc
val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).get , customerId)
logger.debug(s"Kafka getKycDocuments Req is: $req")
processRequest[InBound](req) map(validateRequiredFields(apiVersion)) map (convertToTuple(callContext))
processRequest[InBound](req) map (convertToTuple(callContext))
}
}
@ -3782,7 +3782,7 @@ trait KafkaMappedConnector_vSept2018 extends Connector with KafkaHelper with Mdc
val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).get , customerId)
logger.debug(s"Kafka getKycMedias Req is: $req")
processRequest[InBound](req) map(validateRequiredFields(apiVersion)) map (convertToTuple(callContext))
processRequest[InBound](req) map (convertToTuple(callContext))
}
}
@ -3856,7 +3856,7 @@ trait KafkaMappedConnector_vSept2018 extends Connector with KafkaHelper with Mdc
val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).get , customerId)
logger.debug(s"Kafka getKycStatuses Req is: $req")
processRequest[InBound](req) map(validateRequiredFields(apiVersion)) map (convertToTuple(callContext))
processRequest[InBound](req) map (convertToTuple(callContext))
}
}
@ -3877,22 +3877,6 @@ trait KafkaMappedConnector_vSept2018 extends Connector with KafkaHelper with Mdc
//-----helper methods
private[this] def validateRequiredFields[T: TypeTag: Manifest](version: ApiVersion)(box: Box[T]): Box[T] =
box match {
case Full(entity) => {
val value: Either[List[String], T] = RequiredFieldValidation.getRequiredInfo(typeTag[T].tpe).validate(entity, version)
value match {
case Left(missingFields) =>
val message = missingFields.mkString(s"INTERNAL-$InvalidConnectorResponseForMissingRequiredValues The missing fields: [", ", ", "]")
logger.error(message)
ParamFailure(message, Empty, Empty, APIFailure(message, 400))
case _ => box
}
}
case _ => box
}
private[this] def convertToTuple[T](callContext: Option[CallContext]) (inbound: Box[InBoundTrait[T]]): (Box[T], Option[CallContext]) = {
val boxedResult = inbound match {
case Full(in) if (in.status.hasNoError) => Full(in.data)

View File

@ -12,6 +12,7 @@ import net.liftweb.json.{Formats, JValue}
import net.liftweb.json.JsonDSL._
import scala.collection.GenTraversableOnce
import scala.collection.mutable.ArrayBuffer
/**
* Mark given type's field or constructor variable is required for some apiVersion
@ -100,8 +101,8 @@ case class RequiredInfo(requiredArgs: Seq[RequiredArgs]) extends RequiredFields
val scannedPathValue: JValue = prePathValue match {
case JArray(arr) => {
val (jArrayList: List[JArray], jValueList) = arr.classify(_.isInstanceOf[JArray])
val newArr: List[JValue] = jArrayList.flatMap(_.arr) :: jValueList
val (jArrayList: List[_], jValueList) = arr.classify(_.isInstanceOf[JArray])
val newArr: List[JValue] = jArrayList.flatMap(_.asInstanceOf[JArray].arr) :: jValueList
val noEmpties = newArr.filterNot(isEmpty)
JArray(noEmpties) \ currentPath
@ -132,7 +133,7 @@ case class RequiredInfo(requiredArgs: Seq[RequiredArgs]) extends RequiredFields
}
}
def validate[T: Manifest](entity: T, apiVersion: ApiVersion)(implicit formats: Formats): Either[List[String], T] = {
def validate[T](entity: T, apiVersion: ApiVersion): Either[List[String], T] = {
val noValuePath = scala.collection.mutable.ListBuffer[String]()
val map = scala.collection.mutable.Map[String, Any]()
@ -184,6 +185,7 @@ case class RequiredInfo(requiredArgs: Seq[RequiredArgs]) extends RequiredFields
*/
private def flatten(any: Any): Any = any match {
case a:Array[_] => Functions.deepFlatten(a)
case ab: ArrayBuffer[_] => Functions.deepFlatten(ab.toArray[Any])
case coll: GenTraversableOnce[_] => Functions.deepFlatten(coll.toArray[Any])
case _ => any
}