diff --git a/build.sbt b/build.sbt index 808cbd2bfa0f..101f03aa16a2 100644 --- a/build.sbt +++ b/build.sbt @@ -1553,6 +1553,115 @@ lazy val `zio-wrapper` = project } ) +/** JPMS module wrapper for AWS SDK. + */ +lazy val `aws-wrapper` = project + .in(file("lib/java/aws-wrapper")) + .enablePlugins(JPMSPlugin) + .settings( + modularFatJarWrapperSettings, + javaModuleName := "org.enso.aws.wrapper", + libraryDependencies ++= Seq( + "com.amazon.redshift" % "redshift-jdbc42" % redshiftVersion, + "com.amazonaws" % "aws-java-sdk-core" % awsJavaSdkV1Version, + "com.amazonaws" % "aws-java-sdk-redshift" % awsJavaSdkV1Version, + "com.amazonaws" % "aws-java-sdk-sts" % awsJavaSdkV1Version, + "software.amazon.awssdk" % "aws-core" % awsJavaSdkV2Version, + "software.amazon.awssdk" % "auth" % awsJavaSdkV2Version, + "software.amazon.awssdk" % "bom" % awsJavaSdkV2Version, + "software.amazon.awssdk" % "s3" % awsJavaSdkV2Version, + "software.amazon.awssdk" % "sso" % awsJavaSdkV2Version, + "software.amazon.awssdk" % "ssooidc" % awsJavaSdkV2Version, + "com.fasterxml.jackson.core" % "jackson-databind" % "2.12.7.1", + "com.fasterxml.jackson.core" % "jackson-annotations" % "2.12.7", + "com.fasterxml.jackson.core" % "jackson-core" % "2.12.7", + "com.fasterxml.jackson.dataformat" % "jackson-dataformat-cbor" % "2.12.6", + "org.slf4j" % "slf4j-api" % slf4jVersion, + "commons-logging" % "commons-logging" % "1.2", + "commons-codec" % "commons-codec" % "1.15" + ), + Compile / moduleDependencies := Seq( + "org.slf4j" % "slf4j-api" % slf4jVersion, + "org.reactivestreams" % "reactive-streams" % "1.0.4", + "org.apache.httpcomponents" % "httpcore" % "4.4.13", + "org.apache.httpcomponents" % "httpclient" % "4.5.13", + "commons-logging" % "commons-logging" % "1.2" + ), + // Remove all the transitive dependencies of AWS SDK and leave only those that + // include `software.amazon.awssdk.*` classes. + assembly / assemblyExcludedJars := { + val excludedJars = JPMSUtils.filterModulesFromClasspath( + (Compile / dependencyClasspath).value, + Seq( + "com.fasterxml.jackson.core" % "jackson-databind" % "2.12.7.1", + "com.fasterxml.jackson.core" % "jackson-annotations" % "2.12.7", + "com.fasterxml.jackson.core" % "jackson-core" % "2.12.7", + "com.fasterxml.jackson.dataformat" % "jackson-dataformat-cbor" % "2.12.6", + "org.slf4j" % "slf4j-api" % slf4jVersion, + "org.apache.httpcomponents" % "httpclient" % "4.5.13", + "org.apache.httpcomponents" % "httpcore" % "4.4.13", + "commons-logging" % "commons-logging" % "1.2", + "commons-codec" % "commons-codec" % "1.15", + "org.reactivestreams" % "reactive-streams" % "1.0.4", + "joda-time" % "joda-time" % "2.8.1", + "io.netty" % "netty-common" % "4.1.108.Final", + "io.netty" % "netty-codec" % "4.1.108.Final", + "io.netty" % "netty-codec-http" % "4.1.108.Final", + "io.netty" % "netty-codec-http2" % "4.1.108.Final", + "io.netty" % "netty-buffer" % "4.1.108.Final", + "io.netty" % "netty-handler" % "4.1.108.Final", + "io.netty" % "netty-resolver" % "4.1.108.Final", + "io.netty" % "netty-transport" % "4.1.108.Final", + "io.netty" % "netty-transport-classes-epoll" % "4.1.108.Final", + "io.netty" % "netty-transport-native-unix-common" % "4.1.108.Final" + ), + streams.value.log, + scalaBinaryVersion.value, + moduleName.value, + shouldContainAll = true + ) + excludedJars + }, + assembly / assemblyMergeStrategy := { + case PathList("META-INF", "io.netty.versions.properties") => + MergeStrategy.first + case PathList("META-INF", "MANIFEST.MF") => MergeStrategy.discard + case PathList("META-INF", "LICENSE") => MergeStrategy.concat + case PathList("META-INF", "LICENSE.txt") => MergeStrategy.concat + case PathList("META-INF", "NOTICE") => MergeStrategy.concat + case PathList("META-INF", "NOTICE.txt") => MergeStrategy.concat + case PathList("META-INF", "DEPENDENCIES") => MergeStrategy.discard + case PathList("META-INF", "INDEX.LIST") => MergeStrategy.discard + case PathList("META-INF", "SIGNER.RSA") => MergeStrategy.discard + case PathList("META-INF", "SIGNER.SF") => MergeStrategy.discard + case PathList("module-info.class") => MergeStrategy.preferProject + case _ => MergeStrategy.deduplicate + }, + autoScalaLibrary := false, + Compile / patchModules := { + val aws = JPMSUtils.filterModulesFromUpdate( + update.value, + Seq( + "software.amazon.awssdk" % "auth" % awsJavaSdkV2Version, + "software.amazon.awssdk" % "aws-core" % awsJavaSdkV2Version, + "software.amazon.awssdk" % "sdk-core" % awsJavaSdkV2Version, + "software.amazon.awssdk" % "profiles" % awsJavaSdkV2Version, + "software.amazon.awssdk" % "regions" % awsJavaSdkV2Version, + "software.amazon.awssdk" % "http-client-spi" % awsJavaSdkV2Version, + "software.amazon.awssdk" % "apache-client" % awsJavaSdkV2Version, + "software.amazon.awssdk" % "s3" % awsJavaSdkV2Version + ), + streams.value.log, + moduleName.value, + scalaBinaryVersion.value, + shouldContainAll = true + ) + Map( + javaModuleName.value -> aws + ) + } + ) + lazy val cli = project .in(file("lib/scala/cli")) .enablePlugins(JPMSPlugin) @@ -3490,7 +3599,7 @@ lazy val `engine-runner` = project Compile / run / mainClass := Some("org.enso.runner.Main"), commands += WithDebugCommand.withDebug, inConfig(Compile)(truffleRunOptionsSettings), - libraryDependencies ++= GraalVM.modules ++ Seq( + libraryDependencies ++= GraalVM.modules ++ GraalVM.toolsPkgs ++ Seq( "org.graalvm.polyglot" % "polyglot" % graalMavenPackagesVersion, "org.graalvm.sdk" % "polyglot-tck" % graalMavenPackagesVersion % Provided, "commons-cli" % "commons-cli" % commonsCliVersion, @@ -3575,7 +3684,7 @@ lazy val `engine-runner` = project val NI_MODULES = "org.graalvm.nativeimage,org.graalvm.nativeimage.builder,org.graalvm.nativeimage.base,org.graalvm.nativeimage.driver,org.graalvm.nativeimage.librarysupport,org.graalvm.nativeimage.objectfile,org.graalvm.nativeimage.pointsto,com.oracle.graal.graal_enterprise,com.oracle.svm.svm_enterprise" val JDK_MODULES = - "jdk.localedata,jdk.httpserver,java.naming,java.net.http" + "jdk.localedata,jdk.httpserver,java.naming,java.net.http,java.xml" val DEBUG_MODULES = "jdk.jdwp.agent" val PYTHON_MODULES = "jdk.security.auth,java.naming" @@ -4034,7 +4143,7 @@ lazy val `std-benchmarks` = (project in file("std-bits/benchmarks")) (Compile / run).toTask("").tag(Exclusive).value } .dependsOn( - buildEngineDistribution + buildEngineDistributionNoIndex ) .value, benchOnly := Def.inputTaskDyn { @@ -4436,6 +4545,7 @@ val `std-tableau-polyglot-root` = lazy val `std-base` = project .in(file("std-bits") / "base") + .enablePlugins(JPMSPlugin) .settings( frgaalJavaCompilerSetting, autoScalaLibrary := false, @@ -4445,9 +4555,19 @@ lazy val `std-base` = project Compile / packageBin / artifactPath := `base-polyglot-root` / "std-base.jar", libraryDependencies ++= Seq( - "org.graalvm.polyglot" % "polyglot" % graalMavenPackagesVersion, - "org.netbeans.api" % "org-openide-util-lookup" % netbeansApiVersion % "provided", - "com.fasterxml.jackson.core" % "jackson-databind" % jacksonVersion + "org.graalvm.polyglot" % "polyglot" % graalMavenPackagesVersion, + "com.fasterxml.jackson.core" % "jackson-databind" % jacksonVersion + ), + Compile / moduleDependencies ++= Seq( + "org.graalvm.polyglot" % "polyglot" % graalMavenPackagesVersion, + "org.graalvm.sdk" % "collections" % graalMavenPackagesVersion, + "com.ibm.icu" % "icu4j" % icuVersion, + "com.fasterxml.jackson.core" % "jackson-databind" % jacksonVersion, + "com.fasterxml.jackson.core" % "jackson-annotations" % jacksonVersion, + "com.fasterxml.jackson.core" % "jackson-core" % jacksonVersion + ), + Compile / internalModuleDependencies := Seq( + (`common-polyglot-core-utils` / Compile / exportedModule).value ), Compile / packageBin := Def.task { val result = (Compile / packageBin).value @@ -4484,6 +4604,7 @@ lazy val `common-polyglot-core-utils` = project lazy val `enso-test-java-helpers` = project .in(file("test/Base_Tests/polyglot-sources/enso-test-java-helpers")) + .enablePlugins(JPMSPlugin) .settings( frgaalJavaCompilerSetting, autoScalaLibrary := false, @@ -4492,6 +4613,13 @@ lazy val `enso-test-java-helpers` = project libraryDependencies ++= Seq( "org.graalvm.polyglot" % "polyglot" % graalMavenPackagesVersion % "provided" ), + Compile / moduleDependencies ++= Seq( + "org.graalvm.polyglot" % "polyglot" % graalMavenPackagesVersion + ), + Compile / internalModuleDependencies := Seq( + (`std-base` / Compile / exportedModule).value, + (`std-table` / Compile / exportedModule).value + ), Compile / packageBin := Def.task { val result = (Compile / packageBin).value val primaryLocation = (Compile / packageBin / artifactPath).value @@ -4550,6 +4678,7 @@ lazy val `benchmark-java-helpers` = project lazy val `std-table` = project .in(file("std-bits") / "table") .enablePlugins(Antlr4Plugin) + .enablePlugins(JPMSPlugin) .settings( frgaalJavaCompilerSetting, autoScalaLibrary := false, @@ -4574,6 +4703,21 @@ lazy val `std-table` = project "org.antlr" % "antlr4-runtime" % antlrVersion, "org.apache.logging.log4j" % "log4j-to-slf4j" % "2.18.0" // org.apache.poi uses log4j ), + Compile / moduleDependencies ++= Seq( + "org.graalvm.polyglot" % "polyglot" % graalMavenPackagesVersion, + "org.antlr" % "antlr4-runtime" % antlrVersion, + "com.univocity" % "univocity-parsers" % univocityParsersVersion, + "org.apache.poi" % "poi" % poiOoxmlVersion, + "org.apache.poi" % "poi-ooxml" % poiOoxmlVersion, + "org.apache.poi" % "poi-ooxml-lite" % poiOoxmlVersion, + "org.apache.xmlbeans" % "xmlbeans" % xmlbeansVersion, + "org.graalvm.sdk" % "collections" % graalMavenPackagesVersion, + "com.ibm.icu" % "icu4j" % icuVersion + ), + Compile / internalModuleDependencies := Seq( + (`common-polyglot-core-utils` / Compile / exportedModule).value, + (`std-base` / Compile / exportedModule).value + ), Compile / packageBin := Def.task { val result = (Compile / packageBin).value val _ = StdBits @@ -4590,6 +4734,7 @@ lazy val `std-table` = project lazy val `std-image` = project .in(file("std-bits") / "image") + .enablePlugins(JPMSPlugin) .settings( frgaalJavaCompilerSetting, autoScalaLibrary := false, @@ -4599,9 +4744,15 @@ lazy val `std-image` = project Compile / packageBin / artifactPath := `image-polyglot-root` / "std-image.jar", libraryDependencies ++= Seq( - "org.graalvm.polyglot" % "polyglot" % graalMavenPackagesVersion % "provided", - "org.netbeans.api" % "org-openide-util-lookup" % netbeansApiVersion % "provided", - "org.openpnp" % "opencv" % opencvVersion + "org.graalvm.polyglot" % "polyglot" % graalMavenPackagesVersion % "provided", + "org.openpnp" % "opencv" % opencvVersion + ), + Compile / moduleDependencies ++= Seq( + "org.graalvm.polyglot" % "polyglot" % graalMavenPackagesVersion, + "org.openpnp" % "opencv" % opencvVersion + ), + Compile / internalModuleDependencies := Seq( + (`std-base` / Compile / exportedModule).value ), Compile / packageBin := Def.task { val result = (Compile / packageBin).value @@ -4649,6 +4800,7 @@ lazy val `std-google-api` = project lazy val `std-database` = project .in(file("std-bits") / "database") + .enablePlugins(JPMSPlugin) .settings( frgaalJavaCompilerSetting, autoScalaLibrary := false, @@ -4658,10 +4810,20 @@ lazy val `std-database` = project Compile / packageBin / artifactPath := `database-polyglot-root` / "std-database.jar", libraryDependencies ++= Seq( - "org.graalvm.polyglot" % "polyglot" % graalMavenPackagesVersion % "provided", - "org.netbeans.api" % "org-openide-util-lookup" % netbeansApiVersion % "provided", - "org.xerial" % "sqlite-jdbc" % sqliteVersion, - "org.postgresql" % "postgresql" % postgresVersion + "org.netbeans.api" % "org-openide-util-lookup" % netbeansApiVersion % "provided", + "org.xerial" % "sqlite-jdbc" % sqliteVersion, + "org.postgresql" % "postgresql" % postgresVersion + ), + Compile / moduleDependencies ++= Seq( + "org.graalvm.sdk" % "collections" % graalMavenPackagesVersion, + "org.graalvm.polyglot" % "polyglot" % graalMavenPackagesVersion, + "com.fasterxml.jackson.core" % "jackson-databind" % jacksonVersion, + "com.fasterxml.jackson.core" % "jackson-annotations" % jacksonVersion, + "com.fasterxml.jackson.core" % "jackson-core" % jacksonVersion + ), + Compile / internalModuleDependencies := Seq( + (`common-polyglot-core-utils` / Compile / exportedModule).value, + (`std-base` / Compile / exportedModule).value ), Compile / packageBin := Def.task { val result = (Compile / packageBin).value @@ -4680,6 +4842,7 @@ lazy val `std-database` = project lazy val `std-aws` = project .in(file("std-bits") / "aws") + .enablePlugins(JPMSPlugin) .settings( frgaalJavaCompilerSetting, autoScalaLibrary := false, @@ -4688,18 +4851,18 @@ lazy val `std-aws` = project .value, Compile / packageBin / artifactPath := `std-aws-polyglot-root` / "std-aws.jar", - libraryDependencies ++= Seq( - "org.netbeans.api" % "org-openide-util-lookup" % netbeansApiVersion % "provided", - "com.amazon.redshift" % "redshift-jdbc42" % redshiftVersion, - "com.amazonaws" % "aws-java-sdk-core" % awsJavaSdkV1Version, - "com.amazonaws" % "aws-java-sdk-redshift" % awsJavaSdkV1Version, - "com.amazonaws" % "aws-java-sdk-sts" % awsJavaSdkV1Version, - "software.amazon.awssdk" % "auth" % awsJavaSdkV2Version, - "software.amazon.awssdk" % "bom" % awsJavaSdkV2Version, - "software.amazon.awssdk" % "s3" % awsJavaSdkV2Version, - "software.amazon.awssdk" % "sso" % awsJavaSdkV2Version, - "software.amazon.awssdk" % "ssooidc" % awsJavaSdkV2Version + Compile / internalModuleDependencies := Seq( + (`aws-wrapper` / Compile / exportedModule).value, + (`std-base` / Compile / exportedModule).value, + (`std-database` / Compile / exportedModule).value ), + // This will cause `aws-wrapper-assembly.jar` and its dependencies to be copied into the + // `AWS/polyglot/java` directory. + Compile / unmanagedJars := { + val wrapperJar = (`aws-wrapper` / Compile / exportedModuleBin).value + val wrapperDeps = (`aws-wrapper` / Compile / modulePath).value + Seq(Attributed.blank(wrapperJar)) ++ wrapperDeps.map(Attributed.blank) + }, Compile / packageBin := Def.task { val result = (Compile / packageBin).value val _ = StdBits @@ -4712,12 +4875,14 @@ lazy val `std-aws` = project result }.value ) + .dependsOn(`aws-wrapper` % "provided") .dependsOn(`std-base` % "provided") .dependsOn(`std-table` % "provided") .dependsOn(`std-database` % "provided") lazy val `std-snowflake` = project .in(file("std-bits") / "snowflake") + .enablePlugins(JPMSPlugin) .settings( frgaalJavaCompilerSetting, autoScalaLibrary := false, @@ -4748,6 +4913,7 @@ lazy val `std-snowflake` = project lazy val `std-microsoft` = project .in(file("std-bits") / "microsoft") + .enablePlugins(JPMSPlugin) .settings( frgaalJavaCompilerSetting, autoScalaLibrary := false, @@ -4757,8 +4923,10 @@ lazy val `std-microsoft` = project Compile / packageBin / artifactPath := `std-microsoft-polyglot-root` / "std-microsoft.jar", libraryDependencies ++= Seq( - "org.netbeans.api" % "org-openide-util-lookup" % netbeansApiVersion % "provided", - "com.microsoft.sqlserver" % "mssql-jdbc" % mssqlserverJDBCVersion + "com.microsoft.sqlserver" % "mssql-jdbc" % mssqlserverJDBCVersion + ), + Compile / moduleDependencies ++= Seq( + "com.microsoft.sqlserver" % "mssql-jdbc" % mssqlserverJDBCVersion ), Compile / packageBin := Def.task { val result = (Compile / packageBin).value @@ -4770,7 +4938,11 @@ lazy val `std-microsoft` = project ) .value result - }.value + }.value, + Compile / internalModuleDependencies := Seq( + (`std-base` / Compile / exportedModule).value, + (`std-database` / Compile / exportedModule).value + ) ) .dependsOn(`std-base` % "provided") .dependsOn(`std-table` % "provided") @@ -4874,7 +5046,7 @@ lazy val `std-tableau` = project `std-tableau-polyglot-root` / "std-tableau.jar", libraryDependencies ++= Seq( "org.netbeans.api" % "org-openide-util-lookup" % netbeansApiVersion % "provided", - "net.java.dev.jna" % "jna-platform" % jnaVersion + "net.java.dev.jna" % "jna-platform" % jnaVersion % "provided" ), Compile / packageBin := Def.task { val result = (Compile / packageBin).value diff --git a/distribution/lib/Standard/AWS/0.0.0-dev/package.yaml b/distribution/lib/Standard/AWS/0.0.0-dev/package.yaml index d9ac9519a586..6fd17c0347a3 100644 --- a/distribution/lib/Standard/AWS/0.0.0-dev/package.yaml +++ b/distribution/lib/Standard/AWS/0.0.0-dev/package.yaml @@ -8,3 +8,6 @@ authors: maintainers: - name: Enso Team email: contact@enso.org +requires: + - Standard.Base + - Standard.Database diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Main.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Main.enso index 4dfbac3034a9..4fb82c0d1687 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Main.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Main.enso @@ -170,7 +170,6 @@ export project.Nothing.Nothing export project.Panic.Panic -export project.Polyglot.Java export project.Polyglot.Polyglot export project.Random.Random diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Meta.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Meta.enso index 49d4095ef40c..e2b84eb05976 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Meta.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Meta.enso @@ -13,7 +13,6 @@ import project.Error.Error as Base_Error import project.Errors.Common.Not_Found import project.Function.Function import project.Nothing.Nothing -import project.Polyglot.Java from project.Data.Boolean import Boolean, False, True from project.Runtime.Managed_Resource import Managed_Resource @@ -445,7 +444,7 @@ is_a value typ = @Builtin_Method "Meta.is_a" java_instance_check value typ = val_java = get_polyglot_language value == "java" typ_java = get_polyglot_language typ == "java" - val_java && typ_java && Java.is_instance value typ + val_java && typ_java && typ.class.isInstance value ## PRIVATE ADVANCED diff --git a/distribution/lib/Standard/Base/0.0.0-dev/src/Polyglot.enso b/distribution/lib/Standard/Base/0.0.0-dev/src/Polyglot.enso index 55f4684c7bd8..0fb2d57240e0 100644 --- a/distribution/lib/Standard/Base/0.0.0-dev/src/Polyglot.enso +++ b/distribution/lib/Standard/Base/0.0.0-dev/src/Polyglot.enso @@ -132,50 +132,3 @@ type Polyglot Returns the executable name of a polyglot object. get_executable_name : Any -> Text get_executable_name value = @Builtin_Method "Polyglot.get_executable_name" - -## Utilities for working with Java polyglot objects. -type Java - ## PRIVATE - ADVANCED - Adds the provided entry to the host class path. - - Arguments: - - path: The java classpath entry to add. - - Use of the actual polyglot imports system should be preferred to use of - this method. - - > Example - Adding Random to the classpath. - - Java.add_to_class_path "java.util.Random" - add_to_class_path : Text -> Nothing - add_to_class_path path = @Builtin_Method "Java.add_to_class_path" - - ## PRIVATE - ADVANCED - Looks up a java symbol on the classpath by name. - - Arguments: - - name: The name of the java symbol to look up. - - Use of the actual polyglot imports system should be preferred to use of - this method. - - > Example - Look up java's Random class. - - Java.lookup_class "java.util.Random" - lookup_class : Text -> Any - lookup_class name = @Builtin_Method "Java.lookup_class" - - ## PRIVATE - Checks whether an object is an instance of a given class. - - Arguments: - - object: The object to check for class membership. - - class: The java class to check for membership in. - is_instance : Any -> Any -> Boolean - is_instance object class = - class_object = class.class - class_object.isInstance object diff --git a/distribution/lib/Standard/Database/0.0.0-dev/package.yaml b/distribution/lib/Standard/Database/0.0.0-dev/package.yaml index d6a92a2b8338..c959d0381154 100644 --- a/distribution/lib/Standard/Database/0.0.0-dev/package.yaml +++ b/distribution/lib/Standard/Database/0.0.0-dev/package.yaml @@ -8,3 +8,6 @@ authors: maintainers: - name: Enso Team email: contact@enso.org +requires: + - Standard.Base + - Standard.Table diff --git a/distribution/lib/Standard/Image/0.0.0-dev/package.yaml b/distribution/lib/Standard/Image/0.0.0-dev/package.yaml index ad9365fc61e5..f21f0a66e737 100644 --- a/distribution/lib/Standard/Image/0.0.0-dev/package.yaml +++ b/distribution/lib/Standard/Image/0.0.0-dev/package.yaml @@ -8,3 +8,5 @@ authors: maintainers: - name: Enso Team email: contact@enso.org +requires: + - Standard.Base diff --git a/distribution/lib/Standard/Microsoft/0.0.0-dev/package.yaml b/distribution/lib/Standard/Microsoft/0.0.0-dev/package.yaml index b5b48b74c9c7..89ba5ede1e86 100644 --- a/distribution/lib/Standard/Microsoft/0.0.0-dev/package.yaml +++ b/distribution/lib/Standard/Microsoft/0.0.0-dev/package.yaml @@ -8,3 +8,6 @@ authors: maintainers: - name: Enso Team email: contact@enso.org +requires: + - Standard.Base + - Standard.Database diff --git a/distribution/lib/Standard/Table/0.0.0-dev/package.yaml b/distribution/lib/Standard/Table/0.0.0-dev/package.yaml index 9fda257cdb0d..88af7cb11961 100644 --- a/distribution/lib/Standard/Table/0.0.0-dev/package.yaml +++ b/distribution/lib/Standard/Table/0.0.0-dev/package.yaml @@ -8,3 +8,5 @@ authors: maintainers: - name: Enso Team email: contact@enso.org +requires: + - Standard.Base diff --git a/distribution/lib/Standard/Tableau/0.0.0-dev/package.yaml b/distribution/lib/Standard/Tableau/0.0.0-dev/package.yaml index d757c865dabe..74483152f96e 100644 --- a/distribution/lib/Standard/Tableau/0.0.0-dev/package.yaml +++ b/distribution/lib/Standard/Tableau/0.0.0-dev/package.yaml @@ -8,3 +8,5 @@ authors: maintainers: - name: Enso Team email: contact@enso.org +requires: + - Standard.Table diff --git a/distribution/lib/Standard/Test/0.0.0-dev/package.yaml b/distribution/lib/Standard/Test/0.0.0-dev/package.yaml index 6aa554fb2bea..0f3233e77da7 100644 --- a/distribution/lib/Standard/Test/0.0.0-dev/package.yaml +++ b/distribution/lib/Standard/Test/0.0.0-dev/package.yaml @@ -8,3 +8,5 @@ authors: maintainers: - name: Enso Team email: contact@enso.org +requires: + - Standard.Base diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/libraries/ComponentGroupsResolverSpec.scala b/engine/language-server/src/test/scala/org/enso/languageserver/libraries/ComponentGroupsResolverSpec.scala index 8466dd4d6184..e0a1be8fdcb1 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/libraries/ComponentGroupsResolverSpec.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/libraries/ComponentGroupsResolverSpec.scala @@ -278,6 +278,7 @@ object ComponentGroupsResolverSpec { license = "", authors = Nil, maintainers = Nil, + requires = List(), edition = None, preferLocalLibraries = true, componentGroups = Some(componentGroups) @@ -296,6 +297,7 @@ object ComponentGroupsResolverSpec { license = "", authors = Nil, maintainers = Nil, + requires = List(), edition = None, preferLocalLibraries = true, componentGroups = None diff --git a/engine/language-server/src/test/scala/org/enso/languageserver/libraries/ComponentGroupsValidatorSpec.scala b/engine/language-server/src/test/scala/org/enso/languageserver/libraries/ComponentGroupsValidatorSpec.scala index 1c3fc19e06e0..69ee367981fb 100644 --- a/engine/language-server/src/test/scala/org/enso/languageserver/libraries/ComponentGroupsValidatorSpec.scala +++ b/engine/language-server/src/test/scala/org/enso/languageserver/libraries/ComponentGroupsValidatorSpec.scala @@ -188,6 +188,7 @@ object ComponentGroupsValidatorSpec { authors = Nil, maintainers = Nil, edition = None, + requires = List(), preferLocalLibraries = true, componentGroups = Some( ComponentGroups( diff --git a/engine/runtime-integration-tests/src/test/scala/org/enso/interpreter/test/semantic/PolyglotTest.scala b/engine/runtime-integration-tests/src/test/scala/org/enso/interpreter/test/semantic/PolyglotTest.scala index c0f8463a0b21..21a5114435c0 100644 --- a/engine/runtime-integration-tests/src/test/scala/org/enso/interpreter/test/semantic/PolyglotTest.scala +++ b/engine/runtime-integration-tests/src/test/scala/org/enso/interpreter/test/semantic/PolyglotTest.scala @@ -17,9 +17,10 @@ class PolyglotTest extends InterpreterTest { val code = """from Standard.Base import all |import Standard.Base.Data.Array.Array + |polyglot java import org.enso.example.TestClass | |main = - | class = Java.lookup_class "org.enso.example.TestClass" + | class = TestClass | method = Polyglot.get_member class "add" | Polyglot.execute method ([1, 2].to_array) |""".stripMargin @@ -60,9 +61,10 @@ class PolyglotTest extends InterpreterTest { "allow instantiating objects and calling methods on them" in { val code = """from Standard.Base import all + |polyglot java import org.enso.example.TestClass | |main = - | class = Java.lookup_class "org.enso.example.TestClass" + | class = TestClass | instance = Polyglot.new class [x -> x * 2] | Polyglot.invoke instance "callFunctionAndIncrement" [10] |""".stripMargin @@ -72,9 +74,10 @@ class PolyglotTest extends InterpreterTest { "allow listing available members of an object" in { val code = """from Standard.Base import all + |polyglot java import org.enso.example.TestClass | |main = - | class = Java.lookup_class "org.enso.example.TestClass" + | class = TestClass | instance = Polyglot.new class [] | members = Polyglot.get_members instance | IO.println members.length diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/java/AddToClassPathNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/java/AddToClassPathNode.java deleted file mode 100644 index 4d757a703502..000000000000 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/java/AddToClassPathNode.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.enso.interpreter.node.expression.builtin.interop.java; - -import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; -import java.io.File; -import org.enso.interpreter.dsl.BuiltinMethod; -import org.enso.interpreter.node.expression.builtin.text.util.ExpectStringNode; -import org.enso.interpreter.runtime.EnsoContext; - -@BuiltinMethod( - type = "Java", - name = "add_to_class_path", - description = "Adds a path to the host class path.", - autoRegister = false) -public abstract class AddToClassPathNode extends Node { - - static AddToClassPathNode build() { - return AddToClassPathNodeGen.create(); - } - - abstract Object execute(Object path); - - @CompilerDirectives.TruffleBoundary - @Specialization - Object doExecute(Object path, @Cached ExpectStringNode expectStringNode) { - var ctx = EnsoContext.get(this); - var file = ctx.getTruffleFile(new File(expectStringNode.execute(path))); - ctx.addToClassPath(file); - return ctx.getBuiltins().nothing(); - } -} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/java/LookupClassNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/java/LookupClassNode.java deleted file mode 100644 index 60e84837fbb4..000000000000 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/interop/java/LookupClassNode.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.enso.interpreter.node.expression.builtin.interop.java; - -import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; -import org.enso.interpreter.dsl.BuiltinMethod; -import org.enso.interpreter.node.expression.builtin.text.util.ExpectStringNode; -import org.enso.interpreter.runtime.EnsoContext; - -@BuiltinMethod( - type = "Java", - name = "lookup_class", - description = "Looks up a Java symbol.", - autoRegister = false) -public abstract class LookupClassNode extends Node { - static LookupClassNode build() { - return LookupClassNodeGen.create(); - } - - @Specialization - @CompilerDirectives.TruffleBoundary - Object doExecute(Object name, @Cached("build()") ExpectStringNode expectStringNode) { - return EnsoContext.get(this).lookupJavaClass(expectStringNode.execute(name)); - } - - abstract Object execute(Object name); -} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/EnsoClassPath.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/EnsoClassPath.java new file mode 100644 index 000000000000..2d249e3401e8 --- /dev/null +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/EnsoClassPath.java @@ -0,0 +1,138 @@ +package org.enso.interpreter.runtime; + +import com.oracle.truffle.api.TruffleLogger; +import java.lang.module.Configuration; +import java.lang.module.FindException; +import java.lang.module.ModuleFinder; +import java.lang.module.ResolutionException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.logging.Level; + +/** Representation of an Enso library class path. */ +public final class EnsoClassPath { + static final EnsoClassPath EMPTY = new EnsoClassPath("empty", null, null, null); + private final Object id; + private final ModuleLayer.Controller cntrl; + private final ModuleLayer layer; + final ClassLoader loader; + + private EnsoClassPath( + Object id, ModuleLayer.Controller cntrl, ModuleLayer layer, ClassLoader loader) { + this.id = id; + if (cntrl != null) { + // cannot be null + layer.getClass(); + } + this.cntrl = cntrl; + this.layer = layer; + this.loader = loader; + } + + private static ModuleLayer bootLayer() { + var myLayer = EnsoClassPath.class.getModule().getLayer(); + if (myLayer != null) { + return myLayer; + } else { + return ModuleLayer.boot(); + } + } + + static EnsoClassPath create(Path file, List parents, TruffleLogger log) { + try { + return createImpl(file, parents); + } catch (FindException | ResolutionException e) { + var sb = new StringBuilder(); + sb.append("Cannot instantiate modules at ").append(file); + log.log(Level.FINE, sb.toString(), e); + for (var cp : parents) { + sb.append("\n with parent ").append(cp); + } + e.setStackTrace( + Arrays.asList(e.getStackTrace()).stream().limit(10).toArray(StackTraceElement[]::new)); + log.log(Level.SEVERE, sb.toString(), e); + return EnsoClassPath.EMPTY; + } + } + + private static EnsoClassPath createImpl(Path file, List parents) { + var locations = new ArrayList(); + var moduleNames = new ArrayList(); + MODULE_LOOP: + for (var mod : ModuleFinder.of(file).findAll()) { + if (bootLayer().findModule(mod.descriptor().name()).isPresent()) { + continue; + } + for (var p : parents) { + if (p.layer != null && p.layer.findModule(mod.descriptor().name()).isPresent()) { + continue MODULE_LOOP; + } + } + moduleNames.add(mod.descriptor().name()); + var uri = mod.location().get(); + locations.add(Path.of(uri)); + } + if (moduleNames.isEmpty() && parents.isEmpty()) { + return EMPTY; + } else { + var finder = ModuleFinder.of(locations.toArray(new Path[0])); + ModuleLayer.Controller cntrl; + if (parents.isEmpty()) { + var parent = bootLayer(); + var parentLoader = parent.findLoader("java.base"); + var parentCfgs = Collections.singletonList(parent.configuration()); + var parentModules = Collections.singletonList(parent); + var cfg = + Configuration.resolveAndBind(finder, parentCfgs, ModuleFinder.ofSystem(), moduleNames); + cntrl = ModuleLayer.defineModulesWithOneLoader(cfg, parentModules, parentLoader); + } else { + var parentCfgs = new ArrayList(); + var parentLayers = new ArrayList(); + for (var cp : parents) { + if (cp.layer == null) { + continue; + } + parentLayers.add(cp.layer); + parentCfgs.add(cp.layer.configuration()); + } + if (parentLayers.isEmpty()) { + parentLayers.add(ModuleLayer.boot()); + parentCfgs.add(ModuleLayer.boot().configuration()); + } + var parentLoader = bootLayer().findLoader("java.base"); + var cfg = + Configuration.resolveAndBind(finder, parentCfgs, ModuleFinder.ofSystem(), moduleNames); + cntrl = ModuleLayer.defineModulesWithOneLoader(cfg, parentLayers, parentLoader); + } + var layer = cntrl.layer(); + var loader = + !moduleNames.isEmpty() ? layer.findLoader(moduleNames.get(0)) : parents.get(0).loader; + + registerLayer(layer); + return new EnsoClassPath(file, cntrl, layer, loader); + } + } + + @SuppressWarnings("unchecked") + private static void registerLayer(ModuleLayer moduleLayer) { + var props = System.getProperties(); + Collection layers; + if (props.get("enso.class.path") instanceof Collection registeredLayers) { + layers = registeredLayers; + } else { + layers = new LinkedHashSet<>(); + props.put("enso.class.path", layers); + } + layers.add(moduleLayer); + } + + @Override + public String toString() { + return "EnsoClassPath[id=" + id + "]"; + } +} diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/EnsoContext.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/EnsoContext.java index 531a116cc317..7e4f93dca6dd 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/EnsoContext.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/EnsoContext.java @@ -26,11 +26,13 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintStream; -import java.net.MalformedURLException; import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.UUID; @@ -69,6 +71,7 @@ import org.enso.pkg.QualifiedName; import org.enso.polyglot.debugger.IdExecutionService; import org.graalvm.options.OptionKey; +import scala.jdk.javaapi.CollectionConverters; import scala.jdk.javaapi.OptionConverters; /** @@ -82,7 +85,7 @@ public final class EnsoContext { private final EnsoLanguage language; private final Env environment; - private final HostClassLoader hostClassLoader = new HostClassLoader(); + private final Map, EnsoClassPath> classPaths = new HashMap<>(); private final boolean assertionsEnabled; private final boolean isPrivateCheckDisabled; private final boolean isStaticTypeAnalysisEnabled; @@ -297,7 +300,6 @@ public void shutdown() { packageRepository.shutdown(); guestJava = null; topScope = null; - hostClassLoader.close(); EnsoParser.freeAll(); } @@ -463,30 +465,44 @@ public Optional findModuleByExpressionId(UUID expressionId) { } /** - * Modifies the classpath to use to lookup {@code polyglot java} imports. + * Creates a class path. A class path is capable to load Java classes in an isolated manner. * - * @param file the file to register + * @param pkg package to find class path for + * @return representation of an Enso library Java class path for given package */ @TruffleBoundary - public void addToClassPath(TruffleFile file) { - if (findGuestJava() == null) { - try { - var url = file.toUri().toURL(); - hostClassLoader.add(url); - } catch (MalformedURLException ex) { - throw new IllegalStateException(ex); - } - } else { - try { - var path = new File(file.toUri()).getAbsoluteFile(); - if (!path.exists()) { - throw new IllegalStateException("File not found " + path); + public synchronized EnsoClassPath findClassPath(Package pkg) { + org.enso.interpreter.runtime.EnsoClassPath l = classPaths.get(pkg); + if (l == null) { + if (pkg != null) { + var polyDir = pkg.polyglotDir(); + if (polyDir == null) { + throw new NullPointerException("No polyglot dir for " + pkg); } - InteropLibrary.getUncached().invokeMember(findGuestJava(), "addPath", path.getPath()); - } catch (InteropException ex) { - throw new IllegalStateException(ex); + var ch = polyDir.resolve("java"); + var requires = CollectionConverters.asJava(pkg.getConfig().requires()); + var parents = + requires.stream() + .map( + n -> { + var name = LibraryName.fromModuleName(n); + if (name.isDefined()) { + var ln = name.get(); + var lib = this.packageRepository.getPackageForLibrary(ln); + if (lib.isDefined()) { + return findClassPath(lib.get()); + } + } + return findClassPath(null); + }) + .toList(); + l = EnsoClassPath.create(Paths.get(ch.toUri()), parents, logger); + } else { + l = EnsoClassPath.EMPTY; } + classPaths.put(pkg, l); } + return l; } /** @@ -557,19 +573,24 @@ public boolean isColorTerminalOutput() { * resolves to an inner class, then the import of the outer class is resolved, and the inner class * is looked up by iterating the members of the outer class via Truffle's interop protocol. * + * @param pkg Enso package to load the class for * @param className Fully qualified class name, can also be nested static inner class. * @return If the java class is found, return it, otherwise return {@link DataflowError}. */ @TruffleBoundary - public TruffleObject lookupJavaClass(String className) { - var binaryName = new StringBuilder(className); + public TruffleObject lookupJavaClass(Package pkg, String className) { + org.enso.interpreter.runtime.EnsoClassPath cp = findClassPath(pkg); + if (className == null) { + return null; + } var collectedExceptions = new ArrayList(); + var binaryName = new StringBuilder(className); for (; ; ) { var fqn = binaryName.toString(); try { - var hostSymbol = lookupHostSymbol(fqn); - if (hostSymbol != null) { - return (TruffleObject) hostSymbol; + var hostSymbol = lookupHostSymbol(cp.loader, fqn); + if (hostSymbol instanceof TruffleObject truffleSymbol) { + return truffleSymbol; } } catch (ClassNotFoundException | RuntimeException | InteropException ex) { collectedExceptions.add(ex); @@ -589,11 +610,17 @@ public TruffleObject lookupJavaClass(String className) { return getBuiltins().error().makeMissingPolyglotImportError(className); } - private Object lookupHostSymbol(String fqn) + private Object lookupHostSymbol(ClassLoader loader, String fqn) throws ClassNotFoundException, UnknownIdentifierException, UnsupportedMessageException { try { if (findGuestJava() == null) { - return environment.asHostSymbol(hostClassLoader.loadClass(fqn)); + Class clazz; + if (loader == null) { + clazz = Class.forName(fqn); + } else { + clazz = loader.loadClass(fqn); + } + return environment.asHostSymbol(clazz); } else { return InteropLibrary.getUncached().readMember(findGuestJava(), fqn); } diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/TruffleCompilerContext.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/TruffleCompilerContext.java index cfed0237247f..160cc7231bc4 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/TruffleCompilerContext.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/TruffleCompilerContext.java @@ -147,7 +147,8 @@ public void truffleRunCodegen( var s = org.enso.interpreter.runtime.scope.ModuleScope.Builder.fromCompilerModuleScopeBuilder( scopeBuilder); - new IrToTruffle(context, m.getSource(), s, config).run(module.getIr()); + var pkg = ((Module) module).getPackage(); + new IrToTruffle(context, m.getSource(), s, config).run(pkg, module.getIr()); } // module related diff --git a/engine/runtime/src/main/scala/org/enso/interpreter/runtime/DefaultPackageRepository.scala b/engine/runtime/src/main/scala/org/enso/interpreter/runtime/DefaultPackageRepository.scala index 3723cab9b1ae..a4e2507bbc1f 100644 --- a/engine/runtime/src/main/scala/org/enso/interpreter/runtime/DefaultPackageRepository.scala +++ b/engine/runtime/src/main/scala/org/enso/interpreter/runtime/DefaultPackageRepository.scala @@ -196,9 +196,6 @@ private class DefaultPackageRepository( pkg: Package[TruffleFile], isLibrary: Boolean ): Unit = { - val extensions = pkg.listPolyglotExtensions("java") - extensions.foreach(context.addToClassPath) - val (regularModules, syntheticModulesMetadata) = pkg .listSources() .map(srcFile => diff --git a/engine/runtime/src/main/scala/org/enso/interpreter/runtime/IrToTruffle.scala b/engine/runtime/src/main/scala/org/enso/interpreter/runtime/IrToTruffle.scala index d071f6e07c94..569d62d0bc22 100644 --- a/engine/runtime/src/main/scala/org/enso/interpreter/runtime/IrToTruffle.scala +++ b/engine/runtime/src/main/scala/org/enso/interpreter/runtime/IrToTruffle.scala @@ -1,5 +1,6 @@ package org.enso.interpreter.runtime +import com.oracle.truffle.api.TruffleFile import java.util.logging.Level import com.oracle.truffle.api.source.{Source, SourceSection} import com.oracle.truffle.api.interop.InteropLibrary @@ -151,7 +152,8 @@ class IrToTruffle( * * @param ir the IR to generate code for */ - def run(ir: Module): Unit = processModule(ir) + def run(p: org.enso.pkg.Package[TruffleFile], ir: Module): Unit = + processModule(p, ir) /** Executes the codegen pass on an inline input. * @@ -184,7 +186,10 @@ class IrToTruffle( * * @param module the module for which code should be generated */ - private def processModule(module: Module): Unit = { + private def processModule( + p: org.enso.pkg.Package[TruffleFile], + module: Module + ): Unit = { generateReExportBindings(module) val bindingsMap = module @@ -195,7 +200,7 @@ class IrToTruffle( registerModuleExports(bindingsMap) registerModuleImports(bindingsMap) - registerPolyglotImports(module) + registerPolyglotImports(p, module) registerTypeDefinitions(module) registerMethodDefinitions(module) @@ -230,16 +235,21 @@ class IrToTruffle( } } - private def registerPolyglotImports(module: Module): Unit = + private def registerPolyglotImports( + p: org.enso.pkg.Package[TruffleFile], + module: Module + ): Unit = module.imports.foreach { - case poly @ imports.Polyglot(i: imports.Polyglot.Java, _, _, _) => + case poly @ imports.Polyglot(i: imports.Polyglot.Java, _, _, _) => { + context.lookupJavaClass(p, null) this.scopeBuilder.registerPolyglotSymbol( poly.getVisibleName, () => { - val hostSymbol = context.lookupJavaClass(i.getJavaName) + val hostSymbol = context.lookupJavaClass(p, i.getJavaName) hostSymbol } ) + } case _: Import.Module => case _: Error => } diff --git a/lib/java/aws-wrapper/src/main/java/module-info.java b/lib/java/aws-wrapper/src/main/java/module-info.java new file mode 100644 index 000000000000..5b3382a370ec --- /dev/null +++ b/lib/java/aws-wrapper/src/main/java/module-info.java @@ -0,0 +1,25 @@ +module org.enso.aws.wrapper { + // Class software.amazon.awssdk.protocols.query.unmarshall.XmlDomParser acesses javax.xml.stream.XMLInputFactory + requires java.xml; + requires org.slf4j; + requires org.reactivestreams; // Automatic module + requires org.apache.httpcomponents.httpcore; // Automatic module + requires org.apache.httpcomponents.httpclient; // Automatic module + requires commons.logging; // Automatic module (with derived name) + + exports software.amazon.awssdk.auth.credentials; + exports software.amazon.awssdk.core; + exports software.amazon.awssdk.core.exception; + exports software.amazon.awssdk.core.sync; + exports software.amazon.awssdk.awscore.exception; + exports software.amazon.awssdk.http; + exports software.amazon.awssdk.services.s3; + exports software.amazon.awssdk.services.s3.model; + exports software.amazon.awssdk.profiles; + exports software.amazon.awssdk.regions; + exports software.amazon.awssdk.regions.providers; + + uses software.amazon.awssdk.http.SdkHttpService; + provides software.amazon.awssdk.http.SdkHttpService with + software.amazon.awssdk.http.apache.ApacheSdkHttpService; +} diff --git a/lib/scala/pkg/src/main/scala/org/enso/pkg/Config.scala b/lib/scala/pkg/src/main/scala/org/enso/pkg/Config.scala index 46435a9b6544..ab3f4e5c920d 100644 --- a/lib/scala/pkg/src/main/scala/org/enso/pkg/Config.scala +++ b/lib/scala/pkg/src/main/scala/org/enso/pkg/Config.scala @@ -109,7 +109,8 @@ case class Config( maintainers: List[Contact], edition: Option[Editions.RawEdition], preferLocalLibraries: Boolean, - componentGroups: Option[ComponentGroups] + componentGroups: Option[ComponentGroups], + requires: List[String] ) { /** Converts the configuration into a YAML representation. */ @@ -144,6 +145,7 @@ object Config { val Author: String = "authors" val Namespace: String = "namespace" val Maintainer: String = "maintainers" + val Requires: String = "requires" val Edition: String = "edition" val PreferLocalLibraries = "prefer-local-libraries" val ComponentGroups = "component-groups" @@ -158,6 +160,7 @@ object Config { val normalizedNameDecoder = implicitly[YamlDecoder[Option[String]]] val contactDecoder = implicitly[YamlDecoder[List[Contact]]] + val requiresDecoder = implicitly[YamlDecoder[List[String]]] val editionNameDecoder = implicitly[YamlDecoder[EditionName]] val editionDecoder = implicitly[YamlDecoder[Option[Editions.RawEdition]]] @@ -195,6 +198,10 @@ object Config { .get(JsonFields.Maintainer) .map(contactDecoder.decode) .getOrElse(Right(Nil)) + requires <- clazzMap + .get(JsonFields.Requires) + .map(requiresDecoder.decode) + .getOrElse(Right(Nil)) rawEdition = clazzMap .get(JsonFields.Edition) .flatMap(x => editionNameDecoder.decode(x).toOption.map(Left(_))) @@ -230,7 +237,8 @@ object Config { maintainers, edition, preferLocalLibraries, - componentGroups + componentGroups, + requires ) } } @@ -239,6 +247,7 @@ object Config { new YamlEncoder[Config] { override def encode(value: Config) = { val contactsEncoder = implicitly[YamlEncoder[List[Contact]]] + val requiresEncoder = implicitly[YamlEncoder[List[String]]] val editionEncoder = implicitly[YamlEncoder[Editions.RawEdition]] val booleanEncoder = implicitly[YamlEncoder[Boolean]] val componentGroupsEncoder = @@ -268,6 +277,11 @@ object Config { (JsonFields.Maintainer, contactsEncoder.encode(value.maintainers)) ) } + if (value.requires.nonEmpty) { + elements.add( + (JsonFields.Requires, requiresEncoder.encode(value.requires.toList)) + ) + } value.edition.foreach { edition => if (edition.isDerivingWithoutOverrides) diff --git a/lib/scala/pkg/src/main/scala/org/enso/pkg/Package.scala b/lib/scala/pkg/src/main/scala/org/enso/pkg/Package.scala index 32279c2764b0..8ab548150b92 100644 --- a/lib/scala/pkg/src/main/scala/org/enso/pkg/Package.scala +++ b/lib/scala/pkg/src/main/scala/org/enso/pkg/Package.scala @@ -300,7 +300,8 @@ class PackageManager[F](implicit val fileSystem: FileSystem[F]) { edition = edition, preferLocalLibraries = true, maintainers = maintainers, - componentGroups = componentGroups + componentGroups = componentGroups, + requires = List() ) create(root, config, template) } diff --git a/lib/scala/pkg/src/test/scala/org/enso/pkg/ConfigSpec.scala b/lib/scala/pkg/src/test/scala/org/enso/pkg/ConfigSpec.scala index d813d7fc0912..8722d3842060 100644 --- a/lib/scala/pkg/src/test/scala/org/enso/pkg/ConfigSpec.scala +++ b/lib/scala/pkg/src/test/scala/org/enso/pkg/ConfigSpec.scala @@ -32,7 +32,8 @@ class ConfigSpec Contact(None, Some("c@example.com")) ), preferLocalLibraries = true, - componentGroups = None + componentGroups = None, + requires = List() ) val deserialized = Config.fromYaml(config.toYaml).get deserialized shouldEqual config diff --git a/project/JPMSUtils.scala b/project/JPMSUtils.scala index 59e483f957bb..5128d683c0e3 100644 --- a/project/JPMSUtils.scala +++ b/project/JPMSUtils.scala @@ -43,8 +43,11 @@ object JPMSUtils { val distinctModules = modules.distinct val ret = cp.filter(dep => { - val moduleID = dep.metadata.get(AttributeKey[ModuleID]("moduleID")).get - shouldFilterModule(distinctModules, scalaBinaryVersion)(moduleID) + dep.metadata.get(AttributeKey[ModuleID]("moduleID")) match { + case Some(moduleID) => + shouldFilterModule(distinctModules, scalaBinaryVersion)(moduleID) + case None => false + } }) if (shouldContainAll) { diff --git a/std-bits/aws/src/main/java/module-info.java b/std-bits/aws/src/main/java/module-info.java new file mode 100644 index 000000000000..0881f23a454a --- /dev/null +++ b/std-bits/aws/src/main/java/module-info.java @@ -0,0 +1,23 @@ +import org.enso.aws.database.RedshiftConnectionDetailsSPI; +import org.enso.aws.file_system.S3FileSystemSPI; +import org.enso.base.enso_cloud.DataLinkSPI; +import org.enso.base.file_system.FileSystemSPI; +import org.enso.database.DatabaseConnectionDetailsSPI; + +module org.enso.std.aws { + requires java.base; + requires org.enso.std.base; + requires org.enso.std.database; + requires java.logging; + requires org.enso.aws.wrapper; + requires java.net.http; + + exports org.enso.aws; + + provides FileSystemSPI with + S3FileSystemSPI; + provides DataLinkSPI with + org.enso.aws.file_system.S3DataLinkSPI; + provides DatabaseConnectionDetailsSPI with + RedshiftConnectionDetailsSPI; +} diff --git a/std-bits/aws/src/main/java/org/enso/aws/database/RedshiftConnectionDetailsSPI.java b/std-bits/aws/src/main/java/org/enso/aws/database/RedshiftConnectionDetailsSPI.java index e3c25b498324..39a9718411bd 100644 --- a/std-bits/aws/src/main/java/org/enso/aws/database/RedshiftConnectionDetailsSPI.java +++ b/std-bits/aws/src/main/java/org/enso/aws/database/RedshiftConnectionDetailsSPI.java @@ -2,8 +2,7 @@ import org.enso.database.DatabaseConnectionDetailsSPI; -@org.openide.util.lookup.ServiceProvider(service = DatabaseConnectionDetailsSPI.class) -public class RedshiftConnectionDetailsSPI extends DatabaseConnectionDetailsSPI { +public final class RedshiftConnectionDetailsSPI extends DatabaseConnectionDetailsSPI { @Override protected String getModuleName() { return "Standard.AWS.Database.Redshift.Redshift_Details"; diff --git a/std-bits/aws/src/main/java/org/enso/aws/file_system/S3DataLinkSPI.java b/std-bits/aws/src/main/java/org/enso/aws/file_system/S3DataLinkSPI.java index 0f6692e93421..de9af591d790 100644 --- a/std-bits/aws/src/main/java/org/enso/aws/file_system/S3DataLinkSPI.java +++ b/std-bits/aws/src/main/java/org/enso/aws/file_system/S3DataLinkSPI.java @@ -2,8 +2,7 @@ import org.enso.base.enso_cloud.DataLinkSPI; -@org.openide.util.lookup.ServiceProvider(service = DataLinkSPI.class) -public class S3DataLinkSPI extends DataLinkSPI { +public final class S3DataLinkSPI extends DataLinkSPI { @Override protected String getModuleName() { return "Standard.AWS.S3.S3_Data_Link"; diff --git a/std-bits/aws/src/main/java/org/enso/aws/file_system/S3FileSystemSPI.java b/std-bits/aws/src/main/java/org/enso/aws/file_system/S3FileSystemSPI.java index 360c4cfb2f70..c448ab2f158b 100644 --- a/std-bits/aws/src/main/java/org/enso/aws/file_system/S3FileSystemSPI.java +++ b/std-bits/aws/src/main/java/org/enso/aws/file_system/S3FileSystemSPI.java @@ -2,7 +2,6 @@ import org.enso.base.file_system.FileSystemSPI; -@org.openide.util.lookup.ServiceProvider(service = FileSystemSPI.class) public class S3FileSystemSPI extends FileSystemSPI { @Override protected String getModuleName() { diff --git a/std-bits/base/src/main/java/module-info.java b/std-bits/base/src/main/java/module-info.java new file mode 100644 index 000000000000..b9283a26e08e --- /dev/null +++ b/std-bits/base/src/main/java/module-info.java @@ -0,0 +1,71 @@ +import org.enso.base.enso_cloud.DataLinkSPI; +import org.enso.base.enso_cloud.EnsoFileDataLinkSPI; +import org.enso.base.enso_cloud.EnsoPathFileSystemSPI; +import org.enso.base.file_format.ByteFormatSPI; +import org.enso.base.file_format.FileFormatSPI; +import org.enso.base.file_format.JSONFormatSPI; +import org.enso.base.file_format.TextFormatSPI; +import org.enso.base.file_format.XMLFormatSPI; +import org.enso.base.file_system.FileSystemSPI; +import org.enso.base.net.http.HTTPFetchDataLinkSPI; +import org.enso.base.read.BaseReadManyReturnSPI; +import org.enso.base.read.ReadManyReturnSPI; + +module org.enso.std.base { + requires java.logging; + requires java.xml; + requires java.net.http; + requires java.sql; + requires org.graalvm.collections; + requires com.ibm.icu; + requires org.graalvm.polyglot; + requires com.fasterxml.jackson.databind; + requires org.enso.common.polyglot.core.utils; + + uses FileSystemSPI; + uses FileFormatSPI; + uses DataLinkSPI; + uses ReadManyReturnSPI; + + // following packages are accessed by Java code in other Enso modules + exports org.enso.base; + exports org.enso.base.file_system; + exports org.enso.base.file_format; + exports org.enso.base.enso_cloud; + exports org.enso.base.enso_cloud.audit; + exports org.enso.base.lookup; + exports org.enso.base.numeric; + exports org.enso.base.parser; + exports org.enso.base.polyglot; + exports org.enso.base.time; + exports org.enso.base.text; + exports org.enso.base.arrays; + exports org.enso.base.statistics; + + // following packages are accessed by Enso via polyglot java import + opens org.enso.base; + opens org.enso.base.arrays; + + exports org.enso.base.encoding; + + opens org.enso.base.numeric; + opens org.enso.base.net; + opens org.enso.base.net.http; + opens org.enso.base.polyglot; + opens org.enso.base.random; + opens org.enso.base.statistics; + opens org.enso.base.text; + + provides FileSystemSPI with + EnsoPathFileSystemSPI; + provides FileFormatSPI with + ByteFormatSPI, + JSONFormatSPI, + TextFormatSPI, + XMLFormatSPI; + provides DataLinkSPI with + EnsoFileDataLinkSPI, + HTTPFetchDataLinkSPI; + provides ReadManyReturnSPI with + BaseReadManyReturnSPI; +} diff --git a/std-bits/base/src/main/java/org/enso/base/Environment_Utils.java b/std-bits/base/src/main/java/org/enso/base/Environment_Utils.java index 8e90645c0e9f..80bce96f90a1 100644 --- a/std-bits/base/src/main/java/org/enso/base/Environment_Utils.java +++ b/std-bits/base/src/main/java/org/enso/base/Environment_Utils.java @@ -2,7 +2,9 @@ import java.util.HashMap; -public class Environment_Utils { +public final class Environment_Utils { + private Environment_Utils() {} + /** Gets the environment variable, including any overrides. */ public static String get_environment_variable(String name) { String override = overrides.get(name); diff --git a/std-bits/base/src/main/java/org/enso/base/enso_cloud/DataLinkSPI.java b/std-bits/base/src/main/java/org/enso/base/enso_cloud/DataLinkSPI.java index 84cbe3cf341b..4ec005335e92 100644 --- a/std-bits/base/src/main/java/org/enso/base/enso_cloud/DataLinkSPI.java +++ b/std-bits/base/src/main/java/org/enso/base/enso_cloud/DataLinkSPI.java @@ -2,6 +2,7 @@ import java.util.ServiceLoader; import java.util.stream.Collectors; +import org.enso.base.lookup.Lookup; import org.enso.base.polyglot.EnsoMeta; import org.graalvm.polyglot.Value; @@ -11,8 +12,8 @@ * type should return a configured datalink instance that can later be `read`. */ public abstract class DataLinkSPI { - private static final ServiceLoader loader = - ServiceLoader.load(DataLinkSPI.class, DataLinkSPI.class.getClassLoader()); + private static final Lookup loader = + Lookup.lookup((layer) -> ServiceLoader.load(layer, DataLinkSPI.class)); public void reload() { loader.reload(); diff --git a/std-bits/base/src/main/java/org/enso/base/enso_cloud/EnsoFileDataLinkSPI.java b/std-bits/base/src/main/java/org/enso/base/enso_cloud/EnsoFileDataLinkSPI.java index 6e496d4c61fb..4841d839ec21 100644 --- a/std-bits/base/src/main/java/org/enso/base/enso_cloud/EnsoFileDataLinkSPI.java +++ b/std-bits/base/src/main/java/org/enso/base/enso_cloud/EnsoFileDataLinkSPI.java @@ -1,7 +1,6 @@ package org.enso.base.enso_cloud; -@org.openide.util.lookup.ServiceProvider(service = DataLinkSPI.class) -public class EnsoFileDataLinkSPI extends DataLinkSPI { +public final class EnsoFileDataLinkSPI extends DataLinkSPI { @Override protected String getModuleName() { return "Standard.Base.Enso_Cloud.Internal.Enso_File_Data_Link"; diff --git a/std-bits/base/src/main/java/org/enso/base/enso_cloud/EnsoPathFileSystemSPI.java b/std-bits/base/src/main/java/org/enso/base/enso_cloud/EnsoPathFileSystemSPI.java index 2008cb61a9d5..aa325acfb39f 100644 --- a/std-bits/base/src/main/java/org/enso/base/enso_cloud/EnsoPathFileSystemSPI.java +++ b/std-bits/base/src/main/java/org/enso/base/enso_cloud/EnsoPathFileSystemSPI.java @@ -7,7 +7,6 @@ * *

See `Enso_File.new` for more information on path resolution. */ -@org.openide.util.lookup.ServiceProvider(service = FileSystemSPI.class) public class EnsoPathFileSystemSPI extends FileSystemSPI { @Override protected String getModuleName() { diff --git a/std-bits/base/src/main/java/org/enso/base/enso_cloud/EnsoSecretHelper.java b/std-bits/base/src/main/java/org/enso/base/enso_cloud/EnsoSecretHelper.java index 9859ab54cc7e..b491eb378bdb 100644 --- a/std-bits/base/src/main/java/org/enso/base/enso_cloud/EnsoSecretHelper.java +++ b/std-bits/base/src/main/java/org/enso/base/enso_cloud/EnsoSecretHelper.java @@ -8,7 +8,7 @@ import java.net.http.HttpRequest.Builder; import java.net.http.HttpResponse; import java.sql.Connection; -import java.sql.DriverManager; +import java.sql.Driver; import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; @@ -26,13 +26,23 @@ public final class EnsoSecretHelper extends SecretValueResolver { /** Gets a JDBC connection resolving EnsoKeyValuePair into the properties. */ public static Connection getJDBCConnection( - String url, List> properties) throws SQLException { + Iterable drivers, String url, List> properties) + throws SQLException { var javaProperties = new Properties(); for (var pair : properties) { javaProperties.setProperty(pair.getLeft(), resolveValue(pair.getRight())); } - return DriverManager.getConnection(url, javaProperties); + var err = new StringBuilder(); + for (var driver : drivers) { + err.append("\nTrying ").append(driver.getClass().getName()); + var c = driver.connect(url, javaProperties); + if (c != null) { + return c; + } + } + err.insert(0, "No handler to connect to " + url); + throw new SQLException(err.toString()); } /** diff --git a/std-bits/base/src/main/java/org/enso/base/file_format/ByteFormatSPI.java b/std-bits/base/src/main/java/org/enso/base/file_format/ByteFormatSPI.java index 35df9626cab6..fccd140ff7e9 100644 --- a/std-bits/base/src/main/java/org/enso/base/file_format/ByteFormatSPI.java +++ b/std-bits/base/src/main/java/org/enso/base/file_format/ByteFormatSPI.java @@ -1,7 +1,6 @@ package org.enso.base.file_format; -@org.openide.util.lookup.ServiceProvider(service = FileFormatSPI.class) -public class ByteFormatSPI extends FileFormatSPI { +public final class ByteFormatSPI extends FileFormatSPI { @Override protected String getModuleName() { return "Standard.Base.System.File_Format"; diff --git a/std-bits/base/src/main/java/org/enso/base/file_format/FileFormatSPI.java b/std-bits/base/src/main/java/org/enso/base/file_format/FileFormatSPI.java index e3a3fb867775..a1b19bfc0013 100644 --- a/std-bits/base/src/main/java/org/enso/base/file_format/FileFormatSPI.java +++ b/std-bits/base/src/main/java/org/enso/base/file_format/FileFormatSPI.java @@ -1,14 +1,16 @@ package org.enso.base.file_format; +import java.util.ArrayList; import java.util.Objects; import java.util.ServiceLoader; import java.util.stream.Collectors; +import org.enso.base.lookup.Lookup; import org.enso.base.polyglot.EnsoMeta; import org.graalvm.polyglot.Value; public abstract class FileFormatSPI { - private static final ServiceLoader loader = - ServiceLoader.load(FileFormatSPI.class, FileFormatSPI.class.getClassLoader()); + private static final Lookup loader = + Lookup.lookup((l) -> ServiceLoader.load(l, FileFormatSPI.class)); public static Value[] get_types(boolean refresh) { if (refresh) { @@ -20,19 +22,19 @@ public static Value[] get_types(boolean refresh) { public static Value findFormatForDataLinkSubType(String subType) { Objects.requireNonNull(subType, "subType must not be null/Nothing."); - var providers = - loader.stream() - .filter(provider -> subType.equalsIgnoreCase(provider.get().getDataLinkFormatName())) - .toList(); + var providers = new ArrayList(); + for (var s : loader) { + if (subType.equalsIgnoreCase(s.getDataLinkFormatName())) { + providers.add(s); + } + } if (providers.isEmpty()) { return null; } if (providers.size() > 1) { var modules = - providers.stream() - .map(provider -> provider.get().getModuleName()) - .collect(Collectors.joining(", ")); + providers.stream().map(s -> s.getModuleName()).collect(Collectors.joining(", ")); throw new IllegalStateException( "Error: Multiple Format providers found for format: " + subType @@ -41,7 +43,7 @@ public static Value findFormatForDataLinkSubType(String subType) { + "."); } - return providers.get(0).get().getTypeObject(); + return providers.get(0).getTypeObject(); } public Value getTypeObject() { diff --git a/std-bits/base/src/main/java/org/enso/base/file_format/JSONFormatSPI.java b/std-bits/base/src/main/java/org/enso/base/file_format/JSONFormatSPI.java index 575e6d4bc23f..d1a88c0b852d 100644 --- a/std-bits/base/src/main/java/org/enso/base/file_format/JSONFormatSPI.java +++ b/std-bits/base/src/main/java/org/enso/base/file_format/JSONFormatSPI.java @@ -1,7 +1,6 @@ package org.enso.base.file_format; -@org.openide.util.lookup.ServiceProvider(service = FileFormatSPI.class) -public class JSONFormatSPI extends FileFormatSPI { +public final class JSONFormatSPI extends FileFormatSPI { @Override protected String getModuleName() { return "Standard.Base.System.File_Format"; diff --git a/std-bits/base/src/main/java/org/enso/base/file_format/TextFormatSPI.java b/std-bits/base/src/main/java/org/enso/base/file_format/TextFormatSPI.java index 2ee2ce353b9a..6e92b4ac8653 100644 --- a/std-bits/base/src/main/java/org/enso/base/file_format/TextFormatSPI.java +++ b/std-bits/base/src/main/java/org/enso/base/file_format/TextFormatSPI.java @@ -1,7 +1,6 @@ package org.enso.base.file_format; -@org.openide.util.lookup.ServiceProvider(service = FileFormatSPI.class) -public class TextFormatSPI extends FileFormatSPI { +public final class TextFormatSPI extends FileFormatSPI { @Override protected String getModuleName() { return "Standard.Base.System.File_Format"; diff --git a/std-bits/base/src/main/java/org/enso/base/file_format/XMLFormatSPI.java b/std-bits/base/src/main/java/org/enso/base/file_format/XMLFormatSPI.java index a1ff39077660..8a2abaa95ef9 100644 --- a/std-bits/base/src/main/java/org/enso/base/file_format/XMLFormatSPI.java +++ b/std-bits/base/src/main/java/org/enso/base/file_format/XMLFormatSPI.java @@ -1,7 +1,6 @@ package org.enso.base.file_format; -@org.openide.util.lookup.ServiceProvider(service = FileFormatSPI.class) -public class XMLFormatSPI extends FileFormatSPI { +public final class XMLFormatSPI extends FileFormatSPI { @Override protected String getModuleName() { return "Standard.Base.Data.XML.XML_Format"; diff --git a/std-bits/base/src/main/java/org/enso/base/file_system/FileSystemSPI.java b/std-bits/base/src/main/java/org/enso/base/file_system/FileSystemSPI.java index 78ba411c31d9..0017d1d42b40 100644 --- a/std-bits/base/src/main/java/org/enso/base/file_system/FileSystemSPI.java +++ b/std-bits/base/src/main/java/org/enso/base/file_system/FileSystemSPI.java @@ -1,14 +1,13 @@ package org.enso.base.file_system; import java.util.ServiceLoader; +import org.enso.base.lookup.Lookup; import org.enso.base.polyglot.EnsoMeta; import org.graalvm.polyglot.Value; public abstract class FileSystemSPI { - private static final ServiceLoader loader = - ServiceLoader.load( - org.enso.base.file_system.FileSystemSPI.class, - org.enso.base.file_format.FileFormatSPI.class.getClassLoader()); + private static final Lookup loader = + Lookup.lookup((l) -> ServiceLoader.load(l, org.enso.base.file_system.FileSystemSPI.class)); public static Value get_type(String protocol, boolean refresh) { if (refresh) { diff --git a/std-bits/base/src/main/java/org/enso/base/lookup/Lookup.java b/std-bits/base/src/main/java/org/enso/base/lookup/Lookup.java new file mode 100644 index 000000000000..439bf03f22bb --- /dev/null +++ b/std-bits/base/src/main/java/org/enso/base/lookup/Lookup.java @@ -0,0 +1,80 @@ +package org.enso.base.lookup; + +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.ServiceLoader; +import java.util.function.Function; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.stream.Stream; + +public final class Lookup implements Iterable { + private final Function> factory; + private List> found; + private static final Logger logger = Logger.getLogger(Lookup.class.getName()); + + private Lookup(Function> factory) { + this.factory = factory; + } + + @Override + public Iterator iterator() { + return stream().map(p -> p.get()).toList().iterator(); + } + + public Stream> stream() { + var tmp = found; + if (tmp == null) { + found = tmp = findAll(); + } + return tmp.stream(); + } + + public void reload() { + found = null; + } + + private List> findAll() { + var serviceProviders = new LinkedHashMap, ModuleLayer>(); + if (System.getProperties().get("enso.class.path") instanceof Collection layers) { + for (var obj : layers) { + if (obj instanceof ModuleLayer layer) { + factory.apply(layer).stream() + .forEach( + (p) -> { + if (serviceProviders.containsKey(p)) { + var prevLayer = serviceProviders.get(p); + logger.log( + Level.WARNING, + String.format( + "Duplicate provider found: %s. Previous provider in layer '%s'." + + " Current provider in layer '%s'.", + providerToString(p), prevLayer, layer)); + } + serviceProviders.put(p, layer); + }); + } + } + } + return serviceProviders.keySet().stream().toList(); + } + + public static Lookup lookup(Function> factory) { + return new Lookup<>(factory); + } + + private static String providerToString(ServiceLoader.Provider provider) { + var mod = provider.type().getModule(); + var modLayer = mod.getLayer(); + var tp = provider.type(); + return "Provider[type='" + + tp + + "', module='" + + mod.getName() + + "', moduleLayer={" + + modLayer + + "}]"; + } +} diff --git a/std-bits/base/src/main/java/org/enso/base/net/http/HTTPFetchDataLinkSPI.java b/std-bits/base/src/main/java/org/enso/base/net/http/HTTPFetchDataLinkSPI.java index 027b157de63c..175f5b50e316 100644 --- a/std-bits/base/src/main/java/org/enso/base/net/http/HTTPFetchDataLinkSPI.java +++ b/std-bits/base/src/main/java/org/enso/base/net/http/HTTPFetchDataLinkSPI.java @@ -2,8 +2,7 @@ import org.enso.base.enso_cloud.DataLinkSPI; -@org.openide.util.lookup.ServiceProvider(service = DataLinkSPI.class) -public class HTTPFetchDataLinkSPI extends DataLinkSPI { +public final class HTTPFetchDataLinkSPI extends DataLinkSPI { @Override protected String getModuleName() { return "Standard.Base.Network.HTTP.Internal.HTTP_Fetch_Data_Link"; diff --git a/std-bits/base/src/main/java/org/enso/base/read/BaseReadManyReturnSPI.java b/std-bits/base/src/main/java/org/enso/base/read/BaseReadManyReturnSPI.java index 55308ce81f3c..9f79817d9a18 100644 --- a/std-bits/base/src/main/java/org/enso/base/read/BaseReadManyReturnSPI.java +++ b/std-bits/base/src/main/java/org/enso/base/read/BaseReadManyReturnSPI.java @@ -1,7 +1,6 @@ package org.enso.base.read; -@org.openide.util.lookup.ServiceProvider(service = ReadManyReturnSPI.class) -public class BaseReadManyReturnSPI extends ReadManyReturnSPI { +public final class BaseReadManyReturnSPI extends ReadManyReturnSPI { @Override protected String getModuleName() { return "Standard.Base.Data.Read.Return_As"; diff --git a/std-bits/database/src/main/java/module-info.java b/std-bits/database/src/main/java/module-info.java new file mode 100644 index 000000000000..d389a3c12fff --- /dev/null +++ b/std-bits/database/src/main/java/module-info.java @@ -0,0 +1,34 @@ +import org.enso.base.enso_cloud.DataLinkSPI; +import org.enso.base.file_format.FileFormatSPI; +import org.enso.database.DatabaseConnectionDetailsSPI; +import org.enso.database.postgres.PostgresConnectionDetailsSPI; +import org.enso.database.postgres.PostgresDataLinkSPI; +import org.enso.database.sqlite.SQLiteConnectionDetailsSPI; +import org.enso.database.sqlite.SQLiteFormatSPI; +import org.enso.database.sqlite.SQLiteInMemoryDetailsSPI; + +module org.enso.std.database { + requires java.logging; + requires java.sql; + requires org.enso.std.base; + requires org.enso.common.polyglot.core.utils; + requires org.graalvm.collections; + requires org.graalvm.polyglot; + requires com.fasterxml.jackson.databind; + + uses DatabaseConnectionDetailsSPI; + uses java.sql.Driver; + + exports org.enso.database; + + provides DatabaseConnectionDetailsSPI with + PostgresConnectionDetailsSPI, + SQLiteConnectionDetailsSPI, + SQLiteInMemoryDetailsSPI; + provides DataLinkSPI with + PostgresDataLinkSPI; + provides FileFormatSPI with + SQLiteFormatSPI; + + opens org.enso.database.dryrun; +} diff --git a/std-bits/database/src/main/java/org/enso/database/DatabaseConnectionDetailsSPI.java b/std-bits/database/src/main/java/org/enso/database/DatabaseConnectionDetailsSPI.java index ac075118f3b3..c9de669d1c7a 100644 --- a/std-bits/database/src/main/java/org/enso/database/DatabaseConnectionDetailsSPI.java +++ b/std-bits/database/src/main/java/org/enso/database/DatabaseConnectionDetailsSPI.java @@ -1,13 +1,13 @@ package org.enso.database; import java.util.ServiceLoader; +import org.enso.base.lookup.Lookup; import org.enso.base.polyglot.EnsoMeta; import org.graalvm.polyglot.Value; public abstract class DatabaseConnectionDetailsSPI { - private static final ServiceLoader loader = - ServiceLoader.load( - DatabaseConnectionDetailsSPI.class, DatabaseConnectionDetailsSPI.class.getClassLoader()); + private static final Lookup loader = + Lookup.lookup((l) -> ServiceLoader.load(l, DatabaseConnectionDetailsSPI.class)); /** * Returns an array of pairs, where the first element is the user facing connection name and the diff --git a/std-bits/database/src/main/java/org/enso/database/JDBCProxy.java b/std-bits/database/src/main/java/org/enso/database/JDBCProxy.java index f76b0689ef44..62cf5618faa2 100644 --- a/std-bits/database/src/main/java/org/enso/database/JDBCProxy.java +++ b/std-bits/database/src/main/java/org/enso/database/JDBCProxy.java @@ -1,7 +1,6 @@ package org.enso.database; import java.sql.Connection; -import java.sql.DriverManager; import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; @@ -11,6 +10,7 @@ import org.enso.base.enso_cloud.EnsoSecretAccessDenied; import org.enso.base.enso_cloud.EnsoSecretHelper; import org.enso.base.enso_cloud.HideableValue; +import org.enso.base.lookup.Lookup; import org.enso.database.audit.CloudAuditedConnection; import org.enso.database.audit.LocalAuditedConnection; import org.graalvm.collections.Pair; @@ -31,7 +31,8 @@ public final class JDBCProxy { * @return an array of JDBC drivers that are currently registered */ public static Object[] getDrivers() { - return DriverManager.drivers().toArray(); + var drivers = Lookup.lookup((l) -> ServiceLoader.load(l, java.sql.Driver.class)); + return drivers.stream().toArray(); } /** @@ -46,17 +47,11 @@ public static Object[] getDrivers() { */ public static Connection getConnection(String url, List> properties) throws SQLException { - // We need to manually register all the drivers because the DriverManager is not able - // to correctly use our class loader, it only delegates to the platform class loader when - // loading the java.sql.Driver service. - var sl = ServiceLoader.load(java.sql.Driver.class, JDBCProxy.class.getClassLoader()); - for (var driver : sl) { - DriverManager.registerDriver(driver); - } + var drivers = Lookup.lookup((l) -> ServiceLoader.load(l, java.sql.Driver.class)); PartitionedProperties partitionedProperties = PartitionedProperties.parse(properties); var rawConnection = - EnsoSecretHelper.getJDBCConnection(url, partitionedProperties.jdbcProperties); + EnsoSecretHelper.getJDBCConnection(drivers, url, partitionedProperties.jdbcProperties); return switch (partitionedProperties.audited()) { case "local" -> new LocalAuditedConnection(rawConnection); case "cloud" -> new CloudAuditedConnection( diff --git a/std-bits/database/src/main/java/org/enso/database/postgres/PostgresConnectionDetailsSPI.java b/std-bits/database/src/main/java/org/enso/database/postgres/PostgresConnectionDetailsSPI.java index ee357856e205..a0f0c98a67a0 100644 --- a/std-bits/database/src/main/java/org/enso/database/postgres/PostgresConnectionDetailsSPI.java +++ b/std-bits/database/src/main/java/org/enso/database/postgres/PostgresConnectionDetailsSPI.java @@ -2,8 +2,7 @@ import org.enso.database.DatabaseConnectionDetailsSPI; -@org.openide.util.lookup.ServiceProvider(service = DatabaseConnectionDetailsSPI.class) -public class PostgresConnectionDetailsSPI extends DatabaseConnectionDetailsSPI { +public final class PostgresConnectionDetailsSPI extends DatabaseConnectionDetailsSPI { @Override protected String getModuleName() { return "Standard.Database.Connection.Postgres"; diff --git a/std-bits/database/src/main/java/org/enso/database/postgres/PostgresDataLinkSPI.java b/std-bits/database/src/main/java/org/enso/database/postgres/PostgresDataLinkSPI.java index 589f6202b74a..b953898b1372 100644 --- a/std-bits/database/src/main/java/org/enso/database/postgres/PostgresDataLinkSPI.java +++ b/std-bits/database/src/main/java/org/enso/database/postgres/PostgresDataLinkSPI.java @@ -2,8 +2,7 @@ import org.enso.base.enso_cloud.DataLinkSPI; -@org.openide.util.lookup.ServiceProvider(service = DataLinkSPI.class) -public class PostgresDataLinkSPI extends DataLinkSPI { +public final class PostgresDataLinkSPI extends DataLinkSPI { @Override protected String getModuleName() { return "Standard.Database.Connection.Data_Link.Postgres_Data_Link"; diff --git a/std-bits/database/src/main/java/org/enso/database/sqlite/SQLiteConnectionDetailsSPI.java b/std-bits/database/src/main/java/org/enso/database/sqlite/SQLiteConnectionDetailsSPI.java index a758ffd5980f..f81805a2f27e 100644 --- a/std-bits/database/src/main/java/org/enso/database/sqlite/SQLiteConnectionDetailsSPI.java +++ b/std-bits/database/src/main/java/org/enso/database/sqlite/SQLiteConnectionDetailsSPI.java @@ -2,8 +2,7 @@ import org.enso.database.DatabaseConnectionDetailsSPI; -@org.openide.util.lookup.ServiceProvider(service = DatabaseConnectionDetailsSPI.class) -public class SQLiteConnectionDetailsSPI extends DatabaseConnectionDetailsSPI { +public final class SQLiteConnectionDetailsSPI extends DatabaseConnectionDetailsSPI { @Override protected String getModuleName() { return "Standard.Database.Connection.SQLite"; diff --git a/std-bits/database/src/main/java/org/enso/database/sqlite/SQLiteFormatSPI.java b/std-bits/database/src/main/java/org/enso/database/sqlite/SQLiteFormatSPI.java index f8d3a9b9b463..e6149777791a 100644 --- a/std-bits/database/src/main/java/org/enso/database/sqlite/SQLiteFormatSPI.java +++ b/std-bits/database/src/main/java/org/enso/database/sqlite/SQLiteFormatSPI.java @@ -2,8 +2,7 @@ import org.enso.base.file_format.FileFormatSPI; -@org.openide.util.lookup.ServiceProvider(service = FileFormatSPI.class) -public class SQLiteFormatSPI extends FileFormatSPI { +public final class SQLiteFormatSPI extends FileFormatSPI { @Override protected String getModuleName() { return "Standard.Database.Connection.SQLite_Format"; diff --git a/std-bits/database/src/main/java/org/enso/database/sqlite/SQLiteInMemoryDetailsSPI.java b/std-bits/database/src/main/java/org/enso/database/sqlite/SQLiteInMemoryDetailsSPI.java index ea91624afead..490ba2094322 100644 --- a/std-bits/database/src/main/java/org/enso/database/sqlite/SQLiteInMemoryDetailsSPI.java +++ b/std-bits/database/src/main/java/org/enso/database/sqlite/SQLiteInMemoryDetailsSPI.java @@ -2,8 +2,7 @@ import org.enso.database.DatabaseConnectionDetailsSPI; -@org.openide.util.lookup.ServiceProvider(service = DatabaseConnectionDetailsSPI.class) -public class SQLiteInMemoryDetailsSPI extends DatabaseConnectionDetailsSPI { +public final class SQLiteInMemoryDetailsSPI extends DatabaseConnectionDetailsSPI { @Override protected String getModuleName() { return "Standard.Database.Connection.SQLite"; diff --git a/std-bits/image/src/main/java/module-info.java b/std-bits/image/src/main/java/module-info.java new file mode 100644 index 000000000000..6132173e4e3e --- /dev/null +++ b/std-bits/image/src/main/java/module-info.java @@ -0,0 +1,14 @@ +import org.enso.base.file_format.FileFormatSPI; +import org.enso.image.ImageFormatSPI; + +module org.enso.std.image { + requires org.graalvm.polyglot; + requires org.enso.std.base; + requires opencv; + + provides FileFormatSPI with + ImageFormatSPI; + + opens org.enso.image; + opens org.enso.image.data; +} diff --git a/std-bits/image/src/main/java/org/enso/image/ImageFormatSPI.java b/std-bits/image/src/main/java/org/enso/image/ImageFormatSPI.java index 3893bcdc4e49..b57024996843 100644 --- a/std-bits/image/src/main/java/org/enso/image/ImageFormatSPI.java +++ b/std-bits/image/src/main/java/org/enso/image/ImageFormatSPI.java @@ -2,7 +2,6 @@ import org.enso.base.file_format.FileFormatSPI; -@org.openide.util.lookup.ServiceProvider(service = FileFormatSPI.class) public class ImageFormatSPI extends FileFormatSPI { @Override protected String getModuleName() { diff --git a/std-bits/microsoft/src/main/java/module-info.java b/std-bits/microsoft/src/main/java/module-info.java new file mode 100644 index 000000000000..f6abccc42e77 --- /dev/null +++ b/std-bits/microsoft/src/main/java/module-info.java @@ -0,0 +1,11 @@ +import org.enso.database.DatabaseConnectionDetailsSPI; +import org.enso.microsoft.SQLServerConnectionDetailsSPI; + +module org.enso.std.microsoft { + requires org.enso.std.base; + requires org.enso.std.database; + requires com.microsoft.sqlserver.jdbc; + + provides DatabaseConnectionDetailsSPI with + SQLServerConnectionDetailsSPI; +} diff --git a/std-bits/microsoft/src/main/java/org/enso/microsoft/SQLServerConnectionDetailsSPI.java b/std-bits/microsoft/src/main/java/org/enso/microsoft/SQLServerConnectionDetailsSPI.java index ad426745eb60..e123cb47e00d 100644 --- a/std-bits/microsoft/src/main/java/org/enso/microsoft/SQLServerConnectionDetailsSPI.java +++ b/std-bits/microsoft/src/main/java/org/enso/microsoft/SQLServerConnectionDetailsSPI.java @@ -2,8 +2,7 @@ import org.enso.database.DatabaseConnectionDetailsSPI; -@org.openide.util.lookup.ServiceProvider(service = DatabaseConnectionDetailsSPI.class) -public class SQLServerConnectionDetailsSPI extends DatabaseConnectionDetailsSPI { +public final class SQLServerConnectionDetailsSPI extends DatabaseConnectionDetailsSPI { @Override protected String getModuleName() { diff --git a/std-bits/microsoft/src/main/java/org/enso/microsoft/SQLServerDataLinkSPI.java b/std-bits/microsoft/src/main/java/org/enso/microsoft/SQLServerDataLinkSPI.java index c8acfd42cef7..b9cd5693a0f2 100644 --- a/std-bits/microsoft/src/main/java/org/enso/microsoft/SQLServerDataLinkSPI.java +++ b/std-bits/microsoft/src/main/java/org/enso/microsoft/SQLServerDataLinkSPI.java @@ -2,7 +2,6 @@ import org.enso.base.enso_cloud.DataLinkSPI; -@org.openide.util.lookup.ServiceProvider(service = DataLinkSPI.class) public class SQLServerDataLinkSPI extends DataLinkSPI { @Override protected String getModuleName() { diff --git a/std-bits/table/src/main/java/module-info.java b/std-bits/table/src/main/java/module-info.java new file mode 100644 index 000000000000..c717596c58e8 --- /dev/null +++ b/std-bits/table/src/main/java/module-info.java @@ -0,0 +1,68 @@ +import org.enso.base.file_format.FileFormatSPI; +import org.enso.table.read.DelimitedFormatSPI; +import org.enso.table.read.ExcelFormatSPI; + +module org.enso.std.table { + requires java.xml; + requires jdk.xml.dom; + requires com.ibm.icu; + requires org.antlr.antlr4.runtime; + requires org.apache.poi.ooxml; + requires org.apache.poi.ooxml.schemas; + requires org.apache.poi.poi; + requires org.apache.xmlbeans; + requires org.graalvm.collections; + requires org.graalvm.polyglot; + requires org.enso.common.polyglot.core.utils; + requires org.enso.std.base; + requires univocity.parsers; + + provides FileFormatSPI with + ExcelFormatSPI, + DelimitedFormatSPI; + + // + // opening up for reflection from Enso code + // + opens org.enso.table.aggregations; + opens org.enso.table.expressions; + opens org.enso.table.formatting; + opens org.enso.table.excel; + + exports org.enso.table.problems; + + opens org.enso.table.parsing; + opens org.enso.table.parsing.problems; + + exports org.enso.table.data.column.storage; + + opens org.enso.table.data.column.storage.numeric; + + exports org.enso.table.data.column.builder; + + opens org.enso.table.data.column.operation; + opens org.enso.table.data.column.operation.cast; + + exports org.enso.table.data.column.operation.map; + + opens org.enso.table.data.column.operation.unary; + + exports org.enso.table.data.column.storage.type; + exports org.enso.table.data.mask; + exports org.enso.table.data.index; + exports org.enso.table.data.table; + + opens org.enso.table.data.table.problems; + opens org.enso.table.data.table.join; + + exports org.enso.table.data.table.join.between; + + opens org.enso.table.data.table.join.conditions; + opens org.enso.table.data.table.join.lookup; + opens org.enso.table.error; + opens org.enso.table.read; + opens org.enso.table.operations; + opens org.enso.table.util; + opens org.enso.table.util.problems; + opens org.enso.table.write; +} diff --git a/std-bits/table/src/main/java/org/enso/table/read/DelimitedFormatSPI.java b/std-bits/table/src/main/java/org/enso/table/read/DelimitedFormatSPI.java index c4ddbbda9a42..220624e14649 100644 --- a/std-bits/table/src/main/java/org/enso/table/read/DelimitedFormatSPI.java +++ b/std-bits/table/src/main/java/org/enso/table/read/DelimitedFormatSPI.java @@ -2,8 +2,7 @@ import org.enso.base.file_format.FileFormatSPI; -@org.openide.util.lookup.ServiceProvider(service = FileFormatSPI.class) -public class DelimitedFormatSPI extends FileFormatSPI { +public final class DelimitedFormatSPI extends FileFormatSPI { @Override protected String getModuleName() { return "Standard.Table.Delimited.Delimited_Format"; diff --git a/std-bits/table/src/main/java/org/enso/table/read/ExcelFormatSPI.java b/std-bits/table/src/main/java/org/enso/table/read/ExcelFormatSPI.java index 3f554a2780a0..4256a92aefbb 100644 --- a/std-bits/table/src/main/java/org/enso/table/read/ExcelFormatSPI.java +++ b/std-bits/table/src/main/java/org/enso/table/read/ExcelFormatSPI.java @@ -2,8 +2,7 @@ import org.enso.base.file_format.FileFormatSPI; -@org.openide.util.lookup.ServiceProvider(service = FileFormatSPI.class) -public class ExcelFormatSPI extends FileFormatSPI { +public final class ExcelFormatSPI extends FileFormatSPI { @Override protected String getModuleName() { return "Standard.Table.Excel.Excel_Format"; diff --git a/test/AWS_Tests/package.yaml b/test/AWS_Tests/package.yaml index 3e7516ddccaa..729ec7948b63 100644 --- a/test/AWS_Tests/package.yaml +++ b/test/AWS_Tests/package.yaml @@ -5,3 +5,5 @@ license: MIT author: enso-dev@enso.org maintainer: enso-dev@enso.org prefer-local-libraries: true +requires: + - Standard.Database diff --git a/test/Base_Tests/package.yaml b/test/Base_Tests/package.yaml index 71c3b3be8894..032a106d7330 100644 --- a/test/Base_Tests/package.yaml +++ b/test/Base_Tests/package.yaml @@ -7,3 +7,6 @@ author: enso-dev@enso.org maintainer: enso-dev@enso.org # Base_Tests import stuff from Helpers sibling project. So we need this property here. prefer-local-libraries: true +requires: + - Standard.Base + - Standard.Table diff --git a/test/Base_Tests/polyglot-sources/enso-test-java-helpers/src/main/java/module-info.java b/test/Base_Tests/polyglot-sources/enso-test-java-helpers/src/main/java/module-info.java new file mode 100644 index 000000000000..6cabb380f852 --- /dev/null +++ b/test/Base_Tests/polyglot-sources/enso-test-java-helpers/src/main/java/module-info.java @@ -0,0 +1,7 @@ +module org.enso.test.java_helpers { + requires static org.graalvm.polyglot; + requires static org.enso.std.table; + + exports org.enso.base_test_helpers; + exports org.enso.table_test_helpers; +} diff --git a/test/Benchmarks/package.yaml b/test/Benchmarks/package.yaml index cc894674bf77..a2c0639e5f2a 100644 --- a/test/Benchmarks/package.yaml +++ b/test/Benchmarks/package.yaml @@ -4,3 +4,5 @@ version: 0.0.1 license: MIT author: enso-dev@enso.org maintainer: enso-dev@enso.org +requires: + - Standard.Table diff --git a/test/Microsoft_Tests/package.yaml b/test/Microsoft_Tests/package.yaml index d6db8970ee87..a9c6b2cf9fbd 100644 --- a/test/Microsoft_Tests/package.yaml +++ b/test/Microsoft_Tests/package.yaml @@ -5,3 +5,5 @@ license: MIT author: enso-dev@enso.org maintainer: enso-dev@enso.org prefer-local-libraries: true +requires: + - Standard.Microsoft diff --git a/test/Table_Tests/package.yaml b/test/Table_Tests/package.yaml index d1174d2d9404..51d8f8fa7c17 100644 --- a/test/Table_Tests/package.yaml +++ b/test/Table_Tests/package.yaml @@ -5,3 +5,6 @@ license: MIT author: enso-dev@enso.org maintainer: enso-dev@enso.org prefer-local-libraries: true +requires: + - Standard.Table + - Standard.Base_Tests