diff --git a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala index 3893d9441..da0bb1bdf 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/APIMethods400.scala @@ -873,7 +873,7 @@ trait APIMethods400 { case EntityName(entityName) :: Nil JsonGet req => { cc => val listName = StringHelpers.snakify(English.plural(entityName)) for { - (Full(resultList: JObject), _) <- NewStyle.function.invokeDynamicConnector(GET_ALL, entityName, None, None, Some(cc)) + (Full(resultList: JArray), _) <- NewStyle.function.invokeDynamicConnector(GET_ALL, entityName, None, None, Some(cc)) } yield { import net.liftweb.json.JsonDSL._ val jValue: JObject = listName -> resultList diff --git a/obp-api/src/main/scala/code/api/v4_0_0/DynamicEntityHelper.scala b/obp-api/src/main/scala/code/api/v4_0_0/DynamicEntityHelper.scala index 48e06859a..cc3906968 100644 --- a/obp-api/src/main/scala/code/api/v4_0_0/DynamicEntityHelper.scala +++ b/obp-api/src/main/scala/code/api/v4_0_0/DynamicEntityHelper.scala @@ -53,7 +53,11 @@ object MockerConnector { def getAll(entityName: String) = persistedEntities.filter(pair => pair._1._2 == entityName).values - def delete(entityName: String, id: String): Box[Boolean] = persistedEntities.remove(id -> entityName).map(_ => true) + def delete(entityName: String, id: String): Box[Boolean] = { + val idName = StringUtils.uncapitalize(entityName) + "Id" + require(persistedEntities.contains(id -> entityName), s"$InvalidUrl not exists ${entityName} of ${idName} = $id") + persistedEntities.remove(id -> entityName).map(_ => true) + } def doc = { val docs: Seq[ResourceDoc] = definitionsMap.values.flatMap(createDocs).toSeq diff --git a/obp-api/src/main/scala/code/bankconnectors/ConnectorEndpoints.scala b/obp-api/src/main/scala/code/bankconnectors/ConnectorEndpoints.scala index c5130576b..2be0a303a 100644 --- a/obp-api/src/main/scala/code/bankconnectors/ConnectorEndpoints.scala +++ b/obp-api/src/main/scala/code/bankconnectors/ConnectorEndpoints.scala @@ -144,8 +144,8 @@ object ConnectorEndpoints extends RestHelper{ // it is impossible to get the type of OBPQueryParam*, ru.typeOf[OBPQueryParam*] not work, it is Seq type indeed private val paramsType = ru.typeOf[Seq[OBPQueryParam]] - // (methodName, paramNames, method, allParamNames) - lazy val allMethods: List[(String, List[String], ru.MethodSymbol, List[String])] = { + // (methodName, paramNames, method, allParamNames, fn: paramName => isOption) + lazy val allMethods: List[(String, List[String], ru.MethodSymbol, List[String], String => Boolean)] = { val mirror: ru.Mirror = ru.runtimeMirror(this.getClass.getClassLoader) val objMirror = mirror.reflect(LocalMappedConnector) @@ -161,14 +161,17 @@ object ConnectorEndpoints extends RestHelper{ val names = allParams .filterNot(symbol => isCallContextOrQueryParams(symbol.info)) .map(_.name.toString.trim) - (it.name.toString, names, it.asMethod, allNames) + val paramNameToIsOption: Map[String, Boolean] = allParams.map(it => (it.name.toString.trim, it.info <:< ru.typeOf[Option[_]])).toMap + val isParamOption: String => Boolean = name => paramNameToIsOption.get(name).filter(true ==).isDefined + (it.name.toString, names, it.asMethod, allNames, isParamOption) }) .toList } def getMethod(methodName: String, json: JValue): Option[ru.MethodSymbol] = { - this.allMethods.filter { triple => - triple._1 == methodName && triple._2.forall(paramName => (json \ paramName) != JNothing) + this.allMethods.filter { quadruple => + val (mName, paramNames, _, _, isParamOption) = quadruple + mName == methodName && paramNames.forall(paramName => isParamOption(paramName) || (json \ paramName) != JNothing) } .sortBy(_._2.size) .lastOption diff --git a/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala b/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala index c4b72553a..82ae24715 100644 --- a/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala +++ b/obp-api/src/main/scala/code/bankconnectors/LocalMappedConnector.scala @@ -13,6 +13,7 @@ import code.api.util.ErrorMessages._ import com.openbankproject.commons.model.enums.StrongCustomerAuthentication.SCA import code.api.util._ import code.api.v4_0_0.MockerConnector +import code.api.v4_0_0.MockerConnector.persistedEntities import code.atms.Atms.Atm import code.atms.MappedAtm import code.branches.Branches.Branch @@ -64,6 +65,7 @@ import net.liftweb.mapper.{By, _} import net.liftweb.util.Helpers.{tryo, _} import net.liftweb.util.Mailer import net.liftweb.util.Mailer.{From, PlainMailBodyType, Subject, To} +import org.apache.commons.lang3.StringUtils import org.mindrot.jbcrypt.BCrypt import scalacache.ScalaCache import scalacache.guava.GuavaCache @@ -2793,25 +2795,39 @@ object LocalMappedConnector extends Connector with MdcLoggable { entityName: String, requestBody: Option[JObject], entityId: Option[String], - callContext: Option[CallContext]): OBPReturnType[Box[JValue]] = Future { - val processResult: Box[JValue] = operation match { - case GET_ALL => Full { - JArray(MockerConnector.getAll(entityName).toList) - } - case GET_ONE => { - val boxedEntity: Box[JValue] = MockerConnector.getSingle(entityName, entityId.getOrElse(throw new RuntimeException(s"$DynamicEntityMissArgument the entityId is required."))) - boxedEntity - } - case CREATE | UPDATE => { - val body = requestBody.getOrElse(throw new RuntimeException(s"$DynamicEntityMissArgument please supply the requestBody.")) - val persistedEntity = MockerConnector.persist(entityName, body, entityId) - Full(persistedEntity) - } - case DELETE => { - val deleteResult = MockerConnector.delete(entityName, entityId.getOrElse(throw new RuntimeException(s"$DynamicEntityMissArgument the entityId is required. "))) - deleteResult.map(JBool(_)) + callContext: Option[CallContext]): OBPReturnType[Box[JValue]] = { + operation match { + case GET_ONE | UPDATE | DELETE => { + val id = entityId.getOrElse(throw new RuntimeException(s"$DynamicEntityMissArgument the entityId is required.")) + val idName = StringUtils.uncapitalize(entityName) + "Id" + val idExists = persistedEntities.contains(id -> entityName) + if(!idExists) { + throw new RuntimeException(s"$InvalidUrl not exists ${entityName} of ${idName} = $id") + } } + case _ => Unit + } + + Future { + val processResult: Box[JValue] = operation match { + case GET_ALL => Full { + JArray(MockerConnector.getAll(entityName).toList) + } + case GET_ONE => { + val boxedEntity: Box[JValue] = MockerConnector.getSingle(entityName, entityId.getOrElse(throw new RuntimeException(s"$DynamicEntityMissArgument the entityId is required."))) + boxedEntity + } + case CREATE | UPDATE => { + val body = requestBody.getOrElse(throw new RuntimeException(s"$DynamicEntityMissArgument please supply the requestBody.")) + val persistedEntity = MockerConnector.persist(entityName, body, entityId) + Full(persistedEntity) + } + case DELETE => { + val deleteResult = MockerConnector.delete(entityName, entityId.getOrElse(throw new RuntimeException(s"$DynamicEntityMissArgument the entityId is required. "))) + deleteResult.map(JBool(_)) + } + } + (processResult, callContext) } - (processResult, callContext) } } diff --git a/obp-api/src/main/scala/code/bankconnectors/package.scala b/obp-api/src/main/scala/code/bankconnectors/package.scala index 426b98d5c..0775ad09d 100644 --- a/obp-api/src/main/scala/code/bankconnectors/package.scala +++ b/obp-api/src/main/scala/code/bankconnectors/package.scala @@ -71,6 +71,12 @@ package object bankconnectors { } val connectorName: Box[String] = bankId match { + case None if methodName == "dynamicEntityProcess" => { + val entityName = args.tail.head + NewStyle.function.getMethodRoutings(Some(methodName)) + .find(_.parameters.exists(it => it.key == "entityName" && it.value == entityName)) + .map(_.connectorName) + } case None => NewStyle.function.getMethodRoutings(Some(methodName), Some(false)) .find {routing => val bankIdPattern = routing.bankIdPattern 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 ae9d2a910..bc9d5c8d6 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 @@ -57,7 +57,7 @@ import code.api.util.APIUtil._ import com.openbankproject.commons.model.enums.StrongCustomerAuthentication.SCA import code.customer.internalMapping.MappedCustomerIdMappingProvider import code.model.dataAccess.internalMapping.MappedAccountIdMappingProvider -import com.openbankproject.commons.model.enums.{AccountAttributeType, CardAttributeType, ProductAttributeType} +import com.openbankproject.commons.model.enums.{AccountAttributeType, CardAttributeType, DynamicEntityOperation, ProductAttributeType} import com.openbankproject.commons.util.ReflectUtils import net.liftweb.json._ @@ -9240,9 +9240,19 @@ trait RestConnector_vMar2019 extends Connector with KafkaHelper with MdcLoggable val result: OBPReturnType[Box[TransactionId]] = sendRequest[InBound](url, HttpMethods.POST, req, callContext).map(convertToTuple(callContext)) result } - -//---------------- dynamic end ---------------------please don't modify this line - + + //---------------- dynamic end ---------------------please don't modify this line + override def dynamicEntityProcess(operation: DynamicEntityOperation, + entityName: String, + requestBody: Option[JObject], + entityId: Option[String], + callContext: Option[CallContext]): OBPReturnType[Box[JValue]] = { + import com.openbankproject.commons.dto.{OutBoundDynamicEntityProcess => OutBound, InBoundDynamicEntityProcess => InBound} + val url = getUrl(callContext, "dynamicEntityProcess") + val req = OutBound(callContext.map(_.toOutboundAdapterCallContext).orNull , operation, entityName, requestBody, entityId) + val result: OBPReturnType[Box[JValue]] = sendRequest[InBound](url, HttpMethods.POST, req, callContext).map(convertToTuple(callContext)) + result + } //In RestConnector, we use the headers to propagate the parameters to Adapter. The parameters come from the CallContext.outboundAdapterAuthInfo.userAuthContext diff --git a/obp-commons/pom.xml b/obp-commons/pom.xml index 91e4084ed..c8d52f56b 100644 --- a/obp-commons/pom.xml +++ b/obp-commons/pom.xml @@ -40,6 +40,11 @@ org.scalactic scalactic_${scala.version} + + net.liftweb + lift-json_${scala.version} + ${lift.version} + diff --git a/obp-commons/src/main/scala/com/openbankproject/commons/dto/JsonsTransfer.scala b/obp-commons/src/main/scala/com/openbankproject/commons/dto/JsonsTransfer.scala index a38c49748..10381839b 100644 --- a/obp-commons/src/main/scala/com/openbankproject/commons/dto/JsonsTransfer.scala +++ b/obp-commons/src/main/scala/com/openbankproject/commons/dto/JsonsTransfer.scala @@ -28,9 +28,10 @@ package com.openbankproject.commons.dto import java.util.Date -import com.openbankproject.commons.model.enums.CardAttributeType +import com.openbankproject.commons.model.enums.{CardAttributeType, DynamicEntityOperation} import com.openbankproject.commons.model.enums.StrongCustomerAuthentication.SCA import com.openbankproject.commons.model.{enums, _} +import net.liftweb.json.{JObject, JValue} import scala.collection.immutable.List @@ -1157,4 +1158,11 @@ case class InBoundGetBankAccountByIban (inboundAdapterCallContext: InboundAdapte case class OutBoundGetBankAccounts (outboundAdapterCallContext: OutboundAdapterCallContext, bankIdAccountIds: List[BankIdAccountId]) extends TopicTrait -case class InBoundGetBankAccounts (inboundAdapterCallContext: InboundAdapterCallContext, status: Status, data: List[BankAccountCommons]) extends InBoundTrait[List[BankAccountCommons]] \ No newline at end of file +case class InBoundGetBankAccounts (inboundAdapterCallContext: InboundAdapterCallContext, status: Status, data: List[BankAccountCommons]) extends InBoundTrait[List[BankAccountCommons]] + +case class OutBoundDynamicEntityProcess (outboundAdapterCallContext: OutboundAdapterCallContext, + operation: DynamicEntityOperation, + entityName: String, + requestBody: Option[JObject], + entityId: Option[String]) extends TopicTrait +case class InBoundDynamicEntityProcess (inboundAdapterCallContext: InboundAdapterCallContext, status: Status, data: JValue) extends InBoundTrait[JValue] \ No newline at end of file