diff --git a/obp-api/src/main/scala/code/api/util/APIUtil.scala b/obp-api/src/main/scala/code/api/util/APIUtil.scala index 3aa668df9..6e4851639 100644 --- a/obp-api/src/main/scala/code/api/util/APIUtil.scala +++ b/obp-api/src/main/scala/code/api/util/APIUtil.scala @@ -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) diff --git a/obp-api/src/main/scala/code/bankconnectors/Connector.scala b/obp-api/src/main/scala/code/bankconnectors/Connector.scala index 759be170e..6c9e4800b 100644 --- a/obp-api/src/main/scala/code/bankconnectors/Connector.scala +++ b/obp-api/src/main/scala/code/bankconnectors/Connector.scala @@ -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) } -} \ No newline at end of file +} diff --git a/obp-api/src/main/scala/code/bankconnectors/package.scala b/obp-api/src/main/scala/code/bankconnectors/package.scala index 5898df246..14ad1812e 100644 --- a/obp-api/src/main/scala/code/bankconnectors/package.scala +++ b/obp-api/src/main/scala/code/bankconnectors/package.scala @@ -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))) + } } diff --git a/obp-api/src/main/scala/code/bankconnectors/rest/RestConnector_vMar2019.scala b/obp-api/src/main/scala/code/bankconnectors/rest/RestConnector_vMar2019.scala index 6d187a295..46ef41564 100644 --- a/obp-api/src/main/scala/code/bankconnectors/rest/RestConnector_vMar2019.scala +++ b/obp-api/src/main/scala/code/bankconnectors/rest/RestConnector_vMar2019.scala @@ -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) }) } diff --git a/obp-api/src/main/scala/code/bankconnectors/storedprocedure/StoredProcedureConnector_vDec2019.scala b/obp-api/src/main/scala/code/bankconnectors/storedprocedure/StoredProcedureConnector_vDec2019.scala index fc0cc5fb3..399088bbc 100644 --- a/obp-api/src/main/scala/code/bankconnectors/storedprocedure/StoredProcedureConnector_vDec2019.scala +++ b/obp-api/src/main/scala/code/bankconnectors/storedprocedure/StoredProcedureConnector_vDec2019.scala @@ -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)) } diff --git a/obp-api/src/main/scala/code/bankconnectors/storedprocedure/StoredProcedureUtils.scala b/obp-api/src/main/scala/code/bankconnectors/storedprocedure/StoredProcedureUtils.scala index 919caf92d..d1ee41bc4 100644 --- a/obp-api/src/main/scala/code/bankconnectors/storedprocedure/StoredProcedureUtils.scala +++ b/obp-api/src/main/scala/code/bankconnectors/storedprocedure/StoredProcedureUtils.scala @@ -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) } - } diff --git a/obp-api/src/main/scala/code/bankconnectors/vMay2019/KafkaConnectorBuilder.scala b/obp-api/src/main/scala/code/bankconnectors/vMay2019/KafkaConnectorBuilder.scala index 0e153f611..9749c6bfe 100644 --- a/obp-api/src/main/scala/code/bankconnectors/vMay2019/KafkaConnectorBuilder.scala +++ b/obp-api/src/main/scala/code/bankconnectors/vMay2019/KafkaConnectorBuilder.scala @@ -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 diff --git a/obp-api/src/main/scala/code/bankconnectors/vMay2019/KafkaMappedConnector_vMay2019.scala b/obp-api/src/main/scala/code/bankconnectors/vMay2019/KafkaMappedConnector_vMay2019.scala index 1a32ec9ad..d48639306 100644 --- a/obp-api/src/main/scala/code/bankconnectors/vMay2019/KafkaMappedConnector_vMay2019.scala +++ b/obp-api/src/main/scala/code/bankconnectors/vMay2019/KafkaMappedConnector_vMay2019.scala @@ -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 diff --git a/obp-api/src/main/scala/code/bankconnectors/vSept2018/KafkaConnectorBuilder.scala b/obp-api/src/main/scala/code/bankconnectors/vSept2018/KafkaConnectorBuilder.scala index 211414227..288f0bdcc 100644 --- a/obp-api/src/main/scala/code/bankconnectors/vSept2018/KafkaConnectorBuilder.scala +++ b/obp-api/src/main/scala/code/bankconnectors/vSept2018/KafkaConnectorBuilder.scala @@ -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 diff --git a/obp-api/src/main/scala/code/bankconnectors/vSept2018/KafkaMappedConnector_vSept2018.scala b/obp-api/src/main/scala/code/bankconnectors/vSept2018/KafkaMappedConnector_vSept2018.scala index 4b7270a21..94169cc4b 100644 --- a/obp-api/src/main/scala/code/bankconnectors/vSept2018/KafkaMappedConnector_vSept2018.scala +++ b/obp-api/src/main/scala/code/bankconnectors/vSept2018/KafkaMappedConnector_vSept2018.scala @@ -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) diff --git a/obp-commons/src/main/scala/com/openbankproject/commons/util/RequiredFieldValidation.scala b/obp-commons/src/main/scala/com/openbankproject/commons/util/RequiredFieldValidation.scala index 4fcc1b202..f10412d99 100644 --- a/obp-commons/src/main/scala/com/openbankproject/commons/util/RequiredFieldValidation.scala +++ b/obp-commons/src/main/scala/com/openbankproject/commons/util/RequiredFieldValidation.scala @@ -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 }