From dd7f2ea5ef8ec2f69e6c8e05098864c7f6283d62 Mon Sep 17 00:00:00 2001
From: Janeen Yamak <88203072+janeenyamak1@users.noreply.github.com>
Date: Mon, 2 Oct 2023 07:46:16 -0500
Subject: [PATCH 01/26] update open api gen to pass packageable elements
(#2330)
---
.../pom.xml | 4 +
.../OpenApiArtifactGenerationExtension.java | 7 +-
.../fromPure/pureToOpenApi.pure | 88 +++++++++++++------
.../transformation/fromPure/tests/tests.pure | 29 +++---
4 files changed, 87 insertions(+), 41 deletions(-)
diff --git a/legend-engine-xts-openapi/legend-engine-xt-openapi-generation/pom.xml b/legend-engine-xts-openapi/legend-engine-xt-openapi-generation/pom.xml
index 50cfa164e50..38dd975b153 100644
--- a/legend-engine-xts-openapi/legend-engine-xt-openapi-generation/pom.xml
+++ b/legend-engine-xts-openapi/legend-engine-xt-openapi-generation/pom.xml
@@ -70,6 +70,10 @@
org.eclipse.collections
eclipse-collections-api
+
+ org.eclipse.collections
+ eclipse-collections
+
diff --git a/legend-engine-xts-openapi/legend-engine-xt-openapi-generation/src/main/java/org/finos/legend/engine/generation/OpenApiArtifactGenerationExtension.java b/legend-engine-xts-openapi/legend-engine-xt-openapi-generation/src/main/java/org/finos/legend/engine/generation/OpenApiArtifactGenerationExtension.java
index 765ec5a4cf2..4ff2b8dfc90 100644
--- a/legend-engine-xts-openapi/legend-engine-xt-openapi-generation/src/main/java/org/finos/legend/engine/generation/OpenApiArtifactGenerationExtension.java
+++ b/legend-engine-xts-openapi/legend-engine-xt-openapi-generation/src/main/java/org/finos/legend/engine/generation/OpenApiArtifactGenerationExtension.java
@@ -14,10 +14,13 @@
package org.finos.legend.engine.generation;
+import org.eclipse.collections.api.RichIterable;
+import org.eclipse.collections.impl.factory.Lists;
import org.finos.legend.engine.language.pure.compiler.toPureGraph.PureModel;
import org.finos.legend.engine.language.pure.dsl.generation.extension.Artifact;
import org.finos.legend.engine.language.pure.dsl.generation.extension.ArtifactGenerationExtension;
import org.finos.legend.engine.protocol.pure.v1.model.context.PureModelContextData;
+import org.finos.legend.engine.protocol.pure.v1.model.packageableElement.domain.Class;
import org.finos.legend.pure.generated.Root_meta_external_function_description_openapi_metamodel_Server_Impl;
import org.finos.legend.pure.generated.Root_meta_legend_service_metamodel_Service;
import org.finos.legend.pure.generated.core_external_format_openapi_transformation_fromPure_pureToOpenApi;
@@ -26,6 +29,7 @@
import java.util.Collections;
import java.util.List;
+import java.util.stream.Collectors;
public class OpenApiArtifactGenerationExtension implements ArtifactGenerationExtension
{
@@ -60,7 +64,8 @@ public List generate(PackageableElement element, PureModel pureModel,
{
try
{
- String result = core_external_format_openapi_transformation_fromPure_pureToOpenApi.Root_meta_external_function_description_openapi_transformation_fromPure_serviceToOpenApi_Service_1__Server_1__String_1_((Root_meta_legend_service_metamodel_Service) element, new Root_meta_external_function_description_openapi_metamodel_Server_Impl("")._url(HOST), pureModel.getExecutionSupport());
+ RichIterable packageableElements = Lists.immutable.withAll(data.getElements().stream().filter(e -> e instanceof Class).map(e -> pureModel.getPackageableElement(e._package + "::" + e.name)).collect(Collectors.toList()));
+ String result = core_external_format_openapi_transformation_fromPure_pureToOpenApi.Root_meta_external_function_description_openapi_transformation_fromPure_serviceToOpenApi_Service_1__PackageableElement_MANY__Server_1__String_1_((Root_meta_legend_service_metamodel_Service) element, packageableElements, new Root_meta_external_function_description_openapi_metamodel_Server_Impl("")._url(HOST), pureModel.getExecutionSupport());
Artifact output = new Artifact(result, element.getName() + "_spec.json", "json");
return Collections.singletonList(output);
}
diff --git a/legend-engine-xts-openapi/legend-engine-xt-openapi-pure/src/main/resources/core_external_format_openapi/transformation/fromPure/pureToOpenApi.pure b/legend-engine-xts-openapi/legend-engine-xt-openapi-pure/src/main/resources/core_external_format_openapi/transformation/fromPure/pureToOpenApi.pure
index 9e5fe861eb4..173940126fd 100644
--- a/legend-engine-xts-openapi/legend-engine-xt-openapi-pure/src/main/resources/core_external_format_openapi/transformation/fromPure/pureToOpenApi.pure
+++ b/legend-engine-xts-openapi/legend-engine-xt-openapi-pure/src/main/resources/core_external_format_openapi/transformation/fromPure/pureToOpenApi.pure
@@ -20,7 +20,6 @@ import meta::legend::service::metamodel::*;
import meta::external::function::description::openapi::transformation::fromPure::*;
import meta::pure::functions::meta::*;
import meta::pure::metamodel::path::*;
-import meta::pure::service::*;
import meta::external::function::description::openapi::profiles::*;
import meta::pure::generation::metamodel::*;
import meta::external::query::sql::transformation::queryToPure::tests::*;
@@ -73,6 +72,11 @@ function meta::external::function::description::openapi::transformation::fromPur
}
function <> meta::external::function::description::openapi::transformation::fromPure::serviceToOpenApi(service: Service[1], server: Server[1]):String[1]
+{
+ $service->serviceToOpenApi([], $server);
+}
+
+function <> meta::external::function::description::openapi::transformation::fromPure::serviceToOpenApi(service: Service[1], elements: PackageableElement[*], server: Server[1]):String[1]
{
^FunctionInfo(
func = $service.execution->cast(@PureExecution).func,
@@ -81,13 +85,12 @@ function <> meta::external::function::description
version = '1.0.0',
title = 'Legend API',
paramsExample = ^Map()
- )->meta::external::function::description::openapi::transformation::fromPure::funcInfoToOpenApi($server)
+ )->meta::external::function::description::openapi::transformation::fromPure::funcInfoToOpenApi($elements, $server)
->asString()->makeString()->replace('\\/','/');
}
-function <> meta::external::function::description::openapi::transformation::fromPure::funcInfoToOpenApi(funcInfos:FunctionInfo[*], server:Server[1]):OpenApi[1]
+function <> meta::external::function::description::openapi::transformation::fromPure::funcInfoToOpenApi(funcInfos:FunctionInfo[*], elements: PackageableElement[*], server:Server[1]):OpenApi[1]
{
- let allClasses = $funcInfos->returnTypesFromFunctions();
^OpenApi(
openapi='3.0.0',
info=^Info(title='Legend API', version='1.0.0'),
@@ -118,28 +121,61 @@ function <> meta::external::function::description::openapi::tran
);
)
),
- components= ^Components(schemas=newMap(
- $allClasses->map(
- c|pair(
- $c.rawType.name->toOne(),
- ^Schema
- (
- type='object',
- properties=newMap(
- $c.rawType->cast(@Class).properties
- ->filter(p|$p.name!='elementOverride' && $p.name!='classifierGenericType')
- ->map(p|
- pair
- (
- $p.name->toOne(),
- $p->functionReturnType()->buildComponent($p.multiplicity)
- )
+ components= generateComponent($funcInfos, $elements)
+
+ );
+}
+
+function <> meta::external::function::description::openapi::transformation::fromPure::generateComponent(funcInfos: FunctionInfo[*], elements: PackageableElement[*]):Components[1]
+{
+ let schema = $funcInfos->map(f| if($f->getReturnType()->instanceOf(RootGraphFetchTree),
+ |let allClasses = $elements->filter(e|$e->instanceOf(Class));
+ $allClasses->map(
+ c|pair(
+ $c.name->toOne(),
+ ^Schema
+ (
+ type='object',
+ properties=newMap(
+ $c->cast(@Class).properties
+ ->filter(p|$p.name!='elementOverride' && $p.name!='classifierGenericType')
+ ->map(p|
+ pair
+ (
+ $p.name->toOne(),
+ $p->functionReturnType()->buildComponent($p.multiplicity)
+ )
+ )
+ )
+ )
+ );
+ );,
+ |let allClasses = $funcInfos->returnTypesFromFunctions();
+ $allClasses->map(
+ c|pair(
+ $c.rawType.name->toOne(),
+ ^Schema
+ (
+ type='object',
+ properties=newMap(
+ $c.rawType->cast(@Class).properties
+ ->filter(p|$p.name!='elementOverride' && $p.name!='classifierGenericType')
+ ->map(p|
+ pair
+ (
+ $p.name->toOne(),
+ $p->functionReturnType()->buildComponent($p.multiplicity)
+ )
+ )
)
- )
- )
- )
- )
- )));
+ )
+ )
+ );
+ );
+ );
+
+
+ ^Components(schemas = newMap($schema));
}
function <> meta::external::function::description::openapi::transformation::fromPure::getEvaluatedExecutionFunction(funcInfo:FunctionInfo[1]):FunctionDefinition[1]
@@ -169,7 +205,7 @@ function <> meta::external::function::description::openapi::tran
$funcInfos->map(f|$f->getReturnType())
->map(r| if($r->instanceOf(RootGraphFetchTree), | $r.classifierGenericType->toOne(), | $r))
->map(r|$r->cast(@GenericType)->toOne())
- ->map(r|if($r.rawType==JSONResult||$r.rawType==RootGraphFetchTree,|$r.typeArguments,|$r))
+ ->map(r|if($r.rawType== meta::external::function::description::openapi::tostring::JSONResult||$r.rawType==RootGraphFetchTree,|$r.typeArguments,|$r))
->filter(c|!$c.rawType->isEmpty() && $c.rawType->toOne()->instanceOf(Class))
->map(t|if($t.rawType.specializations->isEmpty(),|$t,|$t.rawType->toOne().classifierGenericType.typeArguments))
->removeDuplicates(cmpGenericType_GenericType_1__GenericType_1__Boolean_1_)
diff --git a/legend-engine-xts-openapi/legend-engine-xt-openapi-pure/src/main/resources/core_external_format_openapi/transformation/fromPure/tests/tests.pure b/legend-engine-xts-openapi/legend-engine-xt-openapi-pure/src/main/resources/core_external_format_openapi/transformation/fromPure/tests/tests.pure
index c6ba94c2261..febfad58185 100644
--- a/legend-engine-xts-openapi/legend-engine-xt-openapi-pure/src/main/resources/core_external_format_openapi/transformation/fromPure/tests/tests.pure
+++ b/legend-engine-xts-openapi/legend-engine-xt-openapi-pure/src/main/resources/core_external_format_openapi/transformation/fromPure/tests/tests.pure
@@ -149,7 +149,7 @@ function <> meta::external::function::description::openapi::transformation::fromPure::tests::testServiceWithExtendAndManyParam():Service[1]
+function <> meta::external::function::description::openapi::transformation::fromPure::tests::serviceWithExtendAndManyParam():Service[1]
{
^Service(
pattern = '/test/service/with/extend',
@@ -157,54 +157,55 @@ function <filter(item | $planningAreas->isEmpty() || $planningAreas->contains($item.firstName))->project( [ col(x | $x.lastName, 'kerberos'), col(x | $x.age, 'planningArea') ]) ->extend(^BasicColumnSpecification(name = 'ageString', func = {row:TDSRow[1]|$row.getInteger('age') ->toString()}));,
+ func = planningAreas: String[*]| Person.all()->filter(item | $planningAreas->isEmpty() || $planningAreas->contains($item.firstName))->project( [ col(x | $x.lastName, 'kerberos'), col(x | $x.age, 'planningArea') ])->extend(^BasicColumnSpecification(name = 'ageString', func = {row:TDSRow[1]|$row.getInteger('age') ->toString()}));,
mapping = personMapping,
runtime = []
)
);
}
-
-
-
-
-
-
function <> meta::external::function::description::openapi::transformation::fromPure::tests::testServiceWithoutColumnSpecificationOpenapiString():Boolean[1]
{
- let openapi = meta::external::function::description::openapi::transformation::fromPure::tests::testServiceWithoutColumnSpecification()->serviceToOpenApi(^Server(url='test'));
+ let openapi = meta::external::function::description::openapi::transformation::fromPure::tests::testServiceWithoutColumnSpecification()->serviceToOpenApi(packageableElem(), ^Server(url='test'));
let expected = readFile('/core_external_format_openapi/transformation/fromPure/tests/resources/testOpenApiSpecWithoutColumnSpec.txt')->toOne();
assertJsonStringsEqual($expected, $openapi);
}
function <> meta::external::function::description::openapi::transformation::fromPure::tests::testServiceShouldReturnCorrectOpenapiString():Boolean[1]
{
- let openapi = simpleService()->serviceToOpenApi(^Server(url='test'));
+ let openapi = simpleService()->serviceToOpenApi(packageableElem(), ^Server(url='test'));
let expected = readFile('/core_external_format_openapi/transformation/fromPure/tests/resources/testOpenApiSpec.txt')->toOne();
assertJsonStringsEqual($expected, $openapi);
}
-function <> meta::external::function::description::openapi::transformation::fromPure::tests::testFailedService():Boolean[1]
+function <> meta::external::function::description::openapi::transformation::fromPure::tests::testServiceWithExtendAndManyParam():Boolean[1]
{
- let openapi = meta::external::function::description::openapi::transformation::fromPure::tests::testServiceWithExtendAndManyParam()->serviceToOpenApi(^Server(url='test'));
+ let openapi = meta::external::function::description::openapi::transformation::fromPure::tests::serviceWithExtendAndManyParam()->serviceToOpenApi(packageableElem(), ^Server(url='test'));
let expected = readFile('/core_external_format_openapi/transformation/fromPure/tests/resources/testOpenApiSpecWithExtendAndManyParam.txt')->toOne();
assertJsonStringsEqual($expected, $openapi);
}
function <> meta::external::function::description::openapi::transformation::fromPure::tests::testGraphFetchServiceShouldReturnCorrectOpenapiString():Boolean[1]
{
- let openapi = simpleServiceWithGraphFetch()->serviceToOpenApi(^Server(url='test'));
+ let openapi = simpleServiceWithGraphFetch()->serviceToOpenApi(packageableElem(), ^Server(url='test'));
let expected = readFile('/core_external_format_openapi/transformation/fromPure/tests/resources/testGraphFetchOpenApiSpec.txt')->toOne();
assertJsonStringsEqual($expected, $openapi);
}
function <> meta::external::function::description::openapi::transformation::fromPure::tests::testServiceWithParamShouldReturnCorrectOpenapiString():Boolean[1]
{
- let openapi = simpleServiceWithParams()->serviceToOpenApi(^Server(url='test'));
+ let openapi = simpleServiceWithParams()->serviceToOpenApi(packageableElem(), ^Server(url='test'));
let expected = readFile('/core_external_format_openapi/transformation/fromPure/tests/resources/testOpenApiSpecWithServiceParams.txt')->toOne();
assertJsonStringsEqual($expected, $openapi);
}
+function meta::external::function::description::openapi::transformation::fromPure::tests::packageableElem():PackageableElement[*]
+{
+ [
+ pathToElement('meta::external::function::description::openapi::transformation::fromPure::tests::Person')
+ ]
+}
+
###Mapping
import meta::external::function::description::openapi::transformation::fromPure::tests::*;
From d948bd95c4e7ddaf1d40b5b163cb96cab9fd8a98 Mon Sep 17 00:00:00 2001
From: Mohammed Ibrahim
Date: Mon, 2 Oct 2023 09:25:05 -0400
Subject: [PATCH 02/26] Add SparkSQL dialect (#2335)
* Uplift Service Ownership
* Add SparkSQL modules
* Add SparkSQL modules in idelight
* Add sparkSQL generation tests
* Add sparkSQL testSuite
* add extension
---
.../pom.xml | 5 +
.../collection/generation/TestExtensions.java | 1 +
.../legend-engine-server/pom.xml | 5 +
.../finos/legend/engine/ide/PureIDELight.java | 1 +
.../pom.xml | 267 +++++++
...ationalSparkSQLCodeRepositoryProvider.java | 29 +
...lesystem.repository.CodeRepositoryProvider | 1 +
.../core_relational_sparksql.definition.json | 5 +
.../tests/executionPlanTestSparkSQL.pure | 93 +++
.../sqlQueryToString/sparkSQLExtension.pure | 654 ++++++++++++++++++
.../tests/testSparkSQLToSQLString.pure | 45 ++
.../core/Test_Pure_Relational_SparkSQL.java | 35 +
...arkSQLCodeRepositoryProviderAvailable.java | 36 +
.../pom.xml | 34 +
.../pom.xml | 1 +
pom.xml | 5 +
16 files changed, 1217 insertions(+)
create mode 100644 legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sparksql/legend-engine-xt-relationalStore-sparksql-pure/pom.xml
create mode 100644 legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sparksql/legend-engine-xt-relationalStore-sparksql-pure/src/main/java/org/finos/legend/pure/code/core/CoreRelationalSparkSQLCodeRepositoryProvider.java
create mode 100644 legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sparksql/legend-engine-xt-relationalStore-sparksql-pure/src/main/resources/META-INF/services/org.finos.legend.pure.m3.serialization.filesystem.repository.CodeRepositoryProvider
create mode 100644 legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sparksql/legend-engine-xt-relationalStore-sparksql-pure/src/main/resources/core_relational_sparksql.definition.json
create mode 100644 legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sparksql/legend-engine-xt-relationalStore-sparksql-pure/src/main/resources/core_relational_sparksql/relational/executionPlan/tests/executionPlanTestSparkSQL.pure
create mode 100644 legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sparksql/legend-engine-xt-relationalStore-sparksql-pure/src/main/resources/core_relational_sparksql/relational/sqlQueryToString/sparkSQLExtension.pure
create mode 100644 legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sparksql/legend-engine-xt-relationalStore-sparksql-pure/src/main/resources/core_relational_sparksql/relational/sqlQueryToString/tests/testSparkSQLToSQLString.pure
create mode 100644 legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sparksql/legend-engine-xt-relationalStore-sparksql-pure/src/test/java/org/finos/legend/pure/code/core/Test_Pure_Relational_SparkSQL.java
create mode 100644 legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sparksql/legend-engine-xt-relationalStore-sparksql-pure/src/test/java/org/finos/legend/pure/code/core/test/TestSparkSQLCodeRepositoryProviderAvailable.java
create mode 100644 legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sparksql/pom.xml
diff --git a/legend-engine-config/legend-engine-extensions-collection-generation/pom.xml b/legend-engine-config/legend-engine-extensions-collection-generation/pom.xml
index 7d0531e7440..e6319e13369 100644
--- a/legend-engine-config/legend-engine-extensions-collection-generation/pom.xml
+++ b/legend-engine-config/legend-engine-extensions-collection-generation/pom.xml
@@ -295,6 +295,11 @@
legend-engine-xt-relationalStore-sybaseiq-pure
runtime
+
+ org.finos.legend.engine
+ legend-engine-xt-relationalStore-sparksql-pure
+ runtime
+
org.finos.legend.engine
legend-engine-xt-relationalStore-javaPlatformBinding-pure
diff --git a/legend-engine-config/legend-engine-extensions-collection-generation/src/test/java/org/finos/legend/engine/extensions/collection/generation/TestExtensions.java b/legend-engine-config/legend-engine-extensions-collection-generation/src/test/java/org/finos/legend/engine/extensions/collection/generation/TestExtensions.java
index 5ae46944c3d..da2039c880d 100644
--- a/legend-engine-config/legend-engine-extensions-collection-generation/src/test/java/org/finos/legend/engine/extensions/collection/generation/TestExtensions.java
+++ b/legend-engine-config/legend-engine-extensions-collection-generation/src/test/java/org/finos/legend/engine/extensions/collection/generation/TestExtensions.java
@@ -509,6 +509,7 @@ protected Iterable getExpectedCodeRepositories()
.with("core_relational_presto")
.with("core_relational_sybase")
.with("core_relational_sybaseiq")
+ .with("core_relational_sparksql")
.with("core_relational_store_entitlement")
.with("core_servicestore")
.with("core_authentication")
diff --git a/legend-engine-config/legend-engine-server/pom.xml b/legend-engine-config/legend-engine-server/pom.xml
index f1a088aa20b..56ee8d4d193 100644
--- a/legend-engine-config/legend-engine-server/pom.xml
+++ b/legend-engine-config/legend-engine-server/pom.xml
@@ -134,6 +134,11 @@
legend-engine-xt-relationalStore-sybaseiq-pure
runtime
+
+ org.finos.legend.engine
+ legend-engine-xt-relationalStore-sparksql-pure
+ runtime
+
org.finos.legend.engine
legend-engine-language-pure-grammar-api
diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/PureIDELight.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/PureIDELight.java
index 2eea4dbd2b9..ad32fdc40f1 100644
--- a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/PureIDELight.java
+++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/PureIDELight.java
@@ -61,6 +61,7 @@ protected MutableList buildRepositories(SourceLocationCon
.with(this.buildCore("legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-presto/legend-engine-xt-relationalStore-presto-pure", "relational_presto"))
.with(this.buildCore("legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sybase/legend-engine-xt-relationalStore-sybase-pure", "relational_sybase"))
.with(this.buildCore("legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sybaseiq/legend-engine-xt-relationalStore-sybaseiq-pure", "relational_sybaseiq"))
+ .with(this.buildCore("legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sparksql/legend-engine-xt-relationalStore-sparksql-pure", "relational_sparksql"))
.with(this.buildCore("legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-analytics/legend-engine-xt-relationalStore-store-entitlement-pure", "relational_store_entitlement"))
.with(this.buildCore("legend-engine-xts-serviceStore/legend-engine-xt-serviceStore-pure", "servicestore"))
.with(this.buildCore("legend-engine-xts-serviceStore/legend-engine-xt-serviceStore-javaPlatformBinding-pure", "servicestore-java-platform-binding"))
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sparksql/legend-engine-xt-relationalStore-sparksql-pure/pom.xml b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sparksql/legend-engine-xt-relationalStore-sparksql-pure/pom.xml
new file mode 100644
index 00000000000..dfb1bdf5e16
--- /dev/null
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sparksql/legend-engine-xt-relationalStore-sparksql-pure/pom.xml
@@ -0,0 +1,267 @@
+
+
+
+
+
+ org.finos.legend.engine
+ legend-engine-xt-relationalStore-sparksql
+ 4.29.2-SNAPSHOT
+
+ 4.0.0
+
+ legend-engine-xt-relationalStore-sparksql-pure
+ jar
+ Legend Engine - XT - Relational Store - sparksql - Pure
+
+
+
+
+ org.finos.legend.pure
+ legend-pure-maven-generation-par
+
+ src/main/resources
+ ${legend.pure.version}
+
+ core_relational_sparksql
+
+
+ ${project.basedir}/src/main/resources/core_relational_sparksql.definition.json
+
+
+
+
+
+ generate-sources
+
+ build-pure-jar
+
+
+
+
+
+ org.finos.legend.pure
+ legend-pure-m2-functions-pure
+ ${legend.pure.version}
+
+
+ org.finos.legend.pure
+ legend-pure-m2-dsl-mapping-grammar
+ ${legend.pure.version}
+
+
+ org.finos.legend.pure
+ legend-pure-m2-dsl-path-grammar
+ ${legend.pure.version}
+
+
+ org.finos.legend.pure
+ legend-pure-m2-dsl-graph-grammar
+ ${legend.pure.version}
+
+
+ org.finos.legend.pure
+ legend-pure-m2-dsl-diagram-grammar
+ ${legend.pure.version}
+
+
+ org.finos.legend.pure
+ legend-pure-m2-store-relational-grammar
+ ${legend.pure.version}
+
+
+ org.finos.legend.engine
+ legend-engine-pure-code-compiled-core
+ ${project.version}
+
+
+ org.finos.legend.engine
+ legend-engine-xt-relationalStore-pure
+ ${project.version}
+
+
+
+
+ org.finos.legend.pure
+ legend-pure-maven-generation-java
+
+
+ compile
+
+ build-pure-compiled-jar
+
+
+ true
+ true
+ modular
+ true
+
+ core_relational_sparksql
+
+
+
+
+
+
+ org.finos.legend.pure
+ legend-pure-m2-dsl-mapping-grammar
+ ${legend.pure.version}
+
+
+ org.finos.legend.pure
+ legend-pure-m2-dsl-path-grammar
+ ${legend.pure.version}
+
+
+ org.finos.legend.pure
+ legend-pure-m2-dsl-graph-grammar
+ ${legend.pure.version}
+
+
+ org.finos.legend.pure
+ legend-pure-m2-dsl-diagram-grammar
+ ${legend.pure.version}
+
+
+ org.finos.legend.pure
+ legend-pure-m2-store-relational-grammar
+ ${legend.pure.version}
+
+
+ org.finos.legend.engine
+ legend-engine-pure-code-compiled-core
+ ${project.version}
+
+
+ org.finos.legend.engine
+ legend-engine-xt-relationalStore-pure
+ ${project.version}
+
+
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+
+
+ dependency-analyze
+
+
+
+ org.finos.legend.pure:legend-pure-m2-dsl-mapping-pure
+ org.finos.legend.pure:legend-pure-m2-dsl-path-pure
+ org.finos.legend.engine:legend-engine-pure-platform-store-relational-java
+ org.finos.legend.engine:legend-engine-pure-platform-dsl-mapping-java
+
+
+
+
+
+
+
+
+
+
+ org.finos.legend.pure
+ legend-pure-m4
+
+
+ org.finos.legend.pure
+ legend-pure-m3-core
+
+
+ org.finos.legend.pure
+ legend-pure-m2-dsl-mapping-pure
+
+
+ org.finos.legend.pure
+ legend-pure-m2-dsl-path-pure
+
+
+ org.finos.legend.pure
+ legend-pure-m2-store-relational-pure
+
+
+ org.finos.legend.pure
+ legend-pure-runtime-java-engine-compiled
+
+
+
+ org.finos.legend.engine
+ legend-engine-pure-code-compiled-core
+
+
+ org.finos.legend.engine
+ legend-engine-pure-code-compiled-functions
+
+
+ org.finos.legend.engine
+ legend-engine-pure-platform-dsl-mapping-java
+
+
+ org.finos.legend.engine
+ legend-engine-pure-platform-java
+
+
+ org.finos.legend.engine
+ legend-engine-pure-platform-functions-java
+
+
+ org.finos.legend.engine
+ legend-engine-xt-relationalStore-pure
+
+
+ org.finos.legend.engine
+ legend-engine-pure-platform-store-relational-java
+
+
+
+ org.eclipse.collections
+ eclipse-collections
+
+
+ org.eclipse.collections
+ eclipse-collections-api
+
+
+
+
+ org.finos.legend.pure
+ legend-pure-m2-functions-json-pure
+ test
+
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+ test
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ test
+
+
+ com.fasterxml.jackson.core
+ jackson-core
+ test
+
+
+ junit
+ junit
+
+
+
+
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sparksql/legend-engine-xt-relationalStore-sparksql-pure/src/main/java/org/finos/legend/pure/code/core/CoreRelationalSparkSQLCodeRepositoryProvider.java b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sparksql/legend-engine-xt-relationalStore-sparksql-pure/src/main/java/org/finos/legend/pure/code/core/CoreRelationalSparkSQLCodeRepositoryProvider.java
new file mode 100644
index 00000000000..a652f3bddc0
--- /dev/null
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sparksql/legend-engine-xt-relationalStore-sparksql-pure/src/main/java/org/finos/legend/pure/code/core/CoreRelationalSparkSQLCodeRepositoryProvider.java
@@ -0,0 +1,29 @@
+// Copyright 2023 Goldman Sachs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.finos.legend.pure.code.core;
+
+import org.finos.legend.pure.m3.serialization.filesystem.repository.CodeRepository;
+import org.finos.legend.pure.m3.serialization.filesystem.repository.CodeRepositoryProvider;
+import org.finos.legend.pure.m3.serialization.filesystem.repository.GenericCodeRepository;
+
+public class CoreRelationalSparkSQLCodeRepositoryProvider implements CodeRepositoryProvider
+{
+ @Override
+ public CodeRepository repository()
+ {
+ return GenericCodeRepository.build("core_relational_sparksql.definition.json");
+ }
+}
+
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sparksql/legend-engine-xt-relationalStore-sparksql-pure/src/main/resources/META-INF/services/org.finos.legend.pure.m3.serialization.filesystem.repository.CodeRepositoryProvider b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sparksql/legend-engine-xt-relationalStore-sparksql-pure/src/main/resources/META-INF/services/org.finos.legend.pure.m3.serialization.filesystem.repository.CodeRepositoryProvider
new file mode 100644
index 00000000000..96a2fb109ac
--- /dev/null
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sparksql/legend-engine-xt-relationalStore-sparksql-pure/src/main/resources/META-INF/services/org.finos.legend.pure.m3.serialization.filesystem.repository.CodeRepositoryProvider
@@ -0,0 +1 @@
+org.finos.legend.pure.code.core.CoreRelationalSparkSQLCodeRepositoryProvider
\ No newline at end of file
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sparksql/legend-engine-xt-relationalStore-sparksql-pure/src/main/resources/core_relational_sparksql.definition.json b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sparksql/legend-engine-xt-relationalStore-sparksql-pure/src/main/resources/core_relational_sparksql.definition.json
new file mode 100644
index 00000000000..ed5893f3ad1
--- /dev/null
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sparksql/legend-engine-xt-relationalStore-sparksql-pure/src/main/resources/core_relational_sparksql.definition.json
@@ -0,0 +1,5 @@
+{
+ "name" : "core_relational_sparksql",
+ "pattern" : "(meta::relational::functions::sqlQueryToString::sparkSQL|meta::relational::tests::sqlQueryToString::sparkSQL|meta::relational::tests::sqlToString::sparkSQL|meta::pure::executionPlan::tests::sparkSQL|meta::relational::tests::mapping::sqlFunction::sparkSQL|meta::relational::tests::postProcessor::sparkSQL|meta::relational::tests::query::function::sparkSQL|meta::relational::tests::functions::sqlstring::sparkSQL|meta::relational::tests::tds::sparkSQL|meta::relational::tests::projection::sparkSQL|meta::pure::alloy::connections|meta::protocols::pure)(::.*)?",
+ "dependencies" : ["platform", "platform_functions", "platform_store_relational", "platform_dsl_mapping", "core_functions", "core", "core_relational"]
+}
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sparksql/legend-engine-xt-relationalStore-sparksql-pure/src/main/resources/core_relational_sparksql/relational/executionPlan/tests/executionPlanTestSparkSQL.pure b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sparksql/legend-engine-xt-relationalStore-sparksql-pure/src/main/resources/core_relational_sparksql/relational/executionPlan/tests/executionPlanTestSparkSQL.pure
new file mode 100644
index 00000000000..5a3121306e1
--- /dev/null
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sparksql/legend-engine-xt-relationalStore-sparksql-pure/src/main/resources/core_relational_sparksql/relational/executionPlan/tests/executionPlanTestSparkSQL.pure
@@ -0,0 +1,93 @@
+// Copyright 2023 Goldman Sachs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import meta::pure::alloy::connections::alloy::authentication::*;
+import meta::pure::alloy::connections::alloy::specification::*;
+import meta::pure::alloy::connections::*;
+import meta::pure::mapping::modelToModel::test::createInstances::*;
+import meta::relational::postProcessor::*;
+import meta::pure::extension::*;
+import meta::relational::extension::*;
+import meta::pure::mapping::modelToModel::test::shared::*;
+import meta::pure::mapping::modelToModel::test::enumerationMapping::enumToEnum::mapping::*;
+import meta::pure::mapping::modelToModel::test::enumerationMapping::enumToEnum::model::*;
+import meta::pure::mapping::modelToModel::test::enumeration::*;
+import meta::pure::graphFetch::execution::*;
+import meta::pure::executionPlan::tests::datetime::*;
+import meta::relational::tests::tds::tabletds::*;
+import meta::pure::mapping::*;
+import meta::relational::mapping::*;
+import meta::relational::runtime::*;
+import meta::relational::tests::mapping::inheritance::relational::*;
+import meta::relational::metamodel::join::*;
+import meta::relational::tests::tds::tdsJoin::*;
+import meta::pure::executionPlan::toString::*;
+import meta::pure::executionPlan::tests::*;
+import meta::relational::tests::groupBy::datePeriods::mapping::*;
+import meta::relational::tests::groupBy::datePeriods::*;
+import meta::relational::tests::groupBy::datePeriods::domain::*;
+import meta::pure::executionPlan::*;
+import meta::relational::tests::*;
+import meta::relational::tests::model::simple::*;
+import meta::pure::runtime::*;
+import meta::pure::mapping::modelToModel::test::shared::src::*;
+import meta::pure::graphFetch::executionPlan::*;
+import meta::pure::graphFetch::routing::*;
+import meta::pure::functions::collection::*;
+import meta::pure::executionPlan::tests::SparkSQL::*;
+
+function <> meta::pure::executionPlan::tests::sparkSQL::testFilterEqualsWithOptionalParameter_SparkSQL():Boolean[1]
+{
+ let expectedPlan ='Sequence\n'+
+ '(\n'+
+ ' type = TDS[(Time, Integer, INT, "")]\n'+
+ ' (\n'+
+ ' FunctionParametersValidationNode\n'+
+ ' (\n'+
+ ' functionParameters = [optionalID:String[0..1], optionalActive:Boolean[0..1]]\n'+
+ ' )\n'+
+ ' Relational\n'+
+ ' (\n'+
+ ' type = TDS[(Time, Integer, INT, "")]\n'+
+ ' resultColumns = [("Time", INT)]\n'+
+ ' sql = select "root"."time" as "Time" from interactionTable as "root" where ((${optionalVarPlaceHolderOperationSelector(optionalID![], \'"root".ID = ${varPlaceHolderToString(optionalID![] "\\\'" "\\\'" {"\\\'" : "\\\'\\\'"} "null")}\', \'"root".ID is null\')}) and (${optionalVarPlaceHolderOperationSelector(optionalActive![], \'case when "root"."active" = \\\'Y\\\' then \\\'true\\\' else \\\'false\\\' end = ${varPlaceHolderToString(optionalActive![] "\\\'" "\\\'" {} "null")}\', \'case when "root"."active" = \\\'Y\\\' then \\\'true\\\' else \\\'false\\\' end is null\')}))\n'+
+ ' connection = DatabaseConnection(type = "SparkSQL")\n'+
+ ' )\n'+
+ ' )\n'+
+ ')\n';
+ assertPlanGenerationForOptionalParameter(DatabaseType.SparkSQL, $expectedPlan);
+}
+
+function <> meta::pure::executionPlan::tests::sparkSQL::testGreaterThanLessThanEqualsWithOptionalParameter_SparkSQL():Boolean[1]
+{
+ let func = {optionalAgeLowerLimit: Integer[0..1], optionalAgeHigherLimit: Integer[0..1]|Person.all()->filter(p|$p.age>$optionalAgeLowerLimit && ($p.age<=$optionalAgeHigherLimit))->project(col(a|$a.firstName, 'firstName'))};
+ let expectedPlan ='Sequence\n'+
+ '(\n'+
+ ' type = TDS[(firstName, String, VARCHAR(200), "")]\n'+
+ ' (\n'+
+ ' FunctionParametersValidationNode\n'+
+ ' (\n'+
+ ' functionParameters = [optionalAgeLowerLimit:Integer[0..1], optionalAgeHigherLimit:Integer[0..1]]\n'+
+ ' )\n'+
+ ' Relational\n'+
+ ' (\n'+
+ ' type = TDS[(firstName, String, VARCHAR(200), "")]\n'+
+ ' resultColumns = [("firstName", VARCHAR(200))]\n'+
+ ' sql = select "root".FIRSTNAME as "firstName" from personTable as "root" where ((("root".AGE is not null and ${varPlaceHolderToString(optionalAgeLowerLimit![] "" "" {} "null")} is not null) and "root".AGE > ${varPlaceHolderToString(optionalAgeLowerLimit![] "" "" {} "null")}) and (("root".AGE is not null and ${varPlaceHolderToString(optionalAgeHigherLimit![] "" "" {} "null")} is not null) and "root".AGE <= ${varPlaceHolderToString(optionalAgeHigherLimit![] "" "" {} "null")}))\n'+
+ ' connection = DatabaseConnection(type = "SparkSQL")\n'+
+ ' )\n'+
+ ' )\n'+
+ ')\n';
+ assertPlanGenerationForOptionalParameterWithGreaterThanLessThan($func, DatabaseType.SparkSQL, $expectedPlan);
+}
\ No newline at end of file
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sparksql/legend-engine-xt-relationalStore-sparksql-pure/src/main/resources/core_relational_sparksql/relational/sqlQueryToString/sparkSQLExtension.pure b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sparksql/legend-engine-xt-relationalStore-sparksql-pure/src/main/resources/core_relational_sparksql/relational/sqlQueryToString/sparkSQLExtension.pure
new file mode 100644
index 00000000000..a14c2f8aad0
--- /dev/null
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sparksql/legend-engine-xt-relationalStore-sparksql-pure/src/main/resources/core_relational_sparksql/relational/sqlQueryToString/sparkSQLExtension.pure
@@ -0,0 +1,654 @@
+import meta::relational::metamodel::*;
+import meta::relational::functions::sqlQueryToString::sparkSQL::*;
+import meta::relational::functions::sqlQueryToString::default::*;
+import meta::relational::functions::sqlQueryToString::*;
+import meta::relational::metamodel::operation::*;
+import meta::relational::metamodel::relation::*;
+import meta::relational::runtime::*;
+import meta::pure::extension::*;
+import meta::relational::extension::*;
+
+function <> meta::relational::functions::sqlQueryToString::sparkSQL::dbExtensionLoaderForSparkSQL():DbExtensionLoader[1]
+{
+ ^DbExtensionLoader(dbType = DatabaseType.SparkSQL, loader = createDbExtensionForSparkSQL__DbExtension_1_);
+}
+
+function <> meta::relational::functions::sqlQueryToString::sparkSQL::createDbExtensionForSparkSQL():DbExtension[1]
+{
+ let reservedWords = sybaseReservedWords();
+ let literalProcessors = getDefaultLiteralProcessors()->putAll(getLiteralProcessorsForSparkSQL());
+ let literalProcessor = {type:Type[1]| $literalProcessors->get(if($type->instanceOf(Enumeration), | Enum, | $type))->toOne()};
+ let dynaFuncDispatch = getDynaFunctionToSqlDefault($literalProcessor)->groupBy(d| $d.funcName)->putAll(
+ getDynaFunctionToSqlForSparkSQL()->groupBy(d| $d.funcName))->getDynaFunctionDispatcher();
+
+ ^DbExtension(
+ isBooleanLiteralSupported = false,
+ collectionThresholdLimit = 250000,
+ aliasLimit = 255,
+ isDbReservedIdentifier = {str:String[1]| $str->in($reservedWords)},
+ literalProcessor = $literalProcessor,
+ windowColumnProcessor = processWindowColumn_WindowColumn_1__SqlGenerationContext_1__String_1_,
+ joinStringsProcessor = processJoinStringsOperationForSparkSQL_JoinStrings_1__SqlGenerationContext_1__String_1_,
+ selectSQLQueryProcessor = processSelectSQLQueryForSparkSQL_SelectSQLQuery_1__SqlGenerationContext_1__Boolean_1__String_1_,
+ columnNameToIdentifier = columnNameToIdentifierForSparkSQL_String_1__DbConfig_1__String_1_,
+ identifierProcessor = processIdentifierWithDoubleQuotes_String_1__DbConfig_1__String_1_,
+ dynaFuncDispatch = $dynaFuncDispatch,
+ ddlCommandsTranslator = getDDLCommandsTranslator(),
+ processTempTableName = processTempTableNameDefault_String_1__String_1_
+ );
+}
+
+function meta::relational::functions::sqlQueryToString::sparkSQL::getDDLCommandsTranslator(): RelationalDDLCommandsTranslator[1]
+{
+ ^RelationalDDLCommandsTranslator(
+ createSchema = translateCreateSchemaStatementDefault_CreateSchemaSQL_1__DbConfig_1__String_1_,
+ dropSchema = translateDropSchemaStatementDefault_DropSchemaSQL_1__DbConfig_1__String_1_,
+ createTable = translateCreateTableStatementForSparkSQL_CreateTableSQL_1__DbConfig_1__String_1_,
+ dropTable = translateDropTableStatementDefault_DropTableSQL_1__DbConfig_1__String_1_,
+ loadTable = loadValuesToDbTableForSparkSQL_LoadTableSQL_1__DbConfig_1__String_MANY_
+ );
+}
+
+function <> meta::relational::functions::sqlQueryToString::sparkSQL::getLiteralProcessorsForSparkSQL():Map[1]
+{
+ newMap([
+ pair(StrictDate, ^LiteralProcessor(format = 'convert(DATE, \'%s\', 121)', transform = {d:StrictDate[1], dbTimeZone:String[0..1] | $d->convertDateToSqlString($dbTimeZone)})),
+ pair(DateTime, ^LiteralProcessor(format = 'convert(DATETIME, \'%s\', 121)', transform = {d:DateTime[1], dbTimeZone:String[0..1] | $d->convertDateToSqlString($dbTimeZone)})),
+ pair(Date, ^LiteralProcessor(format = 'convert(DATETIME, \'%s\', 121)', transform = {d:Date[1], dbTimeZone:String[0..1] | $d->convertDateToSqlString($dbTimeZone)}))
+ ])
+}
+
+function <> meta::relational::functions::sqlQueryToString::sparkSQL::getDynaFunctionToSqlForSparkSQL(): DynaFunctionToSql[*]
+{
+ let allStates = allGenerationStates();
+
+ [
+ dynaFnToSql('contains', $allStates, ^ToSql(format=likePattern('%%%s%%'), transform={p:String[2]|$p->transformLikeParamsForSparkSQL()})),
+ dynaFnToSql('dateDiff', $allStates, ^ToSql(format='datediff(%s,%s,%s)', transform={p:String[*]|[$p->at(2)->replace('\'', '')->processDateDiffDurationUnitForSparkSQL(),$p->at(0),$p->at(1)]})),
+ dynaFnToSql('datePart', $allStates, ^ToSql(format='date(%s)')),
+ dynaFnToSql('endsWith', $allStates, ^ToSql(format=likePattern('%%%s'), transform={p:String[2]|$p->transformLikeParamsForSparkSQL()})),
+ dynaFnToSql('isAlphaNumeric', $allStates, ^ToSql(format=likePatternWithoutEscape('%%%s%%'), transform={p:String[1]|$p->transformAlphaNumericParamsForSparkSQL()})),
+ dynaFnToSql('startsWith', $allStates, ^ToSql(format=likePattern('%s%%'), transform={p:String[2]|$p->transformLikeParamsForSparkSQL()}))
+ ]->concatenate(getDynaFunctionToSqlCommonToBothSybases());
+}
+
+function meta::relational::functions::sqlQueryToString::sparkSQL::getDynaFunctionToSqlCommonToBothSybases(): DynaFunctionToSql[*]
+{
+ let allStates = allGenerationStates();
+ let selectOutsideWhen = selectOutsideWhenGenerationState();
+ let notSelectOutsideWhen = notSelectOutsideWhenGenerationStates();
+
+ [
+ dynaFnToSql('adjust', $allStates, ^ToSql(format='dateadd(%s)', transform={p:String[3] | $p->at(2)->mapToDBUnitType() + ', ' + $p->at(1) + ', ' + $p->at(0)})),
+ dynaFnToSql('atan2', $allStates, ^ToSql(format='atan2(%s,%s)')),
+ dynaFnToSql('char', $allStates, ^ToSql(format='char(%s)')),
+ dynaFnToSql('concat', $allStates, ^ToSql(format='%s', transform={p:String[*]|$p->joinStrings(' + ')})),
+ dynaFnToSql('convertDate', $allStates, ^ToSql(format='%s', transform={p:String[*] | $p->convertToDateIQ()})),
+ dynaFnToSql('convertDateTime', $allStates, ^ToSql(format='%s' , transform={p:String[*] | $p->convertToDateTimeIQ()})),
+ dynaFnToSql('convertVarchar128', $allStates, ^ToSql(format='convert(VARCHAR(128), %s)')),
+ dynaFnToSql('dayOfMonth', $allStates, ^ToSql(format='datepart(DAY,%s)')),
+ dynaFnToSql('dayOfWeek', $allStates, ^ToSql(format='datename(WEEKDAY,%s)')),
+ dynaFnToSql('dayOfWeekNumber', $allStates, ^ToSql(format='%s',transform={p:String[1..2]| if($p->size()==1,| 'datepart(Weekday,'+ $p->at(0)+')',|$p->dayOfWeekNumberSparkSQL());})),
+ dynaFnToSql('dayOfYear', $allStates, ^ToSql(format='datepart(DAYOFYEAR,%s)')),
+ dynaFnToSql('firstDayOfMonth', $allStates, ^ToSql(format='dateadd(DAY, -(day(%s) - 1), %s)', transform={p:String[1] | $p->repeat(2)})),
+ dynaFnToSql('firstDayOfQuarter', $allStates, ^ToSql(format='dateadd(QUARTER, quarter(%s) - 1, dateadd(DAY, -(datepart(dayofyear, %s) - 1), %s))', transform={p:String[1] | $p->repeat(3)})),
+ dynaFnToSql('firstDayOfThisMonth', $allStates, ^ToSql(format='dateadd(DAY, -(day(today()) - 1), today())%s', transform={p:String[*] | ''})),
+ dynaFnToSql('firstDayOfThisQuarter', $allStates, ^ToSql(format='dateadd(QUARTER, quarter(today()) - 1, dateadd(DAY, -(datepart(dayofyear, today()) - 1), today()))%s', transform={p:String[*] | ''})),
+ dynaFnToSql('firstDayOfThisYear', $allStates, ^ToSql(format='dateadd(DAY, -(datepart(dayofyear, today()) - 1), today())%s', transform={p:String[*] | ''})),
+ dynaFnToSql('firstDayOfWeek', $allStates, ^ToSql(format='dateadd(DAY, -(mod(datepart(weekday, %s)+5, 7)), %s)', transform={p:String[1] | $p->repeat(2)})),
+ dynaFnToSql('firstDayOfYear', $allStates, ^ToSql(format='dateadd(DAY, -(datepart(dayofyear, %s) - 1), %s)', transform={p:String[1] | $p->repeat(2)})),
+ dynaFnToSql('firstHourOfDay', $allStates, ^ToSql(format='datetime(date(%s))')),
+ dynaFnToSql('firstMillisecondOfSecond', $allStates, ^ToSql(format='dateadd(microsecond, -(datepart(microsecond, %s)), %s)', transform={p:String[1] | $p->repeat(2)})),
+ dynaFnToSql('firstMinuteOfHour', $allStates, ^ToSql(format='dateadd(hour, datepart(hour, %s), date(%s))', transform={p:String[1] | $p->repeat(2)})),
+ dynaFnToSql('firstSecondOfMinute', $allStates, ^ToSql(format='dateadd(minute, datepart(minute, %s), dateadd(hour, datepart(hour, %s), date(%s)))', transform={p:String[1] | $p->repeat(3)})),
+ dynaFnToSql('hour', $allStates, ^ToSql(format='hour(%s)')),
+ dynaFnToSql('indexOf', $allStates, ^ToSql(format='LOCATE(%s)', transform={p:String[2] | $p->at(0) + ', ' + $p->at(1)})),
+ dynaFnToSql('isEmpty', $selectOutsideWhen, ^ToSql(format='case when (%s is null) then \'true\' else \'false\' end', parametersWithinWhenClause=true)),
+ dynaFnToSql('isEmpty', $notSelectOutsideWhen, ^ToSql(format='%s is null')),
+ dynaFnToSql('isNotEmpty', $selectOutsideWhen, ^ToSql(format='case when (%s is not null) then \'true\' else \'false\' end', parametersWithinWhenClause=true)),
+ dynaFnToSql('isNotEmpty', $notSelectOutsideWhen, ^ToSql(format='%s is not null')),
+ dynaFnToSql('isNotNull', $selectOutsideWhen, ^ToSql(format='case when (%s is not null) then \'true\' else \'false\' end', parametersWithinWhenClause=true)),
+ dynaFnToSql('isNotNull', $notSelectOutsideWhen, ^ToSql(format='%s is not null')),
+ dynaFnToSql('isNull', $selectOutsideWhen, ^ToSql(format='case when (%s is null) then \'true\' else \'false\' end', parametersWithinWhenClause=true)),
+ dynaFnToSql('isNull', $notSelectOutsideWhen, ^ToSql(format='%s is null')),
+ dynaFnToSql('isNumeric', $allStates, ^ToSql(format='isnumeric(%s)')),
+ dynaFnToSql('joinStrings', $allStates, ^ToSql(format='list(%s,%s)')),
+ dynaFnToSql('left', $allStates, ^ToSql(format='left(%s,%s)')),
+ dynaFnToSql('length', $allStates, ^ToSql(format='char_length(%s)')),
+ dynaFnToSql('matches', $allStates, ^ToSql(format=regexpPattern('%s'), transform={p:String[2]|$p->transformRegexpParams()})),
+ dynaFnToSql('md5', $allStates, ^ToSql(format='hash(%s, \'MD5\')')),
+ dynaFnToSql('minute', $allStates, ^ToSql(format='minute(%s)')),
+ dynaFnToSql('mod', $allStates, ^ToSql(format='mod(%s,%s)')),
+ dynaFnToSql('month', $allStates, ^ToSql(format='month(%s)')),
+ dynaFnToSql('monthNumber', $allStates, ^ToSql(format='month(%s)')),
+ dynaFnToSql('mostRecentDayOfWeek', $allStates, ^ToSql(format='dateadd(Day, case when %s - dow(%s) > 0 then %s - dow(%s) - 7 else %s - dow(%s) end, %s)', transform={p:String[1..2] | $p->formatMostRecentSybase('today()')}, parametersWithinWhenClause = [false, false])),
+ dynaFnToSql('now', $allStates, ^ToSql(format='now(%s)', transform={p:String[*] | ''})),
+ dynaFnToSql('parseDate', $allStates, ^ToSql(format='%s', transform={p:String[*] | if( $p->size()==1,|'cast('+$p->at(0)+' as timestamp)' ,|'convert( datetime,'+ $p->at(0)+','+$p->at(1)+')' )})),
+ dynaFnToSql('parseDecimal', $allStates, ^ToSql(format='cast(%s as decimal)')),
+ dynaFnToSql('parseFloat', $allStates, ^ToSql(format='cast(%s as float)')),
+ dynaFnToSql('parseInteger', $allStates, ^ToSql(format='cast(%s as integer)')),
+ dynaFnToSql('position', $allStates, ^ToSql(format='charindex(%s, %s)')),
+ dynaFnToSql('previousDayOfWeek', $allStates, ^ToSql(format='dateadd(DAY, case when %s - dow(%s) >= 0 then %s - dow(%s) - 7 else %s - dow(%s) end, %s)', transform={p:String[1..2] | $p->formatMostRecentSybase('today()')}, parametersWithinWhenClause = [false, false])),
+ dynaFnToSql('quarter', $allStates, ^ToSql(format='quarter(%s)')),
+ dynaFnToSql('quarterNumber', $allStates, ^ToSql(format='quarter(%s)')),
+ dynaFnToSql('rem', $allStates, ^ToSql(format='mod(%s,%s)')),
+ dynaFnToSql('right', $allStates, ^ToSql(format='right(%s,%s)')),
+ dynaFnToSql('round', $allStates, ^ToSql(format='round(%s, %s)', transform=transformRound_String_MANY__String_MANY_)),
+ dynaFnToSql('second', $allStates, ^ToSql(format='second(%s)')),
+ dynaFnToSql('sha1', $allStates, ^ToSql(format='hash(%s, \'SHA1\')')),
+ dynaFnToSql('sha256', $allStates, ^ToSql(format='hash(%s, \'SHA256\')')),
+ dynaFnToSql('substring', $allStates, ^ToSql(format='substring%s', transform={p:String[*]|$p->joinStrings('(', ', ', ')')})),
+ dynaFnToSql('stdDevPopulation', $allStates, ^ToSql(format='stddev_pop(%s)')),
+ dynaFnToSql('stdDevSample', $allStates, ^ToSql(format='stddev_samp(%s)')),
+ dynaFnToSql('today', $allStates, ^ToSql(format='today(%s)', transform={p:String[*] | ''})),
+ dynaFnToSql('toDecimal', $allStates, ^ToSql(format='cast(%s as decimal)')),
+ dynaFnToSql('toFloat', $allStates, ^ToSql(format='cast(%s as double)')),
+ dynaFnToSql('toString', $allStates, ^ToSql(format='cast(%s as varchar)')),
+ dynaFnToSql('toTimestamp', $allStates, ^ToSql(format='%s', transform={p:String[2] | $p->transformToTimestampSparkSQL()})),
+ dynaFnToSql('weekOfYear', $allStates, ^ToSql(format='datepart(WEEK,%s)')),
+ dynaFnToSql('year', $allStates, ^ToSql(format='year(%s)'))
+ ];
+}
+
+function <> meta::relational::functions::sqlQueryToString::sparkSQL::convertToDateIQ(params:String[*]):String[1]
+{
+ $params->convertDateFunctionHasCorrectParams();
+ let dateFormat = if( $params->size() == 1,| 120,| dateFormats()->get($params->at(1)->replace('\'', ''))->toOne(););
+ if ($dateFormat == 106,
+ |'convert ( date,(\'01 \' + ' + 'substring(' + $params->at(0) + ',1,3)' + ' + \' \' + ' + 'substring(' + $params->at(0) + ',4,4))' + ',' + $dateFormat->toString() + ')',
+ |'convert ( date,'+$params->at(0)+','+$dateFormat->toString() +')';);
+}
+
+function <> meta::relational::functions::sqlQueryToString::sparkSQL::transformLikeParamsForSparkSQL(params: String[2]):String[*]
+{
+ let likeExpression = $params->at(1)->removeQuotes()->escapeLikeExprForSparkSQL();
+ $params->at(0)
+ ->concatenate($likeExpression)
+ ->concatenate(likeEscapeClauseForSparkSQL($likeExpression));
+}
+
+function <> meta::relational::functions::sqlQueryToString::sparkSQL::likeEscapeClauseForSparkSQL(expr: String[1]):String[*]
+{
+ if($expr->contains('\\'),
+ |' escape \'\\\'',
+ |'');
+}
+
+function <> meta::relational::functions::sqlQueryToString::sparkSQL::escapeLikeExprForSparkSQL(query: String[1]):String[1]
+{
+ // Escaping references...
+ // Sybase IQ: http://infocenter.sybase.com/help/index.jsp?topic=/com.sybase.infocenter.dc38151.1520/html/iqrefbb/CACGCGGC.htm
+
+ $query
+ ->replace('_', '\\_')
+ ->replace('%', '\\%')
+ ->replace('[', '\\[');
+}
+
+function <> meta::relational::functions::sqlQueryToString::sparkSQL::convertToDateTimeIQ(params:String[*]):String[1]
+{
+ $params->convertDateTimeFunctionHasCorrectParams();
+ let dateTimeFormat = if( $params->size() == 1,| 120 ,| dateTimeFormats()->get($params->at(1)->replace('\'', ''))->toOne(););
+ //http://infocenter.sybase.com/help/index.jsp?topic=/com.sybase.infocenter.dc38151.1520/html/iqrefbb/Dateformat.htm
+ 'convert( timestamp,'+$params->at(0)+','+$dateTimeFormat->toString() +')';
+}
+
+function <> meta::relational::functions::sqlQueryToString::sparkSQL::transformToTimestampSparkSQL(params:String[2]):String[1]
+{
+ // Temporarily revert functionality to handle scenarios that have date string of the format yyyyMMdd
+ 'cast('+$params->at(0)+' as timestamp)';
+
+ //Standardizing the format as per Postgres specification, will include mappings for the formats in future.
+ // assert($params->at(1)->replace('\'', '') == 'YYYY-MM-DD HH24:MI:SS', | $params->at(1) +' not supported ');
+ // let timestampFormat = 121;
+ // 'convert(datetime,'+$params->at(0)+','+$timestampFormat->toString() +')';
+}
+
+function <> meta::relational::functions::sqlQueryToString::sparkSQL::formatMostRecentSybase(p:String[1..2], defaultDay:String[1]):String[*]
+{
+ let day = $p->last()->toOne()->mapToDBDayOfWeekNumber()->toString();
+ let current = if ($p->size() == 2, | $p->first()->toOne(), | $defaultDay);
+ [$day, $current, $day, $current, $day, $current, $current];
+}
+
+function <> meta::relational::functions::sqlQueryToString::sparkSQL::processDateDiffDurationUnitForSparkSQL(durationUnit:String[1]):String[1]
+{
+ let durationEnumNames = [DurationUnit.YEARS,DurationUnit.MONTHS,DurationUnit.WEEKS,DurationUnit.DAYS,DurationUnit.HOURS,DurationUnit.MINUTES,DurationUnit.SECONDS,DurationUnit.MILLISECONDS]->map(e|$e->toString());
+ let durationDbNames = ['yy', 'mm', 'wk', 'dd', 'hh', 'mi', 'ss', 'ms'];
+ $durationEnumNames->zip($durationDbNames)->filter(h | $h.first == $durationUnit).second->toOne();
+}
+
+function <> meta::relational::functions::sqlQueryToString::sparkSQL::transformAlphaNumericParamsForSparkSQL(params: String[1]):String[*]
+{
+ let param = '\'[^a-zA-Z0-9]\'';
+ let expression = $param->removeQuotes();
+ $params->at(0)->concatenate($expression);
+}
+
+function <> meta::relational::functions::sqlQueryToString::sparkSQL::processJoinStringsOperationForSparkSQL(js:JoinStrings[1], sgc:SqlGenerationContext[1]): String[1]
+{
+ processJoinStringsOperation($js, $sgc, {col, sep| 'list(' + $col + ',' + $sep + ' )'}, {strs, sep| $strs->joinStrings(if('\'\'' == $sep, |'+', |'+' + $sep + '+'))});
+}
+
+function <> meta::relational::functions::sqlQueryToString::sparkSQL::processSelectSQLQueryForSparkSQL(s:SelectSQLQuery[1], sgc:SqlGenerationContext[1], isSubSelect:Boolean[1]):String[1]
+{
+ $s->processSelectSQLQueryForSparkSQL($sgc.dbConfig, $sgc.format, $sgc.config, $isSubSelect, $sgc.extensions);
+}
+
+function <> meta::relational::functions::sqlQueryToString::sparkSQL::processSelectSQLQueryForSparkSQL(sq:SelectSQLQuery[1], dbConfig : DbConfig[1], format:Format[1], config:Config[1], isSubSelect : Boolean[1], extensions:Extension[*]):String[1]
+{
+ // Sybase IQ does not support limit / offset in a subselect, so we need to adjust it, e.g.
+ // select * from (select top 10 "root".id as "ID" from trades as "root" ) as x
+ // gives
+ // SQL Anywhere Error -1001030: Feature, TOP/FIRST/LIMIT in a view, is not supported.
+ // but instead needs to be
+ // select * from (select "limitoffset_via_window_subquery"."ID" as "ID" from (select "root".id as "ID", row_number() OVER (Order By "root".id) as "row_number" from trades as "root")
+ // as "limitoffset_via_window_subquery" where "limitoffset_via_window_subquery".row_number < 10) as x
+ // Also see https://www.jooq.org/doc/3.1/manual/sql-building/sql-statements/select-statement/limit-clause/#N467C4
+
+ let s = if($isSubSelect && ($sq.fromRow->isNotEmpty() || $sq.toRow->isNotEmpty()), |$sq->rewriteSliceAsWindowFunction(), |$sq);
+ let opStr = if($s.filteringOperation->isEmpty(), |'', |$s.filteringOperation->map(s|$s->wrapAsBooleanOperation($extensions)->processOperation($dbConfig, $format->indent(), ^$config(callingFromFilter = true), $extensions))->filter(s|$s != '')->joinStrings(' <||> '));
+ let havingStr = if($s.havingOperation->isEmpty(), |'', |$s.havingOperation->map(s|$s->processOperation($dbConfig, $format->indent(), $config, $extensions))->filter(s|$s != '')->joinStrings(' <||> '));
+
+ $format.separator + 'select ' + if($s.distinct == true,|'distinct ',|'') + processTop($s, $format, $dbConfig, $extensions) +
+ processSelectColumns($s.columns, $dbConfig, $format->indent(), false, $extensions) +
+ if ($s.data == [],|'',| ' ' + $format.separator + 'from ' + $s.data->toOne()->processJoinTreeNode([], $dbConfig, $format->indent(), [], $extensions)) +
+ if (eq($opStr, ''), |'', | ' ' + $format.separator + 'where ' + $opStr) +
+ if ($s.groupBy->isEmpty(),|'',| ' ' + $format.separator + 'group by '+$s.groupBy->processGroupByColumns($dbConfig, $format->indent(), true, $extensions)->makeString(','))+
+ if (eq($havingStr, ''), |'', | ' ' + $format.separator + 'having ' + $havingStr) +
+ if ($s.orderBy->isEmpty(),|'',| ' ' + $format.separator + 'order by '+ $s.orderBy->processOrderBy($dbConfig, $format->indent(), $config, $extensions)->makeString(','))+
+ + processLimit($s, $dbConfig, $format, $extensions, [], processSliceOrDropForSparkSQL_SelectSQLQuery_1__Format_1__DbConfig_1__Extension_MANY__Any_1__String_1_);
+}
+
+function <> meta::relational::functions::sqlQueryToString::sparkSQL::processSliceOrDropForSparkSQL(s:SelectSQLQuery[1], format:Format[1], dbConfig : DbConfig[1], extensions:Extension[*], size:Any[1]):String[1]
+{
+ // queries where specifying query with "limit 100,1000" would return 1100 rows.
+ // However when a order by column is specified, the expected number of rows is returned (i.e. 900 rows).
+ // Given that a slice without an order is largely meaningless, we'll simply report an error (rather than trying to simulate something)
+ //
+ // http://infocenter.sybase.com/help/index.jsp?topic=/com.sybase.infocenter.dc00801.1601/doc/html/san1281564978024.html
+
+ assert($s.orderBy->isNotEmpty(), | 'SparkSQL requires an order by column for meaningful limit/offset');
+ '%s limit %s,%s'->format([$format.separator, $s.fromRow->toOne()->getValueForTake($format, $dbConfig, $extensions), $size]);
+}
+
+function <> meta::relational::functions::sqlQueryToString::sparkSQL::columnNameToIdentifierForSparkSQL(columnName: String[1], dbConfig: DbConfig[1]): String[1]
+{
+ if($dbConfig.isDbReservedIdentifier($columnName->toLower()), |'"' + $columnName->toLower() + '"', |$columnName->quoteIdentifierDefault());
+}
+
+function <> meta::relational::functions::sqlQueryToString::sparkSQL::dayOfWeekNumberSparkSQL(dayOfWeek: String[*]):String[1]
+{
+ let day = if(startsWith($dayOfWeek->at(1),'\''),|$dayOfWeek->at(1)->removeQuotes(),|$dayOfWeek->at(1));
+ assert(or($day == 'Sunday',$day == 'Monday'),'DayOfWeekNumber Function requires either Sunday or Monday as First Day of Week');
+ if($day =='Sunday',|'datepart(Weekday,'+$dayOfWeek->at(0)+')',|'mod (datepart(weekday,'+$dayOfWeek->at(0)+')+5,7)+1');
+}
+
+function meta::relational::functions::sqlQueryToString::sparkSQL::translateCreateTableStatementForSparkSQL(c:CreateTableSQL[1], dbConfig: DbConfig[1]): String[1]
+{
+ let columns = $c.table.columns->map(r|$r->match([c:Column[1]| '[' + $c.name->processColumnName($dbConfig) + '] ' + $c.type->getColumnTypeSqlTextDefault(),
+ r:RelationalOperationElement[1]| fail('Only \'Column\' types are supported when creating temporary tables, found: '+$r->type()->toOne()->elementToPath());'';]));
+
+ if($c.isTempTable->isTrue(),| 'DECLARE LOCAL TEMPORARY TABLE ' + $c.table->tableToString($dbConfig) + '('+ $columns->joinStrings(',') + ') ON COMMIT PRESERVE ROWS'
+ ,| $c->meta::relational::functions::sqlQueryToString::default::translateCreateTableStatementDefault($dbConfig));
+
+}
+
+function meta::relational::functions::sqlQueryToString::sparkSQL::loadValuesToDbTableForSparkSQL(l:LoadTableSQL[1], dbConfig: DbConfig[1]): String[*]
+{
+ let columns = $l.table.columns->map(r|$r->match([c:Column[1]| $c.name->toOne(),
+ r:RelationalOperationElement[1]| fail('Only \'Column\' types are supported when creating temporary tables, found: '+$r->type()->toOne()->elementToPath());'';]));
+
+ if($l.absolutePathToFile->isNotEmpty(),| 'load table ' + $l.table->tableToString($dbConfig) +'( '+ $columns->map(c|'['+$c + '] null(blanks)')->joinStrings(',') + ' ) USING CLIENT FILE \'' + $l.absolutePathToFile->toOne()->processOperation($dbConfig.dbType, []) + '\' FORMAT BCP \nwith checkpoint on \nquotes on \nescapes off \ndelimited by \',\' \nROW DELIMITED BY \'\r\n\'';
+
+ ,| $l->meta::relational::functions::sqlQueryToString::default::loadValuesToDbTableDefault($dbConfig));
+}
+
+function <> meta::relational::functions::sqlQueryToString::sparkSQL::sybaseReservedWords():String[*]
+{
+ //Based on
+ // http://infocenter.sybase.com/help/index.jsp?topic=/com.sybase.infocenter.dc38151.1510/html/iqrefbb/Alhakeywords.htm
+ // and
+ // http://infocenter.sybase.com/help/index.jsp?topic=/com.sybase.infocenter.dc38151.1601/doc/html/san1278452828146.html
+
+ [
+ 'active',
+ 'add',
+ 'algorithm',
+ 'all',
+ 'alter',
+ 'and',
+ 'any',
+ 'append',
+ 'array',
+ 'as',
+ 'asc',
+ 'attach',
+ 'auto',
+ 'backup',
+ 'begin',
+ 'between',
+ 'bigint',
+ 'binary',
+ 'bit',
+ 'bottom',
+ 'break',
+ 'by',
+ 'calibrate',
+ 'calibration',
+ 'call',
+ 'cancel',
+ 'capability',
+ 'cascade',
+ 'case',
+ 'cast',
+ 'certificate',
+ 'char',
+ 'char_convert',
+ 'character',
+ 'check',
+ 'checkpoint',
+ 'checksum',
+ 'clientport',
+ 'close',
+ 'columns',
+ 'comment',
+ 'commit',
+ 'committed',
+ 'comparisons',
+ 'compressed',
+ 'computes',
+ 'conflict',
+ 'connect',
+ 'constraint',
+ 'contains',
+ 'continue',
+ 'convert',
+ 'create',
+ 'cross',
+ 'cube',
+ 'current',
+ 'current_timestamp',
+ 'current_user',
+ 'cursor',
+ 'date',
+ 'datetimeoffset',
+ 'dbspace',
+ 'dbspacename',
+ 'deallocate',
+ 'debug',
+ 'dec',
+ 'decimal',
+ 'declare',
+ 'decoupled',
+ 'decrypted',
+ 'default',
+ 'delay',
+ 'delete',
+ 'deleting',
+ 'density',
+ 'desc',
+ 'detach',
+ 'deterministic',
+ 'disable',
+ 'distinct',
+ 'do',
+ 'double',
+ 'drop',
+ 'dynamic',
+ 'elements',
+ 'else',
+ 'elseif',
+ 'enable',
+ 'encapsulated',
+ 'encrypted',
+ 'end',
+ 'endif',
+ 'escape',
+ 'except',
+ 'exception',
+ 'exclude',
+ 'exec',
+ 'execute',
+ 'existing',
+ 'exists',
+ 'explicit',
+ 'express',
+ 'externlogin',
+ 'fastfirstrow',
+ 'fetch',
+ 'first',
+ 'float',
+ 'following',
+ 'for',
+ 'force',
+ 'foreign',
+ 'forward',
+ 'from',
+ 'full',
+ 'gb',
+ 'goto',
+ 'grant',
+ 'group',
+ 'grouping',
+ 'having',
+ 'hidden',
+ 'history',
+ 'holdlock',
+ 'identified',
+ 'if',
+ 'in',
+ 'inactive',
+ 'index',
+ 'index_lparen',
+ 'inner',
+ 'inout',
+ 'input',
+ 'insensitive',
+ 'insert',
+ 'inserting',
+ 'install',
+ 'instead',
+ 'int',
+ 'integer',
+ 'integrated',
+ 'intersect',
+ 'into',
+ 'iq',
+ 'is',
+ 'isolation',
+ 'jdk',
+ 'join',
+ 'json',
+ 'kb',
+ 'kerberos',
+ 'key',
+ 'lateral',
+ 'left',
+ 'like',
+ 'limit',
+ 'lock',
+ 'logging',
+ 'login',
+ 'long',
+ 'match',
+ 'mb',
+ 'membership',
+ 'merge',
+ 'message',
+ 'mode',
+ 'modify',
+ 'namespace',
+ 'natural',
+ 'nchar',
+ 'new',
+ 'no',
+ 'noholdlock',
+ 'nolock',
+ 'not',
+ 'notify',
+ 'null',
+ 'numeric',
+ 'nvarchar',
+ 'of',
+ 'off',
+ 'on',
+ 'open',
+ 'openstring',
+ 'openxml',
+ 'optimization',
+ 'option',
+ 'options',
+ 'or',
+ 'order',
+ 'others',
+ 'out',
+ 'outer',
+ 'over',
+ 'pages',
+ 'paglock',
+ 'partial',
+ 'partition',
+ 'passthrough',
+ 'password',
+ 'plan',
+ 'preceding',
+ 'precision',
+ 'prepare',
+ 'primary',
+ 'print',
+ 'privileges',
+ 'proc',
+ 'procedure',
+ 'proxy',
+ 'publication',
+ 'raiserror',
+ 'range',
+ 'raw',
+ 'readcommitted',
+ 'readonly',
+ 'readpast',
+ 'readtext',
+ 'readuncommitted',
+ 'readwrite',
+ 'real',
+ 'recursive',
+ 'reference',
+ 'references',
+ 'refresh',
+ 'release',
+ 'relocate',
+ 'remote',
+ 'remove',
+ 'rename',
+ 'reorganize',
+ 'repeatable',
+ 'repeatableread',
+ 'reserve',
+ 'resizing',
+ 'resource',
+ 'restore',
+ 'restrict',
+ 'return',
+ 'revoke',
+ 'right',
+ 'rollback',
+ 'rollup',
+ 'root',
+ 'row',
+ 'rowlock',
+ 'rows',
+ 'rowtype',
+ 'save',
+ 'savepoint',
+ 'schedule',
+ 'scroll',
+ 'secure',
+ 'select',
+ 'sensitive',
+ 'serializable',
+ 'service',
+ 'session',
+ 'set',
+ 'setuser',
+ 'share',
+ 'smallint',
+ 'soapaction',
+ 'some',
+ 'space',
+ 'spatial',
+ 'sqlcode',
+ 'sqlstate',
+ 'start',
+ 'stop',
+ 'subtrans',
+ 'subtransaction',
+ 'synchronize',
+ 'syntax_error',
+ 'table',
+ 'tablock',
+ 'tablockx',
+ 'tb',
+ 'temporary',
+ 'then',
+ 'ties',
+ 'time',
+ 'timestamp',
+ 'tinyint',
+ 'to',
+ 'top',
+ 'tran',
+ 'transaction',
+ 'transactional',
+ 'transfer',
+ 'treat',
+ 'tries',
+ 'trigger',
+ 'truncate',
+ 'tsequal',
+ 'unbounded',
+ 'uncommitted',
+ 'union',
+ 'unique',
+ 'uniqueidentifier',
+ 'unknown',
+ 'unnest',
+ 'unsigned',
+ 'update',
+ 'updating',
+ 'updlock',
+ 'url',
+ 'user',
+ 'using',
+ 'utc',
+ 'validate',
+ 'values',
+ 'varbinary',
+ 'varbit',
+ 'varchar',
+ 'variable',
+ 'varray',
+ 'varying',
+ 'view',
+ 'virtual',
+ 'wait',
+ 'waitfor',
+ 'web',
+ 'when',
+ 'where',
+ 'while',
+ 'window',
+ 'with',
+ 'with_cube',
+ 'with_lparen',
+ 'with_rollup',
+ 'withauto',
+ 'within',
+ 'word',
+ 'work',
+ 'writeserver',
+ 'writetext',
+ 'xlock',
+ 'xml'
+ ]
+}
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sparksql/legend-engine-xt-relationalStore-sparksql-pure/src/main/resources/core_relational_sparksql/relational/sqlQueryToString/tests/testSparkSQLToSQLString.pure b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sparksql/legend-engine-xt-relationalStore-sparksql-pure/src/main/resources/core_relational_sparksql/relational/sqlQueryToString/tests/testSparkSQLToSQLString.pure
new file mode 100644
index 00000000000..53baa3649a6
--- /dev/null
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sparksql/legend-engine-xt-relationalStore-sparksql-pure/src/main/resources/core_relational_sparksql/relational/sqlQueryToString/tests/testSparkSQLToSQLString.pure
@@ -0,0 +1,45 @@
+// Copyright 2023 Goldman Sachs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import meta::relational::tests::functions::sqlstring::*;
+import meta::pure::mapping::*;
+import meta::relational::functions::asserts::*;
+import meta::relational::mapping::*;
+import meta::relational::tests::*;
+import meta::relational::tests::model::simple::*;
+import meta::pure::profiles::*;
+import meta::relational::functions::sqlstring::*;
+import meta::relational::runtime::*;
+
+function <> meta::relational::tests::functions::sqlstring::sparkSQL::testProcessLiteralForSpark():Boolean[1]
+{
+ let result = toSQLString(|Person.all()->project([
+ a | 'String',
+ b | %2016-03-01,
+ c | %2016-03-01T12:18:18.976+0200,
+ d | 1,
+ e | 1.1
+ ],
+ ['a','b','c','d', 'e'])->take(0),
+ simpleRelationalMapping, DatabaseType.SparkSQL, meta::relational::extension::relationalExtensions());
+ assertEquals('select top 0 \'String\' as "a", convert(DATE, \'2016-03-01\', 121) as "b", convert(DATETIME, \'2016-03-01 10:18:18.976\', 121) as "c", 1 as "d", 1.1 as "e" from personTable as "root"', $result);
+}
+
+function <> meta::relational::tests::functions::sqlstring::sparkSQL::testToSQLStringWithLength():Boolean[1]
+{
+ [DatabaseType.SparkSQL]->map(db|
+ let s = toSQLString(|Person.all()->project(p|length($p.firstName), 'nameLength'), simpleRelationalMapping, $db, meta::relational::extension::relationalExtensions());
+ assertEquals('select char_length("root".FIRSTNAME) as "nameLength" from personTable as "root"', $s);
+ );
+}
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sparksql/legend-engine-xt-relationalStore-sparksql-pure/src/test/java/org/finos/legend/pure/code/core/Test_Pure_Relational_SparkSQL.java b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sparksql/legend-engine-xt-relationalStore-sparksql-pure/src/test/java/org/finos/legend/pure/code/core/Test_Pure_Relational_SparkSQL.java
new file mode 100644
index 00000000000..c729562435f
--- /dev/null
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sparksql/legend-engine-xt-relationalStore-sparksql-pure/src/test/java/org/finos/legend/pure/code/core/Test_Pure_Relational_SparkSQL.java
@@ -0,0 +1,35 @@
+// Copyright 2023 Goldman Sachs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.finos.legend.pure.code.core;
+
+import junit.framework.TestSuite;
+import org.finos.legend.pure.m3.execution.test.PureTestBuilder;
+import org.finos.legend.pure.runtime.java.compiled.testHelper.PureTestBuilderCompiled;
+import org.finos.legend.pure.m3.execution.test.TestCollection;
+import org.finos.legend.pure.runtime.java.compiled.execution.CompiledExecutionSupport;
+
+public class Test_Pure_Relational_SparkSQL
+{
+ public static TestSuite suite()
+ {
+ CompiledExecutionSupport executionSupport = PureTestBuilderCompiled.getClassLoaderExecutionSupport();
+ executionSupport.getConsole().disable();
+ TestSuite suite = new TestSuite();
+
+ suite.addTest(PureTestBuilderCompiled.buildSuite(TestCollection.collectTests("meta::pure::executionPlan::tests::sparkSQL", executionSupport.getProcessorSupport(), fn -> PureTestBuilderCompiled.generatePureTestCollection(fn, executionSupport), ci -> PureTestBuilder.satisfiesConditions(ci, executionSupport.getProcessorSupport())), executionSupport));
+ suite.addTest(PureTestBuilderCompiled.buildSuite(TestCollection.collectTests("meta::relational::tests::functions::sqlstring::sparkSQL", executionSupport.getProcessorSupport(), fn -> PureTestBuilderCompiled.generatePureTestCollection(fn, executionSupport), ci -> PureTestBuilder.satisfiesConditions(ci, executionSupport.getProcessorSupport())), executionSupport));
+ return suite;
+ }
+}
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sparksql/legend-engine-xt-relationalStore-sparksql-pure/src/test/java/org/finos/legend/pure/code/core/test/TestSparkSQLCodeRepositoryProviderAvailable.java b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sparksql/legend-engine-xt-relationalStore-sparksql-pure/src/test/java/org/finos/legend/pure/code/core/test/TestSparkSQLCodeRepositoryProviderAvailable.java
new file mode 100644
index 00000000000..a127f31c56e
--- /dev/null
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sparksql/legend-engine-xt-relationalStore-sparksql-pure/src/test/java/org/finos/legend/pure/code/core/test/TestSparkSQLCodeRepositoryProviderAvailable.java
@@ -0,0 +1,36 @@
+// Copyright 2023 Goldman Sachs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.finos.legend.pure.code.core.test;
+
+import org.eclipse.collections.api.list.MutableList;
+import org.eclipse.collections.impl.factory.Lists;
+import org.finos.legend.pure.code.core.CoreRelationalSparkSQLCodeRepositoryProvider;
+import org.finos.legend.pure.m3.serialization.filesystem.repository.CodeRepositoryProvider;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.ServiceLoader;
+
+public class TestSparkSQLCodeRepositoryProviderAvailable
+{
+ @Test
+ public void testCodeRepositoryProviderAvailable()
+ {
+ MutableList> codeRepositoryProviders =
+ Lists.mutable.withAll(ServiceLoader.load(CodeRepositoryProvider.class))
+ .collect(Object::getClass);
+ Assert.assertTrue(codeRepositoryProviders.contains(CoreRelationalSparkSQLCodeRepositoryProvider.class));
+ }
+}
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sparksql/pom.xml b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sparksql/pom.xml
new file mode 100644
index 00000000000..40505c3634c
--- /dev/null
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sparksql/pom.xml
@@ -0,0 +1,34 @@
+
+
+
+
+ org.finos.legend.engine
+ legend-engine-xt-relationalStore-dbExtension
+ 4.29.2-SNAPSHOT
+
+ 4.0.0
+
+ legend-engine-xt-relationalStore-sparksql
+ pom
+ Legend Engine - XT - Relational Store - DB Extension - sparksql
+
+
+
+ legend-engine-xt-relationalStore-sparksql-pure
+
+
+
\ No newline at end of file
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/pom.xml b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/pom.xml
index 3e8f7643639..60ac6ba1b38 100644
--- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/pom.xml
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/pom.xml
@@ -41,6 +41,7 @@
legend-engine-xt-relationalStore-hive
legend-engine-xt-relationalStore-presto
legend-engine-xt-relationalStore-databricks
+ legend-engine-xt-relationalStore-sparksql
legend-engine-xt-relationalStore-test-reports
diff --git a/pom.xml b/pom.xml
index dc0dd3e1d23..33a34a50769 100644
--- a/pom.xml
+++ b/pom.xml
@@ -967,6 +967,11 @@
legend-engine-xt-relationalStore-sybaseiq-pure
${project.version}
+
+ org.finos.legend.engine
+ legend-engine-xt-relationalStore-sparksql-pure
+ ${project.version}
+
org.finos.legend.engine
legend-engine-xt-relationalStore-hive-pure
From 2eb7c83719d6feb40db7bced0c1ad12e9698bd6f Mon Sep 17 00:00:00 2001
From: An Phi
Date: Mon, 2 Oct 2023 09:29:07 -0400
Subject: [PATCH 03/26] connection manager: cleanups (#2332)
* connman: address review in #2323
* connman: tidy up connection builder interface
* connman: improve immutability
* connman: cleanup ConnectionFactory
* connman: cleanup
---
.../pom.xml | 19 ---
.../test/AbstractConnectionFactoryTest.java | 21 +--
.../test/TestPostgresConnection.java | 6 +-
.../test/TestSnowflakeConnection.java | 14 +-
.../AuthenticationMechanismLoader.java | 24 ----
.../AuthenticationMechanismProvider.java | 24 ----
.../legend/connection/Authenticator.java | 19 ++-
.../legend/connection/ConnectionBuilder.java | 9 +-
.../legend/connection/ConnectionFactory.java | 132 +++++-------------
.../legend/connection/CredentialBuilder.java | 4 +-
.../connection/CredentialExtractor.java | 42 ------
.../DefaultAuthenticationMechanismLoader.java | 30 ----
...efaultAuthenticationMechanismProvider.java | 29 ----
.../DefaultConnectionBuilderProvider.java | 29 ----
.../DefaultCredentialBuilderProvider.java | 29 ----
.../DefaultStoreInstanceProvider.java | 89 ++++++++++++
.../legend/connection/IdentityFactory.java | 14 +-
.../InstrumentedLegendEnvironment.java | 64 +++++++++
.../InstrumentedStoreInstanceProvider.java | 43 ++++++
...figuration.java => LegendEnvironment.java} | 70 +++-------
.../legend/connection/StoreInstance.java | 35 +++--
...ovider.java => StoreInstanceProvider.java} | 6 +-
.../finos/legend/connection/StoreSupport.java | 14 +-
.../impl/KerberosCredentialExtractor.java | 18 ++-
.../impl/KeyPairCredentialBuilder.java | 8 +-
.../impl/UserPasswordCredentialBuilder.java | 6 +-
.../protocol/AuthenticationMechanism.java | 2 -
...d.connection.AuthenticationMechanismLoader | 1 -
....finos.legend.connection.CredentialBuilder | 2 -
.../connection/ConnectionFactoryTest.java | 110 +++++++--------
...onTest.java => LegendEnvironmentTest.java} | 8 +-
.../legend/connection/StoreSupportTest.java | 49 ++++++-
.../server/ConnectionFactoryBundle.java | 29 ++--
.../jdbc/JDBCConnectionManager.java | 2 +-
.../jdbc/StaticJDBCConnectionBuilder.java | 3 +-
.../StaticJDBCConnectionSpecification.java | 2 -
.../impl/SnowflakeConnectionBuilder.java | 4 +-
....finos.legend.connection.ConnectionBuilder | 1 -
38 files changed, 473 insertions(+), 538 deletions(-)
delete mode 100644 legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/AuthenticationMechanismLoader.java
delete mode 100644 legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/AuthenticationMechanismProvider.java
delete mode 100644 legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/CredentialExtractor.java
delete mode 100644 legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/DefaultAuthenticationMechanismLoader.java
delete mode 100644 legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/DefaultAuthenticationMechanismProvider.java
delete mode 100644 legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/DefaultConnectionBuilderProvider.java
delete mode 100644 legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/DefaultCredentialBuilderProvider.java
create mode 100644 legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/DefaultStoreInstanceProvider.java
create mode 100644 legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/InstrumentedLegendEnvironment.java
create mode 100644 legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/InstrumentedStoreInstanceProvider.java
rename legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/{EnvironmentConfiguration.java => LegendEnvironment.java} (69%)
rename legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/{CredentialBuilderProvider.java => StoreInstanceProvider.java} (85%)
delete mode 100644 legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/resources/META-INF/services/org.finos.legend.connection.AuthenticationMechanismLoader
delete mode 100644 legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/resources/META-INF/services/org.finos.legend.connection.CredentialBuilder
rename legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/test/java/org/finos/legend/connection/{EnvironmentConfigurationTest.java => LegendEnvironmentTest.java} (96%)
delete mode 100644 legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-snowflake/legend-engine-xt-relationalStore-snowflake-connection/src/main/resources/META-INF/services/org.finos.legend.connection.ConnectionBuilder
diff --git a/legend-engine-config/legend-engine-connection-integration-tests/pom.xml b/legend-engine-config/legend-engine-connection-integration-tests/pom.xml
index 6953e8a064b..06744106c48 100644
--- a/legend-engine-config/legend-engine-connection-integration-tests/pom.xml
+++ b/legend-engine-config/legend-engine-connection-integration-tests/pom.xml
@@ -74,26 +74,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- junit
- junit
- test
-
org.junit.jupiter
junit-jupiter-api
diff --git a/legend-engine-config/legend-engine-connection-integration-tests/src/test/java/org/finos/legend/engine/connection/test/AbstractConnectionFactoryTest.java b/legend-engine-config/legend-engine-connection-integration-tests/src/test/java/org/finos/legend/engine/connection/test/AbstractConnectionFactoryTest.java
index 880898bb024..a72de8a4250 100644
--- a/legend-engine-config/legend-engine-connection-integration-tests/src/test/java/org/finos/legend/engine/connection/test/AbstractConnectionFactoryTest.java
+++ b/legend-engine-config/legend-engine-connection-integration-tests/src/test/java/org/finos/legend/engine/connection/test/AbstractConnectionFactoryTest.java
@@ -20,9 +20,10 @@
import org.finos.legend.connection.Authenticator;
import org.finos.legend.connection.ConnectionFactory;
import org.finos.legend.connection.DatabaseType;
-import org.finos.legend.connection.EnvironmentConfiguration;
import org.finos.legend.connection.IdentityFactory;
import org.finos.legend.connection.IdentitySpecification;
+import org.finos.legend.connection.InstrumentedStoreInstanceProvider;
+import org.finos.legend.connection.LegendEnvironment;
import org.finos.legend.connection.RelationalDatabaseStoreSupport;
import org.finos.legend.connection.StoreInstance;
import org.finos.legend.connection.impl.KerberosCredentialExtractor;
@@ -41,8 +42,9 @@ public abstract class AbstractConnectionFactoryTest
{
protected static final String TEST_STORE_INSTANCE_NAME = "test-store";
- protected EnvironmentConfiguration environmentConfiguration;
+ protected LegendEnvironment environment;
protected IdentityFactory identityFactory;
+ protected InstrumentedStoreInstanceProvider storeInstanceProvider;
protected ConnectionFactory connectionFactory;
@BeforeEach
@@ -50,7 +52,7 @@ public void initialize()
{
this.setup();
- EnvironmentConfiguration.Builder environmentConfigurationBuilder = new EnvironmentConfiguration.Builder()
+ LegendEnvironment.Builder environmentBuilder = new LegendEnvironment.Builder()
.withVaults(
new SystemPropertiesCredentialVault(),
new EnvironmentCredentialVault()
@@ -82,15 +84,16 @@ public void initialize()
CredentialVault credentialVault = this.getCredentialVault();
if (credentialVault != null)
{
- environmentConfigurationBuilder.withVault(credentialVault);
+ environmentBuilder.withVault(credentialVault);
}
- this.environmentConfiguration = environmentConfigurationBuilder.build();
+ this.environment = environmentBuilder.build();
- this.identityFactory = new IdentityFactory.Builder(environmentConfiguration)
+ this.identityFactory = new IdentityFactory.Builder(this.environment)
.build();
- this.connectionFactory = new ConnectionFactory.Builder(environmentConfiguration)
+ this.storeInstanceProvider = new InstrumentedStoreInstanceProvider();
+ this.connectionFactory = new ConnectionFactory.Builder(this.environment, this.storeInstanceProvider)
.withCredentialBuilders(
new KerberosCredentialExtractor(),
new UserPasswordCredentialBuilder(),
@@ -129,12 +132,12 @@ public CredentialVault getCredentialVault()
@Test
public void runTest() throws Exception
{
- this.connectionFactory.injectStoreInstance(this.getStoreInstance());
+ this.storeInstanceProvider.injectStoreInstance(this.getStoreInstance());
Identity identity = this.getIdentity();
AuthenticationConfiguration authenticationConfiguration = this.getAuthenticationConfiguration();
Authenticator authenticator = this.connectionFactory.getAuthenticator(identity, TEST_STORE_INSTANCE_NAME, authenticationConfiguration);
- T connection = this.connectionFactory.getConnection(authenticator);
+ T connection = this.connectionFactory.getConnection(identity, authenticator);
this.runTestWithConnection(connection);
System.out.println("Successfully established and checked connection!");
diff --git a/legend-engine-config/legend-engine-connection-integration-tests/src/test/java/org/finos/legend/engine/connection/test/TestPostgresConnection.java b/legend-engine-config/legend-engine-connection-integration-tests/src/test/java/org/finos/legend/engine/connection/test/TestPostgresConnection.java
index 1f92986d3e6..eef783ac898 100644
--- a/legend-engine-config/legend-engine-connection-integration-tests/src/test/java/org/finos/legend/engine/connection/test/TestPostgresConnection.java
+++ b/legend-engine-config/legend-engine-connection-integration-tests/src/test/java/org/finos/legend/engine/connection/test/TestPostgresConnection.java
@@ -30,7 +30,7 @@
import java.sql.Statement;
import java.util.Properties;
-import static org.junit.Assume.assumeTrue;
+import static org.junit.jupiter.api.Assumptions.assumeTrue;
public class TestPostgresConnection
{
@@ -48,7 +48,7 @@ public void setup()
}
catch (Exception e)
{
- assumeTrue("Can't start PostgreSQLContainer", false);
+ assumeTrue(false, "Can't start PostgreSQLContainer");
}
}
@@ -77,7 +77,7 @@ public StoreInstance getStoreInstance()
this.postgresContainer.getPort(),
this.postgresContainer.getDatabaseName()
);
- return new StoreInstance.Builder(this.environmentConfiguration)
+ return new StoreInstance.Builder(this.environment)
.withIdentifier(TEST_STORE_INSTANCE_NAME)
.withStoreSupportIdentifier("Postgres")
.withAuthenticationMechanisms(
diff --git a/legend-engine-config/legend-engine-connection-integration-tests/src/test/java/org/finos/legend/engine/connection/test/TestSnowflakeConnection.java b/legend-engine-config/legend-engine-connection-integration-tests/src/test/java/org/finos/legend/engine/connection/test/TestSnowflakeConnection.java
index 2d522ff96d8..c95604ba9c6 100644
--- a/legend-engine-config/legend-engine-connection-integration-tests/src/test/java/org/finos/legend/engine/connection/test/TestSnowflakeConnection.java
+++ b/legend-engine-config/legend-engine-connection-integration-tests/src/test/java/org/finos/legend/engine/connection/test/TestSnowflakeConnection.java
@@ -29,14 +29,14 @@
import java.sql.Statement;
import java.util.Properties;
-import static org.junit.Assume.assumeTrue;
+import static org.junit.jupiter.api.Assumptions.assumeTrue;
public class TestSnowflakeConnection
{
public static class WithKeyPair extends AbstractConnectionFactoryTest
{
- private static final String TEST_SNOWFLAKE_PK = "TEST_SNOWFLAKE_PK";
- private static final String TEST_SNOWFLAKE_PK_PASSPHRASE = "TEST_SNOWFLAKE_PK_PASSPHRASE";
+ private static final String CONNECTION_INTEGRATION_TEST__SNOWFLAKE_PK = "CONNECTION_INTEGRATION_TEST__SNOWFLAKE_PK";
+ private static final String CONNECTION_INTEGRATION_TEST__SNOWFLAKE_PK_PASSPHRASE = "CONNECTION_INTEGRATION_TEST__SNOWFLAKE_PK_PASSPHRASE";
private String snowflakePrivateKey;
private String snowflakePassPhrase;
@@ -45,12 +45,12 @@ public void setup()
{
try
{
- this.snowflakePrivateKey = this.environmentConfiguration.lookupVaultSecret(new EnvironmentCredentialVaultSecret(TEST_SNOWFLAKE_PK), null);
- this.snowflakePassPhrase = this.environmentConfiguration.lookupVaultSecret(new EnvironmentCredentialVaultSecret(TEST_SNOWFLAKE_PK_PASSPHRASE), null);
+ this.snowflakePrivateKey = this.environment.lookupVaultSecret(new EnvironmentCredentialVaultSecret(CONNECTION_INTEGRATION_TEST__SNOWFLAKE_PK), null);
+ this.snowflakePassPhrase = this.environment.lookupVaultSecret(new EnvironmentCredentialVaultSecret(CONNECTION_INTEGRATION_TEST__SNOWFLAKE_PK_PASSPHRASE), null);
}
catch (Exception e)
{
- assumeTrue("Can't retrieve Snowflake test instance key-pair info (TEST_SNOWFLAKE_PK, TEST_SNOWFLAKE_PK_PASSPHRASE)", false);
+ assumeTrue(false, String.format("Can't retrieve Snowflake connection key-pair info (%s, %s environment variables are expected)", CONNECTION_INTEGRATION_TEST__SNOWFLAKE_PK, CONNECTION_INTEGRATION_TEST__SNOWFLAKE_PK_PASSPHRASE));
}
}
@@ -79,7 +79,7 @@ public StoreInstance getStoreInstance()
connectionSpecification.region = "us-east-2";
connectionSpecification.cloudType = "aws";
connectionSpecification.role = "SUMMIT_DEV";
- return new StoreInstance.Builder(this.environmentConfiguration)
+ return new StoreInstance.Builder(this.environment)
.withIdentifier(TEST_STORE_INSTANCE_NAME)
.withStoreSupportIdentifier("Snowflake")
.withAuthenticationMechanisms(
diff --git a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/AuthenticationMechanismLoader.java b/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/AuthenticationMechanismLoader.java
deleted file mode 100644
index 377d2aa4656..00000000000
--- a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/AuthenticationMechanismLoader.java
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2023 Goldman Sachs
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package org.finos.legend.connection;
-
-import org.finos.legend.connection.protocol.AuthenticationMechanism;
-
-import java.util.List;
-
-public interface AuthenticationMechanismLoader
-{
- List getMechanisms();
-}
diff --git a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/AuthenticationMechanismProvider.java b/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/AuthenticationMechanismProvider.java
deleted file mode 100644
index d9ad6a7195e..00000000000
--- a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/AuthenticationMechanismProvider.java
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2023 Goldman Sachs
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package org.finos.legend.connection;
-
-import org.finos.legend.connection.protocol.AuthenticationMechanism;
-
-import java.util.List;
-
-public interface AuthenticationMechanismProvider
-{
- List getLoaders();
-}
diff --git a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/Authenticator.java b/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/Authenticator.java
index 85120be4ab4..71b949b1b80 100644
--- a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/Authenticator.java
+++ b/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/Authenticator.java
@@ -14,6 +14,8 @@
package org.finos.legend.connection;
+import org.eclipse.collections.api.factory.Lists;
+import org.eclipse.collections.api.list.ImmutableList;
import org.finos.legend.connection.protocol.AuthenticationConfiguration;
import org.finos.legend.engine.shared.core.identity.Credential;
import org.finos.legend.engine.shared.core.identity.Identity;
@@ -23,31 +25,28 @@
public class Authenticator
{
- private final Identity identity;
private final StoreInstance storeInstance;
private final AuthenticationConfiguration authenticationConfiguration;
private final Class extends Credential> sourceCredentialType;
-
- private final List credentialBuilders;
+ private final ImmutableList credentialBuilders;
private final ConnectionBuilder connectionBuilder;
- public Authenticator(Identity identity, StoreInstance storeInstance, AuthenticationConfiguration authenticationConfiguration, Class extends Credential> sourceCredentialType, List credentialBuilders, ConnectionBuilder connectionBuilder)
+ public Authenticator(StoreInstance storeInstance, AuthenticationConfiguration authenticationConfiguration, Class extends Credential> sourceCredentialType, List credentialBuilders, ConnectionBuilder connectionBuilder)
{
- this.identity = identity;
this.storeInstance = storeInstance;
this.authenticationConfiguration = authenticationConfiguration;
this.sourceCredentialType = sourceCredentialType;
- this.credentialBuilders = credentialBuilders;
+ this.credentialBuilders = Lists.immutable.withAll(credentialBuilders);
this.connectionBuilder = connectionBuilder;
}
- public Credential makeCredential(EnvironmentConfiguration configuration) throws Exception
+ public Credential makeCredential(Identity identity, LegendEnvironment environment) throws Exception
{
Credential credential = null;
// no need to resolve the source credential if the flow starts with generic `Credential` node
if (!this.sourceCredentialType.equals(Credential.class))
{
- Optional credentialOptional = this.identity.getCredential((Class) this.sourceCredentialType);
+ Optional credentialOptional = identity.getCredential((Class) this.sourceCredentialType);
if (!credentialOptional.isPresent())
{
throw new RuntimeException(String.format("Can't resolve source credential of type '%s' from the specified identity", this.sourceCredentialType.getSimpleName()));
@@ -59,7 +58,7 @@ public Credential makeCredential(EnvironmentConfiguration configuration) throws
}
for (CredentialBuilder credentialBuilder : this.credentialBuilders)
{
- credential = credentialBuilder.makeCredential(this.identity, this.authenticationConfiguration, credential, configuration);
+ credential = credentialBuilder.makeCredential(identity, this.authenticationConfiguration, credential, environment);
}
return credential;
}
@@ -79,7 +78,7 @@ public Class extends Credential> getSourceCredentialType()
return sourceCredentialType;
}
- public List getCredentialBuilders()
+ public ImmutableList getCredentialBuilders()
{
return credentialBuilders;
}
diff --git a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/ConnectionBuilder.java b/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/ConnectionBuilder.java
index 2119dd37648..276c9d7a8af 100644
--- a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/ConnectionBuilder.java
+++ b/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/ConnectionBuilder.java
@@ -21,9 +21,9 @@
import java.lang.reflect.Type;
import java.util.Objects;
-public abstract class ConnectionBuilder
+public abstract class ConnectionBuilder
{
- public abstract T getConnection(CRED credential, SPEC connectionSpecification, StoreInstance storeInstance) throws Exception;
+ public abstract CONNECTION getConnection(StoreInstance storeInstance, CRED credential) throws Exception;
public Class extends Credential> getCredentialType()
{
@@ -42,6 +42,11 @@ private Type[] actualTypeArguments()
return parameterizedType.getActualTypeArguments();
}
+ protected SPEC getCompatibleConnectionSpecification(StoreInstance storeInstance)
+ {
+ return (SPEC) storeInstance.getConnectionSpecification(this.getConnectionSpecificationType());
+ }
+
public static class Key
{
private final Class extends ConnectionSpecification> connectionSpecificationType;
diff --git a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/ConnectionFactory.java b/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/ConnectionFactory.java
index 4f9a88dde27..c90f266b041 100644
--- a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/ConnectionFactory.java
+++ b/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/ConnectionFactory.java
@@ -15,7 +15,6 @@
package org.finos.legend.connection;
import org.eclipse.collections.api.factory.Lists;
-import org.eclipse.collections.impl.utility.ListIterate;
import org.finos.legend.connection.protocol.AuthenticationConfiguration;
import org.finos.legend.connection.protocol.AuthenticationMechanism;
import org.finos.legend.connection.protocol.ConnectionSpecification;
@@ -39,14 +38,15 @@
public class ConnectionFactory
{
- private final EnvironmentConfiguration environmentConfiguration;
+ private final LegendEnvironment environment;
+ private final StoreInstanceProvider storeInstanceProvider;
private final Map credentialBuildersIndex = new LinkedHashMap<>();
private final Map connectionBuildersIndex = new LinkedHashMap<>();
- private final Map storeInstancesIndex;
- private ConnectionFactory(EnvironmentConfiguration environmentConfiguration, List credentialBuilders, List connectionBuilders, Map storeInstancesIndex)
+ private ConnectionFactory(LegendEnvironment environment, StoreInstanceProvider storeInstanceProvider, List credentialBuilders, List connectionBuilders)
{
- this.environmentConfiguration = environmentConfiguration;
+ this.environment = environment;
+ this.storeInstanceProvider = storeInstanceProvider;
for (ConnectionBuilder, ?, ?> builder : connectionBuilders)
{
this.connectionBuildersIndex.put(new ConnectionBuilder.Key(builder.getConnectionSpecificationType(), builder.getCredentialType()), builder);
@@ -55,35 +55,16 @@ private ConnectionFactory(EnvironmentConfiguration environmentConfiguration, Lis
{
this.credentialBuildersIndex.put(new CredentialBuilder.Key(builder.getAuthenticationConfigurationType(), builder.getInputCredentialType(), builder.getOutputCredentialType()), builder);
}
- this.storeInstancesIndex = storeInstancesIndex;
- }
-
- /**
- * This method is meant for testing.
- * The recommended usage is to include all the store instances during initialization
- */
- public void injectStoreInstance(StoreInstance storeInstance)
- {
- if (this.storeInstancesIndex.containsKey(storeInstance.getIdentifier()))
- {
- throw new RuntimeException(String.format("Can't register store instance: found multiple store instances with identifier '%s'", storeInstance.getIdentifier()));
- }
- this.storeInstancesIndex.put(storeInstance.getIdentifier(), storeInstance);
- }
-
- private StoreInstance findStoreInstance(String identifier)
- {
- return Objects.requireNonNull(this.storeInstancesIndex.get(identifier), String.format("Can't find store instance with identifier '%s'", identifier));
}
public Authenticator getAuthenticator(Identity identity, String storeInstanceIdentifier, AuthenticationConfiguration authenticationConfiguration)
{
- return this.getAuthenticator(identity, this.findStoreInstance(storeInstanceIdentifier), authenticationConfiguration);
+ return this.getAuthenticator(identity, this.storeInstanceProvider.lookup(storeInstanceIdentifier), authenticationConfiguration);
}
public Authenticator getAuthenticator(Identity identity, StoreInstance storeInstance, AuthenticationConfiguration authenticationConfiguration)
{
- AuthenticationMechanism authenticationMechanism = environmentConfiguration.findAuthenticationMechanismForConfiguration(authenticationConfiguration);
+ AuthenticationMechanism authenticationMechanism = environment.findAuthenticationMechanismForConfiguration(authenticationConfiguration);
String authenticationMechanismLabel = authenticationMechanism != null ? ("authentication mechanism '" + authenticationMechanism.getLabel() + "'") : ("authentication mechanism with configuration '" + authenticationConfiguration.getClass().getSimpleName() + "'");
if (!storeInstance.getAuthenticationConfigurationTypes().contains(authenticationConfiguration.getClass()))
{
@@ -103,24 +84,24 @@ public Authenticator getAuthenticator(Identity identity, StoreInstance storeInst
storeInstance.getConnectionSpecification().getClass().getSimpleName())
);
}
- return new Authenticator(identity, storeInstance, authenticationConfiguration, result.sourceCredentialType, result.flow, connectionBuildersIndex.get(new ConnectionBuilder.Key(storeInstance.getConnectionSpecification().getClass(), result.targetCredentialType)));
+ return new Authenticator(storeInstance, authenticationConfiguration, result.sourceCredentialType, result.flow, connectionBuildersIndex.get(new ConnectionBuilder.Key(storeInstance.getConnectionSpecification().getClass(), result.targetCredentialType)));
}
public Authenticator getAuthenticator(Identity identity, String storeInstanceIdentifier)
{
- return this.getAuthenticator(identity, this.findStoreInstance(storeInstanceIdentifier));
+ return this.getAuthenticator(identity, this.storeInstanceProvider.lookup(storeInstanceIdentifier));
}
public Authenticator getAuthenticator(Identity identity, StoreInstance storeInstance)
{
- List authenticationConfigurations = ListIterate.collect(storeInstance.getAuthenticationMechanisms(), AuthenticationMechanism::generateConfiguration).select(Objects::nonNull);
+ List authenticationConfigurations = storeInstance.getAuthenticationMechanisms().toList().collect(AuthenticationMechanism::generateConfiguration).select(Objects::nonNull);
Authenticator authenticator = null;
for (AuthenticationConfiguration authenticationConfiguration : authenticationConfigurations)
{
AuthenticationFlowResolver.ResolutionResult result = AuthenticationFlowResolver.run(this.credentialBuildersIndex, this.connectionBuildersIndex, identity, authenticationConfiguration, storeInstance.getConnectionSpecification());
if (result != null)
{
- authenticator = new Authenticator(identity, storeInstance, authenticationConfiguration, result.sourceCredentialType, result.flow, connectionBuildersIndex.get(new ConnectionBuilder.Key(storeInstance.getConnectionSpecification().getClass(), result.targetCredentialType)));
+ authenticator = new Authenticator(storeInstance, authenticationConfiguration, result.sourceCredentialType, result.flow, connectionBuildersIndex.get(new ConnectionBuilder.Key(storeInstance.getConnectionSpecification().getClass(), result.targetCredentialType)));
break;
}
}
@@ -128,7 +109,7 @@ public Authenticator getAuthenticator(Identity identity, StoreInstance storeInst
{
throw new RuntimeException(String.format("Can't get authenticator: no authentication flow for store '%s' can be resolved for the specified identity using auto-generated authentication configuration. Try specifying an authentication mechanism by providing a configuration of one of the following types:\n%s",
storeInstance.getIdentifier(),
- ListIterate.select(storeInstance.getAuthenticationMechanisms(), mechanism -> mechanism.generateConfiguration() == null).collect(mechanism -> "- " + mechanism.getAuthenticationConfigurationType().getSimpleName() + " (mechanism: " + mechanism.getLabel() + ")").makeString("\n")
+ storeInstance.getAuthenticationMechanisms().select(mechanism -> mechanism.generateConfiguration() == null).collect(mechanism -> "- " + mechanism.getAuthenticationConfigurationType().getSimpleName() + " (mechanism: " + mechanism.getLabel() + ")").makeString("\n")
));
}
return authenticator;
@@ -177,7 +158,7 @@ private AuthenticationFlowResolver(Map
.filter(builder -> builder.getAuthenticationConfigurationType().equals(authenticationConfiguration.getClass()))
.forEach(builder ->
{
- if (!(builder instanceof CredentialExtractor))
+ if (!(builder.getInputCredentialType().equals(builder.getOutputCredentialType())))
{
this.processEdge(new FlowNode(builder.getInputCredentialType()), new FlowNode(builder.getOutputCredentialType()));
}
@@ -362,131 +343,92 @@ public ResolutionResult(List flow, Class extends Credential
public T getConnection(Identity identity, StoreInstance storeInstance, AuthenticationConfiguration authenticationConfiguration) throws Exception
{
- return this.getConnection(this.getAuthenticator(identity, storeInstance, authenticationConfiguration));
+ return this.getConnection(identity, this.getAuthenticator(identity, storeInstance, authenticationConfiguration));
}
public T getConnection(Identity identity, String storeInstanceIdentifier, AuthenticationConfiguration authenticationConfiguration) throws Exception
{
- return this.getConnection(this.getAuthenticator(identity, storeInstanceIdentifier, authenticationConfiguration));
+ return this.getConnection(identity, this.getAuthenticator(identity, storeInstanceIdentifier, authenticationConfiguration));
}
public T getConnection(Identity identity, StoreInstance storeInstance) throws Exception
{
- return this.getConnection(this.getAuthenticator(identity, storeInstance));
+ return this.getConnection(identity, this.getAuthenticator(identity, storeInstance));
}
public T getConnection(Identity identity, String storeInstanceIdentifier) throws Exception
{
- return this.getConnection(this.getAuthenticator(identity, storeInstanceIdentifier));
+ return this.getConnection(identity, this.getAuthenticator(identity, storeInstanceIdentifier));
}
- public T getConnection(Authenticator authenticator) throws Exception
+ public T getConnection(Identity identity, Authenticator authenticator) throws Exception
{
- Credential credential = authenticator.makeCredential(this.environmentConfiguration);
+ Credential credential = authenticator.makeCredential(identity, this.environment);
ConnectionBuilder flow = (ConnectionBuilder) authenticator.getConnectionBuilder();
- return flow.getConnection(credential, authenticator.getStoreInstance().getConnectionSpecification(), authenticator.getStoreInstance());
+ return flow.getConnection(authenticator.getStoreInstance(), credential);
}
public static class Builder
{
- private final EnvironmentConfiguration environmentConfiguration;
- private CredentialBuilderProvider credentialBuilderProvider;
- private ConnectionBuilderProvider connectionBuilderProvider;
- private final List> credentialBuilders = Lists.mutable.empty();
- private final List> connectionBuilders = Lists.mutable.empty();
- private final Map storeInstancesIndex = new HashMap<>();
-
- public Builder(EnvironmentConfiguration environmentConfiguration)
- {
- this.environmentConfiguration = environmentConfiguration;
- }
+ private final LegendEnvironment environment;
+ private final StoreInstanceProvider storeInstanceProvider;
+ private final List credentialBuilders = Lists.mutable.empty();
+ private final List connectionBuilders = Lists.mutable.empty();
- public Builder withCredentialBuilderProvider(CredentialBuilderProvider provider)
+ public Builder(LegendEnvironment environment, StoreInstanceProvider storeInstanceProvider)
{
- this.credentialBuilderProvider = provider;
- return this;
- }
-
- public Builder withConnectionBuilderProvider(ConnectionBuilderProvider provider)
- {
- this.connectionBuilderProvider = provider;
- return this;
+ this.environment = environment;
+ this.storeInstanceProvider = storeInstanceProvider;
}
- public Builder withCredentialBuilders(List> credentialBuilders)
+ public Builder withCredentialBuilders(List credentialBuilders)
{
this.credentialBuilders.addAll(credentialBuilders);
return this;
}
- public Builder withCredentialBuilders(CredentialBuilder, ?, ?>... credentialBuilders)
+ public Builder withCredentialBuilders(CredentialBuilder... credentialBuilders)
{
this.credentialBuilders.addAll(Lists.mutable.with(credentialBuilders));
return this;
}
- public Builder withCredentialBuilder(CredentialBuilder, ?, ?> credentialBuilder)
+ public Builder withCredentialBuilder(CredentialBuilder credentialBuilder)
{
this.credentialBuilders.add(credentialBuilder);
return this;
}
- public Builder withConnectionBuilders(List> connectionBuilders)
+ public Builder withConnectionBuilders(List connectionBuilders)
{
this.connectionBuilders.addAll(connectionBuilders);
return this;
}
- public Builder withConnectionBuilders(ConnectionBuilder, ?, ?>... connectionBuilders)
+ public Builder withConnectionBuilders(ConnectionBuilder... connectionBuilders)
{
this.connectionBuilders.addAll(Lists.mutable.with(connectionBuilders));
return this;
}
- public Builder withConnectionBuilder(ConnectionBuilder, ?, ?> connectionBuilder)
+ public Builder withConnectionBuilder(ConnectionBuilder connectionBuilder)
{
this.connectionBuilders.add(connectionBuilder);
return this;
}
- public Builder withStoreInstances(List storeInstances)
- {
- storeInstances.forEach(this::registerStoreInstance);
- return this;
- }
-
- public Builder withStoreInstance(StoreInstance storeInstance)
- {
- this.registerStoreInstance(storeInstance);
- return this;
- }
-
- private void registerStoreInstance(StoreInstance storeInstance)
- {
- if (this.storeInstancesIndex.containsKey(storeInstance.getIdentifier()))
- {
- throw new RuntimeException(String.format("Can't register store instance: found multiple store instances with identifier '%s'", storeInstance.getIdentifier()));
- }
- this.storeInstancesIndex.put(storeInstance.getIdentifier(), storeInstance);
- }
-
public ConnectionFactory build()
{
- List credentialBuilders = this.credentialBuilderProvider != null ? this.credentialBuilderProvider.getBuilders() : Lists.mutable.empty();
- credentialBuilders.addAll(this.credentialBuilders);
- List connectionBuilders = this.connectionBuilderProvider != null ? this.connectionBuilderProvider.getBuilders() : Lists.mutable.empty();
- connectionBuilders.addAll(this.connectionBuilders);
-
for (ConnectionManager connectionManager : ServiceLoader.load(ConnectionManager.class))
{
connectionManager.initialize();
}
return new ConnectionFactory(
- this.environmentConfiguration,
- credentialBuilders,
- connectionBuilders,
- this.storeInstancesIndex
+ this.environment,
+ this.storeInstanceProvider,
+ this.credentialBuilders,
+ this.connectionBuilders
);
}
}
diff --git a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/CredentialBuilder.java b/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/CredentialBuilder.java
index 59239f8d311..0f4726abfd7 100644
--- a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/CredentialBuilder.java
+++ b/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/CredentialBuilder.java
@@ -22,9 +22,9 @@
import java.lang.reflect.Type;
import java.util.Objects;
-public abstract class CredentialBuilder
+public abstract class CredentialBuilder
{
- public abstract OUTPUT_CRED makeCredential(Identity identity, SPEC spec, INPUT_CRED cred, EnvironmentConfiguration configuration) throws Exception;
+ public abstract OUTPUT_CRED makeCredential(Identity identity, CONFIG config, INPUT_CRED cred, LegendEnvironment environment) throws Exception;
public Class extends AuthenticationConfiguration> getAuthenticationConfigurationType()
{
diff --git a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/CredentialExtractor.java b/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/CredentialExtractor.java
deleted file mode 100644
index d21f9ea5e5f..00000000000
--- a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/CredentialExtractor.java
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2023 Goldman Sachs
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package org.finos.legend.connection;
-
-import org.finos.legend.connection.protocol.AuthenticationConfiguration;
-import org.finos.legend.engine.shared.core.identity.Credential;
-import org.finos.legend.engine.shared.core.identity.Identity;
-
-import java.util.Optional;
-
-public abstract class CredentialExtractor extends CredentialBuilder
-{
-
- @Override
- public Class extends Credential> getOutputCredentialType()
- {
- return (Class extends Credential>) actualTypeArguments()[1];
- }
-
- @Override
- public CRED makeCredential(Identity identity, SPEC spec, CRED cred, EnvironmentConfiguration configuration) throws Exception
- {
- Optional credentialOptional = identity.getCredential((Class) this.getOutputCredentialType());
- if (!credentialOptional.isPresent())
- {
- throw new RuntimeException(String.format("Can't extract credential of type '%s' from the specified identity", this.getOutputCredentialType().getSimpleName()));
- }
- return credentialOptional.get();
- }
-}
diff --git a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/DefaultAuthenticationMechanismLoader.java b/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/DefaultAuthenticationMechanismLoader.java
deleted file mode 100644
index d099129b9b5..00000000000
--- a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/DefaultAuthenticationMechanismLoader.java
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2023 Goldman Sachs
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package org.finos.legend.connection;
-
-import org.eclipse.collections.api.factory.Lists;
-import org.finos.legend.connection.protocol.AuthenticationMechanism;
-import org.finos.legend.connection.protocol.AuthenticationMechanismType;
-
-import java.util.List;
-
-public class DefaultAuthenticationMechanismLoader implements AuthenticationMechanismLoader
-{
- @Override
- public List getMechanisms()
- {
- return Lists.mutable.with(AuthenticationMechanismType.values());
- }
-}
diff --git a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/DefaultAuthenticationMechanismProvider.java b/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/DefaultAuthenticationMechanismProvider.java
deleted file mode 100644
index cc19a7b9174..00000000000
--- a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/DefaultAuthenticationMechanismProvider.java
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2023 Goldman Sachs
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package org.finos.legend.connection;
-
-import org.eclipse.collections.api.factory.Lists;
-
-import java.util.List;
-import java.util.ServiceLoader;
-
-public class DefaultAuthenticationMechanismProvider implements AuthenticationMechanismProvider
-{
- @Override
- public List getLoaders()
- {
- return Lists.mutable.withAll(ServiceLoader.load(AuthenticationMechanismLoader.class));
- }
-}
diff --git a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/DefaultConnectionBuilderProvider.java b/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/DefaultConnectionBuilderProvider.java
deleted file mode 100644
index e52a422658e..00000000000
--- a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/DefaultConnectionBuilderProvider.java
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2023 Goldman Sachs
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package org.finos.legend.connection;
-
-import org.eclipse.collections.api.factory.Lists;
-
-import java.util.List;
-import java.util.ServiceLoader;
-
-public class DefaultConnectionBuilderProvider implements ConnectionBuilderProvider
-{
- @Override
- public List getBuilders()
- {
- return Lists.mutable.withAll(ServiceLoader.load(ConnectionBuilder.class));
- }
-}
diff --git a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/DefaultCredentialBuilderProvider.java b/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/DefaultCredentialBuilderProvider.java
deleted file mode 100644
index 1d2bc6f769f..00000000000
--- a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/DefaultCredentialBuilderProvider.java
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2023 Goldman Sachs
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package org.finos.legend.connection;
-
-import org.eclipse.collections.api.factory.Lists;
-
-import java.util.List;
-import java.util.ServiceLoader;
-
-public class DefaultCredentialBuilderProvider implements CredentialBuilderProvider
-{
- @Override
- public List getBuilders()
- {
- return Lists.mutable.withAll(ServiceLoader.load(CredentialBuilder.class));
- }
-}
diff --git a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/DefaultStoreInstanceProvider.java b/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/DefaultStoreInstanceProvider.java
new file mode 100644
index 00000000000..4a914100c38
--- /dev/null
+++ b/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/DefaultStoreInstanceProvider.java
@@ -0,0 +1,89 @@
+// Copyright 2023 Goldman Sachs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.finos.legend.connection;
+
+import org.eclipse.collections.api.factory.Lists;
+import org.eclipse.collections.api.factory.Maps;
+import org.eclipse.collections.api.map.ImmutableMap;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.ServiceLoader;
+
+public class DefaultStoreInstanceProvider implements StoreInstanceProvider
+{
+ private final ImmutableMap storeInstancesIndex;
+
+ private DefaultStoreInstanceProvider(Map storeInstancesIndex)
+ {
+
+ this.storeInstancesIndex = Maps.immutable.withAll(storeInstancesIndex);
+ }
+
+ @Override
+ public StoreInstance lookup(String identifier)
+ {
+ return Objects.requireNonNull(this.storeInstancesIndex.get(identifier), String.format("Can't find store instance with identifier '%s'", identifier));
+ }
+
+ public static class Builder
+ {
+ private final Map storeInstancesIndex = new HashMap<>();
+
+ public Builder()
+ {
+
+ }
+
+ public Builder withStoreInstances(List storeInstances)
+ {
+ storeInstances.forEach(this::registerStoreInstance);
+ return this;
+ }
+
+ public Builder withStoreInstances(StoreInstance... storeInstances)
+ {
+ Lists.mutable.with(storeInstances).forEach(this::registerStoreInstance);
+ return this;
+ }
+
+ public Builder withStoreInstance(StoreInstance storeInstance)
+ {
+ this.registerStoreInstance(storeInstance);
+ return this;
+ }
+
+ private void registerStoreInstance(StoreInstance storeInstance)
+ {
+ if (this.storeInstancesIndex.containsKey(storeInstance.getIdentifier()))
+ {
+ throw new RuntimeException(String.format("Can't register store instance: found multiple store instances with identifier '%s'", storeInstance.getIdentifier()));
+ }
+ this.storeInstancesIndex.put(storeInstance.getIdentifier(), storeInstance);
+ }
+
+ public DefaultStoreInstanceProvider build()
+ {
+ for (ConnectionManager connectionManager : ServiceLoader.load(ConnectionManager.class))
+ {
+ connectionManager.initialize();
+ }
+
+ return new DefaultStoreInstanceProvider(this.storeInstancesIndex);
+ }
+ }
+}
diff --git a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/IdentityFactory.java b/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/IdentityFactory.java
index 917f3996657..206f5e61162 100644
--- a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/IdentityFactory.java
+++ b/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/IdentityFactory.java
@@ -23,11 +23,11 @@
public class IdentityFactory
{
- private final EnvironmentConfiguration environmentConfiguration;
+ private final LegendEnvironment environment;
- private IdentityFactory(EnvironmentConfiguration environmentConfiguration)
+ private IdentityFactory(LegendEnvironment environment)
{
- this.environmentConfiguration = environmentConfiguration;
+ this.environment = environment;
}
// TODO: @akphi - this clones the logic from IdentityFactoryProvider, we should
@@ -46,16 +46,16 @@ public Identity createIdentity(IdentitySpecification identitySpecification)
public static class Builder
{
- private final EnvironmentConfiguration environmentConfiguration;
+ private final LegendEnvironment environment;
- public Builder(EnvironmentConfiguration environmentConfiguration)
+ public Builder(LegendEnvironment environment)
{
- this.environmentConfiguration = environmentConfiguration;
+ this.environment = environment;
}
public IdentityFactory build()
{
- return new IdentityFactory(this.environmentConfiguration);
+ return new IdentityFactory(this.environment);
}
}
}
diff --git a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/InstrumentedLegendEnvironment.java b/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/InstrumentedLegendEnvironment.java
new file mode 100644
index 00000000000..4cb67543747
--- /dev/null
+++ b/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/InstrumentedLegendEnvironment.java
@@ -0,0 +1,64 @@
+// Copyright 2023 Goldman Sachs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.finos.legend.connection;
+
+import org.eclipse.collections.api.list.MutableList;
+import org.eclipse.collections.api.map.MutableMap;
+import org.finos.legend.authentication.vault.CredentialVault;
+import org.finos.legend.connection.protocol.AuthenticationMechanism;
+import org.finos.legend.engine.protocol.pure.v1.model.packageableElement.authentication.vault.CredentialVaultSecret;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This is the instrumented version of {@link LegendEnvironment} which is used for testing.
+ */
+public class InstrumentedLegendEnvironment extends LegendEnvironment
+{
+ protected final MutableList vaults;
+ protected final MutableMap, CredentialVault extends CredentialVaultSecret>> vaultsIndex;
+ protected final MutableMap storeSupportsIndex;
+
+ protected final MutableMap authenticationMechanismsIndex;
+
+ protected InstrumentedLegendEnvironment(List vaults, Map storeSupportsIndex, Map authenticationMechanismsIndex)
+ {
+ super(vaults, storeSupportsIndex, authenticationMechanismsIndex);
+ this.vaults = super.vaults.toList();
+ this.vaultsIndex = super.vaultsIndex.toMap();
+ this.storeSupportsIndex = super.storeSupportsIndex.toMap();
+ this.authenticationMechanismsIndex = super.authenticationMechanismsIndex.toMap();
+ }
+
+ public void injectVault(CredentialVault vault)
+ {
+ if (this.vaultsIndex.containsKey(vault.getSecretType()))
+ {
+ throw new RuntimeException(String.format("Can't register credential vault: found multiple vaults with secret type '%s'", vault.getSecretType().getSimpleName()));
+ }
+ this.vaultsIndex.put(vault.getSecretType(), vault);
+ this.vaults.add(vault);
+ }
+
+ public void injectStoreSupport(StoreSupport storeSupport)
+ {
+ if (this.storeSupportsIndex.containsKey(storeSupport.getIdentifier()))
+ {
+ throw new RuntimeException(String.format("Can't register store support: found multiple store supports with identifier '%s'", storeSupport.getIdentifier()));
+ }
+ this.storeSupportsIndex.put(storeSupport.getIdentifier(), storeSupport);
+ }
+}
diff --git a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/InstrumentedStoreInstanceProvider.java b/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/InstrumentedStoreInstanceProvider.java
new file mode 100644
index 00000000000..19314be985d
--- /dev/null
+++ b/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/InstrumentedStoreInstanceProvider.java
@@ -0,0 +1,43 @@
+// Copyright 2023 Goldman Sachs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.finos.legend.connection;
+
+import org.eclipse.collections.api.factory.Maps;
+
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * This is the instrumented version of {@link StoreInstanceProvider} which is used for testing.
+ */
+public class InstrumentedStoreInstanceProvider implements StoreInstanceProvider
+{
+ private final Map storeInstancesIndex = Maps.mutable.empty();
+
+ public void injectStoreInstance(StoreInstance storeInstance)
+ {
+ if (this.storeInstancesIndex.containsKey(storeInstance.getIdentifier()))
+ {
+ throw new RuntimeException(String.format("Can't register store instance: found multiple store instances with identifier '%s'", storeInstance.getIdentifier()));
+ }
+ this.storeInstancesIndex.put(storeInstance.getIdentifier(), storeInstance);
+ }
+
+ @Override
+ public StoreInstance lookup(String identifier)
+ {
+ return Objects.requireNonNull(this.storeInstancesIndex.get(identifier), String.format("Can't find store instance with identifier '%s'", identifier));
+ }
+}
diff --git a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/EnvironmentConfiguration.java b/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/LegendEnvironment.java
similarity index 69%
rename from legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/EnvironmentConfiguration.java
rename to legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/LegendEnvironment.java
index c43c983f909..ed3ac3d345d 100644
--- a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/EnvironmentConfiguration.java
+++ b/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/LegendEnvironment.java
@@ -15,6 +15,9 @@
package org.finos.legend.connection;
import org.eclipse.collections.api.factory.Lists;
+import org.eclipse.collections.api.list.ImmutableList;
+import org.eclipse.collections.api.map.ImmutableMap;
+import org.eclipse.collections.api.map.MutableMap;
import org.eclipse.collections.impl.factory.Maps;
import org.eclipse.collections.impl.utility.ListIterate;
import org.finos.legend.authentication.vault.CredentialVault;
@@ -31,41 +34,28 @@
import java.util.Set;
/**
- * This is meant to the place we package common configs, such as vaults,
- * that can be passed to various parts of engine, authentication, connection factory, etc.
+ * This is the runtime instance of configuration for Legend Engine, the place we package common configs,
+ * such as vaults, that can be passed to various parts of engine, authentication, connection factory, etc.
*/
-public class EnvironmentConfiguration
+public class LegendEnvironment
{
- private final List vaults;
- private final Map, CredentialVault extends CredentialVaultSecret>> vaultsIndex;
- private final Map storeSupportsIndex;
+ protected final ImmutableList vaults;
+ protected final ImmutableMap, CredentialVault extends CredentialVaultSecret>> vaultsIndex;
+ protected final ImmutableMap storeSupportsIndex;
- private final Map authenticationMechanismsIndex;
+ protected final ImmutableMap authenticationMechanismsIndex;
- private EnvironmentConfiguration(List vaults, Map storeSupportsIndex, Map authenticationMechanismsIndex)
+ protected LegendEnvironment(List vaults, Map storeSupportsIndex, Map authenticationMechanismsIndex)
{
- this.vaults = Lists.mutable.withAll(vaults);
- this.vaultsIndex = Maps.mutable.empty();
+ this.vaults = Lists.immutable.withAll(vaults);
+ MutableMap, CredentialVault extends CredentialVaultSecret>> vaultsIndex = Maps.mutable.empty();
for (CredentialVault extends CredentialVaultSecret> vault : vaults)
{
vaultsIndex.put(vault.getSecretType(), vault);
}
- this.storeSupportsIndex = storeSupportsIndex;
- this.authenticationMechanismsIndex = authenticationMechanismsIndex;
- }
-
- /**
- * This method is meant for testing.
- * The recommended usage is to include all the vaults during initialization
- */
- public void injectVault(CredentialVault vault)
- {
- if (this.vaultsIndex.containsKey(vault.getSecretType()))
- {
- throw new RuntimeException(String.format("Can't register credential vault: found multiple vaults with secret type '%s'", vault.getSecretType().getSimpleName()));
- }
- this.vaultsIndex.put(vault.getSecretType(), vault);
- this.vaults.add(vault);
+ this.vaultsIndex = vaultsIndex.toImmutable();
+ this.storeSupportsIndex = Maps.immutable.withAll(storeSupportsIndex);
+ this.authenticationMechanismsIndex = Maps.immutable.withAll(authenticationMechanismsIndex);
}
public String lookupVaultSecret(CredentialVaultSecret credentialVaultSecret, Identity identity) throws Exception
@@ -79,19 +69,6 @@ public String lookupVaultSecret(CredentialVaultSecret credentialVaultSecret, Ide
return vault.lookupSecret(credentialVaultSecret, identity);
}
- /**
- * This method is meant for testing.
- * The recommended usage is to include all the store supports during initialization
- */
- public void injectStoreSupport(StoreSupport storeSupport)
- {
- if (this.storeSupportsIndex.containsKey(storeSupport.getIdentifier()))
- {
- throw new RuntimeException(String.format("Can't register store support: found multiple store supports with identifier '%s'", storeSupport.getIdentifier()));
- }
- this.storeSupportsIndex.put(storeSupport.getIdentifier(), storeSupport);
- }
-
public StoreSupport findStoreSupport(String identifier)
{
return Objects.requireNonNull(this.storeSupportsIndex.get(identifier), String.format("Can't find store support with identifier '%s'", identifier));
@@ -106,7 +83,6 @@ public static class Builder
{
private final List vaults = Lists.mutable.empty();
private final Map storeSupportsIndex = new LinkedHashMap<>();
- private AuthenticationMechanismProvider authenticationMechanismProvider;
private final Set authenticationMechanisms = new LinkedHashSet<>();
public Builder()
@@ -159,12 +135,6 @@ private void registerStoreSupport(StoreSupport storeSupport)
this.storeSupportsIndex.put(storeSupport.getIdentifier(), storeSupport);
}
- public Builder withAuthenticationMechanismProvider(AuthenticationMechanismProvider authenticationMechanismProvider)
- {
- this.authenticationMechanismProvider = authenticationMechanismProvider;
- return this;
- }
-
public Builder withAuthenticationMechanisms(List authenticationMechanisms)
{
this.authenticationMechanisms.addAll(authenticationMechanisms);
@@ -184,12 +154,10 @@ public Builder withAuthenticationMechanism(AuthenticationMechanism authenticatio
return this;
}
- public EnvironmentConfiguration build()
+ public LegendEnvironment build()
{
- List authenticationMechanisms = this.authenticationMechanismProvider != null ? ListIterate.flatCollect(this.authenticationMechanismProvider.getLoaders(), AuthenticationMechanismLoader::getMechanisms) : Lists.mutable.empty();
- authenticationMechanisms.addAll(this.authenticationMechanisms);
Map authenticationMechanismsIndex = new LinkedHashMap<>();
- authenticationMechanisms.forEach(mechanism ->
+ this.authenticationMechanisms.forEach(mechanism ->
{
String key = mechanism.getAuthenticationConfigurationType().getSimpleName();
if (authenticationMechanismsIndex.containsKey(key))
@@ -212,7 +180,7 @@ public EnvironmentConfiguration build()
authenticationMechanismsIndex.put(key, mechanism);
});
- return new EnvironmentConfiguration(this.vaults, this.storeSupportsIndex, authenticationMechanismsIndex);
+ return new LegendEnvironment(this.vaults, this.storeSupportsIndex, authenticationMechanismsIndex);
}
}
}
diff --git a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/StoreInstance.java b/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/StoreInstance.java
index af25e716a92..cd409d5d996 100644
--- a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/StoreInstance.java
+++ b/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/StoreInstance.java
@@ -15,6 +15,7 @@
package org.finos.legend.connection;
import org.eclipse.collections.api.factory.Lists;
+import org.eclipse.collections.api.list.ImmutableList;
import org.eclipse.collections.api.list.MutableList;
import org.eclipse.collections.impl.utility.ListIterate;
import org.finos.legend.connection.protocol.AuthenticationConfiguration;
@@ -27,20 +28,23 @@
import java.util.Objects;
import java.util.Set;
+/**
+ * A StoreInstance represents a named instance of a Store.
+ */
public class StoreInstance
{
private final String identifier;
private final StoreSupport storeSupport;
- private final List authenticationMechanisms;
- private final List> authenticationConfigurationTypes;
+ private final ImmutableList authenticationMechanisms;
+ private final ImmutableList> authenticationConfigurationTypes;
private final ConnectionSpecification connectionSpecification;
private StoreInstance(String identifier, StoreSupport storeSupport, List authenticationMechanisms, ConnectionSpecification connectionSpecification)
{
this.identifier = identifier;
this.storeSupport = storeSupport;
- this.authenticationMechanisms = authenticationMechanisms;
- this.authenticationConfigurationTypes = ListIterate.collect(authenticationMechanisms, AuthenticationMechanism::getAuthenticationConfigurationType);
+ this.authenticationMechanisms = Lists.immutable.withAll(authenticationMechanisms);
+ this.authenticationConfigurationTypes = Lists.immutable.withAll(ListIterate.collect(authenticationMechanisms, AuthenticationMechanism::getAuthenticationConfigurationType));
this.connectionSpecification = connectionSpecification;
}
@@ -54,12 +58,12 @@ public StoreSupport getStoreSupport()
return storeSupport;
}
- public List getAuthenticationMechanisms()
+ public ImmutableList getAuthenticationMechanisms()
{
return authenticationMechanisms;
}
- public List> getAuthenticationConfigurationTypes()
+ public ImmutableList> getAuthenticationConfigurationTypes()
{
return authenticationConfigurationTypes;
}
@@ -69,17 +73,26 @@ public ConnectionSpecification getConnectionSpecification()
return connectionSpecification;
}
+ public T getConnectionSpecification(Class clazz)
+ {
+ if (!this.connectionSpecification.getClass().equals(clazz))
+ {
+ throw new RuntimeException(String.format("Can't get connection specification of type '%s' for store '%s'", clazz.getSimpleName(), this.identifier));
+ }
+ return (T) this.connectionSpecification;
+ }
+
public static class Builder
{
- private final EnvironmentConfiguration environmentConfiguration;
+ private final LegendEnvironment environment;
private String identifier;
private String storeSupportIdentifier;
private final Set authenticationMechanisms = new LinkedHashSet<>();
private ConnectionSpecification connectionSpecification;
- public Builder(EnvironmentConfiguration environmentConfiguration)
+ public Builder(LegendEnvironment environment)
{
- this.environmentConfiguration = environmentConfiguration;
+ this.environment = environment;
}
public Builder withIdentifier(String identifier)
@@ -120,7 +133,7 @@ public Builder withConnectionSpecification(ConnectionSpecification connectionSpe
public StoreInstance build()
{
- StoreSupport storeSupport = this.environmentConfiguration.findStoreSupport(Objects.requireNonNull(this.storeSupportIdentifier, "Store instance store support identifier is required"));
+ StoreSupport storeSupport = this.environment.findStoreSupport(Objects.requireNonNull(this.storeSupportIdentifier, "Store instance store support identifier is required"));
MutableList unsupportedAuthenticationMechanisms = ListIterate.select(new ArrayList<>(this.authenticationMechanisms), mechanism -> !storeSupport.getAuthenticationMechanisms().contains(mechanism));
if (!unsupportedAuthenticationMechanisms.isEmpty())
{
@@ -130,7 +143,7 @@ public StoreInstance build()
Objects.requireNonNull(this.identifier, "Store instance identifier is required"),
storeSupport,
// NOTE: if no mechanism is specified, it means the store instance supports all mechanisms
- this.authenticationMechanisms.isEmpty() ? storeSupport.getAuthenticationMechanisms() : new ArrayList<>(this.authenticationMechanisms),
+ this.authenticationMechanisms.isEmpty() ? storeSupport.getAuthenticationMechanisms().toList() : new ArrayList<>(this.authenticationMechanisms),
Objects.requireNonNull(this.connectionSpecification, "Store instance connection specification is required")
);
}
diff --git a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/CredentialBuilderProvider.java b/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/StoreInstanceProvider.java
similarity index 85%
rename from legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/CredentialBuilderProvider.java
rename to legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/StoreInstanceProvider.java
index 51700704cb6..8b83db33c91 100644
--- a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/CredentialBuilderProvider.java
+++ b/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/StoreInstanceProvider.java
@@ -14,9 +14,7 @@
package org.finos.legend.connection;
-import java.util.List;
-
-public interface CredentialBuilderProvider
+public interface StoreInstanceProvider
{
- List getBuilders();
+ StoreInstance lookup(String identifier);
}
diff --git a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/StoreSupport.java b/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/StoreSupport.java
index 982c6049507..89518bc4dde 100644
--- a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/StoreSupport.java
+++ b/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/StoreSupport.java
@@ -26,17 +26,21 @@
import java.util.Objects;
import java.util.Set;
+/**
+ * A StoreSupport describes the capabilities supported by a Store.
+ * For now, it describes the authentication mechanisms.
+ */
public class StoreSupport
{
private final String identifier;
- private final List authenticationMechanisms;
- private final List> authenticationConfigurationTypes;
+ private final ImmutableList authenticationMechanisms;
+ private final ImmutableList> authenticationConfigurationTypes;
protected StoreSupport(String identifier, List authenticationMechanisms)
{
this.identifier = identifier;
- this.authenticationMechanisms = authenticationMechanisms;
- this.authenticationConfigurationTypes = ListIterate.collect(authenticationMechanisms, AuthenticationMechanism::getAuthenticationConfigurationType);
+ this.authenticationMechanisms = Lists.immutable.withAll(authenticationMechanisms);
+ this.authenticationConfigurationTypes = Lists.immutable.withAll(ListIterate.collect(authenticationMechanisms, AuthenticationMechanism::getAuthenticationConfigurationType));
}
public String getIdentifier()
@@ -44,7 +48,7 @@ public String getIdentifier()
return identifier;
}
- public List getAuthenticationMechanisms()
+ public ImmutableList getAuthenticationMechanisms()
{
return authenticationMechanisms;
}
diff --git a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/impl/KerberosCredentialExtractor.java b/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/impl/KerberosCredentialExtractor.java
index 22499b65ad8..a36c3add1cc 100644
--- a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/impl/KerberosCredentialExtractor.java
+++ b/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/impl/KerberosCredentialExtractor.java
@@ -14,9 +14,23 @@
package org.finos.legend.connection.impl;
-import org.finos.legend.connection.CredentialExtractor;
+import org.finos.legend.connection.CredentialBuilder;
+import org.finos.legend.connection.LegendEnvironment;
+import org.finos.legend.engine.shared.core.identity.Identity;
import org.finos.legend.engine.shared.core.identity.credential.LegendKerberosCredential;
-public class KerberosCredentialExtractor extends CredentialExtractor
+import java.util.Optional;
+
+public class KerberosCredentialExtractor extends CredentialBuilder
{
+ @Override
+ public LegendKerberosCredential makeCredential(Identity identity, KerberosAuthenticationConfiguration authenticationConfiguration, LegendKerberosCredential credential, LegendEnvironment environment) throws Exception
+ {
+ Optional credentialOptional = identity.getCredential(LegendKerberosCredential.class);
+ if (!credentialOptional.isPresent())
+ {
+ throw new RuntimeException(String.format("Can't extract credential of type '%s' from the specified identity", LegendKerberosCredential.class.getSimpleName()));
+ }
+ return credentialOptional.get();
+ }
}
diff --git a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/impl/KeyPairCredentialBuilder.java b/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/impl/KeyPairCredentialBuilder.java
index da47ee7def9..46cc4ddc880 100644
--- a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/impl/KeyPairCredentialBuilder.java
+++ b/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/impl/KeyPairCredentialBuilder.java
@@ -25,7 +25,7 @@
import org.eclipse.collections.api.RichIterable;
import org.eclipse.collections.impl.factory.Strings;
import org.finos.legend.connection.CredentialBuilder;
-import org.finos.legend.connection.EnvironmentConfiguration;
+import org.finos.legend.connection.LegendEnvironment;
import org.finos.legend.engine.shared.core.identity.Credential;
import org.finos.legend.engine.shared.core.identity.Identity;
import org.finos.legend.engine.shared.core.identity.credential.PrivateKeyCredential;
@@ -42,10 +42,10 @@
public class KeyPairCredentialBuilder extends CredentialBuilder
{
@Override
- public PrivateKeyCredential makeCredential(Identity identity, EncryptedPrivateKeyPairAuthenticationConfiguration authenticationConfiguration, Credential credential, EnvironmentConfiguration environmentConfiguration) throws Exception
+ public PrivateKeyCredential makeCredential(Identity identity, EncryptedPrivateKeyPairAuthenticationConfiguration authenticationConfiguration, Credential credential, LegendEnvironment environment) throws Exception
{
- String encryptedPrivateKey = environmentConfiguration.lookupVaultSecret(authenticationConfiguration.privateKey, identity);
- String passphrase = environmentConfiguration.lookupVaultSecret(authenticationConfiguration.passphrase, identity);
+ String encryptedPrivateKey = environment.lookupVaultSecret(authenticationConfiguration.privateKey, identity);
+ String passphrase = environment.lookupVaultSecret(authenticationConfiguration.passphrase, identity);
PrivateKey privateKey = this.getDecryptedPrivateKey(encryptedPrivateKey, passphrase);
return new PrivateKeyCredential(authenticationConfiguration.userName, privateKey);
}
diff --git a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/impl/UserPasswordCredentialBuilder.java b/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/impl/UserPasswordCredentialBuilder.java
index 7739c6ca171..7cec18bd446 100644
--- a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/impl/UserPasswordCredentialBuilder.java
+++ b/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/impl/UserPasswordCredentialBuilder.java
@@ -15,7 +15,7 @@
package org.finos.legend.connection.impl;
import org.finos.legend.connection.CredentialBuilder;
-import org.finos.legend.connection.EnvironmentConfiguration;
+import org.finos.legend.connection.LegendEnvironment;
import org.finos.legend.engine.shared.core.identity.Credential;
import org.finos.legend.engine.shared.core.identity.Identity;
import org.finos.legend.engine.shared.core.identity.credential.PlaintextUserPasswordCredential;
@@ -23,10 +23,10 @@
public class UserPasswordCredentialBuilder extends CredentialBuilder
{
@Override
- public PlaintextUserPasswordCredential makeCredential(Identity identity, UserPasswordAuthenticationConfiguration authenticationConfiguration, Credential credential, EnvironmentConfiguration environmentConfiguration) throws Exception
+ public PlaintextUserPasswordCredential makeCredential(Identity identity, UserPasswordAuthenticationConfiguration authenticationConfiguration, Credential credential, LegendEnvironment environment) throws Exception
{
- String password = environmentConfiguration.lookupVaultSecret(authenticationConfiguration.password, identity);
+ String password = environment.lookupVaultSecret(authenticationConfiguration.password, identity);
return new PlaintextUserPasswordCredential(authenticationConfiguration.username, password);
}
}
diff --git a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/protocol/AuthenticationMechanism.java b/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/protocol/AuthenticationMechanism.java
index 284ac36c7f3..70f75d1f4fd 100644
--- a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/protocol/AuthenticationMechanism.java
+++ b/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/java/org/finos/legend/connection/protocol/AuthenticationMechanism.java
@@ -14,8 +14,6 @@
package org.finos.legend.connection.protocol;
-import java.util.List;
-
public interface AuthenticationMechanism
{
String getLabel();
diff --git a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/resources/META-INF/services/org.finos.legend.connection.AuthenticationMechanismLoader b/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/resources/META-INF/services/org.finos.legend.connection.AuthenticationMechanismLoader
deleted file mode 100644
index f77e7b4a4ab..00000000000
--- a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/resources/META-INF/services/org.finos.legend.connection.AuthenticationMechanismLoader
+++ /dev/null
@@ -1 +0,0 @@
-org.finos.legend.connection.DefaultAuthenticationMechanismLoader
diff --git a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/resources/META-INF/services/org.finos.legend.connection.CredentialBuilder b/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/resources/META-INF/services/org.finos.legend.connection.CredentialBuilder
deleted file mode 100644
index 032f2e6497f..00000000000
--- a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/main/resources/META-INF/services/org.finos.legend.connection.CredentialBuilder
+++ /dev/null
@@ -1,2 +0,0 @@
-org.finos.legend.connection.impl.UserPasswordCredentialBuilder
-org.finos.legend.connection.impl.KerberosCredentialExtractor
diff --git a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/test/java/org/finos/legend/connection/ConnectionFactoryTest.java b/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/test/java/org/finos/legend/connection/ConnectionFactoryTest.java
index d6bc8dbf398..6bf0b357a69 100644
--- a/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/test/java/org/finos/legend/connection/ConnectionFactoryTest.java
+++ b/legend-engine-xts-authentication/legend-engine-xt-authentication-connection-factory/src/test/java/org/finos/legend/connection/ConnectionFactoryTest.java
@@ -24,38 +24,10 @@
import org.junit.Test;
import java.util.List;
+import java.util.Optional;
public class ConnectionFactoryTest
{
- @Test
- public void testStoreInstanceManagement()
- {
- TestEnv env = TestEnv.create();
- StoreInstance storeInstance = new StoreInstance.Builder(env.environmentConfiguration)
- .withIdentifier("test-store")
- .withStoreSupportIdentifier("test")
- .withConnectionSpecification(new TestConnectionSpecification())
- .build();
- env.connectionFactory.injectStoreInstance(storeInstance);
-
- // failure
- Exception exception;
-
- // error: store already registered
- exception = Assert.assertThrows(RuntimeException.class, () ->
- {
- env.connectionFactory.injectStoreInstance(storeInstance);
- });
- Assert.assertEquals("Can't register store instance: found multiple store instances with identifier 'test-store'", exception.getMessage());
-
- // error: store not found
- exception = Assert.assertThrows(RuntimeException.class, () ->
- {
- env.connectionFactory.getAuthenticator(new Identity("test"), "unknown");
- });
- Assert.assertEquals("Can't find store instance with identifier 'unknown'", exception.getMessage());
- }
-
@Test
public void testGetConnection_WithFailures() throws Exception
{
@@ -75,28 +47,28 @@ public void testGetConnection_WithFailures() throws Exception
Identity identity = new Identity("test");
// success
- env.connectionFactory.getConnection(env.connectionFactory.getAuthenticator(identity, "test", new AuthenticationConfiguration_X()));
+ env.connectionFactory.getConnection(identity, env.connectionFactory.getAuthenticator(identity, "test", new AuthenticationConfiguration_X()));
Exception exception;
// error: store not found
exception = Assert.assertThrows(RuntimeException.class, () ->
{
- env.connectionFactory.getConnection(env.connectionFactory.getAuthenticator(identity, "unknown", new AuthenticationConfiguration_X()));
+ env.connectionFactory.getConnection(identity, env.connectionFactory.getAuthenticator(identity, "unknown", new AuthenticationConfiguration_X()));
});
Assert.assertEquals("Can't find store instance with identifier 'unknown'", exception.getMessage());
// error: unsupported authentication mechanism
exception = Assert.assertThrows(RuntimeException.class, () ->
{
- env.connectionFactory.getConnection(env.connectionFactory.getAuthenticator(identity, "test", new AuthenticationConfiguration_Z()));
+ env.connectionFactory.getConnection(identity, env.connectionFactory.getAuthenticator(identity, "test", new AuthenticationConfiguration_Z()));
});
Assert.assertEquals("Can't get authenticator: authentication mechanism 'Z' is not supported by store 'test'. Supported mechanism(s):\n- X (config: AuthenticationConfiguration_X)\n- Y (config: AuthenticationConfiguration_Y)", exception.getMessage());
// error: unresolvable authentication flow
exception = Assert.assertThrows(RuntimeException.class, () ->
{
- env.connectionFactory.getConnection(env.connectionFactory.getAuthenticator(identity, "test", new AuthenticationConfiguration_Y()));
+ env.connectionFactory.getConnection(identity, env.connectionFactory.getAuthenticator(identity, "test", new AuthenticationConfiguration_Y()));
});
Assert.assertEquals("Can't get authenticator: no authentication flow for store 'test' can be resolved for the specified identity using authentication mechanism 'Y' (authentication configuration: AuthenticationConfiguration_Y, connection specification: TestConnectionSpecification)", exception.getMessage());
@@ -114,14 +86,14 @@ public void testGetConnection_WithFailures() throws Exception
// error: unsupported authentication mechanism
exception = Assert.assertThrows(RuntimeException.class, () ->
{
- env2.connectionFactory.getConnection(env2.connectionFactory.getAuthenticator(identity, "test", new AuthenticationConfiguration_Z()));
+ env2.connectionFactory.getConnection(identity, env2.connectionFactory.getAuthenticator(identity, "test", new AuthenticationConfiguration_Z()));
});
Assert.assertEquals("Can't get authenticator: authentication mechanism with configuration 'AuthenticationConfiguration_Z' is not supported by store 'test'. Supported mechanism(s):\n- X (config: AuthenticationConfiguration_X)\n- Y (config: AuthenticationConfiguration_Y)", exception.getMessage());
// error: unresolvable authentication flow
exception = Assert.assertThrows(RuntimeException.class, () ->
{
- env2.connectionFactory.getConnection(env2.connectionFactory.getAuthenticator(identity, "test", new AuthenticationConfiguration_Y()));
+ env2.connectionFactory.getConnection(identity, env2.connectionFactory.getAuthenticator(identity, "test", new AuthenticationConfiguration_Y()));
});
Assert.assertEquals("Can't get authenticator: no authentication flow for store 'test' can be resolved for the specified identity using authentication mechanism with configuration 'AuthenticationConfiguration_Y' (authentication configuration: AuthenticationConfiguration_Y, connection specification: TestConnectionSpecification)", exception.getMessage());
}
@@ -149,7 +121,7 @@ public void testGetConnection_WithSimpleFlow() throws Exception
Identity identity = new Identity("test");
Authenticator authenticator = env.connectionFactory.getAuthenticator(identity, "test", new AuthenticationConfiguration_X());
- assertAuthenticator(env.connectionFactory, authenticator, Credential.class, Lists.mutable.with(
+ assertAuthenticator(identity, env.connectionFactory, authenticator, Credential.class, Lists.mutable.with(
"Credential->Credential_A [AuthenticationConfiguration_X]"
), ConnectionBuilder_A.class);
}
@@ -177,7 +149,7 @@ public void testGetConnection_WithSpecificBuilderOrder() throws Exception
Identity identity = new Identity("test");
Authenticator authenticator = env.connectionFactory.getAuthenticator(identity, "test", new AuthenticationConfiguration_X());
- assertAuthenticator(env.connectionFactory, authenticator, Credential.class, Lists.mutable.with(
+ assertAuthenticator(identity, env.connectionFactory, authenticator, Credential.class, Lists.mutable.with(
"Credential->Credential_B [AuthenticationConfiguration_X]"
), ConnectionBuilder_B.class);
}
@@ -204,7 +176,7 @@ public void testGetConnection_WithChainFlow() throws Exception
Identity identity = new Identity("test");
Authenticator authenticator = env.connectionFactory.getAuthenticator(identity, "test", new AuthenticationConfiguration_X());
- assertAuthenticator(env.connectionFactory, authenticator, Credential.class, Lists.mutable.with(
+ assertAuthenticator(identity, env.connectionFactory, authenticator, Credential.class, Lists.mutable.with(
"Credential->Credential_A [AuthenticationConfiguration_X]",
"Credential_A->Credential_B [AuthenticationConfiguration_X]",
"Credential_B->Credential_C [AuthenticationConfiguration_X]"
@@ -233,7 +205,7 @@ public void testGetConnection_WithShortestFlowResolved() throws Exception
Identity identity = new Identity("test", new Credential_B());
Authenticator authenticator = env.connectionFactory.getAuthenticator(identity, "test", new AuthenticationConfiguration_X());
- assertAuthenticator(env.connectionFactory, authenticator, Credential_B.class, Lists.mutable.with(
+ assertAuthenticator(identity, env.connectionFactory, authenticator, Credential_B.class, Lists.mutable.with(
"Credential_B->Credential_C [AuthenticationConfiguration_X]"
), ConnectionBuilder_C.class);
}
@@ -263,7 +235,7 @@ public void testGetConnection_WithNoAuthConfigProvided() throws Exception
// success
Authenticator authenticator = env.connectionFactory.getAuthenticator(identity, "test");
- assertAuthenticator(env.connectionFactory, authenticator, Credential_A.class, Lists.mutable.with(
+ assertAuthenticator(identity, env.connectionFactory, authenticator, Credential_A.class, Lists.mutable.with(
"Credential_A->Credential_B [AuthenticationConfiguration_Y]"
), ConnectionBuilder_B.class);
@@ -295,7 +267,7 @@ public void testGetConnection_WithCredentialExtractor() throws Exception
Identity identity = new Identity("test", new Credential_A());
Authenticator authenticator = env.connectionFactory.getAuthenticator(identity, "test", new AuthenticationConfiguration_X());
- assertAuthenticator(env.connectionFactory, authenticator, Credential_A.class, Lists.mutable.with(
+ assertAuthenticator(identity, env.connectionFactory, authenticator, Credential_A.class, Lists.mutable.with(
"Credential_A->Credential_A [AuthenticationConfiguration_X]"
), ConnectionBuilder_A.class);
@@ -313,7 +285,7 @@ public void testGetConnection_WithCredentialExtractor() throws Exception
).newStore("test", Lists.mutable.empty());
authenticator = env2.connectionFactory.getAuthenticator(identity, "test", new AuthenticationConfiguration_X());
- assertAuthenticator(env2.connectionFactory, authenticator, Credential_A.class, Lists.mutable.with(
+ assertAuthenticator(identity, env2.connectionFactory, authenticator, Credential_A.class, Lists.mutable.with(
"Credential_A->Credential_A [AuthenticationConfiguration_X]"
), ConnectionBuilder_A.class);
}
@@ -340,35 +312,36 @@ public void testGetConnection_WithoutCredentialExtractor() throws Exception
Identity identity = new Identity("test", new Credential_A());
Exception exception = Assert.assertThrows(RuntimeException.class, () ->
{
- env.connectionFactory.getConnection(env.connectionFactory.getAuthenticator(identity, "test", new AuthenticationConfiguration_X()));
+ env.connectionFactory.getConnection(identity, env.connectionFactory.getAuthenticator(identity, "test", new AuthenticationConfiguration_X()));
});
Assert.assertEquals("Can't get authenticator: no authentication flow for store 'test' can be resolved for the specified identity using authentication mechanism 'X' (authentication configuration: AuthenticationConfiguration_X, connection specification: TestConnectionSpecification)", exception.getMessage());
}
- private void assertAuthenticator(ConnectionFactory connectionFactory, Authenticator authenticator, Class extends Credential> sourceCredentialType, List credentialBuilders, Class extends ConnectionBuilder> connectionBuilderType) throws Exception
+ private void assertAuthenticator(Identity identity, ConnectionFactory connectionFactory, Authenticator authenticator, Class extends Credential> sourceCredentialType, List credentialBuilders, Class extends ConnectionBuilder> connectionBuilderType) throws Exception
{
Assert.assertEquals(sourceCredentialType, authenticator.getSourceCredentialType());
Assert.assertEquals(connectionBuilderType, authenticator.getConnectionBuilder().getClass());
Assert.assertArrayEquals(credentialBuilders.toArray(), authenticator.getCredentialBuilders().stream().map(builder -> String.format("%s->%s [%s]", builder.getInputCredentialType().getSimpleName(), builder.getOutputCredentialType().getSimpleName(), builder.getAuthenticationConfigurationType().getSimpleName())).toArray());
- connectionFactory.getConnection(authenticator);
+ connectionFactory.getConnection(identity, authenticator);
}
private static class TestEnv
{
- final EnvironmentConfiguration environmentConfiguration;
+ final LegendEnvironment environment;
+ final InstrumentedStoreInstanceProvider storeInstanceProvider;
final ConnectionFactory connectionFactory;
- private TestEnv(List> credentialBuilders, List> connectionBuilders, List authenticationMechanisms, List supportedAuthenticationMechanisms)
+ private TestEnv(List credentialBuilders, List connectionBuilders, List authenticationMechanisms, List supportedAuthenticationMechanisms)
{
- this.environmentConfiguration = new EnvironmentConfiguration.Builder()
+ this.environment = new LegendEnvironment.Builder()
.withStoreSupport(new StoreSupport.Builder()
.withIdentifier("test")
.withAuthenticationMechanisms(supportedAuthenticationMechanisms)
.build())
.withAuthenticationMechanisms(authenticationMechanisms)
.build();
-
- this.connectionFactory = new ConnectionFactory.Builder(environmentConfiguration)
+ this.storeInstanceProvider = new InstrumentedStoreInstanceProvider();
+ this.connectionFactory = new ConnectionFactory.Builder(this.environment, this.storeInstanceProvider)
.withCredentialBuilders(credentialBuilders)
.withConnectionBuilders(connectionBuilders)
.build();
@@ -376,7 +349,7 @@ private TestEnv(List> credentialBuilders, List authenticationMechanisms)
{
- this.connectionFactory.injectStoreInstance(new StoreInstance.Builder(environmentConfiguration)
+ this.storeInstanceProvider.injectStoreInstance(new StoreInstance.Builder(this.environment)
.withIdentifier(identifier)
.withStoreSupportIdentifier("test")
.withAuthenticationMechanisms(authenticationMechanisms)
@@ -390,12 +363,12 @@ static TestEnv create()
return new TestEnv(Lists.mutable.empty(), Lists.mutable.empty(), Lists.mutable.empty(), Lists.mutable.empty());
}
- static TestEnv create(List> credentialBuilders, List> connectionBuilders, List authenticationMechanisms, List supportedAuthenticationMechanisms)
+ static TestEnv create(List credentialBuilders, List connectionBuilders, List authenticationMechanisms, List supportedAuthenticationMechanisms)
{
return new TestEnv(credentialBuilders, connectionBuilders, authenticationMechanisms, supportedAuthenticationMechanisms);
}
- static TestEnv create(List> credentialBuilders, List> connectionBuilders, List supportedAuthenticationMechanisms)
+ static TestEnv create(List credentialBuilders, List connectionBuilders, List supportedAuthenticationMechanisms)
{
return new TestEnv(credentialBuilders, connectionBuilders, Lists.mutable.with(
TestAuthenticationMechanismType.X,
@@ -476,7 +449,7 @@ public String getLabel()
private static class CredentialBuilder_A_to_A__withX extends CredentialBuilder
{
@Override
- public Credential_A makeCredential(Identity identity, AuthenticationConfiguration_X authenticationConfiguration, Credential_A credential, EnvironmentConfiguration configuration) throws Exception
+ public Credential_A makeCredential(Identity identity, AuthenticationConfiguration_X authenticationConfiguration, Credential_A credential, LegendEnvironment environment) throws Exception
{
return new Credential_A();
}
@@ -485,7 +458,7 @@ public Credential_A makeCredential(Identity identity, AuthenticationConfiguratio
private static class CredentialBuilder_A_to_B__withX extends CredentialBuilder
{
@Override
- public Credential_B makeCredential(Identity identity, AuthenticationConfiguration_X authenticationConfiguration, Credential_A credential, EnvironmentConfiguration configuration) throws Exception
+ public Credential_B makeCredential(Identity identity, AuthenticationConfiguration_X authenticationConfiguration, Credential_A credential, LegendEnvironment environment) throws Exception
{
return new Credential_B();
}
@@ -494,7 +467,7 @@ public Credential_B makeCredential(Identity identity, AuthenticationConfiguratio
private static class CredentialBuilder_B_to_C__withX extends CredentialBuilder
{
@Override
- public Credential_C makeCredential(Identity identity, AuthenticationConfiguration_X authenticationConfiguration, Credential_B credential, EnvironmentConfiguration configuration) throws Exception
+ public Credential_C makeCredential(Identity identity, AuthenticationConfiguration_X authenticationConfiguration, Credential_B credential, LegendEnvironment environment) throws Exception
{
return new Credential_C();
}
@@ -503,7 +476,7 @@ public Credential_C makeCredential(Identity identity, AuthenticationConfiguratio
private static class CredentialBuilder_Any_to_A__withX extends CredentialBuilder
{
@Override
- public Credential_A makeCredential(Identity identity, AuthenticationConfiguration_X authenticationConfiguration, Credential credential, EnvironmentConfiguration configuration) throws Exception
+ public Credential_A makeCredential(Identity identity, AuthenticationConfiguration_X authenticationConfiguration, Credential credential, LegendEnvironment environment) throws Exception
{
return new Credential_A();
}
@@ -512,7 +485,7 @@ public Credential_A makeCredential(Identity identity, AuthenticationConfiguratio
private static class CredentialBuilder_A_to_B__withY extends CredentialBuilder
{
@Override
- public Credential_B makeCredential(Identity identity, AuthenticationConfiguration_Y authenticationConfiguration, Credential_A credential, EnvironmentConfiguration configuration) throws Exception
+ public Credential_B makeCredential(Identity identity, AuthenticationConfiguration_Y authenticationConfiguration, Credential_A credential, LegendEnvironment environment) throws Exception
{
return new Credential_B();
}
@@ -521,14 +494,25 @@ public Credential_B makeCredential(Identity identity, AuthenticationConfiguratio
private static class CredentialBuilder_Any_to_B__withX extends CredentialBuilder
{
@Override
- public Credential_B makeCredential(Identity identity, AuthenticationConfiguration_X authenticationConfigurationX, Credential credential, EnvironmentConfiguration configuration) throws Exception
+ public Credential_B makeCredential(Identity identity, AuthenticationConfiguration_X authenticationConfigurationX, Credential credential, LegendEnvironment environment) throws Exception
{
return new Credential_B();
}
}
- private static class CredentialExtractor_A__withX extends CredentialExtractor
+ private static class CredentialExtractor_A__withX extends CredentialBuilder
{
+ @Override
+ public Credential_A makeCredential(Identity identity, AuthenticationConfiguration_X authenticationConfiguration, Credential_A credential, LegendEnvironment environment) throws Exception
+ {
+
+ Optional credentialOptional = identity.getCredential(Credential_A.class);
+ if (!credentialOptional.isPresent())
+ {
+ throw new RuntimeException("");
+ }
+ return credentialOptional.get();
+ }
}
// -------------------------- Connection -------------------------------
@@ -540,7 +524,7 @@ private static class TestConnectionSpecification extends ConnectionSpecification
private static class ConnectionBuilder_A extends ConnectionBuilder