Merge pull request #2646 from hongwei1/develop

docfix/fixed tests and added documents
This commit is contained in:
Simon Redfern 2025-12-16 11:25:02 +01:00 committed by GitHub
commit 55ecb640e9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
34 changed files with 178 additions and 170 deletions

3
.gitignore vendored
View File

@ -40,4 +40,5 @@ marketing_diagram_generation/outputs/*
.specstory
project/project
coursier
metals.sbt
metals.sbt
obp-http4s-runner/src/main/resources/git.properties

View File

@ -67,6 +67,17 @@ To compile and run Jetty, install Maven 3, create your configuration in `obp-api
mvn install -pl .,obp-commons && mvn jetty:run -pl obp-api
```
### Running http4s server (obp-http4s-runner)
To run the API using the http4s server (without Jetty), use the `obp-http4s-runner` module from the project root:
```sh
MAVEN_OPTS="-Xms3G -Xmx6G -XX:MaxMetaspaceSize=2G" mvn -pl obp-http4s-runner -am clean package -DskipTests=true -Dmaven.test.skip=true && \
java -jar obp-http4s-runner/target/obp-http4s-runner.jar
```
The http4s server binds to `http4s.host` / `http4s.port` as configured in your props file (defaults are `127.0.0.1` and `8181`).
### ZED IDE Setup
For ZED IDE users, we provide a complete development environment with Scala language server support:

View File

@ -23,52 +23,6 @@
<webXmlPath>src/main/resources/web.xml</webXmlPath>
</properties>
</profile>
<profile>
<id>http4s-jar</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.6.0</version>
<configuration>
<appendAssemblyId>false</appendAssemblyId>
<finalName>${project.artifactId}-http4s</finalName>
<archive>
<manifest>
<mainClass>bootstrap.http4s.Http4sServer</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<dependencySets>
<dependencySet>
<outputDirectory>/</outputDirectory>
<unpack>true</unpack>
<scope>runtime</scope>
</dependencySet>
</dependencySets>
<fileSets>
<fileSet>
<directory>${project.build.outputDirectory}</directory>
<outputDirectory>/</outputDirectory>
</fileSet>
</fileSets>
</configuration>
<executions>
<execution>
<id>http4s-fat-jar</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<pluginRepositories>
<pluginRepository>
@ -83,7 +37,8 @@
<groupId>com.tesobe</groupId>
<artifactId>obp-commons</artifactId>
</dependency>
<!--embed akka adapter start-->
<!--embed akka adapter start - COMMENTED OUT FOR PEKKO MIGRATION-->
<!-- TODO: Find or create Pekko equivalent for adapter-akka-commons
<dependency>
<groupId>com.github.OpenBankProject.OBP-Adapter-Akka-SpringBoot</groupId>
<artifactId>adapter-akka-commons</artifactId>
@ -95,6 +50,7 @@
</exclusion>
</exclusions>
</dependency>
-->
<!--embed akka adapter end-->
<dependency>
<groupId>com.github.everit-org.json-schema</groupId>
@ -288,21 +244,21 @@
<artifactId>signpost-commonshttp4</artifactId>
<version>1.2.1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.typesafe.akka/akka-http-core -->
<!-- https://mvnrepository.com/artifact/org.apache.pekko/pekko-http-core -->
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-http-core_${scala.version}</artifactId>
<version>10.1.6</version>
<groupId>org.apache.pekko</groupId>
<artifactId>pekko-http-core_${scala.version}</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-actor_${scala.version}</artifactId>
<version>${akka.version}</version>
<groupId>org.apache.pekko</groupId>
<artifactId>pekko-actor_${scala.version}</artifactId>
<version>${pekko.version}</version>
</dependency>
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-remote_${scala.version}</artifactId>
<version>${akka.version}</version>
<groupId>org.apache.pekko</groupId>
<artifactId>pekko-remote_${scala.version}</artifactId>
<version>${pekko.version}</version>
</dependency>
<dependency>
<groupId>com.sksamuel.avro4s</groupId>
@ -316,8 +272,8 @@
</dependency>
<dependency>
<groupId>com.twitter</groupId>
<artifactId>chill-akka_${scala.version}</artifactId>
<version>0.9.1</version>
<artifactId>chill_${scala.version}</artifactId>
<version>0.9.3</version>
</dependency>
<dependency>
<groupId>com.twitter</groupId>
@ -337,9 +293,9 @@
<version>0.9.3</version>
</dependency>
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-slf4j_${scala.version}</artifactId>
<version>${akka.version}</version>
<groupId>org.apache.pekko</groupId>
<artifactId>pekko-slf4j_${scala.version}</artifactId>
<version>${pekko.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.github.dwickern/scala-nameof_2.11 -->
<dependency>

View File

@ -1683,3 +1683,13 @@ securelogging_mask_credit_card=true
# Email addresses
securelogging_mask_email=true
############################################
# http4s server configuration
############################################
# Host and port for http4s server (used by bootstrap.http4s.Http4sServer)
# Defaults (if not set) are 127.0.0.1 and 8181
http4s.host=127.0.0.1
http4s.port=8086

View File

@ -13,12 +13,12 @@ object ObpActorConfig {
val commonConf =
"""
akka {
loggers = ["akka.event.slf4j.Slf4jLogger"]
pekko {
loggers = ["org.apache.pekko.event.slf4j.Slf4jLogger"]
loglevel = """ + akka_loglevel + """
actor {
provider = "akka.remote.RemoteActorRefProvider"
allow-java-serialization = off
provider = "org.apache.pekko.remote.RemoteActorRefProvider"
allow-java-serialization = on
kryo {
type = "graph"
idstrategy = "default"
@ -40,31 +40,31 @@ object ObpActorConfig {
resolve-subclasses = true
}
serializers {
kryo = "com.twitter.chill.akka.AkkaSerializer"
java = "org.apache.pekko.serialization.JavaSerializer"
}
serialization-bindings {
"net.liftweb.common.Full" = kryo,
"net.liftweb.common.Empty" = kryo,
"net.liftweb.common.Box" = kryo,
"net.liftweb.common.ParamFailure" = kryo,
"code.api.APIFailure" = kryo,
"com.openbankproject.commons.model.BankAccount" = kryo,
"com.openbankproject.commons.model.View" = kryo,
"com.openbankproject.commons.model.User" = kryo,
"com.openbankproject.commons.model.ViewId" = kryo,
"com.openbankproject.commons.model.BankIdAccountIdViewId" = kryo,
"com.openbankproject.commons.model.Permission" = kryo,
"scala.Unit" = kryo,
"scala.Boolean" = kryo,
"java.io.Serializable" = kryo,
"scala.collection.immutable.List" = kryo,
"akka.actor.ActorSelectionMessage" = kryo,
"code.model.Consumer" = kryo,
"code.model.AppType" = kryo
"net.liftweb.common.Full" = java,
"net.liftweb.common.Empty" = java,
"net.liftweb.common.Box" = java,
"net.liftweb.common.ParamFailure" = java,
"code.api.APIFailure" = java,
"com.openbankproject.commons.model.BankAccount" = java,
"com.openbankproject.commons.model.View" = java,
"com.openbankproject.commons.model.User" = java,
"com.openbankproject.commons.model.ViewId" = java,
"com.openbankproject.commons.model.BankIdAccountIdViewId" = java,
"com.openbankproject.commons.model.Permission" = java,
"scala.Unit" = java,
"scala.Boolean" = java,
"java.io.Serializable" = java,
"scala.collection.immutable.List" = java,
"org.apache.pekko.actor.ActorSelectionMessage" = java,
"code.model.Consumer" = java,
"code.model.AppType" = java
}
}
remote {
enabled-transports = ["akka.remote.netty.tcp"]
enabled-transports = ["org.apache.pekko.remote.netty.tcp"]
netty {
tcp {
send-buffer-size = 50000000
@ -79,7 +79,7 @@ object ObpActorConfig {
val lookupConf =
s"""
${commonConf}
akka {
pekko {
remote.netty.tcp.hostname = ${localHostname}
remote.netty.tcp.port = 0
}
@ -88,7 +88,7 @@ object ObpActorConfig {
val localConf =
s"""
${commonConf}
akka {
pekko {
remote.netty.tcp.hostname = ${localHostname}
remote.netty.tcp.port = ${localPort}
}

View File

@ -1,6 +1,6 @@
package code.actorsystem
import akka.actor.ActorSystem
import org.apache.pekko.actor.ActorSystem
import code.bankconnectors.akka.actor.AkkaConnectorActorConfig
import code.util.Helper
import code.util.Helper.MdcLoggable

View File

@ -1,12 +1,12 @@
package code.actorsystem
import akka.actor.{ActorSystem}
import org.apache.pekko.actor.{ActorSystem}
import code.api.util.APIUtil
import code.bankconnectors.LocalMappedOutInBoundTransfer
import code.bankconnectors.akka.actor.{AkkaConnectorActorConfig, AkkaConnectorHelperActor}
import code.util.Helper
import code.util.Helper.MdcLoggable
import com.openbankproject.adapter.akka.commons.config.AkkaConfig
// import com.openbankproject.adapter.pekko.commons.config.PekkoConfig // TODO: Re-enable when Pekko adapter is available
import com.typesafe.config.ConfigFactory
import net.liftweb.common.Full
@ -38,7 +38,7 @@ trait ObpLookupSystem extends MdcLoggable {
if (port == 0) {
logger.error("Failed to connect to local Remotedata actor, the port is 0, can not find a proper port in current machine.")
}
s"akka.tcp://ObpActorSystem_${props_hostname}@${hostname}:${port}/user/${actorName}"
s"pekko.tcp://ObpActorSystem_${props_hostname}@${hostname}:${port}/user/${actorName}"
}
this.obpLookupSystem.actorSelection(actorPath)
@ -55,7 +55,7 @@ trait ObpLookupSystem extends MdcLoggable {
val hostname = h
val port = p
val akka_connector_hostname = Helper.getAkkaConnectorHostname
s"akka.tcp://SouthSideAkkaConnector_${akka_connector_hostname}@${hostname}:${port}/user/${actorName}"
s"pekko.tcp://SouthSideAkkaConnector_${akka_connector_hostname}@${hostname}:${port}/user/${actorName}"
case _ =>
val hostname = AkkaConnectorActorConfig.localHostname
@ -66,12 +66,12 @@ trait ObpLookupSystem extends MdcLoggable {
}
if(embeddedAdapter) {
AkkaConfig(LocalMappedOutInBoundTransfer, Some(ObpActorSystem.northSideAkkaConnectorActorSystem))
// AkkaConfig(LocalMappedOutInBoundTransfer, Some(ObpActorSystem.northSideAkkaConnectorActorSystem)) // TODO: Re-enable when Pekko adapter is available
} else {
AkkaConnectorHelperActor.startAkkaConnectorHelperActors(ObpActorSystem.northSideAkkaConnectorActorSystem)
}
s"akka.tcp://SouthSideAkkaConnector_${props_hostname}@${hostname}:${port}/user/${actorName}"
s"pekko.tcp://SouthSideAkkaConnector_${props_hostname}@${hostname}:${port}/user/${actorName}"
}
this.obpLookupSystem.actorSelection(actorPath)
}

View File

@ -1,6 +1,6 @@
package code.api.dynamic.endpoint.helper
import akka.http.scaladsl.model.{HttpMethods, HttpMethod => AkkaHttpMethod}
import org.apache.pekko.http.scaladsl.model.{HttpMethods, HttpMethod => PekkoHttpMethod}
import code.DynamicData.{DynamicDataProvider, DynamicDataT}
import code.DynamicEndpoint.{DynamicEndpointProvider, DynamicEndpointT}
import code.api.util.APIUtil.{BigDecimalBody, BigIntBody, BooleanBody, DoubleBody, EmptyBody, FloatBody, IntBody, JArrayBody, LongBody, PrimaryDataBody, ResourceDoc, StringBody}
@ -171,7 +171,7 @@ object DynamicEndpointHelper extends RestHelper {
* @param r HttpRequest
* @return (adapterUrl, requestBodyJson, httpMethod, requestParams, pathParams, role, operationId, mockResponseCode->mockResponseBody)
*/
def unapply(r: Req): Option[(String, JValue, AkkaHttpMethod, Map[String, List[String]], Map[String, String], ApiRole, String, Option[(Int, JValue)], Option[String])] = {
def unapply(r: Req): Option[(String, JValue, PekkoHttpMethod, Map[String, List[String]], Map[String, String], ApiRole, String, Option[(Int, JValue)], Option[String])] = {
val requestUri = r.request.uri //eg: `/obp/dynamic-endpoint/fashion-brand-list/BRAND_ID`
val partPath = r.path.partPath //eg: List("fashion-brand-list","BRAND_ID"), the dynamic is from OBP URL, not in the partPath now.
@ -179,7 +179,7 @@ object DynamicEndpointHelper extends RestHelper {
if (!testResponse_?(r) || !requestUri.startsWith(s"/${ApiStandards.obp.toString}/${ApiShortVersions.`dynamic-endpoint`.toString}"+urlPrefix))//if check the Content-Type contains json or not, and check the if it is the `dynamic_endpoints_url_prefix`
None //if do not match `URL and Content-Type`, then can not find this endpoint. return None.
else {
val akkaHttpMethod = HttpMethods.getForKeyCaseInsensitive(r.requestType.method).get
val pekkoHttpMethod = HttpMethods.getForKeyCaseInsensitive(r.requestType.method).get
val httpMethod = HttpMethod.valueOf(r.requestType.method)
val urlQueryParameters = r.params
// url that match original swagger endpoint.
@ -230,7 +230,7 @@ object DynamicEndpointHelper extends RestHelper {
val Some(role::_) = doc.roles
val requestBodyJValue = body(r).getOrElse(JNothing)
Full(s"""$serverUrl$url""", requestBodyJValue, akkaHttpMethod, urlQueryParameters, pathParams, role, doc.operationId, mockResponse, bankId)
Full(s"""$serverUrl$url""", requestBodyJValue, pekkoHttpMethod, urlQueryParameters, pathParams, role, doc.operationId, mockResponse, bankId)
}
}

View File

@ -242,10 +242,10 @@ object DynamicUtil extends MdcLoggable{
|import java.util.Date
|import java.util.UUID.randomUUID
|
|import _root_.akka.stream.StreamTcpException
|import akka.http.scaladsl.model.headers.RawHeader
|import akka.http.scaladsl.model.{HttpProtocol, _}
|import akka.util.ByteString
|import _root_.org.apache.pekko.stream.StreamTcpException
|import org.apache.pekko.http.scaladsl.model.headers.RawHeader
|import org.apache.pekko.http.scaladsl.model.{HttpProtocol, _}
|import org.apache.pekko.util.ByteString
|import code.api.APIFailureNewStyle
|import code.api.ResourceDocs1_4_0.MessageDocsSwaggerDefinitions
|import code.api.cache.Caching

View File

@ -1,7 +1,7 @@
package code.api.util
import akka.http.scaladsl.model.HttpMethod
import org.apache.pekko.http.scaladsl.model.HttpMethod
import code.DynamicEndpoint.{DynamicEndpointProvider, DynamicEndpointT}
import code.api.Constant.{SYSTEM_READ_ACCOUNTS_BERLIN_GROUP_VIEW_ID, SYSTEM_READ_BALANCES_BERLIN_GROUP_VIEW_ID}
import code.api.builder.PaymentInitiationServicePISApi.APIMethods_PaymentInitiationServicePISApi.checkPaymentServerTypeError

View File

@ -1,6 +1,6 @@
package code.bankconnectors
import _root_.akka.http.scaladsl.model.HttpMethod
import org.apache.pekko.http.scaladsl.model.HttpMethod
import code.api.attributedefinition.AttributeDefinition
import code.api.util.APIUtil.{OBPReturnType, _}
import code.api.util.ErrorMessages._

View File

@ -1,6 +1,6 @@
package code.bankconnectors
import _root_.akka.http.scaladsl.model.HttpMethod
import _root_.org.apache.pekko.http.scaladsl.model.HttpMethod
import code.DynamicData.DynamicDataProvider
import code.accountapplication.AccountApplicationX
import code.accountattribute.AccountAttributeX

View File

@ -1,7 +1,7 @@
package code.bankconnectors.akka
import java.util.Date
import akka.pattern.ask
import org.apache.pekko.pattern.ask
import code.actorsystem.ObpLookupSystem
import code.api.ResourceDocs1_4_0.MessageDocsSwaggerDefinitions
import code.api.ResourceDocs1_4_0.MessageDocsSwaggerDefinitions.{bankAccountCommons, bankCommons, transaction, _}

View File

@ -16,12 +16,12 @@ object AkkaConnectorActorConfig {
val commonConf =
"""
akka {
loggers = ["akka.event.slf4j.Slf4jLogger"]
pekko {
loggers = ["org.apache.pekko.event.slf4j.Slf4jLogger"]
loglevel = """ + akka_loglevel + """
actor {
provider = "akka.remote.RemoteActorRefProvider"
allow-java-serialization = off
provider = "org.apache.pekko.remote.RemoteActorRefProvider"
allow-java-serialization = on
kryo {
type = "graph"
idstrategy = "default"
@ -43,31 +43,31 @@ object AkkaConnectorActorConfig {
resolve-subclasses = true
}
serializers {
kryo = "com.twitter.chill.akka.AkkaSerializer"
java = "org.apache.pekko.serialization.JavaSerializer"
}
serialization-bindings {
"net.liftweb.common.Full" = kryo,
"net.liftweb.common.Empty" = kryo,
"net.liftweb.common.Box" = kryo,
"net.liftweb.common.ParamFailure" = kryo,
"code.api.APIFailure" = kryo,
"com.openbankproject.commons.model.BankAccount" = kryo,
"com.openbankproject.commons.model.View" = kryo,
"com.openbankproject.commons.model.User" = kryo,
"com.openbankproject.commons.model.ViewId" = kryo,
"com.openbankproject.commons.model.BankIdAccountIdViewId" = kryo,
"com.openbankproject.commons.model.Permission" = kryo,
"scala.Unit" = kryo,
"scala.Boolean" = kryo,
"java.io.Serializable" = kryo,
"scala.collection.immutable.List" = kryo,
"akka.actor.ActorSelectionMessage" = kryo,
"code.model.Consumer" = kryo,
"code.model.AppType" = kryo
"net.liftweb.common.Full" = java,
"net.liftweb.common.Empty" = java,
"net.liftweb.common.Box" = java,
"net.liftweb.common.ParamFailure" = java,
"code.api.APIFailure" = java,
"com.openbankproject.commons.model.BankAccount" = java,
"com.openbankproject.commons.model.View" = java,
"com.openbankproject.commons.model.User" = java,
"com.openbankproject.commons.model.ViewId" = java,
"com.openbankproject.commons.model.BankIdAccountIdViewId" = java,
"com.openbankproject.commons.model.Permission" = java,
"scala.Unit" = java,
"scala.Boolean" = java,
"java.io.Serializable" = java,
"scala.collection.immutable.List" = java,
"org.apache.pekko.actor.ActorSelectionMessage" = java,
"code.model.Consumer" = java,
"code.model.AppType" = java
}
}
remote {
enabled-transports = ["akka.remote.netty.tcp"]
enabled-transports = ["org.apache.pekko.remote.netty.tcp"]
netty {
tcp {
send-buffer-size = 50000000
@ -82,7 +82,7 @@ object AkkaConnectorActorConfig {
val lookupConf =
s"""
${commonConf}
akka {
pekko {
remote.netty.tcp.hostname = ${localHostname}
remote.netty.tcp.port = 0
}
@ -91,7 +91,7 @@ object AkkaConnectorActorConfig {
val localConf =
s"""
${commonConf}
akka {
pekko {
remote.netty.tcp.hostname = ${localHostname}
remote.netty.tcp.port = ${localPort}
}
@ -100,7 +100,7 @@ object AkkaConnectorActorConfig {
val remoteConf =
s"""
${commonConf}
akka {
pekko {
remote.netty.tcp.hostname = ${remoteHostname}
remote.netty.tcp.port = ${remotePort}
}

View File

@ -1,6 +1,6 @@
package code.bankconnectors.akka.actor
import akka.util.Timeout
import org.apache.pekko.util.Timeout
import code.api.util.APIUtil
import code.util.Helper.MdcLoggable

View File

@ -1,6 +1,6 @@
package code.bankconnectors.akka.actor
import akka.actor.{ActorSystem, Props}
import org.apache.pekko.actor.{ActorSystem, Props}
import code.api.util.APIUtil
import code.util.Helper.MdcLoggable

View File

@ -1,6 +1,6 @@
package code.bankconnectors.akka.actor
import akka.actor.{Actor, ActorLogging}
import org.apache.pekko.actor.{Actor, ActorLogging}
import code.api.util.APIUtil.DateWithMsFormat
import code.api.util.ErrorMessages.attemptedToOpenAnEmptyBox
import code.api.util.{APIUtil, OBPFromDate, OBPLimit, OBPToDate}

View File

@ -83,7 +83,7 @@ trait CardanoConnector_vJun2025 extends Connector with MdcLoggable {
| $metadataJson
|}""".stripMargin
request = prepareHttpRequest(paramUrl, _root_.akka.http.scaladsl.model.HttpMethods.POST, _root_.akka.http.scaladsl.model.HttpProtocol("HTTP/1.1"), jsonToSend)
request = prepareHttpRequest(paramUrl, _root_.org.apache.pekko.http.scaladsl.model.HttpMethods.POST, _root_.org.apache.pekko.http.scaladsl.model.HttpProtocol("HTTP/1.1"), jsonToSend)
_ = logger.debug(s"CardanoConnector_vJun2025.makePaymentv210 request is : $request")
response <- NewStyle.function.tryons(s"${ErrorMessages.UnknownError} Failed to make HTTP request to Cardano API", 500, callContext) {
@ -91,7 +91,7 @@ trait CardanoConnector_vJun2025 extends Connector with MdcLoggable {
}.flatten
responseBody <- NewStyle.function.tryons(s"${ErrorMessages.UnknownError} Failed to extract response body", 500, callContext) {
response.entity.dataBytes.runFold(_root_.akka.util.ByteString(""))(_ ++ _).map(_.utf8String)
response.entity.dataBytes.runFold(_root_.org.apache.pekko.util.ByteString(""))(_ ++ _).map(_.utf8String)
}.flatten
_ <- Helper.booleanToFuture(s"${ErrorMessages.UnknownError} Cardano API returned error: ${response.status.value}", 500, callContext) {

View File

@ -87,7 +87,7 @@ trait EthereumConnector_vSept2025 extends Connector with MdcLoggable {
}
for {
request <- NewStyle.function.tryons(ErrorMessages.UnknownError + " Failed to build HTTP request", 500, callContext) {prepareHttpRequest(rpcUrl, _root_.akka.http.scaladsl.model.HttpMethods.POST, _root_.akka.http.scaladsl.model.HttpProtocol("HTTP/1.1"), payload)
request <- NewStyle.function.tryons(ErrorMessages.UnknownError + " Failed to build HTTP request", 500, callContext) {prepareHttpRequest(rpcUrl, _root_.org.apache.pekko.http.scaladsl.model.HttpMethods.POST, _root_.org.apache.pekko.http.scaladsl.model.HttpProtocol("HTTP/1.1"), payload)
}
response <- NewStyle.function.tryons(ErrorMessages.UnknownError + " Failed to call Ethereum RPC", 500, callContext) {
@ -95,7 +95,7 @@ trait EthereumConnector_vSept2025 extends Connector with MdcLoggable {
}.flatten
body <- NewStyle.function.tryons(ErrorMessages.UnknownError + " Failed to read Ethereum RPC response", 500, callContext) {
response.entity.dataBytes.runFold(_root_.akka.util.ByteString(""))(_ ++ _).map(_.utf8String)
response.entity.dataBytes.runFold(_root_.org.apache.pekko.util.ByteString(""))(_ ++ _).map(_.utf8String)
}.flatten
_ <- Helper.booleanToFuture(ErrorMessages.UnknownError + s" Ethereum RPC returned error: ${response.status.value}", 500, callContext) {

View File

@ -3,7 +3,7 @@ package code
import java.lang.reflect.Method
import java.util.regex.Pattern
import akka.http.scaladsl.model.HttpMethod
import org.apache.pekko.http.scaladsl.model.HttpMethod
import code.api.{APIFailureNewStyle, ApiVersionHolder}
import code.api.util.{CallContext, FutureUtil, NewStyle}
import code.methodrouting.{MethodRouting, MethodRoutingT}

View File

@ -23,10 +23,10 @@ Osloerstrasse 16/17
Berlin 13359, Germany
*/
import _root_.akka.stream.StreamTcpException
import akka.http.scaladsl.model._
import akka.http.scaladsl.model.headers.RawHeader
import akka.util.ByteString
import _root_.org.apache.pekko.stream.StreamTcpException
import org.apache.pekko.http.scaladsl.model._
import org.apache.pekko.http.scaladsl.model.headers.RawHeader
import org.apache.pekko.util.ByteString
import code.api.APIFailureNewStyle
import code.api.ResourceDocs1_4_0.MessageDocsSwaggerDefinitions
import code.api.dynamic.endpoint.helper.MockResponseHolder

View File

@ -6,7 +6,7 @@ import code.api.util.{APIUtil, OBPQueryParam}
import com.openbankproject.commons.model.{User, _}
import net.liftweb.common.Box
import net.liftweb.util.SimpleInjector
import akka.pattern.pipe
import org.apache.pekko.pattern.pipe
import scala.collection.immutable.List
import scala.concurrent.Future

View File

@ -1,6 +1,6 @@
package code.scheduler
import code.actorsystem.ObpLookupSystem
import code.actorsystem.ObpActorSystem
import code.api.Constant
import code.api.util.APIUtil.generateUUID
import code.api.util.APIUtil
@ -17,7 +17,7 @@ import code.token.Tokens
object DataBaseCleanerScheduler extends MdcLoggable {
private lazy val actorSystem = ObpLookupSystem.obpLookupSystem
private lazy val actorSystem = ObpActorSystem.localActorSystem
implicit lazy val executor = actorSystem.dispatcher
private lazy val scheduler = actorSystem.scheduler
private val oneDayInMillis: Long = 86400000

View File

@ -3,7 +3,7 @@ package code.scheduler
import java.sql.SQLException
import java.util.concurrent.TimeUnit
import code.actorsystem.ObpLookupSystem
import code.actorsystem.ObpActorSystem
import code.util.Helper.MdcLoggable
import net.liftweb.db.{DB, SuperConnection}
@ -12,7 +12,7 @@ import scala.concurrent.duration._
object DatabaseDriverScheduler extends MdcLoggable {
private lazy val actorSystem = ObpLookupSystem.obpLookupSystem
private lazy val actorSystem = ObpActorSystem.localActorSystem
implicit lazy val executor = actorSystem.dispatcher
private lazy val scheduler = actorSystem.scheduler

View File

@ -2,7 +2,7 @@ package code.scheduler
import java.util.concurrent.TimeUnit
import java.util.{Calendar, Date}
import code.actorsystem.ObpLookupSystem
import code.actorsystem.ObpActorSystem
import code.api.Constant
import code.api.util.APIUtil.generateUUID
import code.api.util.{APIUtil, OBPLimit, OBPToDate}
@ -16,7 +16,7 @@ import scala.concurrent.duration._
object MetricsArchiveScheduler extends MdcLoggable {
private lazy val actorSystem = ObpLookupSystem.obpLookupSystem
private lazy val actorSystem = ObpActorSystem.localActorSystem
implicit lazy val executor = actorSystem.dispatcher
private lazy val scheduler = actorSystem.scheduler
private val oneDayInMillis: Long = 86400000

View File

@ -1,14 +1,14 @@
package code.scheduler
import code.actorsystem.ObpLookupSystem
import code.actorsystem.ObpActorSystem
import java.util.concurrent.TimeUnit
import java.util.{Calendar, Date}
import scala.concurrent.duration._
object SchedulerUtil {
private lazy val actorSystem = ObpLookupSystem.obpLookupSystem
private lazy val actorSystem = ObpActorSystem.localActorSystem
implicit lazy val executor = actorSystem.dispatcher
private lazy val scheduler = actorSystem.scheduler

View File

@ -2,7 +2,7 @@ package code.transactionStatusScheduler
import java.util.concurrent.TimeUnit
import code.actorsystem.ObpLookupSystem
import code.actorsystem.ObpActorSystem
import code.transactionrequests.TransactionRequests
import code.util.Helper.MdcLoggable
@ -11,7 +11,7 @@ import scala.concurrent.duration._
object TransactionRequestStatusScheduler extends MdcLoggable {
private lazy val actorSystem = ObpLookupSystem.obpLookupSystem
private lazy val actorSystem = ObpActorSystem.localActorSystem
implicit lazy val executor = actorSystem.dispatcher
private lazy val scheduler = actorSystem.scheduler

View File

@ -1,10 +1,10 @@
package code.util
import akka.http.scaladsl.Http
import akka.http.scaladsl.model._
import akka.http.scaladsl.settings.ConnectionPoolSettings
import akka.stream.ActorMaterializer
import org.apache.pekko.http.scaladsl.Http
import org.apache.pekko.http.scaladsl.model._
import org.apache.pekko.http.scaladsl.settings.ConnectionPoolSettings
import org.apache.pekko.stream.ActorMaterializer
import code.actorsystem.ObpLookupSystem
import code.api.util.{APIUtil, CustomJsonFormats}
import code.util.Helper.MdcLoggable

View File

@ -71,7 +71,7 @@ class SystemViewsTest extends V600ServerSetup with DefaultUsers {
viewsArray.size should be > 0
And("Views should include system views like owner, accountant, auditor")
val viewIds = viewsArray.map(view => (view \ "id").values.toString)
val viewIds = viewsArray.map(view => (view \ "view_id").values.toString)
viewIds should contain("owner")
}
}
@ -137,7 +137,7 @@ class SystemViewsTest extends V600ServerSetup with DefaultUsers {
And("Response should contain the owner view details")
val json = response.body
val viewId = (json \ "id").values.toString
val viewId = (json \ "view_id").values.toString
viewId should equal("owner")
And("View should be marked as system view")
@ -159,7 +159,7 @@ class SystemViewsTest extends V600ServerSetup with DefaultUsers {
Then("We should get a 200 - Success")
responseAccountant.code should equal(200)
val accountantViewId = (responseAccountant.body \ "id").values.toString
val accountantViewId = (responseAccountant.body \ "view_id").values.toString
accountantViewId should equal("accountant")
And("We request the auditor view")
@ -168,7 +168,7 @@ class SystemViewsTest extends V600ServerSetup with DefaultUsers {
Then("We should get a 200 - Success")
responseAuditor.code should equal(200)
val auditorViewId = (responseAuditor.body \ "id").values.toString
val auditorViewId = (responseAuditor.body \ "view_id").values.toString
auditorViewId should equal("auditor")
}

View File

@ -34,6 +34,7 @@ import code.webuiprops.WebUiPropsCommons
import com.github.dwickern.macros.NameOf.nameOf
import com.openbankproject.commons.model.ErrorMessage
import com.openbankproject.commons.util.ApiVersion
import net.liftweb.json.JsonAST.JNothing
import net.liftweb.json.Serialization.write
import org.scalatest.Tag
@ -335,7 +336,8 @@ class WebUiPropsTest extends V600ServerSetup {
val responseDelete = makeDeleteRequest(requestDelete)
Then("We should get a 204 No Content")
responseDelete.code should equal(204)
responseDelete.body.toString should equal("{}")
// HTTP 204 No Content should have empty body
responseDelete.body shouldBe(JNothing)
}
scenario("DELETE WebUiProp - idempotent delete (delete twice)", VersionOfApi, ApiEndpoint3) {

View File

@ -180,7 +180,8 @@ trait SendServerRequests {
private def ApiResponseCommonPart(req: Req) = {
for (response <- Http.default(req > as.Response(p => p)))
yield {
val body = if (response.getResponseBody().isEmpty) "{}" else response.getResponseBody()
//{} -->parse(body) => JObject(List()) , this is not "NO Content", change "" --> JNothing
val body = if (response.getResponseBody().isEmpty) "" else response.getResponseBody()
// Check that every response has a correlationId at Response Header
val list = response.getHeaders(ResponseHeader.`Correlation-Id`).asScala.toList

View File

@ -12,11 +12,11 @@
<properties>
<scala.version>2.12</scala.version>
<scala.compiler>2.12.20</scala.compiler>
<akka.version>2.5.32</akka.version>
<pekko.version>1.1.2</pekko.version>
<avro.version>1.8.2</avro.version>
<lift.version>3.5.0</lift.version>
<http4s.version>0.23.30</http4s.version>
<jetty.version>9.4.50.v20221201</jetty.version>
<jetty.version>9.4.58.v20250814</jetty.version>
<obp-ri.version>2016.11-RC6-SNAPSHOT</obp-ri.version>
<!-- Common plugin settings -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

View File

@ -3,6 +3,33 @@
### Most recent changes at top of file
```
Date Commit Action
12/12/2025 f2e7b827 Http4s runner configuration
Added http4s.host and http4s.port to props sample template:
- http4s.host=127.0.0.1
- http4s.port=8086
These properties control the bind address of bootstrap.http4s.Http4sServer
when running via the obp-http4s-runner fat JAR.
11/12/2025 3c2df942 BREAKING CHANGE: Migration from Akka to Apache Pekko™ 1.1.2
Replaced Akka 2.5.32 with Apache Pekko™ 1.1.2 to address Akka licensing changes.
Updated all imports from com.typesafe.akka to org.apache.pekko.
Updated Jetty from 9.4.50 to 9.4.58 for improved Java 17 compatibility.
Migrated all actor systems to Apache Pekko™ and fixed critical scheduler
actor system initialization conflicts.
Consolidated all schedulers to use shared ObpActorSystem.localActorSystem.
Prevented multiple actor system creation during application boot.
Fixed actor system references in all schedulers:
- DataBaseCleanerScheduler
- DatabaseDriverScheduler
- MetricsArchiveScheduler
- SchedulerUtil
- TransactionRequestStatusScheduler
Resolved 'Address already in use' port binding errors.
Eliminated ExceptionInInitializerError during startup.
Fixed race conditions in actor system initialization.
All scheduler functionality preserved with improved stability.
TBD TBD Performance Improvement: Added caching to getProviders endpoint
Added configurable caching with memoization to GET /obp/v6.0.0/providers endpoint.
- Default cache TTL: 3600 seconds (1 hour)