From 54cee7a6711d38d7d11a2c95d95c16e71e200d64 Mon Sep 17 00:00:00 2001 From: Ivan Subotic <400790+subotic@users.noreply.github.com> Date: Wed, 2 Mar 2022 16:28:13 +0100 Subject: [PATCH] refactor: start on a functional domain design implementation for ontologies (DEV-227) (#2009) --- .gitignore | 2 +- build.sbt | 69 ++++- .../src/main/scala/dsp/api/main/MainApp.scala | 17 ++ .../main/scala/dsp/schema/api/app/App.scala | 13 + .../dsp/schema/domain/SchemaDomain.scala | 279 ++++++++++++++++++ .../dsp/schema/handler/CreateSchema.scala | 5 + .../scala/dsp/schema/repo/SchemaRepo.scala | 18 ++ .../repo/eventstore/EventStoreLive.scala | 3 + .../schema/repo/search/SearchService.scala | 3 + .../dsp/schema/repo/SchemaRepoLive.scala | 19 ++ .../dsp/schema/repo/SchemaRepoTest.scala | 24 ++ project/Dependencies.scala | 156 +++++----- project/plugins.sbt | 2 + .../org/knora/webapi/IntegrationSpec.scala | 12 +- 14 files changed, 524 insertions(+), 98 deletions(-) create mode 100644 dsp-api-main/src/main/scala/dsp/api/main/MainApp.scala create mode 100644 dsp-schema-api/src/main/scala/dsp/schema/api/app/App.scala create mode 100644 dsp-schema-core/src/main/scala/dsp/schema/domain/SchemaDomain.scala create mode 100644 dsp-schema-core/src/main/scala/dsp/schema/handler/CreateSchema.scala create mode 100644 dsp-schema-core/src/main/scala/dsp/schema/repo/SchemaRepo.scala create mode 100644 dsp-schema-repo-eventstore-service/src/main/scala/dsp/schema/repo/eventstore/EventStoreLive.scala create mode 100644 dsp-schema-repo-search-service/src/main/scala/dsp/schema/repo/search/SearchService.scala create mode 100644 dsp-schema-repo/src/main/scala/dsp/schema/repo/SchemaRepoLive.scala create mode 100644 dsp-schema-repo/src/main/scala/dsp/schema/repo/SchemaRepoTest.scala diff --git a/.gitignore b/.gitignore index baa70495ef..23ffe63140 100644 --- a/.gitignore +++ b/.gitignore @@ -21,7 +21,7 @@ sipi/test bazel-* **/project/target/ -/target/ +**/target/ *.aux *.bbl *.bcf diff --git a/build.sbt b/build.sbt index 0c61d27aaf..92c75fb8ee 100644 --- a/build.sbt +++ b/build.sbt @@ -11,9 +11,7 @@ import scala.sys.process.Process // GLOBAL SETTINGS ////////////////////////////////////// -lazy val aggregatedProjects: Seq[ProjectReference] = Seq(webapi) - -lazy val buildSettings = Dependencies.Versions ++ Seq( +lazy val buildSettings = Seq( organization := "org.knora", version := (ThisBuild / version).value ) @@ -21,9 +19,8 @@ lazy val buildSettings = Dependencies.Versions ++ Seq( lazy val rootBaseDir = ThisBuild / baseDirectory lazy val root: Project = Project(id = "root", file(".")) - .aggregate(aggregatedProjects: _*) + .aggregate(webapi, apiMain) .enablePlugins(GitVersioning, GitBranchPrompt) - .settings(Dependencies.Versions) .settings( // values set for all sub-projects // These are normal sbt settings to configure for release, skip if already defined @@ -33,6 +30,7 @@ lazy val root: Project = Project(id = "root", file(".")) ThisBuild / scmInfo := Some( ScmInfo(url("https://github.com/dasch-swiss/dsp-api"), "scm:git:git@github.com:dasch-swiss/dsp-api.git") ), + Global / scalaVersion := Dependencies.scalaVersion, // use 'git describe' for deriving the version git.useGitDescribe := true, // override generated version string because docker hub rejects '+' in tags @@ -160,9 +158,9 @@ lazy val webapi: Project = Project(id = "webapi", base = file("webapi")) buildInfoKeys ++= Seq[BuildInfoKey]( name, version, - "akkaHttp" -> Dependencies.akkaHttpVersion.value, - "sipi" -> Dependencies.sipiImage.value, - "fuseki" -> Dependencies.fusekiImage.value + "akkaHttp" -> Dependencies.akkaHttpVersion, + "sipi" -> Dependencies.sipiImage, + "fuseki" -> Dependencies.fusekiImage ), buildInfoPackage := "org.knora.webapi.http.version" ) @@ -190,3 +188,58 @@ lazy val webapiJavaTestOptions = Seq( //"-XX:MaxGCPauseMillis=500", //"-XX:MaxMetaspaceSize=4096m" ) + + +lazy val apiMain = project + .in(file("dsp-api-main")) + .settings( + name := "dsp-api-main", + Dependencies.webapiLibraryDependencies, + testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework")) + ) + .dependsOn(schemaCore, schemaRepo, schemaApi) + + +lazy val schemaApi = project + .in(file("dsp-schema-api")) + .settings( + name := "schemaApi", + Dependencies.webapiLibraryDependencies, + testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework")) + ) + .dependsOn(schemaCore) + +lazy val schemaCore = project + .in(file("dsp-schema-core")) + .settings( + name := "schemaCore", + Dependencies.webapiLibraryDependencies, + testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework")) + ) + +lazy val schemaRepo = project + .in(file("dsp-schema-repo")) + .settings( + name := "schemaRepo", + Dependencies.webapiLibraryDependencies, + testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework")) + ) + .dependsOn(schemaCore) + +lazy val schemaRepoEventStoreService = project + .in(file("dsp-schema-repo-eventstore-service")) + .settings( + name := "schemaRepoEventstoreService", + Dependencies.webapiLibraryDependencies, + testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework")) + ) + .dependsOn(schemaRepo) + +lazy val schemaRepoSearchService = project + .in(file("dsp-schema-repo-search-service")) + .settings( + name := "dsp-schema-repo-search-service", + Dependencies.webapiLibraryDependencies, + testFrameworks := Seq(new TestFramework("zio.test.sbt.ZTestFramework")) + ) + .dependsOn(schemaRepo) diff --git a/dsp-api-main/src/main/scala/dsp/api/main/MainApp.scala b/dsp-api-main/src/main/scala/dsp/api/main/MainApp.scala new file mode 100644 index 0000000000..cbdc78b01b --- /dev/null +++ b/dsp-api-main/src/main/scala/dsp/api/main/MainApp.scala @@ -0,0 +1,17 @@ +package dsp.api.main + +import dsp.schema.repo.{SchemaRepo, SchemaRepoLive} +import zio.Console.printLine +import zio._ + +object MainApp extends ZIOAppDefault { + val effect: ZIO[Console with SchemaRepo, Nothing, Unit] = + for { + profile <- SchemaRepo.lookup("user1").orDie + _ <- printLine(profile).orDie + _ <- printLine(42).orDie + } yield () + + val mainApp: ZIO[Any, Nothing, Unit] = effect.provide(Console.live ++ SchemaRepoLive.layer) + def run: ZIO[Any, Nothing, Unit] = mainApp +} diff --git a/dsp-schema-api/src/main/scala/dsp/schema/api/app/App.scala b/dsp-schema-api/src/main/scala/dsp/schema/api/app/App.scala new file mode 100644 index 0000000000..7da5a370bc --- /dev/null +++ b/dsp-schema-api/src/main/scala/dsp/schema/api/app/App.scala @@ -0,0 +1,13 @@ +package dsp.schema.api + +import zio._ +import zhttp.http._ +import zhttp.service.Server + +object App extends ZIOAppDefault { + val app = Http.collect[Request] { case Method.GET -> !! / "text" => + Response.text("Hello World!") + } + + def run = Server.start(8090, app) +} \ No newline at end of file diff --git a/dsp-schema-core/src/main/scala/dsp/schema/domain/SchemaDomain.scala b/dsp-schema-core/src/main/scala/dsp/schema/domain/SchemaDomain.scala new file mode 100644 index 0000000000..da9cb214a0 --- /dev/null +++ b/dsp-schema-core/src/main/scala/dsp/schema/domain/SchemaDomain.scala @@ -0,0 +1,279 @@ +/* + * Copyright © 2021 - 2022 Data and Service Center for the Humanities and/or DaSCH Service Platform contributors. + * SPDX-License-Identifier: Apache-2.0 + * + */ + +package dsp.schema.domain + +import zio.prelude.Validation + +object SchemaDomain extends App { + // implicitly["".type =:= "".type] + + type IRI = String + type UserID = String + type UserProfile = String + type SchemaID = String + type Schema = String + + final case class OntologyInfo(name: String, projectIri: IRI, label: String, comment: String) + final case class OntologyClass[A <: Singleton with String](name: A, label: String, comment: String) { self => + type Tag = A + + override def equals(that: Any): Boolean = + that match { + case that: OntologyClass[_] => self.name == that.name + case _ => false + } + override def hashCode: Int = name.hashCode + } + final case class OntologyProperty[A <: Singleton with String]( + name: A, + label: String, + comment: String, + range: String + ) { self => + type Tag = A + + override def equals(that: Any): Boolean = + that match { + case that: OntologyProperty[_] => self.name == that.name + case _ => false + } + + override def hashCode: Int = name.hashCode + } + + trait Cardinality { self => + type ClassTag <: Singleton with String + type PropertyTag <: Singleton with String + + def ontologyClass: OntologyClass[ClassTag] + def ontologyProperty: OntologyProperty[PropertyTag] + def cardinalityType: CardinalityType + } + object Cardinality { + type WithTags[T1, T2] = Cardinality { type ClassTag = T1; type PropertyTag = T2 } + + def apply[A <: Singleton with String, B <: Singleton with String]( + oc: OntologyClass[A], + op: OntologyProperty[B], + ct: CardinalityType + ): WithTags[oc.Tag, op.Tag] = + new Cardinality { + type ClassTag = oc.Tag + type PropertyTag = op.Tag + + val ontologyClass = oc + val ontologyProperty = op + val cardinalityType = ct + } + } + + sealed trait CardinalityType + object CardinalityType { + case object MaxCardinalityOne extends CardinalityType + case object MinCardinalityOne extends CardinalityType + case object MinCardinalityZero extends CardinalityType + } + + sealed trait Ontology[Classes, Properties] { self => + + def withClass[Tag <: Singleton with String](ontoClass: OntologyClass[Tag])(implicit + ev: NotSubtypeOf[Classes, Tag] + ): Ontology[Classes with Tag, Properties] = + Ontology.WithClass[Classes, Properties, Tag](self, ontoClass) + + def withProperty[Tag <: Singleton with String](propertyInfo: OntologyProperty[Tag])(implicit + ev: NotSubtypeOf[Properties, Tag] + ): Ontology[Classes, Properties with Tag] = + Ontology.WithProperty[Classes, Properties, Tag](self, propertyInfo) + + def withCardinality( + cardinality: Cardinality + )(implicit + ev1: Classes <:< cardinality.ClassTag, + ev2: Properties <:< cardinality.PropertyTag + ): Ontology[Classes, Properties] = + Ontology.WithCardinality[Classes, Properties, cardinality.ClassTag, cardinality.PropertyTag]( + self, + cardinality + ) + + lazy val classes: Set[OntologyClass[_ <: Singleton with String]] = + self match { + case _: Ontology.Empty => Set.empty + case Ontology.WithClass(ontology, singleClass) => Set(singleClass) ++ ontology.classes + case Ontology.WithProperty(ontology, _) => ontology.classes + case Ontology.WithCardinality(ontology, _) => ontology.classes + } + + lazy val properties: Set[OntologyProperty[_ <: Singleton with String]] = + self match { + case _: Ontology.Empty => Set.empty + case Ontology.WithClass(ontology, _) => ontology.properties + case Ontology.WithProperty(ontology, singleProp) => Set(singleProp) ++ ontology.properties + case Ontology.WithCardinality(ontology, _) => ontology.properties + } + + lazy val cardinalities: Set[Cardinality] = + self match { + case _: Ontology.Empty => Set.empty + case Ontology.WithClass(ontology, _) => ontology.cardinalities + case Ontology.WithProperty(ontology, _) => ontology.cardinalities + case Ontology.WithCardinality(ontology, cardinality) => Set(cardinality) ++ ontology.cardinalities + } + + def withClassV[Tag <: Singleton with String]( + ontoClass: OntologyClass[Tag] + ): Validation[String, Ontology[Classes with Tag, Properties]] = + if (classes.contains(ontoClass)) { + Validation.fail(s"Class ${ontoClass.name} already exists in ontology") + } else { + Validation.succeed(withClass[Tag](ontoClass)) + } + + def withPropertyV[Tag <: Singleton with String]( + propertyInfo: OntologyProperty[Tag] + ): Validation[String, Ontology[Classes, Properties with Tag]] = + if (properties.contains(propertyInfo)) { + Validation.fail(s"Property ${propertyInfo.name} already exists in ontology") + } else { + Validation.succeed(withProperty[Tag](propertyInfo)) + } + + def withCardinalityV( + cardinality: Cardinality + ): Validation[String, Ontology[Classes, Properties]] = { + def checkClasses: Validation[String, Unit] = + if (!classes.contains(cardinality.ontologyClass)) { + Validation.fail(s"Class ${cardinality.ontologyClass.name} does not exist in ontology") + } else { + Validation.succeed(()) + } + + def checkProperties: Validation[String, Unit] = + if (!properties.contains(cardinality.ontologyProperty)) { + Validation.fail(s"Property ${cardinality.ontologyProperty.name} does not exist in ontology") + } else { + Validation.succeed(()) + } + + def checkCardinality: Validation[String, Unit] = + if ( + cardinalities.exists(c => + c.ontologyClass == cardinality.ontologyClass && c.ontologyProperty == cardinality.ontologyProperty + ) + ) { + Validation.fail( + s"Cardinality ${cardinality.ontologyClass.name} ${cardinality.ontologyProperty.name} already exists in ontology" + ) + } else { + Validation.succeed(()) + } + + (checkClasses &> checkProperties &> checkCardinality).as { + Ontology.WithCardinality[Classes, Properties, cardinality.ClassTag, cardinality.PropertyTag]( + self, + cardinality + ) + } + } + + } + object Ontology { + def empty(ontoInfo: OntologyInfo): Ontology[Any, Any] = Ontology.Empty(ontoInfo) + + private final case class Empty(info: OntologyInfo) extends Ontology[Any, Any] + + private final case class WithClass[Classes, Properties, T1 <: Singleton with String]( + ontology: Ontology[Classes, Properties], + singleClass: OntologyClass[T1] + ) extends Ontology[Classes with T1, Properties] + + private final case class WithProperty[Classes, Properties, T2 <: Singleton with String]( + ontology: Ontology[Classes, Properties], + property: OntologyProperty[T2] + ) extends Ontology[Classes, Properties with T2] + + private final case class WithCardinality[Classes, Properties, Class1, Property1]( + ontology: Ontology[Classes, Properties], + cardinality: Cardinality.WithTags[Class1, Property1] + ) extends Ontology[Classes, Properties] + } + + trait NotSubtypeOf[A, B] + object NotSubtypeOf { + implicit def notSubtypeOf[A, B]: NotSubtypeOf[A, B] = new NotSubtypeOf[A, B] {} + + implicit def isSubtypeOf1[A, B >: A]: NotSubtypeOf[A, B] = new NotSubtypeOf[A, B] {} + implicit def isSubtypeOf2[A, B >: A]: NotSubtypeOf[A, B] = new NotSubtypeOf[A, B] {} + } + + //trying it out + val ontoInfo = OntologyInfo("test", "http://example.org/test", "Test", "Test") + + val classOne = OntologyClass("ClassOne", "Class One", "Class One") + val propertyOne = OntologyProperty("PropertyOne", "Property One", "Property One", "http://example.org/test") + + val classTwo = OntologyClass("ClassTwo", "Class Two", "Class Two") + val propertyTwo = OntologyProperty("PropertyTwo", "Property Two", "Property Two", "http://example.org/test") + + val cardOne = Cardinality(classOne, propertyOne, CardinalityType.MinCardinalityOne) + val cardTwo = Cardinality(classTwo, propertyTwo, CardinalityType.MinCardinalityOne) + val cardThree = Cardinality(classOne, propertyTwo, CardinalityType.MinCardinalityOne) + val cardFour = Cardinality(classTwo, propertyOne, CardinalityType.MinCardinalityOne) + + val exampleOnto: Ontology[Any with "ClassOne" with "ClassTwo", Any with "PropertyOne"] = + Ontology + .empty(ontoInfo) + .withClass(classOne) + .withClass(classTwo) + .withProperty(propertyOne) + //.withProperty(propertyOne) + //.withProperty(propertyTwo) + .withCardinality(cardOne) + .withCardinality(cardOne) + + // TODO: check that at compile time the same class or property is not added twice (uniqueness is defined by the name) + // TODO: check that runtime validation doesn't allow adding a cardinality with the same class and property combination twice + // TODO: add unit tests doing all these tests + // TODO: add the describe method + // TODO: in the next session, do a runtime creation of the ontology by using the describe string + // TODO: sketch out the onion layers for functional domain (includes domain entities?), ontology service, ontology API, and ontology repository + // TODO: Bazel vs SBT + + // Authorization functional domain + // subject verb object + // user/role read id + + // OntoResponder + // + + // OntoAPI v1 / v2 / v3 (could be different SBT projects per API version (at a later time could make sense)) + // calls into OntoResponder (thin wrapper around the functional domain) + // calls into Functional Domain holds all entities and operations + // returns the entity to OntoResponder + // OntoResponder return read to API + // " writes through OntoRepo delta event and sends back answer through API + + // OntoRepo (interfaces) + OntoResponder + FD (one SBT project) + + // OntoRepo (Trait) Type definition never depends on other traits + // + save => EventStoreService.storeEvent() + // + read: OntologyEntity + // + search => SearchService.find() + + // SearchService (concrete implementation) - SBT project + // + find + + // EventStoreService (concrete implementation) - SBT project + +// +// val x: classOne.Tag = ??? +// +// // path dependent types + implicitly[classOne.Tag =:= classOne.Tag] + // implicitly[classOne.Tag =:= classTwo.Tag] +} diff --git a/dsp-schema-core/src/main/scala/dsp/schema/handler/CreateSchema.scala b/dsp-schema-core/src/main/scala/dsp/schema/handler/CreateSchema.scala new file mode 100644 index 0000000000..b0cb24b05a --- /dev/null +++ b/dsp-schema-core/src/main/scala/dsp/schema/handler/CreateSchema.scala @@ -0,0 +1,5 @@ +package dsp.schema.handler + +object CreateSchema { + +} diff --git a/dsp-schema-core/src/main/scala/dsp/schema/repo/SchemaRepo.scala b/dsp-schema-core/src/main/scala/dsp/schema/repo/SchemaRepo.scala new file mode 100644 index 0000000000..00983c9cee --- /dev/null +++ b/dsp-schema-core/src/main/scala/dsp/schema/repo/SchemaRepo.scala @@ -0,0 +1,18 @@ +package dsp.schema.repo + +import zio._ +import dsp.schema.domain.SchemaDomain.{UserID, UserProfile} + + +trait SchemaRepo { + def lookup(id: UserID): Task[UserProfile] + def update(id: UserID, profile: UserProfile): Task[Unit] +} + +object SchemaRepo { + def lookup(id: UserID): ZIO[SchemaRepo, Throwable, UserProfile] = + ZIO.serviceWithZIO[SchemaRepo](_.lookup(id)) + + def update(id: UserID, profile: UserProfile): RIO[SchemaRepo, Unit] = + ZIO.serviceWithZIO[SchemaRepo](_.update(id, profile)) +} diff --git a/dsp-schema-repo-eventstore-service/src/main/scala/dsp/schema/repo/eventstore/EventStoreLive.scala b/dsp-schema-repo-eventstore-service/src/main/scala/dsp/schema/repo/eventstore/EventStoreLive.scala new file mode 100644 index 0000000000..1e26d9dc84 --- /dev/null +++ b/dsp-schema-repo-eventstore-service/src/main/scala/dsp/schema/repo/eventstore/EventStoreLive.scala @@ -0,0 +1,3 @@ +package dsp.schema.repo.eventstore + +trait EventStoreLive {} diff --git a/dsp-schema-repo-search-service/src/main/scala/dsp/schema/repo/search/SearchService.scala b/dsp-schema-repo-search-service/src/main/scala/dsp/schema/repo/search/SearchService.scala new file mode 100644 index 0000000000..e14ea46087 --- /dev/null +++ b/dsp-schema-repo-search-service/src/main/scala/dsp/schema/repo/search/SearchService.scala @@ -0,0 +1,3 @@ +package dsp.schema.repo.search + +object SearchService {} diff --git a/dsp-schema-repo/src/main/scala/dsp/schema/repo/SchemaRepoLive.scala b/dsp-schema-repo/src/main/scala/dsp/schema/repo/SchemaRepoLive.scala new file mode 100644 index 0000000000..dd618a186a --- /dev/null +++ b/dsp-schema-repo/src/main/scala/dsp/schema/repo/SchemaRepoLive.scala @@ -0,0 +1,19 @@ +package dsp.schema.repo + +import zio._ +import dsp.schema.domain.SchemaDomain.{UserID, UserProfile} + +case class SchemaRepoLive() extends SchemaRepo { + + override def lookup(id: UserID): Task[UserProfile] = + zio.Task.succeed("Our great user profile") + override def update(id: UserID, profile: UserProfile): Task[Unit] = { + println(s"updating $id, with $profile") + zio.Task.succeed(()) + } + +} + +object SchemaRepoLive extends (() => SchemaRepo) { + val layer: URLayer[Any, SchemaRepo] = (SchemaRepoLive.apply _).toLayer +} diff --git a/dsp-schema-repo/src/main/scala/dsp/schema/repo/SchemaRepoTest.scala b/dsp-schema-repo/src/main/scala/dsp/schema/repo/SchemaRepoTest.scala new file mode 100644 index 0000000000..ee83a9612e --- /dev/null +++ b/dsp-schema-repo/src/main/scala/dsp/schema/repo/SchemaRepoTest.scala @@ -0,0 +1,24 @@ +package dsp.schema.repo + +import zio._ +import dsp.schema.domain.SchemaDomain.{UserID, UserProfile} + +case class SchemaRepoTest() extends SchemaRepo { + private var map: Map[UserID, UserProfile] = Map() + + def setTestData(map0: Map[UserID, UserProfile]): Task[Unit] = + Task { map = map0 } + + def getTestData: Task[Map[UserID, UserProfile]] = + Task(map) + + def lookup(id: UserID): Task[UserProfile] = + Task(map(id)) + + def update(id: UserID, profile: UserProfile): Task[Unit] = + Task.attempt { map = map + (id -> profile) } +} + +object SchemaRepoTest extends (() => SchemaRepo) { + val layer: URLayer[Any, SchemaRepo] = (SchemaRepoTest.apply _).toLayer +} diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 4454a00ba7..e35066cc84 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -10,87 +10,79 @@ import sbt.{Def, _} object Dependencies { - lazy val sysProps = settingKey[String]("all system properties") - lazy val sysEnvs = settingKey[String]("all system environment variables") - - lazy val sipiImage = settingKey[String]("the SIPI docker image") - lazy val akkaVersion = settingKey[String]("the Akka version") - lazy val akkaHttpVersion = settingKey[String]("the AkkaHttp version") - lazy val jenaVersion = settingKey[String]("the Jena library version") - lazy val metricsVersion = settingKey[String]("the metrics library version") - - lazy val fusekiImage = SettingKey[String]("the DSP specific Apache Jena Fuseki Image") - lazy val knoraSipiImage = SettingKey[String]("the DSP specific Sipi Image") - lazy val knoraWebapiImage = SettingKey[String]("the DSP-API Image") - - val Versions = Seq( - scalaVersion := "2.13.7", - akkaVersion := "2.6.18", - akkaHttpVersion := "10.2.8", - jenaVersion := "4.4.0", - metricsVersion := "4.0.1", - sipiImage := "daschswiss/sipi:3.3.4", - fusekiImage := "daschswiss/apache-jena-fuseki:2.0.8" - ) - - // the user can change the default 'graphdb-se' value by creating an environment variable containing 'graphdb-free' - // e.g., in '$ export KNORA_GDB_TYPE=graphdb-free' in the terminal before launching sbt. - lazy val gdbTypeString: String = sys.env.getOrElse("KNORA_GDB_TYPE", "graphdb-se") + val scalaVersion = "2.13.7" + val akkaVersion = "2.6.18" + val akkaHttpVersion = "10.2.8" + val jenaVersion = "4.4.0" + val metricsVersion = "4.0.1" + val sipiImage = "daschswiss/sipi:v3.3.4" + val fusekiImage = "daschswiss/apache-jena-fuseki:2.0.8" + + val ZioVersion = "2.0.0-RC2" + val ZioHttpVersion = "2.0.0-RC3" + val ZioJsonVersion = "0.3.0-RC3" + val ZioConfigVersion = "3.0.0-RC2" + val ZioSchemaVersion = "0.2.0-RC1-1" + val ZioLoggingVersion = "2.0.0-RC5" + val ZioZmxVersion = "2.0.0-M1" + val ZioPreludeVersion = "1.0.0-RC10" object Compile { + // ZIO - val zio = "dev.zio" %% "zio" % "2.0.0-M3" - val zioJson = "dev.zio" %% "zio-json" % "0.1.5" - val zioTest = "dev.zio" %% "zio-test" % "2.0.0-M3" - val zioTestJunit = "dev.zio" %% "zio-test-junit" % "2.0.0-M3" - val zioPrelude = "dev.zio" %% "zio-prelude" % "1.0.0-RC6" + val zio = "dev.zio" %% "zio" % ZioVersion + val zioHttp = "io.d11" %% "zhttp" % ZioHttpVersion + val zioJson = "dev.zio" %% "zio-json" % ZioJsonVersion + val zioPrelude = "dev.zio" %% "zio-prelude" % ZioPreludeVersion + val zioTest = "dev.zio" %% "zio-test" % ZioVersion % Test + val zioTestSbt = "dev.zio" %% "zio-test-sbt" % ZioVersion % Test // akka - val akkaActor = Def.setting {"com.typesafe.akka" %% "akka-actor" % akkaVersion.value} - val akkaStream = Def.setting {"com.typesafe.akka" %% "akka-stream" % akkaVersion.value} - val akkaSlf4j = Def.setting {"com.typesafe.akka" %% "akka-slf4j" % akkaVersion.value} - val akkaProtobufV3 = Def.setting {"com.typesafe.akka" %% "akka-protobuf-v3" % akkaVersion.value} + val akkaActor = "com.typesafe.akka" %% "akka-actor" % akkaVersion + val akkaStream = "com.typesafe.akka" %% "akka-stream" % akkaVersion + val akkaSlf4j = "com.typesafe.akka" %% "akka-slf4j" % akkaVersion + val akkaProtobufV3 = "com.typesafe.akka" %% "akka-protobuf-v3" % akkaVersion // akka http - val akkaHttp = Def.setting {"com.typesafe.akka" %% "akka-http" % akkaHttpVersion.value} - val akkaHttpXml = Def.setting {"com.typesafe.akka" %% "akka-http-xml" % akkaHttpVersion.value} - val akkaHttpSprayJson = Def.setting {"com.typesafe.akka" %% "akka-http-spray-json" % akkaHttpVersion.value} - val akkaHttpJacksonJava = Def.setting {"com.typesafe.akka" %% "akka-http-jackson" % akkaHttpVersion.value} + val akkaHttp = "com.typesafe.akka" %% "akka-http" % akkaHttpVersion + val akkaHttpXml = "com.typesafe.akka" %% "akka-http-xml" % akkaHttpVersion + val akkaHttpSprayJson = "com.typesafe.akka" %% "akka-http-spray-json" % akkaHttpVersion + val akkaHttpJacksonJava = "com.typesafe.akka" %% "akka-http-jackson" % akkaHttpVersion - val typesafeConfig = "com.typesafe" % "config" % "1.3.3" + val typesafeConfig = "com.typesafe" % "config" % "1.3.3" //CORS support - val akkaHttpCors = "ch.megard" %% "akka-http-cors" % "1.0.0" + val akkaHttpCors = "ch.megard" %% "akka-http-cors" % "1.0.0" // jena - val jenaLibs = Def.setting {"org.apache.jena" % "apache-jena-libs" % jenaVersion.value } - val jenaText = Def.setting {"org.apache.jena" % "jena-text" % jenaVersion.value } + val jenaLibs = "org.apache.jena" % "apache-jena-libs" % jenaVersion + val jenaText = "org.apache.jena" % "jena-text" % jenaVersion // logging - val scalaLogging = "com.typesafe.scala-logging" %% "scala-logging" % "3.9.4" - val logbackClassic = "ch.qos.logback" % "logback-classic" % "1.2.9" + val scalaLogging = "com.typesafe.scala-logging" %% "scala-logging" % "3.9.4" + val logbackClassic = "ch.qos.logback" % "logback-classic" % "1.2.10" // Metrics - val kamonCore = "io.kamon" %% "kamon-core" % "2.1.5" - val kamonScalaFuture = "io.kamon" %% "kamon-scala-future" % "2.1.5" - val kamonAkkaHttpd = "io.kamon" %% "kamon-akka-http" % "2.1.5" - val kamonPrometheus = "io.kamon" %% "kamon-prometheus" % "2.1.5" - val kamonLogback = "io.kamon" %% "kamon-logback" % "2.1.5" - val aspectJWeaver = "org.aspectj" % "aspectjweaver" % "1.9.4" + val kamonCore = "io.kamon" %% "kamon-core" % "2.1.5" + val kamonScalaFuture = "io.kamon" %% "kamon-scala-future" % "2.1.5" + val kamonAkkaHttpd = "io.kamon" %% "kamon-akka-http" % "2.1.5" + val kamonPrometheus = "io.kamon" %% "kamon-prometheus" % "2.1.5" + val kamonLogback = "io.kamon" %% "kamon-logback" % "2.1.5" + val aspectJWeaver = "org.aspectj" % "aspectjweaver" % "1.9.4" // input validation - val commonsValidator = "commons-validator" % "commons-validator" % "1.6" exclude("commons-logging", "commons-logging") + val commonsValidator = "commons-validator" % "commons-validator" % "1.6" exclude("commons-logging", "commons-logging") // authentication - val bcprov = "org.bouncycastle" % "bcprov-jdk15on" % "1.64" - val springSecurityCore = "org.springframework.security" % "spring-security-core" % "5.1.5.RELEASE" exclude("commons-logging", "commons-logging") exclude("org.springframework", "spring-aop") - val jwtSprayJson = "com.pauldijou" %% "jwt-spray-json" % "5.0.0" + val bcprov = "org.bouncycastle" % "bcprov-jdk15on" % "1.64" + val springSecurityCore = "org.springframework.security" % "spring-security-core" % "5.1.5.RELEASE" exclude("commons-logging", "commons-logging") exclude("org.springframework", "spring-aop") + val jwtSprayJson = "com.pauldijou" %% "jwt-spray-json" % "5.0.0" // caching - val ehcache = "net.sf.ehcache" % "ehcache" % "2.10.9.2" - val jedis = "redis.clients" % "jedis" % "3.1.0-m4" + val ehcache = "net.sf.ehcache" % "ehcache" % "2.10.9.2" + val jedis = "redis.clients" % "jedis" % "3.1.0-m4" // serialization - val chill = "com.twitter" %% "chill" % "0.9.5" + val chill = "com.twitter" %% "chill" % "0.9.5" // other //"javax.transaction" % "transaction-api" % "1.1-rev-1", @@ -112,7 +104,6 @@ object Dependencies { val saxonHE = "net.sf.saxon" % "Saxon-HE" % "9.9.0-2" val scalaXml = "org.scala-lang.modules" %% "scala-xml" % "1.2.0" - val scalaJava8Compat = "org.scala-lang.modules" %% "scala-java8-compat" % "1.0.2" // provides akka jackson (json) support val akkaHttpCirce = "de.heikoseeberger" %% "akka-http-circe" % "1.36.0" @@ -153,9 +144,9 @@ object Dependencies { } object WebapiTest { - val akkaTestkit = Def.setting {"com.typesafe.akka" %% "akka-testkit" % akkaVersion.value % "test"} - val akkaStreamTestkit = Def.setting {"com.typesafe.akka" %% "akka-stream-testkit" % akkaVersion.value % "test"} - val akkaHttpTestkit = Def.setting {"com.typesafe.akka" %% "akka-http-testkit" % akkaHttpVersion.value % "test"} + val akkaTestkit = "com.typesafe.akka" %% "akka-testkit" % akkaVersion % "test" + val akkaStreamTestkit = "com.typesafe.akka" %% "akka-stream-testkit" % akkaVersion % "test" + val akkaHttpTestkit = "com.typesafe.akka" %% "akka-http-testkit" % akkaHttpVersion % "test" val scalaTest = "org.scalatest" %% "scalatest" % "3.2.2" % "test" val gatlingHighcharts = "io.gatling.highcharts" % "gatling-charts-highcharts"% "3.7.5" % "test" val gatlingTestFramework = "io.gatling" % "gatling-test-framework" % "3.2.1" % "test" @@ -163,9 +154,9 @@ object Dependencies { } object TestBinaries { - val akkaTestkit = Def.setting {"com.typesafe.akka" %% "akka-testkit" % akkaVersion.value} - val akkaStreamTestkit = Def.setting {"com.typesafe.akka" %% "akka-stream-testkit" % akkaVersion.value} - val akkaHttpTestkit = Def.setting {"com.typesafe.akka" %% "akka-http-testkit" % akkaHttpVersion.value} + val akkaTestkit = "com.typesafe.akka" %% "akka-testkit" % akkaVersion + val akkaStreamTestkit = "com.typesafe.akka" %% "akka-stream-testkit" % akkaVersion + val akkaHttpTestkit = "com.typesafe.akka" %% "akka-http-testkit" % akkaHttpVersion val scalaTest = "org.scalatest" %% "scalatest" % "3.2.2" val gatlingHighcharts = "io.gatling.highcharts" % "gatling-charts-highcharts"% "3.7.5" val gatlingTestFramework = "io.gatling" % "gatling-test-framework" % "3.2.1" @@ -176,16 +167,16 @@ object Dependencies { val l = libraryDependencies val webapiLibraryDependencies = l ++= Seq[sbt.ModuleID]( - akkaActor.value, - akkaHttp.value, + akkaActor, + akkaHttp, akkaHttpCirce, akkaHttpCors, - akkaHttpJacksonJava.value, - akkaHttpSprayJson.value, - akkaHttpXml.value, - akkaProtobufV3.value, - akkaSlf4j.value, - akkaStream.value, + akkaHttpJacksonJava, + akkaHttpSprayJson, + akkaHttpXml, + akkaProtobufV3, + akkaSlf4j, + akkaStream, apacheHttpClient, bcprov, chill, @@ -200,8 +191,8 @@ object Dependencies { jacksonScala, jaxbApi, jedis, - jenaLibs.value, - jenaText.value, + jenaLibs, + jenaText, jodaConvert, jodaTime, jodd, @@ -210,38 +201,37 @@ object Dependencies { kamonLogback, kamonPrometheus, kamonScalaFuture, + logbackCore, logbackClassic, rdf4jClient, rdf4jRuntime, rdf4jStorage, saxonHE, scalaGraph, - scalaJava8Compat, scalaLogging, scalaXml, scallop, springSecurityCore, swaggerAkkaHttp, + titaniumJSONLD, typesafeConfig, - WebapiTest.akkaHttpTestkit.value, - WebapiTest.akkaStreamTestkit.value, - WebapiTest.akkaTestkit.value, + WebapiTest.akkaHttpTestkit, + WebapiTest.akkaStreamTestkit, + WebapiTest.akkaTestkit, WebapiTest.gatlingHighcharts, WebapiTest.gatlingTestFramework, WebapiTest.scalaTest, WebapiTest.testcontainers, xmlunitCore, zio, + zioHttp, zioJson, zioPrelude, zioTest, - zioTestJunit, - // missing from current BAZEL setup - logbackCore, + zioTestSbt, log4jOverSlf4j, jclOverSlf4j, slf4jApi, - titaniumJSONLD, jakartaJSON, twirlApi, junit, diff --git a/project/plugins.sbt b/project/plugins.sbt index 2235c5cbbd..58402081bb 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -20,4 +20,6 @@ addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.11.0") // addSbtPlugin("com.timushev.sbt" % "sbt-updates" % "0.6.1") // addSbtPlugin("com.github.cb372" % "sbt-explicit-dependencies" % "0.2.16") + +// please don't remove or merge uncommented to main // addDependencyTreePlugin diff --git a/webapi/src/test/scala/org/knora/webapi/IntegrationSpec.scala b/webapi/src/test/scala/org/knora/webapi/IntegrationSpec.scala index e8d7da8284..b410273a3a 100644 --- a/webapi/src/test/scala/org/knora/webapi/IntegrationSpec.scala +++ b/webapi/src/test/scala/org/knora/webapi/IntegrationSpec.scala @@ -48,9 +48,9 @@ object IntegrationSpec { } /** - * Defines a base class used in tests where only a running Fuseki Container is needed. - * Does not start the DSP-API server. - */ + * Defines a base class used in tests where only a running Fuseki Container is needed. + * Does not start the DSP-API server. + */ abstract class IntegrationSpec(_config: Config) extends AsyncWordSpecLike with Matchers @@ -98,7 +98,7 @@ abstract class IntegrationSpec(_config: Config) } } yield value - implicit val rt: Runtime[Has[Clock] with Has[Console]] = Runtime.default + implicit val rt: Runtime[Clock with Console] = Runtime.default rt.unsafeRun( checkTriplestore .retry(ScheduleUtil.schedule) @@ -124,7 +124,7 @@ object ScheduleUtil { /** * Retry every second for 60 times, i.e., 60 seconds in total. */ - def schedule[A]: WithState[(Long, Long), Has[Console], Any, (Long, Long)] = Schedule.spaced(1.second) && Schedule + def schedule[A]: WithState[(Long, Long), Console, Any, (Long, Long)] = Schedule.spaced(1.second) && Schedule .recurs(60) .onDecision({ case (_, _, Decision.Done) => printLine(s"done trying").orDie @@ -135,7 +135,7 @@ object ScheduleUtil { //// ZIO helpers //// object LegacyRuntime { - val runtime: Runtime[Has[Clock] with Has[Console]] = Runtime.default + val runtime: Runtime[Clock with Console] = Runtime.default /** * Transforms a [[Task]] into a [[Future]].