diff --git a/docker-compose.yml b/docker-compose.yml index 5e8a531651..8ac33b6f04 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -69,8 +69,6 @@ services: - KNORA_WEBAPI_TRIPLESTORE_FUSEKI_USERNAME=admin - KNORA_WEBAPI_TRIPLESTORE_FUSEKI_PASSWORD=test - KNORA_WEBAPI_CACHE_SERVICE_ENABLED=true - - KNORA_WEBAPI_CACHE_SERVICE_REDIS_HOST=redis - - KNORA_WEBAPI_CACHE_SERVICE_REDIS_PORT=6379 - KNORA_WEBAPI_ALLOW_RELOAD_OVER_HTTP=true - KNORA_WEBAPI_KNORA_API_EXTERNAL_HOST=0.0.0.0 - KNORA_WEBAPI_KNORA_API_EXTERNAL_PORT=3333 diff --git a/docs/04-publishing-deployment/configuration.md b/docs/04-publishing-deployment/configuration.md index 612287504e..1b97cf3c96 100644 --- a/docs/04-publishing-deployment/configuration.md +++ b/docs/04-publishing-deployment/configuration.md @@ -57,8 +57,6 @@ A number of core settings is additionally configurable through system environmen | app.triplestore.fuseki.username | KNORA_WEBAPI_TRIPLESTORE_FUSEKI_USERNAME | admin | | app.triplestore.fuseki.password | KNORA_WEBAPI_TRIPLESTORE_FUSEKI_PASSWORD | test | | app.cache-service.enabled | KNORA_WEBAPI_CACHE_SERVICE_ENABLED | true | -| app.cache-service.redis.host | KNORA_WEBAPI_CACHE_SERVICE_REDIS_HOST | localhost | -| app.cache-service.redis.port | KNORA_WEBAPI_CACHE_SERVICE_REDIS_PORT | 6379 | ## Selectively Disabling Routes diff --git a/docs/05-internals/development/building-and-running.md b/docs/05-internals/development/building-and-running.md index 6c9c0f9460..052af61c6b 100644 --- a/docs/05-internals/development/building-and-running.md +++ b/docs/05-internals/development/building-and-running.md @@ -18,7 +18,7 @@ With [Docker](https://www.docker.com/) installed, to create the knora-test repository and initialize it with loading some test data into the triplestore (Fuseki). -1. Start the entire knora-stack (fuseki (db), sipi, redis, api, salsah1) with the following command: +1. Start the entire knora-stack (fuseki (db), sipi, api, salsah1) with the following command: ``` $ make stack-up @@ -89,8 +89,8 @@ database container can be printed out using the following command: ``` $ make stack-logs-db ``` -Similarly, the logs of the other containers can be printed out by running make with `stack-logs-api`, `stack-logs-sipi`, -or `stack-logs-redis`. These commands print out and follow the logs, to only print the logs out without following, use +Similarly, the logs of the other containers can be printed out by running make with `stack-logs-api` or `stack-logs-sipi`. +These commands print out and follow the logs, to only print the logs out without following, use `-no-follow` version of the commands for example: ``` diff --git a/docs/05-internals/development/generating-client-test-data.md b/docs/05-internals/development/generating-client-test-data.md index 5b24eb7b3b..2bf4997ece 100644 --- a/docs/05-internals/development/generating-client-test-data.md +++ b/docs/05-internals/development/generating-client-test-data.md @@ -14,20 +14,13 @@ client code without the need for a running Knora instance. Client test data is generated as a side effect of running E2E tests. E2E tests use `ClientTestDataCollector` to collect API requests and -responses. The implementation of `ClientTestDataCollector` collects these -in a Redis hash. When the E2E tests have completed, the script +responses. When the E2E tests have completed, the script `webapi/scripts/dump-client-test-data.sh` saves the collected test data in a Zip file. It then checks the filenames in the Zip file by comparing them with the list in `webapi/scripts/expected-client-test-data.txt`. ## Usage -On macOS, you will need to install Redis in order to have the `redis-cli` command-line tool: - -``` -brew install redis -``` - To generate client test data, type: ``` diff --git a/docs/05-internals/development/overview.md b/docs/05-internals/development/overview.md index 5e51f591be..6af6ca2e0b 100644 --- a/docs/05-internals/development/overview.md +++ b/docs/05-internals/development/overview.md @@ -89,16 +89,3 @@ $ docker run --name sipi \ daschswiss/sipi \ /sipi/local/bin/sipi -config /localdir/sipi.test-config.lua ``` - -## Redis Server - -The DSP-API server uses Redis for caching. - -On macOS you can install Redis through [Homebrew](https://brew.sh): - -```bash -$ brew install redis -``` - -If you don't want to use Redis, you can disable caching in `application.conf` -via the `app.use-redis-cache` key, by setting it to `false`. diff --git a/project/Dependencies.scala b/project/Dependencies.scala index c978c0f8fd..13fe9ae0af 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -83,7 +83,6 @@ object Dependencies { // caching val ehcache = "net.sf.ehcache" % "ehcache" % "2.10.9.2" - val jedis = "redis.clients" % "jedis" % "4.3.1" // serialization val chill = "com.twitter" %% "chill" % "0.10.0" // Scala 3 incompatible @@ -145,7 +144,6 @@ object Dependencies { icu4j, jacksonDatabind, jakartaJSON, - jedis, jenaText, jodd, jwtSprayJson, diff --git a/webapi/scripts/zap-client-test-data.sh b/webapi/scripts/zap-client-test-data.sh index c38aa15384..c100198eb6 100755 --- a/webapi/scripts/zap-client-test-data.sh +++ b/webapi/scripts/zap-client-test-data.sh @@ -4,7 +4,7 @@ set -e -# The name of the Zip file that contains client test data download from Redis. +# The name of the Zip file that contains client test data download from cache. zip_file_name=client-test-data.zip # Remove any existing client test data Zip file. diff --git a/webapi/scripts/zip-client-test-data.sh b/webapi/scripts/zip-client-test-data.sh index b01ad7662e..b475cb4b7d 100755 --- a/webapi/scripts/zip-client-test-data.sh +++ b/webapi/scripts/zip-client-test-data.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# Downloads client test data from Redis into a Zip file. +# Downloads client test data from cache into a Zip file. # A pushd that produces no output. pushd () { diff --git a/webapi/src/it/scala/org/knora/webapi/store/cache/config/RedisTestConfig.scala b/webapi/src/it/scala/org/knora/webapi/store/cache/config/RedisTestConfig.scala deleted file mode 100644 index aab347b38e..0000000000 --- a/webapi/src/it/scala/org/knora/webapi/store/cache/config/RedisTestConfig.scala +++ /dev/null @@ -1,16 +0,0 @@ -package org.knora.webapi.store.cache.config - -import zio._ - -import org.knora.webapi.store.cache.config.RedisConfig -import org.knora.webapi.testcontainers.RedisTestContainer - -object RedisTestConfig { - val hardcoded: ULayer[RedisConfig] = ZLayer.succeed(RedisConfig("localhost", 6379)) - val redisTestContainer: ZLayer[RedisTestContainer, Nothing, RedisConfig] = - ZLayer { - for { - rtc <- ZIO.service[RedisTestContainer] - } yield RedisConfig("localhost", rtc.container.getFirstMappedPort()) - }.tap(_ => ZIO.debug(">>> Redis Test Config Initialized <<<")) -} diff --git a/webapi/src/it/scala/org/knora/webapi/store/cache/impl/CacheRedisImplZSpec.scala b/webapi/src/it/scala/org/knora/webapi/store/cache/impl/CacheRedisImplZSpec.scala deleted file mode 100644 index 92a6fb4a56..0000000000 --- a/webapi/src/it/scala/org/knora/webapi/store/cache/impl/CacheRedisImplZSpec.scala +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright © 2021 - 2022 Swiss National Data and Service Center for the Humanities and/or DaSCH Service Platform contributors. - * SPDX-License-Identifier: Apache-2.0 - */ - -package org.knora.webapi.store.cache.impl - -import zio._ -import zio.test.Assertion._ -import zio.test._ - -import dsp.errors.BadRequestException -import org.knora.webapi.messages.StringFormatter -import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectADM -import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM._ -import org.knora.webapi.messages.admin.responder.usersmessages.UserADM -import org.knora.webapi.messages.admin.responder.usersmessages.UserIdentifierADM -import org.knora.webapi.sharedtestdata.SharedTestDataADM -import org.knora.webapi.store.cache.api.CacheService -import org.knora.webapi.store.cache.config.RedisTestConfig -import org.knora.webapi.testcontainers.RedisTestContainer - -/** - * This spec is used to test [[org.knora.webapi.store.cache.impl.CacheServiceRedisImpl]]. - */ -object CacheRedisImplZSpec extends ZIOSpecDefault { - - StringFormatter.initForTest() - implicit val stringFormatter: StringFormatter = StringFormatter.getGeneralInstance - - val user: UserADM = SharedTestDataADM.imagesUser01 - val project: ProjectADM = SharedTestDataADM.imagesProject - - /** - * Defines a layer which encompases all dependencies that are needed for - * for running the tests. - */ - val testLayers = ZLayer.make[CacheService & zio.test.Annotations]( - CacheServiceRedisImpl.layer, - RedisTestConfig.redisTestContainer, - zio.test.Annotations.live, - RedisTestContainer.layer - ) - - def spec = (userTests + projectTests).provideLayerShared(testLayers) @@ TestAspect.sequential - - val userTests = suite("CacheRedisImplSpec - user")( - test("successfully store a user and retrieve by IRI") { - for { - _ <- CacheService.putUserADM(user) - retrievedUser <- CacheService.getUserADM(UserIdentifierADM(maybeIri = Some(user.id))) - } yield assert(retrievedUser)(equalTo(Some(user))) - } @@ TestAspect.ignore, - test("successfully store a user and retrieve by USERNAME")( - for { - _ <- CacheService.putUserADM(user) - retrievedUser <- CacheService.getUserADM(UserIdentifierADM(maybeUsername = Some(user.username))) - } yield assert(retrievedUser)(equalTo(Some(user))) - ) @@ TestAspect.ignore, - test("successfully store a user and retrieve by EMAIL")( - for { - _ <- CacheService.putUserADM(user) - retrievedUser <- CacheService.getUserADM(UserIdentifierADM(maybeEmail = Some(user.email))) - } yield assert(retrievedUser)(equalTo(Some(user))) - ) @@ TestAspect.ignore - ) - - val projectTests = suite("CacheRedisImplSpec - project")( - test("successfully store a project and retrieve by IRI")( - for { - _ <- CacheService.putProjectADM(project) - retrievedProject <- CacheService.getProjectADM( - IriIdentifier - .fromString(project.id) - .getOrElseWith(e => throw BadRequestException(e.head.getMessage)) - ) - } yield assert(retrievedProject)(equalTo(Some(project))) - ), - test("successfully store a project and retrieve by SHORTCODE")( - for { - _ <- CacheService.putProjectADM(project) - retrievedProject <- - CacheService.getProjectADM( - ShortcodeIdentifier - .fromString(project.shortcode) - .getOrElseWith(e => throw BadRequestException(e.head.getMessage)) - ) - } yield assert(retrievedProject)(equalTo(Some(project))) - ), - test("successfully store a project and retrieve by SHORTNAME")( - for { - _ <- CacheService.putProjectADM(project) - retrievedProject <- - CacheService.getProjectADM( - ShortnameIdentifier - .fromString(project.shortname) - .getOrElseWith(e => throw BadRequestException(e.head.getMessage)) - ) - } yield assert(retrievedProject)(equalTo(Some(project))) - ) - ) -} diff --git a/webapi/src/it/scala/org/knora/webapi/testcontainers/RedisTestContainer.scala b/webapi/src/it/scala/org/knora/webapi/testcontainers/RedisTestContainer.scala deleted file mode 100644 index 0f20426449..0000000000 --- a/webapi/src/it/scala/org/knora/webapi/testcontainers/RedisTestContainer.scala +++ /dev/null @@ -1,32 +0,0 @@ -package org.knora.webapi.testcontainers - -import org.testcontainers.containers.GenericContainer -import org.testcontainers.utility.DockerImageName -import zio._ - -final case class RedisTestContainer(container: GenericContainer[Nothing]) - -object RedisTestContainer { - - /** - * A functional effect that initiates a Redis Testcontainer - */ - val acquireRedisTestContainer: Task[GenericContainer[Nothing]] = ZIO.attemptBlocking { - val RedisImageName: DockerImageName = DockerImageName.parse("redis:5") - val container = new GenericContainer(RedisImageName) - container.withExposedPorts(6379) - container.start() - container - }.orDie.tap(_ => ZIO.debug(">>> Acquire Redis TestContainer <<<")) - - def releaseRedisTestContainer(container: GenericContainer[Nothing]): URIO[Any, Unit] = ZIO.attemptBlocking { - container.stop() - }.orDie.tap(_ => ZIO.debug(">>> Release Redis TestContainer <<<")) - - val layer: ZLayer[Any, Nothing, RedisTestContainer] = - ZLayer.scoped { - for { - tc <- ZIO.acquireRelease(acquireRedisTestContainer)(releaseRedisTestContainer(_)).orDie - } yield RedisTestContainer(tc) - } -} diff --git a/webapi/src/main/resources/application.conf b/webapi/src/main/resources/application.conf index 912c919f19..85766cb614 100644 --- a/webapi/src/main/resources/application.conf +++ b/webapi/src/main/resources/application.conf @@ -485,16 +485,8 @@ app { } cache-service { - enabled = true enabled = ${?KNORA_WEBAPI_CACHE_SERVICE_ENABLED} - - redis { - host = "localhost" - host = ${?KNORA_WEBAPI_CACHE_SERVICE_REDIS_HOST} - port = 6379 - port = ${?KNORA_WEBAPI_CACHE_SERVICE_REDIS_PORT} - } } client-test-data-service { diff --git a/webapi/src/main/scala/org/knora/webapi/config/AppConfig.scala b/webapi/src/main/scala/org/knora/webapi/config/AppConfig.scala index f0c8f835a3..b99012be57 100644 --- a/webapi/src/main/scala/org/knora/webapi/config/AppConfig.scala +++ b/webapi/src/main/scala/org/knora/webapi/config/AppConfig.scala @@ -224,13 +224,7 @@ final case class Shacl( } final case class CacheService( - enabled: Boolean, - redis: Redis -) - -final case class Redis( - host: String, - port: Int + enabled: Boolean ) final case class ClientTestDataService( diff --git a/webapi/src/main/scala/org/knora/webapi/instrumentation/InstrumentationSupport.scala b/webapi/src/main/scala/org/knora/webapi/instrumentation/InstrumentationSupport.scala index fae7dc4b3e..93e9a2b28d 100644 --- a/webapi/src/main/scala/org/knora/webapi/instrumentation/InstrumentationSupport.scala +++ b/webapi/src/main/scala/org/knora/webapi/instrumentation/InstrumentationSupport.scala @@ -56,7 +56,7 @@ trait InstrumentationSupport { /** * Based on the current class name, create a logger with the name in the - * form 'M-ClassName', e.g., 'M-RedisManager'. + * form 'M-ClassName', e.g., 'M-CacheManager'. * All loggers returned by this method can be configured in 'logback.xml', * i.e., turned on or off. */ diff --git a/webapi/src/main/scala/org/knora/webapi/responders/admin/StoresResponderADM.scala b/webapi/src/main/scala/org/knora/webapi/responders/admin/StoresResponderADM.scala index 10ebd72ebd..9e710a5f9d 100644 --- a/webapi/src/main/scala/org/knora/webapi/responders/admin/StoresResponderADM.scala +++ b/webapi/src/main/scala/org/knora/webapi/responders/admin/StoresResponderADM.scala @@ -84,7 +84,7 @@ class StoresResponderADM(responderData: ResponderData) extends Responder(respond _ = log.debug(s"resetTriplestoreContent - load ontology done - {}", loadOntologiesResponse.toString) _ <- appActor.ask(CacheServiceFlushDB(systemUser)) - _ = log.debug(s"resetTriplestoreContent - flushing Redis store done.") + _ = log.debug(s"resetTriplestoreContent - flushing cache store done.") result = ResetTriplestoreContentResponseADM(message = "success") diff --git a/webapi/src/main/scala/org/knora/webapi/responders/admin/UsersResponderADM.scala b/webapi/src/main/scala/org/knora/webapi/responders/admin/UsersResponderADM.scala index a67d98f545..af70dec667 100644 --- a/webapi/src/main/scala/org/knora/webapi/responders/admin/UsersResponderADM.scala +++ b/webapi/src/main/scala/org/knora/webapi/responders/admin/UsersResponderADM.scala @@ -2197,7 +2197,7 @@ class UsersResponderADM(responderData: ResponderData) private def invalidateCachedUserADM(maybeUser: Option[UserADM]): Future[Unit] = if (responderData.cacheServiceSettings.cacheServiceEnabled) { val keys: Set[String] = Seq(maybeUser.map(_.id), maybeUser.map(_.email), maybeUser.map(_.username)).flatten.toSet - // only send to Redis if keys are not empty + // only send to cache if keys are not empty if (keys.nonEmpty) { val result = appActor.ask(CacheServiceRemoveValues(keys)) result.map { res => diff --git a/webapi/src/main/scala/org/knora/webapi/settings/package.scala b/webapi/src/main/scala/org/knora/webapi/settings/package.scala index ec87ce883e..1666a84fc6 100644 --- a/webapi/src/main/scala/org/knora/webapi/settings/package.scala +++ b/webapi/src/main/scala/org/knora/webapi/settings/package.scala @@ -113,9 +113,4 @@ package object settings { val IIIFManagerActorPath: String = StoreManagerActorPath + "/" + IIIFManagerActorName val SipiConnectorActorName: String = "sipiConnector" - - /* Cache */ - val CacheServiceManagerActorName: String = "redisManager" - val CacheServiceManagerActorPath: String = StoreManagerActorPath + "/" + CacheServiceManagerActorName - } diff --git a/webapi/src/main/scala/org/knora/webapi/store/cache/config/CacheServiceConfig.scala b/webapi/src/main/scala/org/knora/webapi/store/cache/config/CacheServiceConfig.scala index 8d62b71dd0..8f4c9cca18 100644 --- a/webapi/src/main/scala/org/knora/webapi/store/cache/config/CacheServiceConfig.scala +++ b/webapi/src/main/scala/org/knora/webapi/store/cache/config/CacheServiceConfig.scala @@ -5,6 +5,4 @@ package org.knora.webapi.store.cache.config -final case class CacheServiceConfig(enabled: Boolean, redis: RedisConfig) - -final case class RedisConfig(server: String, port: Int) +final case class CacheServiceConfig(enabled: Boolean) diff --git a/webapi/src/main/scala/org/knora/webapi/store/cache/impl/CacheServiceRedisImpl.scala b/webapi/src/main/scala/org/knora/webapi/store/cache/impl/CacheServiceRedisImpl.scala deleted file mode 100644 index 35742a9f3c..0000000000 --- a/webapi/src/main/scala/org/knora/webapi/store/cache/impl/CacheServiceRedisImpl.scala +++ /dev/null @@ -1,320 +0,0 @@ -/* - * Copyright © 2021 - 2022 Swiss National Data and Service Center for the Humanities and/or DaSCH Service Platform contributors. - * SPDX-License-Identifier: Apache-2.0 - */ - -package org.knora.webapi.store.cache.impl - -import redis.clients.jedis.Jedis -import redis.clients.jedis.JedisPool -import redis.clients.jedis.JedisPoolConfig -import zio._ - -import dsp.errors.ForbiddenException -import dsp.valueobjects.Iri -import dsp.valueobjects.Project -import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectADM -import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM -import org.knora.webapi.messages.admin.responder.projectsmessages.ProjectIdentifierADM._ -import org.knora.webapi.messages.admin.responder.usersmessages.UserADM -import org.knora.webapi.messages.admin.responder.usersmessages.UserIdentifierADM -import org.knora.webapi.messages.admin.responder.usersmessages.UserIdentifierType -import org.knora.webapi.messages.store.cacheservicemessages.CacheServiceStatusNOK -import org.knora.webapi.messages.store.cacheservicemessages.CacheServiceStatusOK -import org.knora.webapi.messages.store.cacheservicemessages.CacheServiceStatusResponse -import org.knora.webapi.store.cache.api.CacheService -import org.knora.webapi.store.cache.api.EmptyKey -import org.knora.webapi.store.cache.api.EmptyValue -import org.knora.webapi.store.cache.config.RedisConfig -import org.knora.webapi.store.cache.serialization.CacheSerialization - -case class CacheServiceRedisImpl(pool: JedisPool) extends CacheService { - - /** - * Stores the user under the IRI and additionally the IRI under the keys of - * USERNAME and EMAIL: - * - * IRI -> byte array - * username -> IRI - * email -> IRI - * - * @param user the user to store. - */ - def putUserADM(user: UserADM): Task[Unit] = - for { - bytes <- CacheSerialization.serialize(user) - _ <- putBytesValue(user.id, bytes) - _ <- putStringValue(user.username, user.id) - _ <- putStringValue(user.email, user.id) - } yield () - - /** - * Retrieves the user stored under the identifier (either iri, username, - * or email). - * - * The data is stored under the IRI key. - * Additionally, the USERNAME and EMAIL keys point to the IRI key - * - * @param identifier the user identifier. - */ - def getUserADM(identifier: UserIdentifierADM): Task[Option[UserADM]] = - identifier.hasType match { - case UserIdentifierType.Iri => getUserByIri(identifier.toIri) - case UserIdentifierType.Username => getUserByUsernameOrEmail(identifier.toUsername) - case UserIdentifierType.Email => getUserByUsernameOrEmail(identifier.toEmail) - } - - /** - * Retrieves the user stored under the IRI. - * - * @param id the user's IRI. - * @return an optional [[UserADM]]. - */ - def getUserByIri(id: String): Task[Option[UserADM]] = - (for { - bytes <- getBytesValue(id).some - user <- CacheSerialization.deserialize[UserADM](bytes).some - } yield user).unsome - - /** - * Retrieves the user stored under the username or email. - * - * @param usernameOrEmail of the user. - * @return an optional [[UserADM]]. - */ - def getUserByUsernameOrEmail(usernameOrEmail: String): Task[Option[UserADM]] = - (for { - iri <- getStringValue(usernameOrEmail).some - user <- getUserByIri(iri).some - } yield user).unsome - - /** - * Stores the project under the IRI and additionally the IRI under the keys - * of SHORTCODE and SHORTNAME: - * - * IRI -> byte array - * shortname -> IRI - * shortcode -> IRI - * - * @param value the stored value - */ - def putProjectADM(project: ProjectADM): Task[Unit] = - for { - bytes <- CacheSerialization.serialize(project) - _ <- putBytesValue(project.id, bytes) - _ <- putStringValue(project.shortcode, project.id) - _ <- putStringValue(project.shortname, project.id) - } yield () - - /** - * Retrieves the project stored under the identifier, either Iri, Shortcode, Shortname or Uuid. - * - * @param identifier the project identifier. - */ - def getProjectADM(identifier: ProjectIdentifierADM): Task[Option[ProjectADM]] = - // The data is stored under the Iri - // Additionally, the Shortcode, Shortname and Uuid point to the Iri - identifier match { - case IriIdentifier(value) => getProjectByIri(value) - case ShortcodeIdentifier(value) => getProjectByShortcode(value) - case ShortnameIdentifier(value) => getProjectByShortname(value) - } - - /** - * Retrieves the project by its IRI. - * - * @param id the project's IRI - * @return an optional [[ProjectADM]]. - */ - def getProjectByIri(iri: Iri.ProjectIri): Task[Option[ProjectADM]] = - (for { - bytes <- getBytesValue(iri.value) - project <- - bytes match { - case Some(value) => CacheSerialization.deserialize[ProjectADM](value) - case None => ZIO.succeed(None) - } - } yield project) - - /** - * Retrieves the project by its SHORTNAME. - * - * @param shortname of the project. - * @return an optional [[ProjectADM]] - */ - def getProjectByShortname(shortname: Project.ShortName): Task[Option[ProjectADM]] = - (for { - iri <- getStringValue(shortname.value) - validIri <- Iri.ProjectIri.make(iri).toZIO - project <- - validIri match { - case Some(value) => getProjectByIri(value) - case None => ZIO.succeed(None) - } - } yield project) - - /** - * Retrieves the project by its SHORTCODE. - * - * @param shortcode of the project. - * @return an optional [[ProjectADM]] - */ - def getProjectByShortcode(shortcode: Project.ShortCode): Task[Option[ProjectADM]] = - (for { - iri <- getStringValue(shortcode.value) - validIri <- Iri.ProjectIri.make(iri).toZIO - project <- - validIri match { - case Some(value) => getProjectByIri(value) - case None => ZIO.succeed(None) - } - } yield project) - - /** - * Store string value under key. - * - * @param key the key. - * @param value the value. - */ - def putStringValue(key: String, value: String): Task[Unit] = ZIO.attempt { - - if (key.isEmpty) - throw EmptyKey("The key under which the value should be written is empty. Aborting writing to redis.") - - if (value.isEmpty) - throw EmptyValue("The string value is empty. Aborting writing to redis.") - - val conn: Jedis = pool.getResource - try { - conn.set(key, value) - () - } finally { - conn.close() - } - - }.catchAll(ex => ZIO.logError(s"Writing to Redis failed: ${ex.getMessage}")) - - /** - * Get value stored under the key as a string. - * - * @param maybeKey the key. - */ - def getStringValue(key: String): Task[Option[String]] = { - // FIXME: make it resource safe, i.e., use Scope and add finalizers for the connection - for { - conn <- ZIO.attempt(pool.getResource) - value <- ZIO.attemptBlocking(conn.get(key)) - res <- - if (value == "nil".getBytes) ZIO.succeed(None) - else ZIO.succeed(Some(value)) - _ = conn.close() - } yield res - }.catchAll(ex => ZIO.logError(s"Reading string from Redis failed: ${ex.getMessage}") *> ZIO.succeed(None)) - - /** - * Removes values for the provided keys. Any invalid keys are ignored. - * - * @param keys the keys. - */ - def removeValues(keys: Set[String]): Task[Unit] = ZIO.attemptBlocking { - - // del takes a vararg so I nee to convert the set to a swq and then to vararg - val conn: Jedis = pool.getResource - try { - conn.del(keys.toSeq: _*) - () - } finally { - conn.close() - } - - }.catchAll(ex => ZIO.logError(s"Removing keys from Redis failed: ${ex.getMessage}")) - - /** - * Store byte array value under key. - * - * @param key the key. - * @param value the value. - */ - private def putBytesValue(key: String, value: Array[Byte]): Task[Unit] = ZIO.attemptBlocking { - - if (key.isEmpty) - throw EmptyKey("The key under which the value should be written is empty. Aborting writing to redis.") - - if (value.isEmpty) - throw EmptyValue("The byte array value is empty. Aborting writing to redis.") - - val conn: Jedis = pool.getResource - try { - conn.set(key.getBytes, value) - () - } finally { - conn.close() - } - - }.catchAll(ex => ZIO.logError(s"Writing to Redis failed: ${ex.getMessage}")) - - /** - * Get value stored under the key as a byte array. If no value is found - * under the key, then a [[None]] is returned.. - * - * @param key the key. - */ - private def getBytesValue(key: String): Task[Option[Array[Byte]]] = - // FIXME: make it resource safe, i.e., use Scope and add finalizers for the connection - for { - conn <- ZIO.attempt(pool.getResource).onError(ZIO.logErrorCause(_)).orDie - value <- ZIO.attemptBlocking(conn.get(key.getBytes)) - res <- - if (value == "nil".getBytes) ZIO.succeed(None) - else ZIO.succeed(Some(value)) - _ = conn.close() - } yield res - - /** - * Flushes (removes) all stored content from the Redis store. - */ - def flushDB(requestingUser: UserADM): Task[Unit] = ZIO.attemptBlocking { - - if (!requestingUser.isSystemUser) { - throw ForbiddenException("Only the system user is allowed to perform this operation.") - } - - val conn: Jedis = pool.getResource - try { - conn.flushDB() - () - } finally { - conn.close() - } - - } - .catchAll(ex => ZIO.logError(s"Flushing DB failed: ${ex.getMessage}")) - .tap(_ => ZIO.logDebug("Redis cache flushed.")) - - /** - * Pings the Redis store to see if it is available. - */ - val getStatus: UIO[CacheServiceStatusResponse] = ZIO.attemptBlocking { - - val conn: Jedis = pool.getResource - try { - conn.ping("test") - CacheServiceStatusOK - } finally { - conn.close() - } - }.catchAll(ex => ZIO.logError(s"Ping failed: ${ex.getMessage}") *> ZIO.succeed(CacheServiceStatusNOK)) -} - -object CacheServiceRedisImpl { - val layer: ZLayer[RedisConfig, Nothing, CacheService] = - ZLayer { - for { - config <- ZIO.service[RedisConfig] - pool <- ZIO - .attempt(new JedisPool(new JedisPoolConfig(), config.server, config.port)) - .onError(ZIO.logErrorCause(_)) - .orDie // the Redis Client Pool - } yield CacheServiceRedisImpl(pool) - }.tap(_ => ZIO.logInfo(">>> Redis Cache Service Initialized <<<")) -} diff --git a/webapi/src/main/scala/org/knora/webapi/store/cache/settings/CacheServiceSettings.scala b/webapi/src/main/scala/org/knora/webapi/store/cache/settings/CacheServiceSettings.scala index f8b29cf512..a27732d861 100644 --- a/webapi/src/main/scala/org/knora/webapi/store/cache/settings/CacheServiceSettings.scala +++ b/webapi/src/main/scala/org/knora/webapi/store/cache/settings/CacheServiceSettings.scala @@ -11,7 +11,5 @@ import org.knora.webapi.config.AppConfig * Holds the Cache Service specific settings. */ class CacheServiceSettings(appConfig: AppConfig) { - val cacheServiceEnabled: Boolean = appConfig.cacheService.enabled - val cacheServiceRedisHost: String = appConfig.cacheService.redis.host - val cacheServiceRedisPort: Int = appConfig.cacheService.redis.port + val cacheServiceEnabled: Boolean = appConfig.cacheService.enabled }