diff --git a/legend-engine-config/legend-engine-pure-code-compiled-core-configuration/pom.xml b/legend-engine-config/legend-engine-pure-code-compiled-core-configuration/pom.xml index 7d9d3ee70d9..45bd61eb250 100644 --- a/legend-engine-config/legend-engine-pure-code-compiled-core-configuration/pom.xml +++ b/legend-engine-config/legend-engine-pure-code-compiled-core-configuration/pom.xml @@ -277,7 +277,7 @@ org.finos.legend.pure - legend-pure-runtime-java-extension-dsl-mapping + legend-pure-runtime-java-extension-compiled-dsl-mapping runtime @@ -293,7 +293,7 @@ org.finos.legend.engine - legend-engine-pure-platform-dsl-mapping-java + legend-engine-pure-platform-dsl-store-java org.finos.legend.engine diff --git a/legend-engine-config/legend-engine-repl/legend-engine-repl-client/pom.xml b/legend-engine-config/legend-engine-repl/legend-engine-repl-client/pom.xml index e4ac07de680..1169242a18f 100644 --- a/legend-engine-config/legend-engine-repl/legend-engine-repl-client/pom.xml +++ b/legend-engine-config/legend-engine-repl/legend-engine-repl-client/pom.xml @@ -91,6 +91,11 @@ org.finos.legend.engine legend-engine-shared-extensions + + + org.finos.legend.engine + legend-engine-shared-core + @@ -120,12 +125,7 @@ junit junit - - - - - org.finos.legend.engine - legend-engine-shared-core + test diff --git a/legend-engine-config/legend-engine-repl/legend-engine-repl-relational/pom.xml b/legend-engine-config/legend-engine-repl/legend-engine-repl-relational/pom.xml index 5f5657922e8..f04ef630faa 100644 --- a/legend-engine-config/legend-engine-repl/legend-engine-repl-relational/pom.xml +++ b/legend-engine-config/legend-engine-repl/legend-engine-repl-relational/pom.xml @@ -27,19 +27,11 @@ Legend Engine - REPL - Relational - - - org.jline - jline - - org.finos.legend.engine legend-engine-repl-client - - org.finos.legend.pure legend-pure-m4 @@ -48,30 +40,31 @@ org.finos.legend.pure legend-pure-m3-core + + org.finos.legend.engine - legend-engine-protocol-pure + legend-engine-language-pure-grammar org.finos.legend.engine - legend-engine-language-pure-grammar + legend-engine-protocol-pure + + + org.finos.legend.engine legend-engine-language-pure-compiler - - - + + org.finos.legend.engine legend-engine-executionPlan-execution - - org.finos.legend.engine - legend-engine-xt-relationalStore-executionPlan - + @@ -84,15 +77,21 @@ org.finos.legend.engine - legend-engine-xt-relationalStore-executionPlan + legend-engine-xt-relationalStore-grammar + Runtime org.finos.legend.engine - legend-engine-xt-relationalStore-grammar - Runtime + legend-engine-xt-relationalStore-executionPlan + + + org.finos.legend.engine + legend-engine-shared-core + + org.eclipse.collections eclipse-collections @@ -107,10 +106,9 @@ junit - - org.finos.legend.engine - legend-engine-shared-core + org.jline + jline diff --git a/legend-engine-config/legend-engine-server/pom.xml b/legend-engine-config/legend-engine-server/pom.xml index e62b6baf2b2..9096b3843f0 100644 --- a/legend-engine-config/legend-engine-server/pom.xml +++ b/legend-engine-config/legend-engine-server/pom.xml @@ -958,7 +958,7 @@ org.finos.legend.pure - legend-pure-runtime-java-extension-functions-json + legend-pure-runtime-java-extension-compiled-functions-json runtime diff --git a/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-external-shared-format-runtime/pom.xml b/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-external-shared-format-runtime/pom.xml index f28cb721ce8..f317bd15ec0 100644 --- a/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-external-shared-format-runtime/pom.xml +++ b/legend-engine-core/legend-engine-core-executionPlan-execution/legend-engine-external-shared-format-runtime/pom.xml @@ -37,7 +37,7 @@ - org.finos.legend.pure:legend-pure-runtime-java-extension-dsl-mapping + org.finos.legend.pure:legend-pure-runtime-java-extension-compiled-dsl-mapping org.finos.legend.pure:legend-pure-m2-dsl-mapping-grammar @@ -189,6 +189,11 @@ legend-pure-m2-dsl-mapping-pure test + + org.finos.legend.engine + legend-engine-pure-platform-dsl-store-java + test + org.finos.legend.engine legend-engine-pure-platform-dsl-mapping-java diff --git a/legend-engine-core/legend-engine-core-executionPlan-generation/legend-engine-executionPlan-generation/pom.xml b/legend-engine-core/legend-engine-core-executionPlan-generation/legend-engine-executionPlan-generation/pom.xml index c6c80098f43..b5b2ebe8f49 100644 --- a/legend-engine-core/legend-engine-core-executionPlan-generation/legend-engine-executionPlan-generation/pom.xml +++ b/legend-engine-core/legend-engine-core-executionPlan-generation/legend-engine-executionPlan-generation/pom.xml @@ -41,7 +41,7 @@ org.finos.legend.engine - legend-engine-pure-platform-dsl-mapping-java + legend-engine-pure-platform-dsl-store-java org.finos.legend.pure diff --git a/legend-engine-core/legend-engine-core-language-pure/legend-engine-external-shared-format-model/pom.xml b/legend-engine-core/legend-engine-core-language-pure/legend-engine-external-shared-format-model/pom.xml index 1a398b9e1b3..78b0c747924 100644 --- a/legend-engine-core/legend-engine-core-language-pure/legend-engine-external-shared-format-model/pom.xml +++ b/legend-engine-core/legend-engine-core-language-pure/legend-engine-external-shared-format-model/pom.xml @@ -56,7 +56,7 @@ - org.finos.legend.pure:legend-pure-runtime-java-extension-dsl-mapping + org.finos.legend.pure:legend-pure-runtime-java-extension-compiled-dsl-mapping org.finos.legend.pure:legend-pure-m2-dsl-mapping-grammar org.finos.legend.pure:legend-pure-runtime-java-engine-compiled diff --git a/legend-engine-core/legend-engine-core-language-pure/legend-engine-language-pure-compiler/pom.xml b/legend-engine-core/legend-engine-core-language-pure/legend-engine-language-pure-compiler/pom.xml index ddb2c9eb0ff..5db5622658d 100644 --- a/legend-engine-core/legend-engine-core-language-pure/legend-engine-language-pure-compiler/pom.xml +++ b/legend-engine-core/legend-engine-core-language-pure/legend-engine-language-pure-compiler/pom.xml @@ -107,16 +107,16 @@ org.finos.legend.pure - legend-pure-runtime-java-extension-dsl-path + legend-pure-runtime-java-extension-compiled-dsl-path org.finos.legend.pure - legend-pure-runtime-java-extension-dsl-graph + legend-pure-runtime-java-extension-compiled-dsl-graph org.finos.legend.pure - legend-pure-runtime-java-extension-dsl-mapping + legend-pure-runtime-java-extension-compiled-dsl-mapping org.finos.legend.engine @@ -138,7 +138,7 @@ org.finos.legend.pure - legend-pure-runtime-java-extension-functions + legend-pure-runtime-java-extension-compiled-functions-base runtime @@ -255,7 +255,7 @@ org.finos.legend.pure - legend-pure-runtime-java-extension-functions-json + legend-pure-runtime-java-extension-compiled-functions-json test diff --git a/legend-engine-core/legend-engine-core-language-pure/legend-engine-protocol-generation-pure/pom.xml b/legend-engine-core/legend-engine-core-language-pure/legend-engine-protocol-generation-pure/pom.xml index d0fb81cf34c..c6c83f22f3e 100644 --- a/legend-engine-core/legend-engine-core-language-pure/legend-engine-protocol-generation-pure/pom.xml +++ b/legend-engine-core/legend-engine-core-language-pure/legend-engine-protocol-generation-pure/pom.xml @@ -130,7 +130,7 @@ org.finos.legend.pure - legend-pure-runtime-java-extension-dsl-store + legend-pure-runtime-java-extension-compiled-dsl-store diff --git a/legend-engine-core/legend-engine-core-query-pure/legend-engine-query-pure/pom.xml b/legend-engine-core/legend-engine-core-query-pure/legend-engine-query-pure/pom.xml index 5eb49af7046..d48ae339d24 100644 --- a/legend-engine-core/legend-engine-core-query-pure/legend-engine-query-pure/pom.xml +++ b/legend-engine-core/legend-engine-core-query-pure/legend-engine-query-pure/pom.xml @@ -45,6 +45,10 @@ org.finos.legend.engine legend-engine-pure-platform-dsl-mapping-java + + org.finos.legend.engine + legend-engine-pure-platform-dsl-store-java + @@ -175,12 +179,12 @@ org.finos.legend.pure - legend-pure-runtime-java-extension-functions-json + legend-pure-runtime-java-extension-compiled-functions-json test org.finos.legend.pure - legend-pure-runtime-java-extension-dsl-mapping + legend-pure-runtime-java-extension-compiled-dsl-mapping test diff --git a/legend-engine-core/legend-engine-core-test/legend-engine-test-runner-function/pom.xml b/legend-engine-core/legend-engine-core-test/legend-engine-test-runner-function/pom.xml index 365fba62655..4b2e927be73 100644 --- a/legend-engine-core/legend-engine-core-test/legend-engine-test-runner-function/pom.xml +++ b/legend-engine-core/legend-engine-core-test/legend-engine-test-runner-function/pom.xml @@ -48,7 +48,7 @@ org.finos.legend.engine - legend-engine-pure-platform-dsl-mapping-java + legend-engine-pure-platform-dsl-store-java org.finos.legend.engine diff --git a/legend-engine-core/legend-engine-core-test/legend-engine-test-runner-mapping/pom.xml b/legend-engine-core/legend-engine-core-test/legend-engine-test-runner-mapping/pom.xml index a69da957576..12017fb8ab1 100644 --- a/legend-engine-core/legend-engine-core-test/legend-engine-test-runner-mapping/pom.xml +++ b/legend-engine-core/legend-engine-core-test/legend-engine-test-runner-mapping/pom.xml @@ -35,7 +35,7 @@ org.finos.legend.pure - legend-pure-runtime-java-extension-functions-json + legend-pure-runtime-java-extension-compiled-functions-json runtime @@ -54,7 +54,7 @@ org.finos.legend.engine - legend-engine-pure-platform-dsl-mapping-java + legend-engine-pure-platform-dsl-store-java org.finos.legend.engine diff --git a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/pom.xml b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/pom.xml index 0fafe583412..a2d32de9aa4 100644 --- a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/pom.xml +++ b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-core/pom.xml @@ -41,7 +41,7 @@ org.finos.legend.engine:legend-engine-pure-platform-dsl-path-java - org.finos.legend.pure:legend-pure-runtime-java-extension-dsl-store + org.finos.legend.pure:legend-pure-runtime-java-extension-compiled-dsl-store @@ -176,7 +176,7 @@ org.finos.legend.pure - legend-pure-runtime-java-extension-dsl-mapping + legend-pure-runtime-java-extension-compiled-dsl-mapping ${legend.pure.version} @@ -187,13 +187,13 @@ org.finos.legend.pure - legend-pure-runtime-java-extension-dsl-diagram + legend-pure-runtime-java-extension-compiled-dsl-diagram ${legend.pure.version} org.finos.legend.pure - legend-pure-runtime-java-extension-functions-json + legend-pure-runtime-java-extension-compiled-functions-json ${legend.pure.version} @@ -252,7 +252,7 @@ - + @@ -292,7 +292,7 @@ org.finos.legend.pure - legend-pure-runtime-java-extension-dsl-store + legend-pure-runtime-java-extension-compiled-dsl-store org.finos.legend.engine @@ -319,22 +319,22 @@ org.finos.legend.pure - legend-pure-runtime-java-extension-store-relational + legend-pure-runtime-java-extension-compiled-store-relational runtime org.finos.legend.pure - legend-pure-runtime-java-extension-dsl-mapping + legend-pure-runtime-java-extension-compiled-dsl-mapping runtime org.finos.legend.pure - legend-pure-runtime-java-extension-dsl-graph + legend-pure-runtime-java-extension-compiled-dsl-graph runtime org.finos.legend.pure - legend-pure-runtime-java-extension-dsl-path + legend-pure-runtime-java-extension-compiled-dsl-path runtime @@ -343,18 +343,18 @@ org.finos.legend.pure - legend-pure-runtime-java-extension-dsl-tds + legend-pure-runtime-java-extension-compiled-dsl-tds runtime org.finos.legend.pure - legend-pure-runtime-java-extension-functions-json + legend-pure-runtime-java-extension-shared-functions-json org.finos.legend.pure - legend-pure-runtime-java-extension-dsl-diagram + legend-pure-runtime-java-extension-compiled-dsl-diagram runtime diff --git a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-functions/pom.xml b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-functions/pom.xml index b9a25a1b9e7..775d651f80c 100644 --- a/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-functions/pom.xml +++ b/legend-engine-pure/legend-engine-pure-code/legend-engine-pure-code-compiled-functions/pom.xml @@ -85,7 +85,7 @@ org.finos.legend.pure - legend-pure-runtime-java-extension-functions + legend-pure-runtime-java-extension-compiled-functions-base ${legend.pure.version} diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-pure/pom.xml b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-pure/pom.xml index bd79978dd5d..65ff826d731 100644 --- a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-pure/pom.xml +++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light-pure/pom.xml @@ -152,7 +152,7 @@ org.finos.legend.pure - legend-pure-runtime-java-extension-functions-relation + legend-pure-runtime-java-extension-compiled-functions-relation ${legend.pure.version} runtime diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/pom.xml b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/pom.xml index cdc762a38d0..e0566ce9104 100644 --- a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/pom.xml +++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/pom.xml @@ -68,7 +68,7 @@ org.finos.legend.pure - legend-pure-ide-light + legend-pure-m4 org.finos.legend.pure @@ -91,7 +91,14 @@ org.finos.legend.pure legend-pure-runtime-java-engine-interpreted - + + org.finos.legend.pure + legend-pure-runtime-java-extension-shared-functions-json + + + org.finos.legend.pure + legend-pure-runtime-java-engine-shared + org.finos.legend.engine @@ -128,25 +135,34 @@ ${project.version} + - com.smoketurner - dropwizard-swagger + com.fasterxml.jackson.core + jackson-annotations + - javax.servlet - javax.servlet-api + org.eclipse.collections + eclipse-collections - org.eclipse.jetty - jetty-servlets + org.eclipse.collections + eclipse-collections-api + - io.dropwizard - dropwizard-core + org.apache.commons + commons-lang3 + + com.googlecode.json-simple + json-simple + + + io.dropwizard - dropwizard-assets + dropwizard-core io.dropwizard @@ -156,14 +172,53 @@ io.dropwizard dropwizard-jersey + + io.dropwizard + dropwizard-assets + io.dropwizard dropwizard-configuration + + - org.eclipse.collections - eclipse-collections-api + org.eclipse.jetty + jetty-servlets + + + + + com.smoketurner + dropwizard-swagger + + + + + + javax.servlet + javax.servlet-api + + + + + + javax.ws.rs + javax.ws.rs-api + + + io.swagger + swagger-annotations + + + + joda-time + joda-time + runtime + + + 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 965298afdf2..5810ae526d9 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 @@ -17,8 +17,8 @@ import org.eclipse.collections.api.factory.Lists; import org.eclipse.collections.api.list.MutableList; import org.finos.legend.engine.pure.runtime.compiler.interpreted.natives.LegendCompileMixedProcessorSupport; -import org.finos.legend.pure.ide.light.PureIDEServer; -import org.finos.legend.pure.ide.light.SourceLocationConfiguration; +import org.finos.legend.engine.ide.PureIDEServer; +import org.finos.legend.engine.ide.SourceLocationConfiguration; import org.finos.legend.pure.m3.serialization.filesystem.repository.GenericCodeRepository; import org.finos.legend.pure.m3.serialization.filesystem.usercodestorage.RepositoryCodeStorage; import org.finos.legend.pure.m3.serialization.filesystem.usercodestorage.fs.MutableFSCodeStorage; diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/PureIDELight_NoExtension.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/PureIDELight_NoExtension.java index 327a1658a1f..719bf7c5541 100644 --- a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/PureIDELight_NoExtension.java +++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/PureIDELight_NoExtension.java @@ -27,24 +27,22 @@ import org.eclipse.collections.api.list.MutableList; import org.eclipse.jetty.servlets.CrossOriginFilter; import org.finos.legend.engine.pure.runtime.compiler.interpreted.natives.LegendCompileMixedProcessorSupport; -import org.finos.legend.pure.ide.light.ServerConfiguration; -import org.finos.legend.pure.ide.light.SourceLocationConfiguration; -import org.finos.legend.pure.ide.light.api.Activities; -import org.finos.legend.pure.ide.light.api.FileManagement; -import org.finos.legend.pure.ide.light.api.LifeCycle; -import org.finos.legend.pure.ide.light.api.Service; -import org.finos.legend.pure.ide.light.api.Suggestion; -import org.finos.legend.pure.ide.light.api.concept.Concept; -import org.finos.legend.pure.ide.light.api.concept.MovePackageableElements; -import org.finos.legend.pure.ide.light.api.concept.RenameConcept; -import org.finos.legend.pure.ide.light.api.execution.function.Execute; -import org.finos.legend.pure.ide.light.api.execution.go.ExecuteGo; -import org.finos.legend.pure.ide.light.api.execution.test.ExecuteTests; -import org.finos.legend.pure.ide.light.api.find.FindInSources; -import org.finos.legend.pure.ide.light.api.find.FindPureFile; -import org.finos.legend.pure.ide.light.api.find.FindTextPreview; -import org.finos.legend.pure.ide.light.api.source.UpdateSource; -import org.finos.legend.pure.ide.light.session.PureSession; +import org.finos.legend.engine.ide.api.Activities; +import org.finos.legend.engine.ide.api.FileManagement; +import org.finos.legend.engine.ide.api.LifeCycle; +import org.finos.legend.engine.ide.api.Service; +import org.finos.legend.engine.ide.api.Suggestion; +import org.finos.legend.engine.ide.api.concept.Concept; +import org.finos.legend.engine.ide.api.concept.MovePackageableElements; +import org.finos.legend.engine.ide.api.concept.RenameConcept; +import org.finos.legend.engine.ide.api.execution.function.Execute; +import org.finos.legend.engine.ide.api.execution.go.ExecuteGo; +import org.finos.legend.engine.ide.api.execution.test.ExecuteTests; +import org.finos.legend.engine.ide.api.find.FindInSources; +import org.finos.legend.engine.ide.api.find.FindPureFile; +import org.finos.legend.engine.ide.api.find.FindTextPreview; +import org.finos.legend.engine.ide.api.source.UpdateSource; +import org.finos.legend.engine.ide.session.PureSession; import org.finos.legend.pure.m3.serialization.filesystem.repository.CodeRepository; import org.finos.legend.pure.m3.serialization.filesystem.repository.CodeRepositoryProviderHelper; import org.finos.legend.pure.m3.serialization.filesystem.repository.CodeRepositorySet; diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/PureIDEServer.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/PureIDEServer.java new file mode 100644 index 00000000000..150e3f049b4 --- /dev/null +++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/PureIDEServer.java @@ -0,0 +1,158 @@ +// Copyright 2020 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.engine.ide; + +import io.dropwizard.Application; +import io.dropwizard.assets.AssetsBundle; +import io.dropwizard.setup.Bootstrap; +import io.dropwizard.setup.Environment; +import io.federecio.dropwizard.swagger.SwaggerBundle; +import io.federecio.dropwizard.swagger.SwaggerBundleConfiguration; +import io.federecio.dropwizard.swagger.SwaggerResource; +import org.eclipse.collections.api.factory.Lists; +import org.eclipse.collections.api.factory.Maps; +import org.eclipse.collections.api.factory.Sets; +import org.eclipse.collections.api.list.MutableList; +import org.eclipse.collections.api.set.MutableSet; +import org.eclipse.jetty.servlets.CrossOriginFilter; +import org.finos.legend.engine.ide.ServerConfiguration; +import org.finos.legend.engine.ide.SourceLocationConfiguration; +import org.finos.legend.engine.ide.api.*; +import org.finos.legend.engine.ide.api.concept.Concept; +import org.finos.legend.engine.ide.api.concept.MovePackageableElements; +import org.finos.legend.engine.ide.api.concept.RenameConcept; +import org.finos.legend.engine.ide.api.execution.function.Execute; +import org.finos.legend.engine.ide.api.execution.go.ExecuteGo; +import org.finos.legend.engine.ide.api.execution.test.ExecuteTests; +import org.finos.legend.engine.ide.api.find.FindInSources; +import org.finos.legend.engine.ide.api.find.FindPureFile; +import org.finos.legend.engine.ide.api.find.FindTextPreview; +import org.finos.legend.engine.ide.api.source.UpdateSource; +import org.finos.legend.engine.ide.session.PureSession; +import org.finos.legend.pure.m3.serialization.filesystem.repository.CodeRepository; +import org.finos.legend.pure.m3.serialization.filesystem.repository.CodeRepositoryProviderHelper; +import org.finos.legend.pure.m3.serialization.filesystem.repository.CodeRepositorySet; +import org.finos.legend.pure.m3.serialization.filesystem.usercodestorage.RepositoryCodeStorage; +import org.finos.legend.pure.m3.serialization.filesystem.usercodestorage.classpath.ClassLoaderCodeStorage; + +import javax.servlet.DispatcherType; +import javax.servlet.FilterRegistration; +import java.util.EnumSet; +import java.util.List; +import java.util.Map; + +public abstract class PureIDEServer extends Application +{ + private PureSession pureSession; + + @Override + public void initialize(Bootstrap bootstrap) + { + bootstrap.addBundle(new SwaggerBundle() + { + @Override + protected SwaggerBundleConfiguration getSwaggerBundleConfiguration( + ServerConfiguration configuration) + { + return configuration.swagger; + } + }); + bootstrap.addBundle(new AssetsBundle("/web/ide", "/ide", "index.html", "static")); + } + + @Override + public void run(ServerConfiguration configuration, Environment environment) throws Exception + { + environment.jersey().setUrlPattern("/*"); + environment.jersey().register(new SwaggerResource( + "", + configuration.swagger.getSwaggerViewConfiguration(), + configuration.swagger.getSwaggerOAuth2Configuration(), + configuration.swagger.getContextRoot() + + (configuration.swagger.getContextRoot().endsWith("/") ? "" : "/") + "api") + ); + + this.pureSession = new PureSession(configuration.sourceLocationConfiguration, this.getRepositories(configuration.sourceLocationConfiguration, configuration.requiredRepositories)); + + environment.jersey().register(new Concept(pureSession)); + environment.jersey().register(new RenameConcept(pureSession)); + environment.jersey().register(new MovePackageableElements(pureSession)); + + environment.jersey().register(new Execute(pureSession)); + environment.jersey().register(new ExecuteGo(pureSession)); + environment.jersey().register(new ExecuteTests(pureSession)); + + environment.jersey().register(new FindInSources(pureSession)); + environment.jersey().register(new FindPureFile(pureSession)); + environment.jersey().register(new FindTextPreview((pureSession))); + + environment.jersey().register(new UpdateSource(pureSession)); + + environment.jersey().register(new Activities(pureSession)); + environment.jersey().register(new FileManagement(pureSession)); + environment.jersey().register(new LifeCycle(pureSession)); + + environment.jersey().register(new Suggestion(pureSession)); + + environment.jersey().register(new Service(pureSession)); + + enableCors(environment); + + postInit(); + } + + protected void postInit() + { + } + + private void enableCors(Environment environment) + { + FilterRegistration.Dynamic corsFilter = environment.servlets().addFilter("CORS", CrossOriginFilter.class); + corsFilter.setInitParameter(CrossOriginFilter.ALLOWED_METHODS_PARAM, "GET,PUT,POST,DELETE,OPTIONS"); + corsFilter.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM, "*"); + corsFilter.setInitParameter(CrossOriginFilter.ALLOWED_TIMING_ORIGINS_PARAM, "*"); + corsFilter.setInitParameter(CrossOriginFilter.ALLOWED_HEADERS_PARAM, "X-Requested-With,Content-Type,Accept,Origin,Access-Control-Allow-Credentials,x-b3-parentspanid,x-b3-sampled,x-b3-spanid,x-b3-traceid"); + corsFilter.setInitParameter(CrossOriginFilter.CHAIN_PREFLIGHT_PARAM, "false"); + corsFilter.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), false, "*"); + } + + private MutableList getRepositories(org.finos.legend.engine.ide.SourceLocationConfiguration sourceLocationConfiguration, List requiredRepositories) + { + Map repoToCodeStorageMap = Maps.mutable.empty(); + repoToCodeStorageMap.putAll(CodeRepositoryProviderHelper.findCodeRepositories().toMap(r -> r, ClassLoaderCodeStorage::new)); + repoToCodeStorageMap.putAll(this.buildRepositories(sourceLocationConfiguration).toMap(cs -> cs.getAllRepositories().getOnly(), cs -> cs)); + + CodeRepositorySet codeRepositorySet = CodeRepositorySet.newBuilder().withCodeRepositories(repoToCodeStorageMap.keySet()).build(); + + if (requiredRepositories != null) + { + MutableSet requiredSet = Sets.mutable.withAll(requiredRepositories); + if (codeRepositorySet.hasRepository("pure_ide")) + { + requiredSet.add("pure_ide"); + } + codeRepositorySet = codeRepositorySet.subset(requiredSet); + } + + return codeRepositorySet.getRepositories().collect(repoToCodeStorageMap::get, Lists.mutable.ofInitialCapacity(codeRepositorySet.size())); + } + + public PureSession getPureSession() + { + return pureSession; + } + + protected abstract MutableList buildRepositories(SourceLocationConfiguration sourceLocationConfiguration); +} diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/ServerConfiguration.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/ServerConfiguration.java new file mode 100644 index 00000000000..b0521074fe3 --- /dev/null +++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/ServerConfiguration.java @@ -0,0 +1,32 @@ +// Copyright 2020 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.engine.ide; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import io.dropwizard.Configuration; +import io.federecio.dropwizard.swagger.SwaggerBundleConfiguration; +import org.finos.legend.engine.ide.SourceLocationConfiguration; + +import java.util.List; + +@JsonIgnoreProperties( + ignoreUnknown = true +) +public class ServerConfiguration extends Configuration +{ + public SwaggerBundleConfiguration swagger; + public SourceLocationConfiguration sourceLocationConfiguration; + public List requiredRepositories; +} \ No newline at end of file diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/SourceLocationConfiguration.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/SourceLocationConfiguration.java new file mode 100644 index 00000000000..415c6c719f3 --- /dev/null +++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/SourceLocationConfiguration.java @@ -0,0 +1,27 @@ +// Copyright 2021 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.engine.ide; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties( + ignoreUnknown = true +) +public class SourceLocationConfiguration +{ + public String welcomeFileDirectory; + public String coreFilesLocation; + public String ideFilesLocation; +} diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/Activities.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/Activities.java new file mode 100644 index 00000000000..8a0fb70cf95 --- /dev/null +++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/Activities.java @@ -0,0 +1,88 @@ +// Copyright 2020 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.engine.ide.api; + +import io.swagger.annotations.Api; +import org.finos.legend.engine.ide.session.PureSession; +import org.json.simple.JSONObject; +import org.json.simple.JSONValue; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.StreamingOutput; +import java.io.PrintWriter; + +@Api(tags = "Activities") +@Path("/") +public class Activities +{ + private PureSession pureSession; + + public Activities(PureSession pureSession) + { + this.pureSession = pureSession; + } + + @GET + @Path("conceptsActivity") + public Response conceptsActivity() + { + return Response.ok((StreamingOutput) outputStream -> + { + outputStream.write(("{\"initializing\":" + !this.pureSession.getPureRuntime().isInitializedNoLock() + ",\"text\":\"" + this.pureSession.message.getMessage() + "\"}").getBytes()); + outputStream.close(); + }).build(); + } + + @GET + @Path("executionActivity") + public Response executionActivity(@Context HttpServletRequest request, @Context HttpServletResponse response) + { + return Response.ok((StreamingOutput) outputStream -> + { + boolean isExecuting = false; + boolean isInitializing = true; + if (pureSession != null) + { + isInitializing = pureSession.getPureRuntime().isInitializing(); + isExecuting = pureSession.getCurrentExecutionCount() != 0; + } + outputStream.write(("{\"executing\":" + (isExecuting || isInitializing) + ",\"text\":\"" + pureSession.message.getMessage() + "\"}").getBytes()); + outputStream.close(); + }).build(); + } + + @GET + @Path("initializationActivity") + public Response initializationActivity() + { + return Response.ok((StreamingOutput) outStream -> + { + JSONObject json = new JSONObject(); + json.put("initializing", false); + json.put("text", this.pureSession.message.getMessage()); + json.put("archiveLocked", false); + try (PrintWriter writer = new PrintWriter(outStream)) + { + JSONValue.writeJSONString(json, writer); + } + outStream.close(); + }).build(); + } +} diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/FileManagement.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/FileManagement.java new file mode 100644 index 00000000000..ac4bec9aa91 --- /dev/null +++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/FileManagement.java @@ -0,0 +1,378 @@ +// Copyright 2020 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.engine.ide.api; + +import io.swagger.annotations.Api; +import org.eclipse.collections.api.block.predicate.Predicate; +import org.eclipse.collections.api.list.MutableList; +import org.eclipse.collections.impl.utility.LazyIterate; +import org.finos.legend.engine.ide.helpers.response.ExceptionTranslation; +import org.finos.legend.engine.ide.session.PureSession; +import org.finos.legend.pure.m3.serialization.filesystem.repository.ScratchCodeRepository; +import org.finos.legend.pure.m3.serialization.filesystem.usercodestorage.CodeStorageNode; +import org.finos.legend.pure.m3.serialization.filesystem.usercodestorage.CodeStorageNodeStatus; +import org.finos.legend.pure.m3.serialization.filesystem.usercodestorage.ImmutableRepositoryCodeStorage; +import org.finos.legend.pure.m3.serialization.filesystem.usercodestorage.MutableRepositoryCodeStorage; +import org.finos.legend.pure.m3.serialization.filesystem.usercodestorage.classpath.Version; +import org.finos.legend.pure.m3.serialization.filesystem.usercodestorage.vcs.VersionControlledCodeStorage; +import org.finos.legend.pure.m3.serialization.filesystem.usercodestorage.welcome.WelcomeCodeStorage; +import org.json.simple.JSONObject; +import org.json.simple.JSONValue; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.*; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.StreamingOutput; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Comparator; +import java.util.Iterator; +import java.util.Optional; +import java.util.regex.Pattern; + +@Api(tags = "File Management") +@Path("/") +public class FileManagement +{ + private static final Pattern FILE_NAME_PATTERN = Pattern.compile("/?+(\\w+/)*+\\w+(\\.\\w++)*+"); + + private final PureSession session; + + public FileManagement(PureSession session) + { + this.session = session; + } + + + private static final Predicate IGNORED_NODE = (Predicate) node -> + { + String name = node.getName(); + return ".svn".equals(name) || (name != null && name.endsWith(".iml")); + }; + + private static final Comparator NODE_COMPARATOR = (node1, node2) -> + { + if (node1.isDirectory()) + { + return node2.isDirectory() ? node1.getName().compareTo(node2.getName()) : -1; + } + else + { + return node2.isDirectory() ? 1 : node1.getName().compareTo(node2.getName()); + } + }; + + @DELETE + @Path("deleteFile/{filePath:.+}") + public Response deleteFile(@PathParam("filePath") String filePath, @Context HttpServletRequest request, @Context HttpServletResponse response) + { + try + { + session.getPureRuntime().delete("/" + filePath); + return Response.ok((StreamingOutput) outputStream -> + { + outputStream.write(("{\"cached\":" + false + "}").getBytes()); + outputStream.close(); + }).build(); + } + catch (Exception e) + { + return Response.status(Response.Status.BAD_REQUEST).entity((StreamingOutput) outputStream -> + { + outputStream.write(("\"" + JSONValue.escape(ExceptionTranslation.buildExceptionMessage(session, e, new ByteArrayOutputStream()).getText()) + "\"").getBytes()); + outputStream.close(); + }).build(); + } + } + + @POST + @Path("newFile/{filePath:.+}") + public Response newFile(@PathParam("filePath") String filePath, @Context HttpServletRequest request, @Context HttpServletResponse response) + { + try + { + session.getPureRuntime().create("/" + filePath); + + return Response.ok((StreamingOutput) outputStream -> + { + outputStream.write(("{\"cached\":" + false + "}").getBytes()); + outputStream.close(); + }).build(); + } + catch (Exception e) + { + return Response.status(Response.Status.BAD_REQUEST).entity((StreamingOutput) outputStream -> + { + outputStream.write(("\"" + JSONValue.escape(ExceptionTranslation.buildExceptionMessage(session, e, new ByteArrayOutputStream()).getText()) + "\"").getBytes()); + outputStream.close(); + }).build(); + } + } + + @POST + @Path("newFolder/{filePath:.+}") + public Response newFolder(@PathParam("filePath") String filePath, @Context HttpServletRequest request, @Context HttpServletResponse response) + { + try + { + session.getCodeStorage().createFolder("/" + filePath); + + return Response.ok((StreamingOutput) outputStream -> + { + outputStream.write(("{\"cached\":" + false + "}").getBytes()); + outputStream.close(); + }).build(); + } + catch (Exception e) + { + return Response.status(Response.Status.BAD_REQUEST).entity((StreamingOutput) outputStream -> + { + outputStream.write(("\"" + JSONValue.escape(ExceptionTranslation.buildExceptionMessage(session, e, new ByteArrayOutputStream()).getText()) + "\"").getBytes()); + outputStream.close(); + }).build(); + } + } + + @PUT + @Path("renameFile") + public Response renameFile(RenameFileInput input, @Context HttpServletRequest request, @Context HttpServletResponse response) + { + try + { + String oldPath = input.oldPath; + String newPath = input.newPath; + + if (oldPath == null || !FILE_NAME_PATTERN.matcher(oldPath).matches()) + { + throw new IllegalArgumentException("Invalid old path"); + } + if (newPath == null || !FILE_NAME_PATTERN.matcher(newPath).matches()) + { + throw new IllegalArgumentException("Invalid new path"); + } + + this.session.getPureRuntime().move(oldPath, newPath); + + return Response.ok((StreamingOutput) outputStream -> + { + outputStream.write(("{\"oldPath\":\"" + JSONValue.escape(oldPath) + "\",\"newPath\":\"" + JSONObject.escape(newPath) + "\"}").getBytes()); + outputStream.close(); + }).build(); + } + catch (Exception e) + { + return Response.status(Response.Status.BAD_REQUEST).entity((StreamingOutput) outputStream -> + { + outputStream.write(("\"" + JSONValue.escape(ExceptionTranslation.buildExceptionMessage(session, e, new ByteArrayOutputStream()).getText()) + "\"").getBytes()); + outputStream.close(); + }).build(); + } + } + + @GET + @Path("dir") + public Response dir(@Context HttpServletRequest request, @Context HttpServletResponse response) + { + try + { + response.setContentType("application/json"); + String path = request.getParameter("parameters"); + StringBuilder json = new StringBuilder("["); + MutableList nodes = LazyIterate.reject(session.getCodeStorage().getFiles(path), IGNORED_NODE).toSortedList(NODE_COMPARATOR); + if ("/".equals(path)) + { + nodes.sortThis((o1, o2) -> + { + String name1 = WelcomeCodeStorage.WELCOME_FILE_NAME.equals(o1.getName()) || "platform".equals(o1.getName()) || ScratchCodeRepository.NAME.equals(o1.getName()) ? "zzz" + o1.getName() : o1.getName(); + String name2 = WelcomeCodeStorage.WELCOME_FILE_NAME.equals(o2.getName()) || "platform".equals(o2.getName()) || ScratchCodeRepository.NAME.equals(o2.getName()) ? "zzz" + o2.getName() : o2.getName(); + return name1.compareTo(name2); + }); + } + ; + if (nodes.notEmpty()) + { + MutableRepositoryCodeStorage codeStorage = session.getCodeStorage(); + Iterator iterator = nodes.iterator(); + writeNode(json, codeStorage, path, iterator.next()); + while (iterator.hasNext()) + { + json.append(','); + writeNode(json, codeStorage, path, iterator.next()); + } + } + json.append(']'); + + return Response.ok((StreamingOutput) outputStream -> + { + outputStream.write(json.toString().getBytes(), 0, json.length()); + outputStream.close(); + }).build(); + } + catch (Exception e) + { + return Response.status(Response.Status.BAD_REQUEST).entity((StreamingOutput) outputStream -> + { + outputStream.write(("\"" + JSONValue.escape(ExceptionTranslation.buildExceptionMessage(session, e, new ByteArrayOutputStream()).getText()) + "\"").getBytes()); + outputStream.close(); + }).build(); + } + } + + @GET + @Path("fileAsJson/{filePath:.+}") + public Response fileAsJson(@PathParam("filePath") String filePath) + { + try + { + MutableRepositoryCodeStorage codeStorage = session.getCodeStorage(); + if (codeStorage == null) + { + throw new RuntimeException("Cannot find code storage"); + } + byte[] content; + try + { + content = codeStorage.getContentAsBytes(filePath); + } + catch (Exception e) + { + StringBuilder message = new StringBuilder("Error accessing resource \""); + message.append(filePath); + message.append('"'); + if (e.getMessage() != null) + { + message.append(": "); + message.append(e.getMessage()); + } + throw new IOException(message.toString(), e); + } + if (content == null) + { + throw new IOException("Could not find resource \"" + filePath + "\""); + } + + return Response.ok((StreamingOutput) outputStream -> + { + outputStream.write(this.transformContent(content, codeStorage.getOriginalCodeStorage(codeStorage.getRepositoryForPath(filePath)) instanceof ImmutableRepositoryCodeStorage)); + outputStream.close(); + }).build(); + } + catch (Exception e) + { + return Response.status(Response.Status.BAD_REQUEST).entity((StreamingOutput) outputStream -> + { + outputStream.write(("\"" + JSONValue.escape(ExceptionTranslation.buildExceptionMessage(session, e, new ByteArrayOutputStream()).getText()) + "\"").getBytes()); + outputStream.close(); + }).build(); + } + } + + private byte[] transformContent(byte[] content, boolean isImmutable) + { + JSONObject object = new JSONObject(); + object.put("content", new String(content)); + object.put("RO", isImmutable); + return object.toJSONString().getBytes(); + } + + private void writeNode(StringBuilder builder, MutableRepositoryCodeStorage codeStorage, String path, CodeStorageNode node) + { + String fullPath = "/".equals(path) ? (path + node.getName()) : (path + "/" + node.getName()); + if (node.isDirectory()) + { + if ("/".equals(path)) + { + writeRepoNode(builder, codeStorage, fullPath, node); + } + else + { + writeDirectoryNode(builder, fullPath, codeStorage, node); + } + } + else + { + writeFileNode(builder, codeStorage, fullPath, node); + } + } + + private void writeRepoNode(StringBuilder builder, MutableRepositoryCodeStorage cs, String path, CodeStorageNode repo) + { + VersionControlledCodeStorage codeStorage = (VersionControlledCodeStorage) cs; + // Assume SVN until Git code storage is added + Optional currentRev = codeStorage.getCurrentRevision(path); + long currentRevision = currentRev.isPresent() ? Long.parseLong(currentRev.get()) : 0L; + String repoName = codeStorage.getRepositoryForPath(path).getName(); + builder.append("{\"li_attr\":{\"id\":\"file_"); + builder.append(path); + builder.append("\",\"path\":\"").append(path).append("\",\"file\":false,\"repo\":true"); + builder.append(",\"RO\":").append(codeStorage.getOriginalCodeStorage(codeStorage.getRepositoryForPath(path)) instanceof ImmutableRepositoryCodeStorage); + builder.append("},\"text\":\""); + builder.append(repo.getName()); + if (currentRevision >= 0) + { + builder.append("\",\"icon\":\"/ide/pure/icons/filesystem/cloud.png\",\"state\":\"closed\",\"children\":true}"); + } + else if ("platform".equals(repoName)) + { + builder.append(" ("); + builder.append(Version.SERVER); + builder.append(')'); + builder.append("\",\"icon\":\"/ide/pure/icons/wrench.png\",\"state\":\"closed\",\"children\":true}"); + } + else + { + builder.append("\",\"icon\":\"/ide/pure/icons/scratchpad.png\",\"state\":\"closed\",\"children\":true}"); + } + } + + private void writeDirectoryNode(StringBuilder builder, String path, MutableRepositoryCodeStorage codeStorage, CodeStorageNode directory) + { + builder.append("{\"li_attr\":{\"id\":\"file_"); + builder.append(path); + builder.append("\",\"path\":\"").append(path).append("\",\"file\":false"); + builder.append(",\"RO\":").append(codeStorage.getOriginalCodeStorage(codeStorage.getRepositoryForPath(path)) instanceof ImmutableRepositoryCodeStorage); + builder.append("},\"text\":\""); + builder.append(directory.getName()); + builder.append("\",\"state\":\"closed\",\"children\":").append(!codeStorage.isEmptyFolder(path)).append("}"); + } + + private void writeFileNode(StringBuilder builder, MutableRepositoryCodeStorage codeStorage, String path, CodeStorageNode file) + { + builder.append("{\"li_attr\":{\"id\":\"file_"); + builder.append(path); + builder.append("\",\"path\":\"").append(path).append("\",\"file\":true"); + builder.append(",\"RO\":").append(codeStorage.getOriginalCodeStorage(codeStorage.getRepositoryForPath(path)) instanceof ImmutableRepositoryCodeStorage); + + if (file.getStatus() != CodeStorageNodeStatus.NORMAL) + { + builder.append(",\"statusType\":\""); + builder.append(file.getStatus()); + builder.append('"'); + } + + builder.append("},\"text\":\""); + builder.append(file.getName()); + builder.append("\",\"icon\":\"/ide/pure/icons/filesystem/txt.png\"}"); + } + + + public static class RenameFileInput + { + public String oldPath; + public String newPath; + } +} \ No newline at end of file diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/LifeCycle.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/LifeCycle.java new file mode 100644 index 00000000000..71cbe84eb8e --- /dev/null +++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/LifeCycle.java @@ -0,0 +1,88 @@ +// Copyright 2020 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.engine.ide.api; + +import io.swagger.annotations.Api; +import org.finos.legend.engine.ide.session.PureSession; +import org.finos.legend.pure.m3.serialization.runtime.PureRuntime; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.StreamingOutput; +import java.io.IOException; + +@Api(tags = "LifeCycle") +@Path("/") +public class LifeCycle +{ + private PureSession pureSession; + + public LifeCycle(PureSession pureSession) + { + this.pureSession = pureSession; + } + + @GET + @Path("initialize") + public Response initialize() + { + PureRuntime pureRuntime = pureSession.getPureRuntime(); + + return Response.ok((StreamingOutput) outStream -> + { + if (pureRuntime.isFullyInitialized()) + { + outStream.write(("{\"cached\":false, \"datamarts\": [" + pureSession.getPureRuntime().getCodeStorage().getAllRepositories().collect(s -> "\"" + s.getName() + "\"").makeString(",") + "]}").getBytes()); + outStream.close(); + return; + } + + try + { + pureRuntime.reset(); + pureRuntime.initialize(pureSession.message); + outStream.write("{\"text\":\"Full recompile completed successfully\", \"cached\":".getBytes()); + outStream.write((pureRuntime.getCache().getCacheState().isCached() + "}").getBytes()); + outStream.close(); + } + catch (IOException | RuntimeException | Error e) + { + //e.printStackTrace(); + pureSession.getPureRuntime().getCache().deleteCache(); + throw e; + } + }).build(); + } + + @POST + @Path("executeSaveAndReset") + public Response executeSaveAndReset(@Context HttpServletRequest request, @Context HttpServletResponse response) + { + return Response.ok((StreamingOutput) outputStream -> + { + PureRuntime pureRuntime = pureSession.getPureRuntime(); + pureRuntime.reset(); + pureRuntime.getCache().deleteCache(); + pureSession.saveFiles(request, response); + outputStream.write(("{\"text\":\"Reset Done\", \"cached\":" + false + "}").getBytes()); + outputStream.close(); + }).build(); + } +} diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/Service.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/Service.java new file mode 100644 index 00000000000..19020df8933 --- /dev/null +++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/Service.java @@ -0,0 +1,62 @@ +// 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.engine.ide.api; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.eclipse.collections.api.tuple.Pair; +import org.finos.legend.engine.ide.api.execution.function.manager.ContentType; +import org.finos.legend.engine.ide.api.execution.function.manager.ExecutionManager; +import org.finos.legend.engine.ide.api.execution.function.manager.ExecutionRequest; +import org.finos.legend.engine.ide.api.execution.function.manager.HttpServletResponseWriter; +import org.finos.legend.engine.ide.session.PureSession; +import org.finos.legend.pure.m4.coreinstance.CoreInstance; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.core.Context; +import java.io.IOException; +import java.util.Map; + +@Api(tags = "Service") +@Path("") +public class Service +{ + private final PureSession pureSession; + + public Service(PureSession pureSession) + { + this.pureSession = pureSession; + } + + @GET + @Path("{path:.+}") + @ApiOperation(value = "") + public void exec(@Context HttpServletRequest request, @Context HttpServletResponse response, @PathParam("path") String path) throws IOException + { + Pair> result = this.pureSession.getPureRuntime().getURLPatternLibrary().tryExecution("/" + path, this.pureSession.getPureRuntime().getProcessorSupport(), request.getParameterMap()); + if (result == null) + { + response.sendError(404, "The service '" + path + "' can't be found!"); + return; + } + + ExecutionManager executionManager = new ExecutionManager(pureSession.getFunctionExecution()); + executionManager.execute(new ExecutionRequest(result.getTwo()), new HttpServletResponseWriter(response), ContentType.text); + } +} diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/Suggestion.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/Suggestion.java new file mode 100644 index 00000000000..f4467316cb3 --- /dev/null +++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/Suggestion.java @@ -0,0 +1,554 @@ +// 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.engine.ide.api; + +import io.swagger.annotations.Api; +import org.eclipse.collections.api.RichIterable; +import org.eclipse.collections.api.factory.Lists; +import org.eclipse.collections.api.factory.Sets; +import org.eclipse.collections.api.list.ListIterable; +import org.eclipse.collections.api.list.MutableList; +import org.eclipse.collections.api.set.MutableSet; +import org.finos.legend.engine.ide.helpers.response.ExceptionTranslation; +import org.finos.legend.engine.ide.session.PureSession; +import org.finos.legend.pure.m3.coreinstance.Package; +import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.extension.Profile; +import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.function.PackageableFunction; +import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.function.property.Property; +import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.type.Class; +import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.type.Enumeration; +import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.valuespecification.InstanceValueInstance; +import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.valuespecification.SimpleFunctionExpression; +import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.valuespecification.VariableExpressionInstance; +import org.finos.legend.pure.m3.navigation.M3Properties; +import org.finos.legend.pure.m3.navigation.PackageableElement.PackageableElement; +import org.finos.legend.pure.m3.navigation.ProcessorSupport; +import org.finos.legend.pure.m3.navigation._class._Class; +import org.finos.legend.pure.m3.navigation.function.Function; +import org.finos.legend.pure.m3.serialization.runtime.PureRuntime; +import org.finos.legend.pure.m3.serialization.runtime.Source; +import org.finos.legend.pure.m4.coreinstance.CoreInstance; +import org.json.simple.JSONValue; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.StreamingOutput; +import java.io.ByteArrayOutputStream; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +@Api(tags = "Suggestion") +@Path("/") +public class Suggestion +{ + // NOTE: this is the list of auto-import packages defined in m3.pure + private static final List AUTO_IMPORTS = Arrays.asList( + "meta::pure::metamodel", + "meta::pure::metamodel::type", + "meta::pure::metamodel::type::generics", + "meta::pure::metamodel::relationship", + "meta::pure::metamodel::valuespecification", + "meta::pure::metamodel::multiplicity", + "meta::pure::metamodel::function", + "meta::pure::metamodel::function::property", + "meta::pure::metamodel::extension", + "meta::pure::metamodel::import", + "meta::pure::functions::date", + "meta::pure::functions::string", + "meta::pure::functions::collection", + "meta::pure::functions::meta", + "meta::pure::functions::constraints", + "meta::pure::functions::lang", + "meta::pure::functions::boolean", + "meta::pure::functions::tools", + "meta::pure::functions::io", + "meta::pure::functions::math", + "meta::pure::functions::asserts", + "meta::pure::functions::test", + "meta::pure::functions::multiplicity", + "meta::pure::router", + "meta::pure::service", + "meta::pure::tds", + "meta::pure::tools", + "meta::pure::profiles" + ); + private final PureSession session; + + public Suggestion(PureSession session) + { + this.session = session; + } + + @POST + @Path("suggestion/incompletePath") + public Response getSuggestionsForIncompletePath( + @Context HttpServletRequest request, + IncompletePathSuggestionInput input, + @Context HttpServletResponse response) + { + PureRuntime runtime = this.session.getPureRuntime(); + ProcessorSupport processorSupport = runtime.getProcessorSupport(); + try + { + CoreInstance coreInstance = runtime.getCoreInstance(input.path); + if (coreInstance instanceof Package) + { + ListIterable children = coreInstance.getValueForMetaPropertyToMany(M3Properties.children) + .select(child -> input.types == null || input.types.isEmpty() || input.types.contains(child.getClassifier().getName())); + + return Response.ok((StreamingOutput) outputStream -> + { + outputStream.write("[".getBytes()); + for (int i = 0; i < children.size(); i++) + { + CoreInstance child = children.get(i); + String pureName = child instanceof PackageableFunction ? child.getValueForMetaPropertyToOne(M3Properties.functionName).getName() : child.getValueForMetaPropertyToOne(M3Properties.name).getName(); + String text = child instanceof PackageableFunction ? Function.prettyPrint(child, processorSupport) : child.getValueForMetaPropertyToOne(M3Properties.name).getName(); + MutableList requiredClassProperties = child instanceof Class ? _Class.getSimpleProperties(child, processorSupport) + // NOTE: make sure to only consider required (non-qualified) properties: i.e. multiplicity lower bound != 0 + .selectInstancesOf(Property.class).select(prop -> + { + CoreInstance lowerBound = prop.getValueForMetaPropertyToOne(M3Properties.multiplicity).getValueForMetaPropertyToOne(M3Properties.lowerBound); + // NOTE: here the lower bound can be nullish when there's multiplicity parameter being used + // but we skip that case for now + return lowerBound != null && !lowerBound.getValueForMetaPropertyToOne(M3Properties.value).getName().equals("0"); + } + ).toList() : Lists.mutable.empty(); + + outputStream.write("{\"pureType\":\"".getBytes()); + outputStream.write(JSONValue.escape(child.getClassifier().getName()).getBytes()); + outputStream.write("\",\"pureName\":\"".getBytes()); + outputStream.write(JSONValue.escape(pureName).getBytes()); + outputStream.write("\",\"pureId\":\"".getBytes()); + outputStream.write(JSONValue.escape(PackageableElement.getUserPathForPackageableElement(child)).getBytes()); + outputStream.write("\",\"text\":\"".getBytes()); + outputStream.write(JSONValue.escape(text).getBytes()); + outputStream.write("\"".getBytes()); + + if (requiredClassProperties.notEmpty()) + { + outputStream.write(",\"requiredClassProperties\":[".getBytes()); + + for (int j = 0; j < requiredClassProperties.size(); j++) + { + outputStream.write("\"".getBytes()); + outputStream.write(JSONValue.escape(requiredClassProperties.get(j).getValueForMetaPropertyToOne(M3Properties.name).getName()).getBytes()); + outputStream.write("\"".getBytes()); + + if (j != requiredClassProperties.size() - 1) + { + outputStream.write(",".getBytes()); + } + } + + outputStream.write("]".getBytes()); + } + + outputStream.write("}".getBytes()); + + if (i != children.size() - 1) + { + outputStream.write(",".getBytes()); + } + } + outputStream.write("]".getBytes()); + outputStream.close(); + }).build(); + } + return Response.ok((StreamingOutput) outputStream -> + { + outputStream.write("[]".getBytes()); + outputStream.close(); + }).build(); + } + catch (Exception e) + { + return Response.status(Response.Status.BAD_REQUEST).entity((StreamingOutput) outputStream -> + { + outputStream.write(("\"" + JSONValue.escape(ExceptionTranslation.buildExceptionMessage(session, e, new ByteArrayOutputStream()).getText()) + "\"").getBytes()); + outputStream.close(); + }).build(); + } + } + + public static class IncompletePathSuggestionInput + { + public String path; + public List types; + } + + @POST + @Path("suggestion/identifier") + public Response getSuggestionsForIdentifier(@Context HttpServletRequest request, + IdentifierSuggestionInput input, + @Context HttpServletResponse response) + { + PureRuntime runtime = this.session.getPureRuntime(); + ProcessorSupport processorSupport = runtime.getProcessorSupport(); + // NOTE: here we take into account: first, the imported packages in scope, then the root package (::) and lastly + // the auto imported packages in the global scope + MutableList allPackagePaths = Lists.mutable.withAll(input.importPaths).with("::").withAll(AUTO_IMPORTS).distinct(); + + try + { + MutableList packages = allPackagePaths.collect(runtime::getCoreInstance).selectInstancesOf(Package.class); + return Response.ok((StreamingOutput) outputStream -> + { + List children = packages.flatCollect(pack -> pack.getValueForMetaPropertyToMany(M3Properties.children)) + // we do not need to get the packages here + .select(child -> !(child instanceof Package)) + .select(child -> input.types == null || input.types.isEmpty() || input.types.contains(child.getClassifier().getName())); + + outputStream.write("[".getBytes()); + for (int i = 0; i < children.size(); i++) + { + CoreInstance child = children.get(i); + String pureName = child instanceof PackageableFunction ? child.getValueForMetaPropertyToOne(M3Properties.functionName).getName() : child.getValueForMetaPropertyToOne(M3Properties.name).getName(); + String text = child instanceof PackageableFunction ? Function.prettyPrint(child, processorSupport) : child.getValueForMetaPropertyToOne(M3Properties.name).getName(); + MutableList requiredClassProperties = child instanceof Class ? _Class.getSimpleProperties(child, processorSupport) + // NOTE: make sure to only consider required (non-qualified) properties: i.e. multiplicity lower bound != 0 + .selectInstancesOf(Property.class).select(prop -> + { + CoreInstance lowerBound = prop.getValueForMetaPropertyToOne(M3Properties.multiplicity).getValueForMetaPropertyToOne(M3Properties.lowerBound); + // NOTE: here the lower bound can be nullish when there's multiplicity parameter being used + // but we skip that case for now + return lowerBound != null && !lowerBound.getValueForMetaPropertyToOne(M3Properties.value).getName().equals("0"); + } + ).toList() : Lists.mutable.empty(); + + outputStream.write("{\"pureType\":\"".getBytes()); + outputStream.write(JSONValue.escape(child.getClassifier().getName()).getBytes()); + outputStream.write("\",\"pureName\":\"".getBytes()); + outputStream.write(JSONValue.escape(pureName).getBytes()); + outputStream.write("\",\"pureId\":\"".getBytes()); + outputStream.write(JSONValue.escape(PackageableElement.getUserPathForPackageableElement(child)).getBytes()); + outputStream.write("\",\"text\":\"".getBytes()); + outputStream.write(JSONValue.escape(text).getBytes()); + outputStream.write("\"".getBytes()); + + if (requiredClassProperties.notEmpty()) + { + outputStream.write(",\"requiredClassProperties\":[".getBytes()); + + for (int j = 0; j < requiredClassProperties.size(); j++) + { + outputStream.write("\"".getBytes()); + outputStream.write(JSONValue.escape(requiredClassProperties.get(j).getValueForMetaPropertyToOne(M3Properties.name).getName()).getBytes()); + outputStream.write("\"".getBytes()); + + if (j != requiredClassProperties.size() - 1) + { + outputStream.write(",".getBytes()); + } + } + + outputStream.write("]".getBytes()); + } + + outputStream.write("}".getBytes()); + + if (i != children.size() - 1) + { + outputStream.write(",".getBytes()); + } + } + outputStream.write("]".getBytes()); + outputStream.close(); + }).build(); + } + catch (Exception e) + { + return Response.status(Response.Status.BAD_REQUEST).entity((StreamingOutput) outputStream -> + { + outputStream.write(("\"" + JSONValue.escape(ExceptionTranslation.buildExceptionMessage(session, e, new ByteArrayOutputStream()).getText()) + "\"").getBytes()); + outputStream.close(); + }).build(); + } + } + + public static class IdentifierSuggestionInput + { + public List importPaths; + public List types; + } + + @POST + @Path("suggestion/attribute") + public Response getSuggestionsForAttribute(@Context HttpServletRequest request, + AttributeSuggestionInput input, + @Context HttpServletResponse response) + { + PureRuntime runtime = this.session.getPureRuntime(); + ProcessorSupport processorSupport = runtime.getProcessorSupport(); + // NOTE: here we take into account: first, the imported packages in scope, then the root package (::) and lastly + // the auto imported packages in the global scope + MutableList allPackagePaths = Lists.mutable.withAll(input.importPaths).withAll(AUTO_IMPORTS).distinct(); + MutableList paths = input.path.contains("::") ? Lists.mutable.of(input.path) : allPackagePaths.collect(pkg -> pkg.concat("::" + input.path)); + + try + { + MutableList suggestions = paths.collect(runtime::getCoreInstance) + // These are the sensible elements to get attributes from at the moment + .select(el -> el instanceof Class || el instanceof Enumeration || el instanceof Profile) + .flatCollect(el -> + { + if (el instanceof Class) + { + return _Class.computePropertiesByName(el, Lists.mutable.withAll(_Class.SIMPLE_PROPERTIES_PROPERTIES).withAll(_Class.QUALIFIED_PROPERTIES_PROPERTIES), processorSupport).collect(property -> new AttributeSuggestion( + property.getClassifier().getName(), + property.getValueForMetaPropertyToOne(M3Properties.name).getName(), + el.getClassifier().getName(), + PackageableElement.getUserPathForPackageableElement(el) + )); + } + if (el instanceof Profile) + { + return Lists.mutable.withAll(el.getValueForMetaPropertyToMany(M3Properties.p_tags).collect(tag -> new AttributeSuggestion( + tag.getClassifier().getName(), + tag.getValueForMetaPropertyToOne(M3Properties.value).getName(), + el.getClassifier().getName(), + PackageableElement.getUserPathForPackageableElement(el) + ))).withAll(el.getValueForMetaPropertyToMany(M3Properties.p_stereotypes).collect(stereotype -> new AttributeSuggestion( + stereotype.getClassifier().getName(), + stereotype.getValueForMetaPropertyToOne(M3Properties.value).getName(), + el.getClassifier().getName(), + PackageableElement.getUserPathForPackageableElement(el))) + ); + } + if (el instanceof Enumeration) + { + return el.getValueForMetaPropertyToMany(M3Properties.values).collect(enumValue -> new AttributeSuggestion( + enumValue.getClassifier().getName(), + enumValue.getValueForMetaPropertyToOne(M3Properties.name).getName(), + el.getClassifier().getName(), + PackageableElement.getUserPathForPackageableElement(el) + )); + } + return Collections.emptyList(); + }); + return Response.ok((StreamingOutput) outputStream -> + { + outputStream.write("[".getBytes()); + for (int i = 0; i < suggestions.size(); i++) + { + AttributeSuggestion suggestion = suggestions.get(i); + + outputStream.write("{\"pureType\":\"".getBytes()); + outputStream.write(JSONValue.escape(suggestion.pureType).getBytes()); + outputStream.write("\",\"pureName\":\"".getBytes()); + outputStream.write(JSONValue.escape(suggestion.pureName).getBytes()); + outputStream.write("\",\"owner\":\"".getBytes()); + outputStream.write(JSONValue.escape(suggestion.owner).getBytes()); + outputStream.write("\",\"ownerPureType\":\"".getBytes()); + outputStream.write(JSONValue.escape(suggestion.ownerPureType).getBytes()); + outputStream.write("\"}".getBytes()); + + if (i != suggestions.size() - 1) + { + outputStream.write(",".getBytes()); + } + } + outputStream.write("]".getBytes()); + outputStream.close(); + }).build(); + } + catch (Exception e) + { + return Response.status(Response.Status.BAD_REQUEST).entity((StreamingOutput) outputStream -> + { + outputStream.write(("\"" + JSONValue.escape(ExceptionTranslation.buildExceptionMessage(session, e, new ByteArrayOutputStream()).getText()) + "\"").getBytes()); + outputStream.close(); + }).build(); + } + } + + private static class AttributeSuggestion + { + public final String pureType; + public final String pureName; + public final String ownerPureType; + public final String owner; + + public AttributeSuggestion(String pureType, String pureName, String ownerPureType, String owner) + { + this.pureType = pureType; + this.pureName = pureName; + this.ownerPureType = ownerPureType; + this.owner = owner; + } + } + + public static class AttributeSuggestionInput + { + public List importPaths; + public String path; + } + + @POST + @Path("suggestion/class") + public Response getSuggestionsForClass(@Context HttpServletRequest request, + ClassSuggestionInput input, + @Context HttpServletResponse response) + { + PureRuntime runtime = this.session.getPureRuntime(); + ProcessorSupport processorSupport = runtime.getProcessorSupport(); + MutableList packagePaths = Lists.mutable.withAll(input.importPaths).withAll(AUTO_IMPORTS).distinct(); + + try + { + MutableList classes = packagePaths.collect(runtime::getCoreInstance) + .flatCollect(pkg -> pkg.getValueForMetaPropertyToMany(M3Properties.children)) + .selectInstancesOf(Class.class); + return Response.ok((StreamingOutput) outputStream -> + { + outputStream.write("[".getBytes()); + for (int i = 0; i < classes.size(); i++) + { + Class cls = classes.get(i); + MutableList requiredClassProperties = _Class.getSimpleProperties(cls, processorSupport) + // NOTE: make sure to only consider required (non-qualified) properties: i.e. multiplicity lower bound != 0 + .selectInstancesOf(Property.class).select(prop -> + { + CoreInstance lowerBound = prop.getValueForMetaPropertyToOne(M3Properties.multiplicity).getValueForMetaPropertyToOne(M3Properties.lowerBound); + // NOTE: here the lower bound can be nullish when there's multiplicity parameter being used + // but we skip that case for now + return lowerBound != null && !lowerBound.getValueForMetaPropertyToOne(M3Properties.value).getName().equals("0"); + } + ).toList(); + + outputStream.write("{\"pureName\":\"".getBytes()); + outputStream.write(JSONValue.escape(cls.getValueForMetaPropertyToOne(M3Properties.name).getName()).getBytes()); + outputStream.write("\",\"pureId\":\"".getBytes()); + outputStream.write(JSONValue.escape(PackageableElement.getUserPathForPackageableElement(cls)).getBytes()); + outputStream.write("\",\"requiredClassProperties\":[".getBytes()); + + for (int j = 0; j < requiredClassProperties.size(); j++) + { + outputStream.write("\"".getBytes()); + outputStream.write(JSONValue.escape(requiredClassProperties.get(j).getValueForMetaPropertyToOne(M3Properties.name).getName()).getBytes()); + outputStream.write("\"".getBytes()); + + if (j != requiredClassProperties.size() - 1) + { + outputStream.write(",".getBytes()); + } + } + + outputStream.write("]}".getBytes()); + + if (i != classes.size() - 1) + { + outputStream.write(",".getBytes()); + } + } + + outputStream.write("]".getBytes()); + outputStream.close(); + }).build(); + } + catch (Exception e) + { + return Response.status(Response.Status.BAD_REQUEST).entity((StreamingOutput) outputStream -> + { + outputStream.write(("\"" + JSONValue.escape(ExceptionTranslation.buildExceptionMessage(session, e, new ByteArrayOutputStream()).getText()) + "\"").getBytes()); + outputStream.close(); + }).build(); + } + } + + public static class ClassSuggestionInput + { + public List importPaths; + } + + @POST + @Path("suggestion/variable") + public Response getSuggestionsForVariable(@Context HttpServletRequest request, + VariableSuggestionInput input, + @Context HttpServletResponse response) + { + PureRuntime runtime = this.session.getPureRuntime(); + try + { + Source source = runtime.getSourceById(input.sourceId); + ListIterable functionsOrLambdas = source.findFunctionsOrLambasAt(input.line, input.column); + MutableSet varNames = Sets.mutable.empty(); + + for (CoreInstance fn : functionsOrLambdas) + { + // scan for the let expressions then follows by the parameters + RichIterable letVars = fn.getValueForMetaPropertyToMany(M3Properties.expressionSequence) + .select(expression -> expression instanceof SimpleFunctionExpression && "letFunction".equals(((SimpleFunctionExpression) expression)._functionName())) + .collect(expression -> ((SimpleFunctionExpression) expression)._parametersValues().toList().getFirst()) + // NOTE: make sure to only consider let statements prior to the call + .select(letVar -> letVar.getSourceInformation().getEndLine() < input.line || (letVar.getSourceInformation().getEndLine() == input.line && letVar.getSourceInformation().getEndColumn() < input.column)) + .selectInstancesOf(InstanceValueInstance.class); + for (InstanceValueInstance var : letVars) + { + varNames.add(var.getValueForMetaPropertyToOne(M3Properties.values).getName()); + } + RichIterable params = fn.getValueForMetaPropertyToOne(M3Properties.classifierGenericType) + .getValueForMetaPropertyToOne(M3Properties.typeArguments) + .getValueForMetaPropertyToOne(M3Properties.rawType) + .getValueForMetaPropertyToMany(M3Properties.parameters) + .selectInstancesOf(VariableExpressionInstance.class); + for (VariableExpressionInstance var : params) + { + varNames.add(var._name()); + } + } + MutableList suggestions = Lists.mutable.withAll(varNames); + + return Response.ok((StreamingOutput) outputStream -> + { + outputStream.write("[".getBytes()); + for (int i = 0; i < suggestions.size(); i++) + { + String varName = suggestions.get(i); + outputStream.write("{\"name\":\"".getBytes()); + outputStream.write(JSONValue.escape(varName).getBytes()); + outputStream.write("\"}".getBytes()); + + if (i != suggestions.size() - 1) + { + outputStream.write(",".getBytes()); + } + } + outputStream.write("]".getBytes()); + outputStream.close(); + }).build(); + } + catch (Exception e) + { + return Response.status(Response.Status.BAD_REQUEST).entity((StreamingOutput) outputStream -> + { + outputStream.write(("\"" + JSONValue.escape(ExceptionTranslation.buildExceptionMessage(session, e, new ByteArrayOutputStream()).getText()) + "\"").getBytes()); + outputStream.close(); + }).build(); + } + } + + public static class VariableSuggestionInput + { + public String sourceId; + public int line; + public int column; + } +} diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/concept/AbstractRenameConceptEntry.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/concept/AbstractRenameConceptEntry.java new file mode 100644 index 00000000000..30d038837a5 --- /dev/null +++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/concept/AbstractRenameConceptEntry.java @@ -0,0 +1,59 @@ +// Copyright 2022 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.engine.ide.api.concept; + +public abstract class AbstractRenameConceptEntry +{ + private final int lineIndex; + private final int columnIndex; + private final String name; + private final String type; + + public AbstractRenameConceptEntry(int lineIndex, int columnIndex, String name, String type) + { + this.lineIndex = lineIndex; + this.columnIndex = columnIndex; + this.name = name; + this.type = type; + } + + public int getConceptLineIndex() + { + return this.lineIndex; + } + + public int getConceptColumnIndex() + { + return this.columnIndex; + } + + public String getConceptName() + { + return this.name; + } + + public String getConceptType() + { + return this.type; + } + + abstract int getReplaceLineIndex(); + + abstract int getReplaceColumnIndex(); + + abstract String getOriginalReplaceString(); + + abstract String getNewReplaceString(); +} diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/concept/Concept.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/concept/Concept.java new file mode 100644 index 00000000000..453e58a6659 --- /dev/null +++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/concept/Concept.java @@ -0,0 +1,118 @@ +// Copyright 2020 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.engine.ide.api.concept; + +import io.swagger.annotations.Api; +import org.finos.legend.engine.ide.api.concept.GetConcept; +import org.finos.legend.engine.ide.session.PureSession; +import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.function.ConcreteFunctionDefinition; +import org.finos.legend.pure.m3.coreinstance.meta.pure.metamodel.function.property.QualifiedPropertyInstance; +import org.finos.legend.pure.m3.navigation.Instance; +import org.finos.legend.pure.m3.navigation.M3Paths; +import org.finos.legend.pure.m3.navigation.M3Properties; +import org.finos.legend.pure.m3.navigation.PackageableElement.PackageableElement; +import org.finos.legend.pure.m3.serialization.runtime.PureRuntime; +import org.finos.legend.pure.m3.serialization.runtime.Source; +import org.finos.legend.pure.m4.coreinstance.CoreInstance; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.StreamingOutput; +import java.io.IOException; +import java.io.OutputStream; + +@Api(tags = "Concepts") +@Path("/") +public class Concept +{ + private final PureSession session; + + public Concept(PureSession session) + { + this.session = session; + } + + @POST + @Path("getConcept") + public Response getConcept(@Context HttpServletRequest request, @Context HttpServletResponse response) + { + return Response.ok((StreamingOutput) outputStream -> + { + this.session.saveOnly(request, response, outputStream, new GetConcept()); + }).build(); + } + + @GET + @Path("getConceptInfo") + public Response getConceptInfo(@Context HttpServletRequest request, @Context HttpServletResponse response) + { + return Response.ok((StreamingOutput) outputStream -> + { + String file = request.getParameter("file"); + String line = request.getParameter("line"); + String column = request.getParameter("column"); + + PureRuntime pureRuntime = session.getPureRuntime(); + Source src = pureRuntime.getSourceById(file); + + response.setContentType("application/json"); + if (src != null) + { + CoreInstance found = src.navigate(Integer.parseInt(line), Integer.parseInt(column), session.getPureRuntime().getProcessorSupport()); + if (found != null) + { + if (Instance.instanceOf(found, M3Paths.AbstractProperty, session.getPureRuntime().getProcessorSupport())) + { + String path = PackageableElement.getUserPathForPackageableElement(found); + CoreInstance owner = Instance.getValueForMetaPropertyToOneResolved(found, M3Properties.owner, session.getPureRuntime().getProcessorSupport()); + String ownerPath = PackageableElement.getUserPathForPackageableElement(owner); + outputStream.write(("{\"path\":\"" + path + "\",\"pureName\":\"" + found.getValueForMetaPropertyToOne(M3Properties.name).getName() + "\",\"owner\":\"" + ownerPath + "\",\"pureType\":\"" + (found instanceof QualifiedPropertyInstance ? "QualifiedProperty" : "Property") + "\"}").getBytes()); + } + else if (Instance.instanceOf(found, M3Paths.Enum, session.getPureRuntime().getProcessorSupport())) + { + String path = PackageableElement.getUserPathForPackageableElement(found); + CoreInstance owner = found.getClassifier(); + String ownerPath = PackageableElement.getUserPathForPackageableElement(owner); + outputStream.write(("{\"path\":\"" + path + "\",\"pureName\":\"" + found.getName() + "\",\"owner\":\"" + ownerPath + "\",\"pureType\":\"Enum\"}").getBytes()); + } + else + { + String path = PackageableElement.getUserPathForPackageableElement(found); + outputStream.write(("{\"path\":\"" + path + "\",\"pureName\":\"" + (found instanceof ConcreteFunctionDefinition ? found.getValueForMetaPropertyToOne(M3Properties.functionName).getName() : found.getName()) + "\",\"pureType\":\"" + found.getValueForMetaPropertyToOne(M3Properties.classifierGenericType).getValueForMetaPropertyToOne(M3Properties.rawType).getName() + "\"}").getBytes()); + } + } + else + { + this.writeErrorResponse(outputStream, file, line, column); + } + } + else + { + this.writeErrorResponse(outputStream, file, line, column); + } + + }).build(); + } + + private void writeErrorResponse(OutputStream outStream, String file, String line, String column) throws IOException + { + outStream.write(("{\"error\":true,\"text\":\"Cannot find source for file: " + file + " line: " + line + " col: " + column + "\"}").getBytes()); + } +} diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/concept/GetConcept.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/concept/GetConcept.java new file mode 100644 index 00000000000..75b765bb940 --- /dev/null +++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/concept/GetConcept.java @@ -0,0 +1,105 @@ +// Copyright 2020 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.engine.ide.api.concept; + +import org.finos.legend.engine.ide.helpers.response.ExceptionTranslation; +import org.finos.legend.engine.ide.session.PureSession; +import org.finos.legend.engine.ide.session.SimpleFunction; +import org.finos.legend.pure.m3.navigation.ProcessorSupport; +import org.finos.legend.pure.m3.serialization.runtime.PureRuntime; +import org.finos.legend.pure.m3.serialization.runtime.Source; +import org.finos.legend.pure.m4.coreinstance.CoreInstance; +import org.finos.legend.pure.m4.coreinstance.SourceInformation; +import org.finos.legend.pure.m4.exception.PureException; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.JSONValue; + +import javax.servlet.http.HttpServletResponse; +import java.io.OutputStream; + +public class GetConcept implements SimpleFunction +{ + @Override + public void run(PureSession pureSession, JSONObject extraParams, JSONArray modifiedFiles, HttpServletResponse response, OutputStream outputStream) throws Exception + { + PureException compilationError = null; + String compilationErrorText = ""; + PureRuntime pureRuntime = pureSession.getPureRuntime(); + + ProcessorSupport processorSupport = pureRuntime.getProcessorSupport(); + + Source src = pureRuntime.getSourceById((String) extraParams.get("file")); + if (!src.isCompiled()) + { + try + { + pureRuntime.compile(); + } + catch (PureException e) + { + compilationError = e; + compilationErrorText = JSONValue.escape(ExceptionTranslation.pureExceptionToJson(pureSession, compilationError, null).getText()); + // check if target file was compiled even if the whole compilation failed. + if (!src.isCompiled()) + { + throw e; + } + } + } + Long line = (Long) extraParams.get("line"); + Long column = (Long) extraParams.get("column"); + CoreInstance found = src.navigate(line.intValue(), column.intValue(), processorSupport); + + if (null != found) + { + SourceInformation sourceInfo = found.getSourceInformation(); + if (null == sourceInfo) + { + outputStream.write(("{\"error\":true,\"text\":\"" + (null == compilationError ? "Navigation is not supported yet for this element!" : compilationErrorText) + "\"").getBytes()); + outputStream.write((",\"compiler\":\"\"").getBytes()); + outputStream.write((",\"cached\":" + pureRuntime.getCache().getCacheState().isCached()).getBytes()); + if (null != compilationError) + { + outputStream.write(",\"exceptionType\":\"Parser error\"".getBytes()); + } + outputStream.write("}".getBytes()); + } + else + { + Source source = pureRuntime.getSourceById(sourceInfo.getSourceId()); + outputStream.write(("{\"text\":\"" + (null == compilationError ? "" : compilationErrorText) + "\"").getBytes()); + outputStream.write((",\"compiler\":\"\"").getBytes()); + outputStream.write((",\"jumpTo\":{\"source\":\"" + sourceInfo.getSourceId() + "\", \"line\":" + sourceInfo.getLine() + ", \"column\":" + sourceInfo.getColumn() + ", \"RO\":\"" + source.isImmutable() + "\"}").getBytes()); + outputStream.write((",\"cached\":" + pureRuntime.getCache().getCacheState().isCached()).getBytes()); + if (null != compilationError) + { + outputStream.write(",\"exceptionType\":\"Parser error\"".getBytes()); + } + outputStream.write("}".getBytes()); + } + } + else + { + outputStream.write(("{\"error\":true,\"text\":\"" + (null == compilationError ? "Navigation is not supported yet for this element!" : compilationErrorText) + "\"").getBytes()); + outputStream.write((",\"compiler\":\"\"").getBytes()); + if (null != compilationError) + { + outputStream.write(",\"exceptionType\":\"Parser error\"".getBytes()); + } + outputStream.write("}".getBytes()); + } + } +} diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/concept/MovePackageableElements.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/concept/MovePackageableElements.java new file mode 100644 index 00000000000..bdce662a9ee --- /dev/null +++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/concept/MovePackageableElements.java @@ -0,0 +1,187 @@ +// 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.engine.ide.api.concept; + +import io.swagger.annotations.Api; +import org.eclipse.collections.api.factory.Lists; +import org.eclipse.collections.api.list.MutableList; +import org.eclipse.collections.api.multimap.list.MutableListMultimap; +import org.eclipse.collections.api.multimap.set.MutableSetMultimap; +import org.eclipse.collections.api.partition.list.PartitionMutableList; +import org.eclipse.collections.impl.factory.Multimaps; +import org.eclipse.collections.impl.tuple.Tuples; +import org.finos.legend.engine.ide.api.concept.AbstractRenameConceptEntry; +import org.finos.legend.engine.ide.api.concept.RenameConceptUtility; +import org.finos.legend.engine.ide.api.concept.RenamePackageEntry; +import org.finos.legend.engine.ide.helpers.response.ExceptionTranslation; +import org.finos.legend.engine.ide.session.PureSession; +import org.json.simple.JSONValue; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.StreamingOutput; +import java.io.ByteArrayOutputStream; +import java.util.List; +import java.util.regex.Pattern; + +@Api(tags = "Concepts") +@Path("/") +public class MovePackageableElements +{ + private static final Pattern PACKAGE_PATH_PATTERN = Pattern.compile("\\w[\\w$]*+(::\\w[\\w$]*+)*+"); + + private final PureSession session; + + public MovePackageableElements(PureSession session) + { + this.session = session; + } + + @PUT + @Path("movePackageableElements") + public Response movePackageableElements(List inputs, @Context HttpServletRequest request, @Context HttpServletResponse response) + { + try + { + MutableListMultimap entryIndex = Multimaps.mutable.list.empty(); + for (MovePackageableElementInput input : inputs) + { + String sourcePackage = input.sourcePackage; + String destinationPackage = input.destinationPackage; + + if (sourcePackage == null || !PACKAGE_PATH_PATTERN.matcher(sourcePackage).matches()) + { + throw new IllegalArgumentException("Invalid source package"); + } + if (destinationPackage == null || !PACKAGE_PATH_PATTERN.matcher(destinationPackage).matches()) + { + throw new IllegalArgumentException("Invalid destination package"); + } + for (org.finos.legend.engine.ide.api.concept.RenameConceptUtility.RenameConceptInputSourceInformation sourceInformation : input.sourceInformations) + { + entryIndex.add( + Tuples.pair( + sourceInformation.sourceId, + new org.finos.legend.engine.ide.api.concept.RenamePackageEntry(sourceInformation.line - 1, sourceInformation.column - 1, input.pureName, input.pureType, sourcePackage, destinationPackage) + ) + ); + } + } + + if (!entryIndex.keysView().allSatisfy(sourceId -> this.session.getPureRuntime().getSourceById(sourceId).isCompiled())) + { + throw new IllegalStateException("Source code must be compiled before refactoring"); + } + if (!entryIndex.keysView().allSatisfy(sourceId -> !sourceId.startsWith("/platform/"))) + { + throw new IllegalArgumentException("Some files belong in /platform directory. Cannot refactor files in /platform directory"); + } + + entryIndex.forEachKeyMultiValues((sourceId, entries) -> + { + String originalSourceCode = session.getPureRuntime().getSourceById(sourceId).getContent(); + String[] originalSourceCodeLines = originalSourceCode.split("\n", -1); + PartitionMutableList partition = (PartitionMutableList) (org.finos.legend.engine.ide.api.concept.RenameConceptUtility.removeInvalidReplaceConceptEntries(originalSourceCodeLines, Lists.mutable.ofAll(entries))) + .partition(entry -> entry.getReplaceColumnIndex() >= 0 && originalSourceCodeLines[entry.getReplaceLineIndex()].startsWith(entry.getOriginalReplaceString(), entry.getReplaceColumnIndex())); + String updatedSourceCode = org.finos.legend.engine.ide.api.concept.RenameConceptUtility.replace(originalSourceCodeLines, partition.getSelected()); + updatedSourceCode = MovePackageableElements.updateImportStatements( + updatedSourceCode.split("\n", -1), + partition.getRejected().sortThisBy(AbstractRenameConceptEntry::getReplaceLineIndex) + ); + session.getPureRuntime().modify(sourceId, updatedSourceCode); + }); + + return Response.noContent().build(); + } + catch (Exception e) + { + return Response.status(Response.Status.BAD_REQUEST).entity((StreamingOutput) outputStream -> + { + outputStream.write(("\"" + JSONValue.escape(ExceptionTranslation.buildExceptionMessage(this.session, e, new ByteArrayOutputStream()).getText()) + "\"").getBytes()); + outputStream.close(); + }).build(); + } + } + + private static String updateImportStatements(String[] sourceCodeLines, MutableList importUpdateEntries) + { + // identify sections which will reset import scopes + MutableList lineIndices = Lists.mutable.empty(); + lineIndices.add(0); + for (int i = 0; i < sourceCodeLines.length; ++i) + { + if (sourceCodeLines[i].trim().startsWith("###")) + { + lineIndices.add(i); + } + } + lineIndices.add(sourceCodeLines.length); + + // find all the import lines to be updated indexed by the section + MutableSetMultimap lineImportStatementsMap = Multimaps.mutable.set.empty(); + int i = 0; + int j = 0; + while (i < importUpdateEntries.size()) + { + while (j < lineIndices.size() - 1) + { + if (lineIndices.get(j) <= importUpdateEntries.get(i).getReplaceLineIndex() && importUpdateEntries.get(i).getReplaceLineIndex() < lineIndices.get(j + 1)) + { + lineImportStatementsMap.add(Tuples.pair(lineIndices.get(j), importUpdateEntries.get(i).getNewReplaceString())); + break; + } + j++; + } + i++; + } + + // update import statements + final StringBuilder stringBuilder = new StringBuilder(); + for (int lineIndex = 0; lineIndex < sourceCodeLines.length; ++lineIndex) + { + if (lineImportStatementsMap.containsKey(lineIndex)) + { + if (sourceCodeLines[lineIndex].trim().startsWith("###")) + { + stringBuilder.append(sourceCodeLines[lineIndex]).append("\n"); + lineImportStatementsMap.get(lineIndex).forEach(destinationPackage -> stringBuilder.append("import ").append(destinationPackage).append("::*;\n")); + } + else + { + lineImportStatementsMap.get(lineIndex).forEach(destinationPackage -> stringBuilder.append("import ").append(destinationPackage).append("::*;\n")); + stringBuilder.append(sourceCodeLines[lineIndex]).append("\n"); + } + } + else + { + stringBuilder.append(sourceCodeLines[lineIndex]).append("\n"); + } + } + return stringBuilder.substring(0, stringBuilder.length() - 1); + } + + public static class MovePackageableElementInput + { + public String pureName; + public String pureType; + public String sourcePackage; + public String destinationPackage; + public List sourceInformations; + } +} diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/concept/RenameConcept.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/concept/RenameConcept.java new file mode 100644 index 00000000000..ef4c5e9ca8b --- /dev/null +++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/concept/RenameConcept.java @@ -0,0 +1,101 @@ +// 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.engine.ide.api.concept; + +import io.swagger.annotations.Api; +import org.eclipse.collections.api.list.MutableList; +import org.eclipse.collections.api.multimap.list.MutableListMultimap; +import org.eclipse.collections.impl.factory.Multimaps; +import org.eclipse.collections.impl.tuple.Tuples; +import org.finos.legend.engine.ide.api.concept.AbstractRenameConceptEntry; +import org.finos.legend.engine.ide.api.concept.RenameConceptEntry; +import org.finos.legend.engine.ide.api.concept.RenameConceptUtility; +import org.finos.legend.engine.ide.helpers.response.ExceptionTranslation; +import org.finos.legend.engine.ide.session.PureSession; +import org.json.simple.JSONValue; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.StreamingOutput; +import java.io.ByteArrayOutputStream; +import java.util.List; + +@Api(tags = "Concepts") +@Path("/") +public class RenameConcept +{ + private final PureSession session; + + public RenameConcept(PureSession session) + { + this.session = session; + } + + @PUT + @Path("renameConcept") + public Response renameConcept(RenameConceptInput input, @Context HttpServletRequest request, @Context HttpServletResponse response) + { + try + { + MutableListMultimap entryIndex = Multimaps.mutable.list.empty(); + for (org.finos.legend.engine.ide.api.concept.RenameConceptUtility.RenameConceptInputSourceInformation sourceInformation : input.sourceInformations) + { + entryIndex.add( + Tuples.pair( + sourceInformation.sourceId, + new RenameConceptEntry(sourceInformation.line - 1, sourceInformation.column - 1, input.oldName, input.pureType, input.newName) + ) + ); + } + + if (!entryIndex.keysView().allSatisfy(sourceId -> this.session.getPureRuntime().getSourceById(sourceId).isCompiled())) + { + throw new IllegalStateException("Source code must be compiled before refactoring"); + } + if (!entryIndex.keysView().allSatisfy(sourceId -> !sourceId.startsWith("/platform/"))) + { + throw new IllegalArgumentException("Some files belong in /platform directory. Cannot refactor files in /platform directory"); + } + + entryIndex.forEachKeyMultiValues((sourceId, entry) -> + { + String[] originalSourceCodeLines = session.getPureRuntime().getSourceById(sourceId).getContent().split("\n", -1); + session.getPureRuntime().modify(sourceId, org.finos.legend.engine.ide.api.concept.RenameConceptUtility.replace(originalSourceCodeLines, org.finos.legend.engine.ide.api.concept.RenameConceptUtility.removeInvalidReplaceConceptEntries(originalSourceCodeLines, (MutableList) entry))); + }); + + return Response.noContent().build(); + } + catch (Exception e) + { + return Response.status(Response.Status.BAD_REQUEST).entity((StreamingOutput) outputStream -> + { + outputStream.write(("\"" + JSONValue.escape(ExceptionTranslation.buildExceptionMessage(this.session, e, new ByteArrayOutputStream()).getText()) + "\"").getBytes()); + outputStream.close(); + }).build(); + } + } + + public static class RenameConceptInput + { + public String oldName; + public String newName; + public String pureType; + public List sourceInformations; + } +} diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/concept/RenameConceptEntry.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/concept/RenameConceptEntry.java new file mode 100644 index 00000000000..243fa8f17ba --- /dev/null +++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/concept/RenameConceptEntry.java @@ -0,0 +1,52 @@ +// Copyright 2022 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.engine.ide.api.concept; + +import org.finos.legend.engine.ide.api.concept.AbstractRenameConceptEntry; + +public class RenameConceptEntry extends AbstractRenameConceptEntry +{ + private final String newName; + + public RenameConceptEntry(int line, int column, String name, String type, String newName) + { + super(line, column, name, type); + this.newName = newName; + } + + @Override + public int getReplaceLineIndex() + { + return this.getConceptLineIndex(); + } + + @Override + public int getReplaceColumnIndex() + { + return this.getConceptColumnIndex(); + } + + @Override + public String getOriginalReplaceString() + { + return this.getConceptName(); + } + + @Override + public String getNewReplaceString() + { + return this.newName; + } +} diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/concept/RenameConceptUtility.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/concept/RenameConceptUtility.java new file mode 100644 index 00000000000..41ebef6c68e --- /dev/null +++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/concept/RenameConceptUtility.java @@ -0,0 +1,84 @@ +// Copyright 2022 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.engine.ide.api.concept; + +import org.eclipse.collections.api.block.predicate.Predicate; +import org.eclipse.collections.api.list.MutableList; +import org.finos.legend.engine.ide.api.concept.AbstractRenameConceptEntry; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class RenameConceptUtility +{ + private static final String CONCRETE_FUNCTION_DEFINITION = "ConcreteFunctionDefinition"; + private static final Pattern IDENTIFIER_REGEX = Pattern.compile("^(\\w[\\w$]*+)"); + private static final Pattern SIGNATURE_SUFFIX_REGEX = Pattern.compile("_[\\w$]+_"); + + private RenameConceptUtility() + { + } + + public static MutableList removeInvalidReplaceConceptEntries(final String[] sourceCodeLines, MutableList entries) + { + return entries.select(new Predicate() + { + @Override + public boolean accept(org.finos.legend.engine.ide.api.concept.AbstractRenameConceptEntry entry) + { + if (entry.getConceptColumnIndex() < 0 || entry.getConceptColumnIndex() >= sourceCodeLines[entry.getConceptLineIndex()].length()) + { + return false; + } + Matcher matcher = IDENTIFIER_REGEX.matcher(sourceCodeLines[entry.getConceptLineIndex()].substring(entry.getConceptColumnIndex())); + if (matcher.find()) + { + String identifierAtThisPoint = matcher.group(1); + boolean isExactMatch = identifierAtThisPoint.equals(entry.getConceptName()); + boolean isSignatureOfOriginal = CONCRETE_FUNCTION_DEFINITION.equals(entry.getConceptType()) && identifierAtThisPoint.startsWith(entry.getConceptName()) && SIGNATURE_SUFFIX_REGEX.matcher(identifierAtThisPoint.substring(entry.getConceptName().length())).matches(); + return isExactMatch || isSignatureOfOriginal; + } + return false; + } + }); + } + + public static String replace(String[] sourceCodeLines, MutableList entries) + { + entries.sortThisBy(org.finos.legend.engine.ide.api.concept.AbstractRenameConceptEntry::getReplaceColumnIndex).sortThisBy(org.finos.legend.engine.ide.api.concept.AbstractRenameConceptEntry::getReplaceLineIndex); + StringBuilder stringBuilder = new StringBuilder(); + int counter = 0; + for (int lineIndex = 0; lineIndex < sourceCodeLines.length; ++lineIndex) + { + int columnIndex = 0; + while (counter < entries.size() && entries.get(counter).getReplaceLineIndex() == lineIndex) + { + AbstractRenameConceptEntry entry = entries.get(counter); + stringBuilder.append(sourceCodeLines[lineIndex], columnIndex, entry.getReplaceColumnIndex()).append(entry.getNewReplaceString()); + columnIndex = entry.getReplaceColumnIndex() + entry.getOriginalReplaceString().length(); + counter++; + } + stringBuilder.append(sourceCodeLines[lineIndex].substring(columnIndex)).append("\n"); + } + return stringBuilder.substring(0, stringBuilder.length() - 1); + } + + public static class RenameConceptInputSourceInformation + { + public String sourceId; + public int line; + public int column; + } +} diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/concept/RenamePackageEntry.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/concept/RenamePackageEntry.java new file mode 100644 index 00000000000..baf2fd5d56a --- /dev/null +++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/concept/RenamePackageEntry.java @@ -0,0 +1,54 @@ +// Copyright 2022 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.engine.ide.api.concept; + +import org.finos.legend.engine.ide.api.concept.AbstractRenameConceptEntry; + +public class RenamePackageEntry extends AbstractRenameConceptEntry +{ + private final String sourcePackage; + private final String destinationPackage; + + public RenamePackageEntry(int line, int column, String name, String type, String sourcePackage, String destinationPackage) + { + super(line, column, name, type); + this.sourcePackage = sourcePackage; + this.destinationPackage = destinationPackage; + } + + @Override + public int getReplaceLineIndex() + { + return this.getConceptLineIndex(); + } + + @Override + public int getReplaceColumnIndex() + { + return this.getConceptColumnIndex() - this.getOriginalReplaceString().length() - 2; + } + + @Override + public String getOriginalReplaceString() + { + return this.sourcePackage; + } + + @Override + public String getNewReplaceString() + { + return this.destinationPackage; + } +} diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/function/Execute.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/function/Execute.java new file mode 100644 index 00000000000..c44baf83220 --- /dev/null +++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/function/Execute.java @@ -0,0 +1,97 @@ +// Copyright 2020 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.engine.ide.api.execution.function; + +import io.swagger.annotations.Api; +import org.eclipse.collections.impl.utility.MapIterate; +import org.finos.legend.engine.ide.api.execution.function.manager.ContentType; +import org.finos.legend.engine.ide.api.execution.function.manager.ExecutionManager; +import org.finos.legend.engine.ide.api.execution.function.manager.ExecutionRequest; +import org.finos.legend.engine.ide.api.execution.function.manager.HttpServletResponseWriter; +import org.finos.legend.engine.ide.helpers.JSONResponseTools; +import org.finos.legend.engine.ide.session.PureSession; +import org.finos.legend.pure.m3.exception.PureExecutionException; +import org.finos.legend.pure.m3.execution.FunctionExecution; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.StreamingOutput; +import java.util.Map; + +@Api(tags = "Execute") +@Path("/") +public class Execute +{ + private PureSession pureSession; + + public Execute(PureSession pureSession) + { + this.pureSession = pureSession; + } + + @GET + @Path("execute") + public Response execute(@Context HttpServletRequest request, @Context HttpServletResponse response) + { + return Response.ok((StreamingOutput) outputStream -> + { + try + { + FunctionExecution functionExecution = this.pureSession.getFunctionExecution(); + if (null == functionExecution || !functionExecution.isFullyInitializedForExecution()) + { + throw new PureExecutionException("System not initialized. Make sure that your pure code has compiled successfully in the IDE."); + } + ExecutionManager executionManager = new ExecutionManager(functionExecution); + + StringBuffer urlBuffer = request.getRequestURL(); + String queryString = request.getQueryString(); + if (null != queryString) + { + urlBuffer.append('?'); + urlBuffer.append(queryString); + } + + Map requestParams = request.getParameterMap(); + boolean isJsonInput = JSONResponseTools.JSON_CONTENT_TYPE.equals(request.getContentType()) && (MapIterate.isEmpty(requestParams) || 1 == requestParams.size()); + + if (isJsonInput) + { + executionManager.execute(new ExecutionRequest(requestParams), new HttpServletResponseWriter(response), ContentType.json); + } + else + { + executionManager.execute(new ExecutionRequest(requestParams), new HttpServletResponseWriter(response), ContentType.text); + } + } + catch (IllegalArgumentException e) + { + JSONResponseTools.sendJSONErrorResponse(response, HttpServletResponse.SC_BAD_REQUEST, e, false); + } + catch (RuntimeException | Error e) + { + if (e instanceof Error) + { + throw (Error) e; + } + JSONResponseTools.sendJSONErrorResponse(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e, false); + } + }).build(); + } +} diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/function/manager/ContentType.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/function/manager/ContentType.java new file mode 100644 index 00000000000..f03ee828f7e --- /dev/null +++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/function/manager/ContentType.java @@ -0,0 +1,36 @@ +// Copyright 2020 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.engine.ide.api.execution.function.manager; + +public enum ContentType +{ + json("application/json"), + csv("text/csv"), + text("text/html;charset=UTF-8"), + xlsx("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + + + private final String type; + + ContentType(String type) + { + this.type = type; + } + + public String getType() + { + return this.type; + } +} diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/function/manager/ExecutionManager.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/function/manager/ExecutionManager.java new file mode 100644 index 00000000000..90eb86ed4d8 --- /dev/null +++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/function/manager/ExecutionManager.java @@ -0,0 +1,297 @@ +// Copyright 2020 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.engine.ide.api.execution.function.manager; + +import org.eclipse.collections.api.factory.Lists; +import org.eclipse.collections.api.factory.Maps; +import org.eclipse.collections.api.list.ListIterable; +import org.eclipse.collections.api.map.ImmutableMap; +import org.eclipse.collections.impl.utility.ArrayIterate; +import org.finos.legend.pure.m3.exception.PureExecutionStreamingException; +import org.finos.legend.pure.m3.execution.FunctionExecution; +import org.finos.legend.pure.m3.execution.OutputWriter; +import org.finos.legend.pure.m3.execution.XLSXOutputWriter; +import org.finos.legend.pure.m3.navigation.M3Paths; +import org.finos.legend.pure.m3.navigation.M3Properties; +import org.finos.legend.pure.m3.navigation.ProcessorSupport; +import org.finos.legend.pure.m3.navigation.function.FunctionDescriptor; +import org.finos.legend.pure.m3.navigation.function.InvalidFunctionDescriptorException; +import org.finos.legend.pure.m3.navigation.importstub.ImportStub; +import org.finos.legend.pure.m4.coreinstance.CoreInstance; +import org.finos.legend.pure.runtime.java.shared.canstreamstate.CanStreamState; + +import java.io.OutputStream; +import java.util.Map; + +public class ExecutionManager +{ + public static final String OUTPUT_FORMAT_PARAMETER = "format"; + public static final String OUTPUT_PROCESSOR_PARAMETER = "outFunc"; + public static final String OUTPUT_PROCESSOR_PARAMETER_PARAMETER = "outParam"; + + public static final String EXECUTION_MODE_PARAM = "mode"; + + public static final String FUNCTION_PARAMETER = "func"; + public static final String PARAMETER_PARAMETER = "param"; + public static final String QUERY_PARAMETER = "query"; + public static final String BLOCK_PARAMETER = "block"; + public static final String PROCESSING_FUNC_PARAMETER = "processingFunc"; + public static final String PROCESSING_PARAM_PARAMETER = "processingParam"; + + public static final String OUTPUT_FORMAT_RAW = "raw"; + public static final String OUTPUT_FORMAT_PRE = "pre"; + public static final String OUTPUT_FORMAT_JSON = "json"; + public static final String OUTPUT_FORMAT_CSV = "csv"; + public static final String OUTPUT_FORMAT_XLSX = "xlsx"; + + private static final ImmutableMap OUTPUT_FORMATS = Maps.mutable.empty() + .withKeyValue(OUTPUT_FORMAT_RAW, org.finos.legend.engine.ide.api.execution.function.manager.OutputFormat.RAW) + .withKeyValue(OUTPUT_FORMAT_PRE, org.finos.legend.engine.ide.api.execution.function.manager.OutputFormat.PRE) + .withKeyValue(OUTPUT_FORMAT_JSON, org.finos.legend.engine.ide.api.execution.function.manager.OutputFormat.JSON) + .withKeyValue(OUTPUT_FORMAT_CSV, org.finos.legend.engine.ide.api.execution.function.manager.OutputFormat.CSV) + .withKeyValue(OUTPUT_FORMAT_XLSX, org.finos.legend.engine.ide.api.execution.function.manager.OutputFormat.XLSX) + .toImmutable(); + + private static final org.finos.legend.engine.ide.api.execution.function.manager.OutputFormat DEFAULT_OUTPUT_FORMAT = org.finos.legend.engine.ide.api.execution.function.manager.OutputFormat.JSON; + + private static final String EXECUTE_FUNCTION = "meta::pure::ide::execute_String_$0_1$__List_MANY__String_$0_1$__String_$0_1$__String_$0_1$__String_$0_1$__List_MANY__String_$0_1$__List_MANY__String_MANY_"; + + private final FunctionExecutionParser parser; + private final FunctionExecution functionExecution; + + public ExecutionManager(FunctionExecution functionExecution) + { + this.parser = new FunctionExecutionParser(functionExecution.getProcessorSupport()); + this.functionExecution = functionExecution; + + } + + public void execute(ExecutionRequest executionRequest, HttpResponseWriter response, ContentType inputContentType) + { + org.finos.legend.engine.ide.api.execution.function.manager.OutputFormat format = this.getOutputFormat(executionRequest.getRequestParams()); + + CoreInstance executeFunction = this.getFunction(EXECUTE_FUNCTION); + + String funcParam = executionRequest.getRequestParamToOne(FUNCTION_PARAMETER); + String blockParam = executionRequest.getRequestParamToOne(BLOCK_PARAMETER); + String queryParam = executionRequest.getRequestParamToOne(QUERY_PARAMETER); + if (funcParam == null && blockParam == null && queryParam == null) + { + StringBuilder message = new StringBuilder("Invalid request, please provide one of these request parameters :"); + message.append(FUNCTION_PARAMETER).append(", ").append(BLOCK_PARAMETER).append(", ").append(QUERY_PARAMETER); + message.append("\nRequest parameters received were:\n"); + executionRequest.getRequestParams().forEach((key, values) -> ArrayIterate.appendString(values, message.append(key), "=[", ", ", "]\n")); + throw new IllegalArgumentException(message.toString()); + } + + HttpInformation httpInformation; + if (format != null) + { + if (format == org.finos.legend.engine.ide.api.execution.function.manager.OutputFormat.RAW && funcParam != null) + { + //try to find a content type on the function itself + String functionId = convertFunctionToFunctionId(funcParam); + CoreInstance function = this.getFunction(functionId); + httpInformation = HttpInformation.fromFunction(function, this.functionExecution.getProcessorSupport()); + + //has no content type flagged so use defaults + if (httpInformation.getContentType() == null) + { + httpInformation = new HttpInformation(format.getDefaultContentType().getType(), format.getDefaultContentDisposition()); + } + } + else + { + httpInformation = new HttpInformation(format.getDefaultContentType().getType(), format.getDefaultContentDisposition()); + } + } + else + { + String outFuncParam = executionRequest.getRequestParamToOne(OUTPUT_PROCESSOR_PARAMETER); + if (outFuncParam != null) + { + String functionId = convertFunctionToFunctionId(outFuncParam); + CoreInstance function = this.getFunction(functionId); + httpInformation = HttpInformation.fromFunction(function, this.functionExecution.getProcessorSupport()); + } + else + { + httpInformation = new HttpInformation(org.finos.legend.engine.ide.api.execution.function.manager.OutputFormat.JSON.getDefaultContentType().getType(), null); + } + } + boolean explicitDisableStreaming = false; + if (funcParam != null) + { + CoreInstance functionToExecute = this.getFunction(funcParam); + explicitDisableStreaming = executionRequest.isStreamingDisabled() || disableStreaming(functionToExecute, this.functionExecution.getProcessorSupport()); + } + boolean canStreamOutput = !explicitDisableStreaming && isStreamingOutputFunction(executionRequest, format); + + this.execute(executeFunction, getParameters(executionRequest, this.parser, inputContentType), response, httpInformation, canStreamOutput, format); + } + + private static boolean disableStreaming(CoreInstance functionToExecute, ProcessorSupport processorSupport) + { + ListIterable functionStereotypes = ImportStub.withImportStubByPasses(functionToExecute.getValueForMetaPropertyToMany(M3Properties.stereotypes), processorSupport); + CoreInstance serviceProfile = processorSupport.package_getByUserPath(M3Paths.service); + return functionStereotypes.anySatisfy(each -> each.getValueForMetaPropertyToOne(M3Properties.profile) == serviceProfile && "disableStreaming".equals(each.getValueForMetaPropertyToOne(M3Properties.value).getName())); + } + + private CoreInstance getFunction(String functionIdOrDescriptor) + { + CoreInstance function = this.functionExecution.getRuntime().getFunction(functionIdOrDescriptor); + if (function == null) + { + throw new IllegalArgumentException("Invalid function specification: " + functionIdOrDescriptor); + } + return function; + } + + private ListIterable getParameters(ExecutionRequest executionRequest, FunctionExecutionParser parser, ContentType inputContentType) + { + + CoreInstance nil = parser.parseParameter("[]", false); + String funcParam = executionRequest.getRequestParamToOne(FUNCTION_PARAMETER); + //todo - just look up the func directly, instead of string? + CoreInstance func = funcParam == null ? nil : parser.parseParameter("'" + convertFunctionToFunctionId(funcParam) + "'", false); + + String[] parametersStrings = executionRequest.getRequestParams().get(PARAMETER_PARAMETER); + CoreInstance params = parametersStrings == null ? nil : ContentType.json.equals(inputContentType) ? parser.parseJsonParameter(parametersStrings[0]) : parser.parseParametersAsList(parametersStrings); + + String blockParam = executionRequest.getRequestParamToOne(BLOCK_PARAMETER); + + String queryParam = executionRequest.getRequestParamToOne(QUERY_PARAMETER); + CoreInstance query = queryParam == null ? nil : parser.parseParameter("'" + queryParam + "'", false); + CoreInstance block = blockParam == null ? nil : parser.wrapString(blockParam); + + String processingFuncParam = executionRequest.getRequestParamToOne(PROCESSING_FUNC_PARAMETER); + CoreInstance processingFunc = processingFuncParam == null ? nil : parser.parseParameter("'" + convertFunctionToFunctionId(processingFuncParam) + "'", false); + + String[] processingParametersStrings = executionRequest.getRequestParams().get(PROCESSING_PARAM_PARAMETER); + CoreInstance processingFuncParams = processingParametersStrings == null ? nil : parser.parseParametersAsList(processingParametersStrings); + + String formatParam = executionRequest.getRequestParamToOne(OUTPUT_FORMAT_PARAMETER); + CoreInstance format = formatParam == null ? nil : parser.parseParameter("'" + formatParam + "'", false); + + String outFuncParam = executionRequest.getRequestParamToOne(OUTPUT_PROCESSOR_PARAMETER); + CoreInstance outFunc = outFuncParam == null ? nil : parser.parseParameter("'" + convertFunctionToFunctionId(outFuncParam) + "'", false); + + String[] outputParametersStrings = executionRequest.getRequestParams().get(OUTPUT_PROCESSOR_PARAMETER_PARAMETER); + CoreInstance outputFuncParams = outputParametersStrings == null ? nil : parser.parseParametersAsList(outputParametersStrings); + + return Lists.fixedSize.of(func, params, query, block, format, processingFunc, processingFuncParams, outFunc, outputFuncParams); + } + + private String convertFunctionToFunctionId(String functionName) + { + String functionId; + try + { + functionId = FunctionDescriptor.functionDescriptorToId(functionName); + } + catch (InvalidFunctionDescriptorException exp) + { + functionId = functionName; + } + return functionId; + } + + private void execute(CoreInstance function, ListIterable parameters, HttpResponseWriter response, HttpInformation httpInformation, boolean canStreamOutput, org.finos.legend.engine.ide.api.execution.function.manager.OutputFormat format) + { + try + { + CanStreamState.setCanStream(canStreamOutput); + response.setIsStreamingResponse(canStreamOutput); + this.addContentTypeAndDispositionHeaders(response, httpInformation); + response.setHeader("Trailer", "X-Streaming-Error"); + // Do not open outputStream in try-with-resources + OutputStream outputStream = response.getOutputStream(); + try + { + OutputWriter writer = this.functionExecution.newOutputWriter(); + if (format == org.finos.legend.engine.ide.api.execution.function.manager.OutputFormat.XLSX) + { + writer = new XLSXOutputWriter(writer); + } + + this.functionExecution.start(function, parameters, outputStream, writer); + } + catch (PureExecutionStreamingException ignore) + { + // ignore streaming exception + } + // outputStream must NOT be closed in case of an uncaught exception + // so the call to close must not be in a finally block or implicit in a try-with-resources + outputStream.close(); + } + catch (Throwable t) + { + if (t instanceof RuntimeException) + { + throw (RuntimeException) t; + } + if (t instanceof Error) + { + throw (Error) t; + } + throw new RuntimeException(t); + } + finally + { + //Reset + CanStreamState.resetCanStream(); + } + } + + private void addContentTypeAndDispositionHeaders(HttpResponseWriter response, HttpInformation httpInformation) + { + String resultContentType = httpInformation.getContentType(); + response.setContentType(resultContentType == null ? ContentType.text.getType() : resultContentType); + String resultContentDisposition = httpInformation.getContentDisposition(); + if (resultContentDisposition != null) + { + response.setContentDisposition(resultContentDisposition); + } + } + + private boolean isStreamingOutputFunction(ExecutionRequest executionRequest, org.finos.legend.engine.ide.api.execution.function.manager.OutputFormat format) + { + return false; +// String[] param = executionRequest.getRequestParams().get(ExecutionManager.OUTPUT_PROCESSOR_PARAMETER); +// return !executionRequest.isStreamingDisabled() && (format == OutputFormat.JSON || format == OutputFormat.CSV || format == OutputFormat.XLSX || +// (param != null && param.length == 1 && (PatternExecutor.func.equals(param[0]) || TDS_TO_JSON_OBJECT_FUNCTION.equals(param[0])))); + } + + + private org.finos.legend.engine.ide.api.execution.function.manager.OutputFormat getOutputFormat(Map requestParams) + { + String[] outputFormatStrings = requestParams.get(OUTPUT_FORMAT_PARAMETER); + if (outputFormatStrings == null) + { + return requestParams.containsKey(OUTPUT_PROCESSOR_PARAMETER) ? null : DEFAULT_OUTPUT_FORMAT; + } + if (outputFormatStrings.length != 1) + { + throw new IllegalArgumentException("Parameter '" + OUTPUT_FORMAT_PARAMETER + "' must have at most one value"); + } + String formatString = outputFormatStrings[0].trim().toLowerCase(); + org.finos.legend.engine.ide.api.execution.function.manager.OutputFormat format = OUTPUT_FORMATS.get(formatString); + if (format == null) + { + throw new IllegalArgumentException("Unknown output format \"" + outputFormatStrings[0] + "\" (valid formats: " + OUTPUT_FORMATS.keysView().toSortedList().makeString(", ") + ")"); + } + return format; + } +} diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/function/manager/ExecutionRequest.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/function/manager/ExecutionRequest.java new file mode 100644 index 00000000000..b3b48e72dce --- /dev/null +++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/function/manager/ExecutionRequest.java @@ -0,0 +1,61 @@ +// Copyright 2020 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.engine.ide.api.execution.function.manager; + +import java.util.Map; + +public class ExecutionRequest +{ + private final Map requestParams; + private boolean disableStreaming = false; + + public ExecutionRequest(Map requestParams) + { + this(requestParams, false); + } + + public ExecutionRequest(Map requestParams, boolean disableStreaming) + { + this.requestParams = requestParams; + this.disableStreaming = disableStreaming; + } + + public Map getRequestParams() + { + return this.requestParams; + } + + public boolean isStreamingDisabled() + { + return this.disableStreaming; + } + + String getRequestParamToOne(String key) + { + String[] vals = this.requestParams.get(key); + if (vals == null) + { + return null; + } + else if (vals.length == 1) + { + return vals[0]; + } + else + { + throw new IllegalArgumentException("Parameter '" + key + "' must have at most one value"); + } + } +} diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/function/manager/FunctionExecutionParser.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/function/manager/FunctionExecutionParser.java new file mode 100644 index 00000000000..ce6bb7aa8ca --- /dev/null +++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/function/manager/FunctionExecutionParser.java @@ -0,0 +1,432 @@ +// Copyright 2020 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.engine.ide.api.execution.function.manager; + +import org.apache.commons.lang3.StringEscapeUtils; +import org.eclipse.collections.api.list.ListIterable; +import org.eclipse.collections.api.list.MutableList; +import org.eclipse.collections.impl.factory.Lists; +import org.eclipse.collections.impl.list.mutable.FastList; +import org.finos.legend.pure.m3.navigation.*; +import org.finos.legend.pure.m3.navigation.enumeration.Enumeration; +import org.finos.legend.pure.m3.navigation.type.Type; +import org.finos.legend.pure.m4.ModelRepository; +import org.finos.legend.pure.m4.coreinstance.CoreInstance; +import org.finos.legend.pure.runtime.java.extension.external.json.shared.JsonParser; + +class FunctionExecutionParser +{ + private static final char QUOTE = '\''; + private static final char DATE_START = '%'; + private static final char COLLECTION_START = '['; + private static final char COLLECTION_END = ']'; + private static final char COLLECTION_SEPARATOR = ','; + + private final ProcessorSupport processorSupport; + + FunctionExecutionParser(ProcessorSupport processorSupport) + { + this.processorSupport = processorSupport; + } + + CoreInstance parseParametersAsList(String[] parameterStrings) + { + MutableList parameters = FastList.newList(parameterStrings.length); + for (int i = 0; i < parameterStrings.length; i++) + { + parameters.add(parseParameter(parameterStrings[i], true)); + } + + return ValueSpecificationBootstrap.wrapValueSpecification(parameters, true, this.processorSupport); + } + + CoreInstance parseJsonParameter(String parameter) + { + CoreInstance jsonElementParameter = new JsonParser(this.processorSupport).toPureJson(parameter); + return ValueSpecificationBootstrap.wrapValueSpecification(wrapAsList(Lists.fixedSize.of(jsonElementParameter)), true, this.processorSupport); + } + + MutableList parseParameters(Iterable parameterStrings, boolean wrapAsList) + { + MutableList parameters = Lists.mutable.with(); + for (String parameterString : parameterStrings) + { + parameters.add(parseParameter(parameterString, wrapAsList)); + } + return parameters; + } + + CoreInstance parseParameter(String parameterString, boolean wrapAsList) + { + int length = parameterString.length(); + return parseParameter(parameterString, findNextNonWhitespace(parameterString, 0, length), findLastNonWhitespace(parameterString, 0, length) + 1, wrapAsList); + } + + private CoreInstance parseParameter(String paramString, int start, int end, boolean wrapAsList) + { + try + { + if (paramString.charAt(start) == COLLECTION_START) + { + ListIterable coreInstances = parseCollectionParameter(paramString, start, end); + + if (wrapAsList) + { + return wrapAsList(coreInstances); + } + else + { + return ValueSpecificationBootstrap.wrapValueSpecification(coreInstances, true, this.processorSupport); + } + } + else + { + CoreInstance value = parseValue(paramString, start, end); + if (wrapAsList) + { + return wrapAsList(Lists.fixedSize.of(value)); + } + else + { + return ValueSpecificationBootstrap.wrapValueSpecification(value, true, this.processorSupport); + } + } + } + catch (Exception e) + { + throw new IllegalArgumentException("Invalid parameter specification: " + paramString, e); + } + } + + private CoreInstance wrapAsList(ListIterable values) + { + CoreInstance inst = this.processorSupport.newEphemeralAnonymousCoreInstance(M3Paths.List); + Instance.addValueToProperty(inst, M3Properties.values, values, this.processorSupport); + + CoreInstance classifierGenericType = this.processorSupport.newEphemeralAnonymousCoreInstance(M3Paths.GenericType); + Instance.setValueForProperty(classifierGenericType, M3Properties.rawType, this.processorSupport.package_getByUserPath(M3Paths.List), this.processorSupport); + Instance.setValueForProperty(classifierGenericType, M3Properties.typeArguments, Type.wrapGenericType(this.processorSupport.package_getByUserPath(M3Paths.Any), this.processorSupport), this.processorSupport); + + Instance.setValueForProperty(inst, M3Properties.classifierGenericType, classifierGenericType, this.processorSupport); + return inst; + } + + private ListIterable parseCollectionParameter(String string, int start, int end) + { + int index = findNextNonWhitespace(string, start + 1, end); + + // Check for empty collection + if (string.charAt(index) == COLLECTION_END) + { + // Check if there is non-whitespace after the collection end character + if (index + 1 < end) + { + throw new IllegalArgumentException("Invalid collection specification: " + string); + } + return Lists.immutable.with(); + } + + // Parse values in the collection + MutableList values = Lists.mutable.with(); + while ((index != -1) && (index < end)) + { + int valueEnd = findValueEnd(string, index, end); + if (valueEnd == -1) + { + throw new IllegalArgumentException("Error parsing value at index " + index + " of collection specification: " + string); + } + values.add(parseValue(string, index, valueEnd)); + + index = findNextNonWhitespace(string, valueEnd, end); + switch (string.charAt(index)) + { + case COLLECTION_SEPARATOR: + { + index = findNextNonWhitespace(string, index + 1, end); + break; + } + case COLLECTION_END: + { + index = findNextNonWhitespace(string, index + 1, end); + if (index != -1) + { + throw new IllegalArgumentException("Invalid collection specification: " + string.substring(start, end)); + } + return values; + } + default: + { + throw new IllegalArgumentException("Invalid collection specification: " + string.substring(start, end)); + } + } + } + throw new IllegalArgumentException("Invalid collection specification: " + string.substring(start, end)); + } + + private CoreInstance parseValue(String string, int start, int end) + { + try + { + if (isPossiblyDate(string, start, end)) + { + return parsePrimitiveParameter(string.substring(start + 1, end), ModelRepository.DATE_TYPE_NAME); + } + else if (isPossiblyString(string, start, end)) + { + // TODO evaluate whether this is the correct type of unescape + return parsePrimitiveParameter(StringEscapeUtils.unescapeJava(string.substring(start + 1, end - 1)), ModelRepository.STRING_TYPE_NAME); + } + else if (isPossiblyInteger(string, start, end)) + { + return parsePrimitiveParameter(string.substring(start, end), ModelRepository.INTEGER_TYPE_NAME); + } + else if (isPossiblyFloat(string, start, end)) + { + return parsePrimitiveParameter(string.substring(start, end), ModelRepository.FLOAT_TYPE_NAME); + } + else if (isPossiblyBoolean(string, start, end)) + { + return parsePrimitiveParameter(string.substring(start, end), ModelRepository.BOOLEAN_TYPE_NAME); + } + else if (isPossiblyPropertyOrEnumeration(string, start, end)) + { + return parsePropertyOrEnumerationParameter(string, start, end); + } + else if (isPossiblyPackageableElement(string, start, end)) + { + return parsePackageableElementParameter(string, start, end); + } + else + { + throw new RuntimeException("Cannot determine type: " + string.substring(start, end)); + } + } + catch (Exception e) + { + throw new IllegalArgumentException("Invalid value specification: " + string.substring(start, end), e); + } + } + + private CoreInstance parsePrimitiveParameter(String string, String primitiveTypeName) + { + return this.processorSupport.newCoreInstance(string, primitiveTypeName, null); + } + + public CoreInstance wrapString(String string) + { + CoreInstance value = this.processorSupport.newCoreInstance(string, ModelRepository.STRING_TYPE_NAME, null); + return ValueSpecificationBootstrap.wrapValueSpecification(value, true, this.processorSupport); + } + + private CoreInstance parsePropertyOrEnumerationParameter(String string, int start, int end) + { + int splitIndex = indexOf(string, '.', start, end); + if (splitIndex == -1) + { + throw new IllegalArgumentException("Invalid property or enumeration specification: " + string.substring(start, end)); + } + + String ownerString = string.substring(start, splitIndex); + CoreInstance owner = this.processorSupport.package_getByUserPath(ownerString); + if (owner == null) + { + throw new IllegalArgumentException("Unknown element: " + ownerString); + } + + String valueString = string.substring(splitIndex + 1, end); + if (this.processorSupport.instance_instanceOf(owner, M3Paths.Enumeration)) + { + CoreInstance enumValue = Enumeration.findEnum(owner, valueString); + if (enumValue == null) + { + throw new IllegalArgumentException("Unknown value for " + ownerString + ": " + valueString); + } + return enumValue; + } + else + { + CoreInstance property = this.processorSupport.class_findPropertyUsingGeneralization(owner, valueString); + if (property == null) + { + throw new IllegalArgumentException("Unknown property for " + ownerString + ": " + valueString); + } + return property; + } + } + + private CoreInstance parsePackageableElementParameter(String string, int start, int end) + { + CoreInstance instance = this.processorSupport.package_getByUserPath(string.substring(start, end)); + if (instance == null) + { + throw new IllegalArgumentException("Unknown element: " + string.substring(start, end)); + } + return instance; + } + + private boolean isPossiblyBoolean(String string, int start, int end) + { + String lower = string.substring(start, end).toLowerCase(); + return ModelRepository.BOOLEAN_TRUE.equals(lower) || ModelRepository.BOOLEAN_FALSE.equals(lower); + } + + private boolean isPossiblyDate(String string, int start, int end) + { + return string.charAt(start) == DATE_START; + } + + private boolean isPossiblyString(String string, int start, int end) + { + return (string.charAt(start) == QUOTE) && (string.charAt(end - 1) == QUOTE); + } + + private boolean isPossiblyInteger(String string, int start, int end) + { + char first = string.charAt(start); + if ((first == '+') || (first == '-') || Character.isDigit(first)) + { + for (int i = start + 1; i < end; i++) + { + if (!Character.isDigit(string.charAt(i))) + { + return false; + } + } + return true; + } + else + { + return false; + } + } + + private boolean isPossiblyFloat(String string, int start, int end) + { + char first = string.charAt(start); + if (first == '.') + { + return ((start + 1) < end) && Character.isDigit(string.charAt(start + 1)); + } + else if ((first == '+') || (first == '-') || Character.isDigit(first)) + { + return contains(string, '.', start + 1, end); + } + else + { + return false; + } + } + + private boolean isPossiblyPropertyOrEnumeration(String string, int start, int end) + { + return Character.isLetter(string.charAt(start)) && contains(string, '.', start + 1, end); + } + + private boolean isPossiblyPackageableElement(String string, int start, int end) + { + char first = string.charAt(start); + if (first == ':') + { + return ((end - start) == 2) && (string.charAt(start + 1) == ':'); + } + else + { + return Character.isLetter(first) && !contains(string, '.', start + 1, end); + } + } + + // General parsing helpers + + private static int findNextNonWhitespace(String string, int start, int end) + { + for (int index = start; index < end; index++) + { + if (!Character.isWhitespace(string.charAt(index))) + { + return index; + } + } + return -1; + } + + private static int findLastNonWhitespace(String string, int start, int end) + { + for (int index = end - 1; index >= start; index--) + { + if (!Character.isWhitespace(string.charAt(index))) + { + return index; + } + } + return -1; + } + + private static int findValueEnd(String string, int start, int end) + { + if (string.charAt(start) == QUOTE) + { + int index = start + 1; + while (index < end) + { + switch (string.charAt(index)) + { + case QUOTE: + { + return index + 1; + } + case '\\': + { + index += 2; + break; + } + default: + { + index += 1; + } + } + } + return -1; + } + else + { + for (int index = start; index < end; index++) + { + char character = string.charAt(index); + if ((character == COLLECTION_SEPARATOR) || (character == COLLECTION_END) || Character.isWhitespace(character)) + { + return index; + } + } + return -1; + } + } + + private static boolean contains(String string, char character, int start, int end) + { + return indexOf(string, character, start, end) != -1; + } + + private static int indexOf(String string, char character, int start, int end) + { + for (int index = start; index < end; index++) + { + if (character == string.charAt(index)) + { + return index; + } + } + return -1; + } +} diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/function/manager/HttpInformation.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/function/manager/HttpInformation.java new file mode 100644 index 00000000000..eb1adf00f43 --- /dev/null +++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/function/manager/HttpInformation.java @@ -0,0 +1,68 @@ +// Copyright 2020 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.engine.ide.api.execution.function.manager; + +import org.eclipse.collections.api.block.predicate.Predicate; +import org.finos.legend.pure.m3.navigation.Instance; +import org.finos.legend.pure.m3.navigation.M3Properties; +import org.finos.legend.pure.m3.navigation.ProcessorSupport; +import org.finos.legend.pure.m4.coreinstance.CoreInstance; + +public class HttpInformation +{ + private final String contentType; + private final String contentDisposition; + + public HttpInformation(String contentType, String contentDisposition) + { + this.contentType = contentType; + this.contentDisposition = contentDisposition; + } + + public String getContentType() + { + return this.contentType; + } + + public String getContentDisposition() + { + return this.contentDisposition; + } + + public static HttpInformation fromFunction(CoreInstance function, final ProcessorSupport processorSupport) + { + + CoreInstance contentTypeObj = function.getValueForMetaPropertyToMany(M3Properties.taggedValues).detect(new Predicate() + { + @Override + public boolean accept(CoreInstance each) + { + return "contentType".equals(Instance.getValueForMetaPropertyToOneResolved(each, M3Properties.tag, processorSupport).getName()); + } + }); + CoreInstance contentDisposition = function.getValueForMetaPropertyToMany(M3Properties.taggedValues).detect(new Predicate() + { + @Override + public boolean accept(CoreInstance each) + { + return "contentDisposition".equals(Instance.getValueForMetaPropertyToOneResolved(each, M3Properties.tag, processorSupport).getName()); + } + }); + return new HttpInformation( + contentTypeObj == null ? null : contentTypeObj.getValueForMetaPropertyToOne(M3Properties.value).getName(), + contentDisposition == null ? null : contentDisposition.getValueForMetaPropertyToOne(M3Properties.value).getName() + ); + } +} diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/function/manager/HttpResponseWriter.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/function/manager/HttpResponseWriter.java new file mode 100644 index 00000000000..8f644dca192 --- /dev/null +++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/function/manager/HttpResponseWriter.java @@ -0,0 +1,32 @@ +// Copyright 2020 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.engine.ide.api.execution.function.manager; + +import java.io.IOException; +import java.io.OutputStream; + +public interface HttpResponseWriter +{ + OutputStream getOutputStream() throws IOException; + + void setContentType(String type); + + void setContentDisposition(String disposition); + + void setHeader(String name, String value); + + void setIsStreamingResponse(boolean streamingResponse); + +} diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/function/manager/HttpServletResponseWriter.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/function/manager/HttpServletResponseWriter.java new file mode 100644 index 00000000000..2b87fdf31e9 --- /dev/null +++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/function/manager/HttpServletResponseWriter.java @@ -0,0 +1,60 @@ +// Copyright 2020 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.engine.ide.api.execution.function.manager; + +import org.finos.legend.engine.ide.api.execution.function.manager.HttpResponseWriter; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.OutputStream; + +public class HttpServletResponseWriter implements HttpResponseWriter +{ + private final HttpServletResponse response; + + public HttpServletResponseWriter(HttpServletResponse response) + { + this.response = response; + } + + @Override + public OutputStream getOutputStream() throws IOException + { + return this.response.getOutputStream(); + } + + @Override + public void setContentType(String type) + { + this.response.setContentType(type); + } + + @Override + public void setContentDisposition(String disposition) + { + this.response.setHeader("Content-Disposition", disposition); + } + + @Override + public void setHeader(String name, String value) + { + this.response.setHeader(name, value); + } + + @Override + public void setIsStreamingResponse(boolean streamingResponse) + { + } +} diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/function/manager/OutputFormat.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/function/manager/OutputFormat.java new file mode 100644 index 00000000000..b508aae3372 --- /dev/null +++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/function/manager/OutputFormat.java @@ -0,0 +1,50 @@ +// Copyright 2020 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.engine.ide.api.execution.function.manager; + +import org.finos.legend.engine.ide.api.execution.function.manager.ContentType; + +enum OutputFormat +{ + RAW(ContentType.text), // Raw output - no formatting whatsoever + PRE(ContentType.text), // Pre-formatted output - surrounded with
 tags
+    JSON(ContentType.json), // JSON output - formatted into JSON
+    CSV(ContentType.csv, "attachment;filename=result.csv"), //CSV
+    XLSX(ContentType.xlsx, "attachment;filename=result.xlsx"); //XLSX
+
+    private final ContentType defaultContentType;
+    private final String contentDisposition;
+
+    OutputFormat(ContentType type)
+    {
+        this(type,null);
+    }
+
+    OutputFormat(ContentType defaultContentType, String contentDisposition)
+    {
+        this.defaultContentType = defaultContentType;
+        this.contentDisposition = contentDisposition;
+    }
+
+    public ContentType getDefaultContentType()
+    {
+        return this.defaultContentType;
+    }
+
+    public String getDefaultContentDisposition()
+    {
+        return this.contentDisposition;
+    }
+}
\ No newline at end of file
diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/go/ExecuteGo.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/go/ExecuteGo.java
new file mode 100644
index 00000000000..a88b21ab5f3
--- /dev/null
+++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/go/ExecuteGo.java
@@ -0,0 +1,49 @@
+// Copyright 2020 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.engine.ide.api.execution.go;
+
+import io.swagger.annotations.Api;
+import org.finos.legend.engine.ide.api.execution.go.GoRun;
+import org.finos.legend.engine.ide.session.PureSession;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.StreamingOutput;
+
+@Api(tags = "Execute")
+@Path("/")
+public class ExecuteGo
+{
+    private PureSession pureSession;
+
+    public ExecuteGo(PureSession pureSession)
+    {
+        this.pureSession = pureSession;
+    }
+
+    @POST
+    @Path("executeGo")
+    public Response executeGo(@Context HttpServletRequest request, @Context HttpServletResponse response)
+    {
+        return Response.ok((StreamingOutput) outputStream ->
+        {
+            this.pureSession.saveFilesAndExecute(request, response, outputStream, new GoRun());
+        }).build();
+    }
+}
diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/go/GoRun.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/go/GoRun.java
new file mode 100644
index 00000000000..9b96fe7f8b8
--- /dev/null
+++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/go/GoRun.java
@@ -0,0 +1,111 @@
+// Copyright 2020 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.engine.ide.api.execution.go;
+
+import org.eclipse.collections.api.factory.Maps;
+import org.eclipse.collections.api.map.MutableMap;
+import org.eclipse.collections.impl.list.mutable.FastList;
+import org.finos.legend.engine.ide.helpers.response.ExceptionTranslation;
+import org.finos.legend.engine.ide.helpers.response.IDEExceptionResponse;
+import org.finos.legend.engine.ide.helpers.response.IDEResponse;
+import org.finos.legend.engine.ide.session.PureSession;
+import org.finos.legend.engine.ide.session.SimpleFunction;
+import org.finos.legend.pure.m3.execution.Console;
+import org.finos.legend.pure.m3.execution.FunctionExecution;
+import org.finos.legend.pure.m3.serialization.runtime.PureRuntime;
+import org.finos.legend.pure.m4.coreinstance.CoreInstance;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.json.simple.JSONValue;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+
+public class GoRun implements SimpleFunction
+{
+    @Override
+    public void run(PureSession pureSession, JSONObject extraParams, JSONArray modifiedFiles, HttpServletResponse response, OutputStream outputStream) throws Exception
+    {
+        PureRuntime pureRuntime = pureSession.getPureRuntime();
+        pureRuntime.compile();
+
+        CoreInstance function = pureRuntime.getFunction("go():Any[*]");
+        if (null == function)
+        {
+            throw new RuntimeException("Please write a go function. Example: function go():Any[*]{print('ok');}");
+        }
+
+        Console console = null;
+        try
+        {
+            outputStream.write("{\"text\":\"".getBytes());
+            FunctionExecution functionExecution = pureSession.getFunctionExecution();
+            console = functionExecution.getConsole();
+            console.setPrintStream(new JSONPrintStream(outputStream));
+            console.setConsole(true);
+            functionExecution.start(function, FastList.newList());
+            outputStream.write("\"".getBytes());
+        }
+        catch (Exception ex)
+        {
+            IDEResponse exceptionResponse = ExceptionTranslation.buildExceptionMessage(pureSession, ex, new ByteArrayOutputStream());
+            outputStream.write(JSONValue.escape("\n" + exceptionResponse.getText()).getBytes());
+            outputStream.write("\"".getBytes());
+
+            if (exceptionResponse instanceof IDEExceptionResponse)
+            {
+                IDEExceptionResponse ideExceptionResponse = (IDEExceptionResponse)exceptionResponse;
+                MutableMap additionalValues = Maps.mutable.of();
+                ideExceptionResponse.addJsonKeyValues(additionalValues);
+                for (String key : additionalValues.keysView())
+                {
+                    outputStream.write((",\"" + key + "\":" + JSONValue.toJSONString(additionalValues.get(key))).getBytes());
+                }
+            }
+        }
+        finally
+        {
+            if (null != console)
+            {
+                ByteArrayOutputStream stream = new ByteArrayOutputStream();
+                PrintStream ps = new PrintStream(stream);
+                console.setPrintStream(ps);
+                console.setConsole(false);
+            }
+        }
+
+        if (null != modifiedFiles)
+        {
+            outputStream.write((",\"modifiedFiles\":" + modifiedFiles.toJSONString()).getBytes());
+        }
+        outputStream.write((",\"compiler\":\"" + JSONValue.escape("pureSession.getCompilerLogs()") + "\", \"cached\":" + pureRuntime.getCache().getCacheState().isCached() + "}").getBytes());
+    }
+
+    private static class JSONPrintStream extends PrintStream
+    {
+        JSONPrintStream(OutputStream out)
+        {
+            super(out, true);
+        }
+
+        @Override
+        public void print(String s)
+        {
+            super.print(JSONValue.escape(s));
+        }
+    }
+}
diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/test/CallBack.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/test/CallBack.java
new file mode 100644
index 00000000000..e367d3e7304
--- /dev/null
+++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/test/CallBack.java
@@ -0,0 +1,67 @@
+// Copyright 2020 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.engine.ide.api.execution.test;
+
+import org.eclipse.collections.api.list.ListIterable;
+import org.eclipse.collections.api.list.MutableList;
+import org.eclipse.collections.api.set.MutableSet;
+import org.eclipse.collections.api.tuple.primitive.BooleanObjectPair;
+import org.eclipse.collections.impl.factory.Lists;
+import org.eclipse.collections.impl.factory.Sets;
+import org.eclipse.collections.impl.tuple.primitive.PrimitiveTuples;
+import org.finos.legend.pure.m3.execution.test.TestCallBack;
+import org.finos.legend.pure.m3.execution.test.TestStatus;
+import org.finos.legend.pure.m4.coreinstance.CoreInstance;
+
+public class CallBack implements TestCallBack
+{
+    private final MutableSet tests = Sets.mutable.with();
+    private final MutableList containers = Lists.mutable.with();
+
+    @Override
+    public void foundTests(Iterable tests)
+    {
+        this.tests.addAllIterable(tests);
+    }
+
+    @Override
+    public void executedTest(CoreInstance test, String testParameterizationId, String consoleOutput, TestStatus status)
+    {
+        synchronized (this.containers)
+        {
+            this.tests.remove(test);
+            this.containers.add(new org.finos.legend.engine.ide.api.execution.test.TestResult(test, testParameterizationId, consoleOutput, status));
+        }
+    }
+
+    public BooleanObjectPair> pullNewResults()
+    {
+        synchronized (this.containers)
+        {
+            ListIterable newContainers = Lists.mutable.withAll(this.containers);
+            this.containers.clear();
+            return PrimitiveTuples.pair(this.tests.isEmpty(), newContainers);
+        }
+    }
+
+    public void clear()
+    {
+        synchronized (this.containers)
+        {
+            this.tests.clear();
+            this.containers.clear();
+        }
+    }
+}
diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/test/ExecuteTests.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/test/ExecuteTests.java
new file mode 100644
index 00000000000..11700cdc2cc
--- /dev/null
+++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/test/ExecuteTests.java
@@ -0,0 +1,174 @@
+// Copyright 2020 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.engine.ide.api.execution.test;
+
+import io.swagger.annotations.Api;
+import org.eclipse.collections.api.list.ListIterable;
+import org.eclipse.collections.api.tuple.primitive.BooleanObjectPair;
+import org.finos.legend.engine.ide.api.execution.test.CallBack;
+import org.finos.legend.engine.ide.api.execution.test.TestResult;
+import org.finos.legend.engine.ide.api.execution.test.TestRun;
+import org.finos.legend.engine.ide.session.PureSession;
+import org.finos.legend.pure.m3.execution.test.TestExceptionStatus;
+import org.finos.legend.pure.m3.execution.test.TestRunner;
+import org.finos.legend.pure.m3.execution.test.TestStatus;
+import org.finos.legend.pure.m3.navigation.PackageableElement.PackageableElement;
+import org.json.simple.JSONValue;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.StreamingOutput;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Iterator;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+@Api(tags = "Execute Tests")
+@Path("/")
+public class ExecuteTests
+{
+    private PureSession pureSession;
+    private final ExecutorService executorService = Executors.newCachedThreadPool();
+
+    public ExecuteTests(PureSession pureSession)
+    {
+        this.pureSession = pureSession;
+    }
+
+    @POST
+    @Path("executeTests")
+    public Response executeTests(@Context HttpServletRequest request, @Context HttpServletResponse response)
+    {
+        return Response.ok((StreamingOutput) outputStream ->
+        {
+            this.pureSession.saveFilesAndExecute(request, response, outputStream, new TestRun(this.executorService));
+        }).build();
+    }
+
+    @GET
+    @Path("testRunnerCancel")
+    public Response testRunnerCancel(@Context HttpServletRequest request, @Context HttpServletResponse response)
+    {
+        return Response.ok((StreamingOutput) outputStream ->
+        {
+            int testRunnerId = getTestRunnerId(request);
+            TestRunner runner = pureSession.removeTestRunner(testRunnerId);
+            if (runner == null)
+            {
+                outputStream.write("{\"text\":\"Unknown test runner: ".getBytes());
+                outputStream.write(Integer.toString(testRunnerId).getBytes());
+                outputStream.write("\"}".getBytes());
+                outputStream.close();
+            }
+            else
+            {
+                runner.stop();
+                outputStream.write("{\"text\":\"Test run ".getBytes());
+                outputStream.write(Integer.toString(testRunnerId).getBytes());
+                outputStream.write(" canceled\"}".getBytes());
+                outputStream.close();
+            }
+        }).build();
+    }
+
+    @GET
+    @Path("testRunnerCheck")
+    public Response testRunnerCheck(@Context HttpServletRequest request, @Context HttpServletResponse response)
+    {
+        return Response.ok((StreamingOutput) outputStream ->
+        {
+            int testRunnerId = getTestRunnerId(request);
+            CallBack callBack = pureSession.getTestCallBack(testRunnerId);
+            if (callBack == null)
+            {
+                outputStream.write("{\"error\":true,\"text\":\"Unknown test runner: ".getBytes());
+                outputStream.write(Integer.toString(testRunnerId).getBytes());
+                outputStream.write("\"}".getBytes());
+                outputStream.close();
+            }
+            else
+            {
+                BooleanObjectPair> pullResult = callBack.pullNewResults();
+                boolean finished = pullResult.getOne();
+                ListIterable testResults = pullResult.getTwo();
+
+                if (finished)
+                {
+                    pureSession.removeTestRunner(testRunnerId);
+                }
+
+                outputStream.write("{\"finished\":".getBytes());
+                outputStream.write(Boolean.toString(finished).getBytes());
+                outputStream.write(",\"tests\":[".getBytes());
+                if (testResults.notEmpty())
+                {
+                    Iterator iterator = testResults.iterator();
+                    writeTestResult(outputStream, iterator.next(), pureSession);
+                    while (iterator.hasNext())
+                    {
+                        outputStream.write(',');
+                        writeTestResult(outputStream, iterator.next(), pureSession);
+                    }
+                }
+                outputStream.write("]}".getBytes());
+                outputStream.close();
+            }
+        }).build();
+    }
+
+    private void writeTestResult(OutputStream outStream, TestResult result, PureSession session) throws IOException
+    {
+        outStream.write("{\"test\":[".getBytes());
+        String parameterizationSuffix = result.getTestParameterizationId() == null ? "" : "[" + result.getTestParameterizationId() + "]";
+        outStream.write(("\"" + PackageableElement.getUserPathForPackageableElement(result.getTestFunction(), "\",\"") + parameterizationSuffix + "\"").getBytes());
+        outStream.write("],\"console\":\"".getBytes());
+        outStream.write(JSONValue.escape(result.getConsoleOutput()).getBytes());
+        outStream.write("\",\"status\":\"".getBytes());
+        outStream.write(result.getStatus().toString().getBytes());
+        outStream.write('"');
+        if (!TestStatus.SUCCESS.equals(result.getStatus()))
+        {
+            outStream.write(",\"error\":".getBytes());
+            outStream.write(PureSession.exceptionToJson(session, ((TestExceptionStatus) result.getStatus()).getException(), null).getBytes());
+        }
+        outStream.write('}');
+    }
+
+
+    private static final String TEST_RUNNER_ID_PARAM = "testRunnerId";
+
+    private int getTestRunnerId(HttpServletRequest request)
+    {
+        String idString = request.getParameter(TEST_RUNNER_ID_PARAM);
+        if (idString == null)
+        {
+            throw new RuntimeException("No test runner id");
+        }
+        try
+        {
+            return Integer.parseInt(idString);
+        }
+        catch (NumberFormatException e)
+        {
+            throw new RuntimeException("Invalid test runner id: " + idString);
+        }
+    }
+}
\ No newline at end of file
diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/test/TestNode.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/test/TestNode.java
new file mode 100644
index 00000000000..91b3d6cba3b
--- /dev/null
+++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/test/TestNode.java
@@ -0,0 +1,100 @@
+// Copyright 2020 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.engine.ide.api.execution.test;
+
+import org.eclipse.collections.api.factory.Lists;
+import org.eclipse.collections.api.list.MutableList;
+import org.finos.legend.engine.ide.helpers.response.ExceptionTranslation;
+import org.finos.legend.pure.m3.navigation.*;
+import org.finos.legend.pure.m3.navigation.PackageableElement.PackageableElement;
+import org.finos.legend.pure.m3.tools.tree.TreeNode;
+import org.finos.legend.pure.m4.coreinstance.CoreInstance;
+import org.finos.legend.pure.m4.coreinstance.SourceInformation;
+
+import java.util.Objects;
+
+public class TestNode implements TreeNode
+{
+    private final CoreInstance coreInstance;
+    private final String testParameterizationId;
+    private final MutableList children = Lists.mutable.empty();
+
+    public TestNode(CoreInstance coreInstance, String testParameterizationId)
+    {
+        this.coreInstance = coreInstance;
+        this.testParameterizationId = testParameterizationId;
+    }
+
+    public TestNode(CoreInstance coreInstance)
+    {
+        this(coreInstance, null);
+    }
+
+    public TestNode getOrCreateChild(CoreInstance instance, String testParameterizationId)
+    {
+        for (TestNode child : this.children)
+        {
+            if (instance == child.coreInstance && Objects.equals(testParameterizationId, child.testParameterizationId))
+            {
+                return child;
+            }
+        }
+        TestNode newChild = new TestNode(instance, testParameterizationId);
+        this.children.add(newChild);
+        return newChild;
+    }
+
+    @Override
+    public MutableList getChildren()
+    {
+        return this.children;
+    }
+
+    @Override
+    public TestNode getChildAt(int index)
+    {
+        return this.children.get(index);
+    }
+
+    @Override
+    public boolean isLeaf()
+    {
+        return this.children.isEmpty();
+    }
+
+    @Override
+    public int indexOf(TestNode node)
+    {
+        return this.children.indexOf(node);
+    }
+
+    @Override
+    public String toString()
+    {
+        return this.coreInstance.getName();
+    }
+
+    public String toJson(final int testId)
+    {
+        CoreInstance coreInstance = this.coreInstance;
+        ProcessorSupport processorSupport = new M3ProcessorSupport(coreInstance.getRepository());
+        SourceInformation si = coreInstance.getSourceInformation() != null ? coreInstance.getSourceInformation() : ExceptionTranslation.DUMMY_SOURCE_INFORMATION;
+        String parameterizationSuffix = this.testParameterizationId == null ? "" : "[" + this.testParameterizationId + "]";
+        return "{\"text\":\"" + (Instance.instanceOf(coreInstance, M3Paths.Function, processorSupport) ? Instance.getValueForMetaPropertyToOneResolved(coreInstance, M3Properties.functionName, processorSupport).getName() : Instance.getValueForMetaPropertyToOneResolved(coreInstance, M3Properties.name, processorSupport).getName()) + parameterizationSuffix + "\"" +
+                (this.children.isEmpty() ? ", \"type\":\"notRan\"" : "") +
+                ",\"li_attr\" : {\"file\":\"" + si.getSourceId() + "\",\"line\":\"" + si.getLine() + "\",\"column\":\"" + si.getColumn() + "\",\"parentId\":\"" + PackageableElement.getUserPathForPackageableElement(Instance.getValueForMetaPropertyToOneResolved(coreInstance, M3Properties._package, new M3ProcessorSupport(coreInstance.getRepository())), "_") + "\", \"id\":\"test" + testId + "_" + PackageableElement.getUserPathForPackageableElement(coreInstance, "_") + parameterizationSuffix + "\"}" +
+                (this.getChildren().isEmpty() ? "" : ",\"children\":[" + this.getChildren().collect(testNode -> testNode.toJson(testId)).makeString() + "]") + "}";
+    }
+}
diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/test/TestResult.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/test/TestResult.java
new file mode 100644
index 00000000000..ccd4c9bf60b
--- /dev/null
+++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/test/TestResult.java
@@ -0,0 +1,54 @@
+// Copyright 2020 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.engine.ide.api.execution.test;
+
+import org.finos.legend.pure.m3.execution.test.TestStatus;
+import org.finos.legend.pure.m4.coreinstance.CoreInstance;
+
+public class TestResult
+{
+    private CoreInstance testFunction;
+    private String testParameterizationId;
+    private String consoleOutput;
+    private TestStatus status;
+
+    TestResult(CoreInstance testFunction, String testParameterizationId, String consoleOutput, TestStatus status)
+    {
+        this.testFunction = testFunction;
+        this.testParameterizationId = testParameterizationId;
+        this.consoleOutput = consoleOutput;
+        this.status = status;
+    }
+
+    public CoreInstance getTestFunction()
+    {
+        return this.testFunction;
+    }
+
+    public String getConsoleOutput()
+    {
+        return this.consoleOutput;
+    }
+
+    public TestStatus getStatus()
+    {
+        return this.status;
+    }
+
+    public String getTestParameterizationId()
+    {
+        return this.testParameterizationId;
+    }
+}
diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/test/TestRun.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/test/TestRun.java
new file mode 100644
index 00000000000..0c548a601d2
--- /dev/null
+++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/execution/test/TestRun.java
@@ -0,0 +1,214 @@
+// Copyright 2020 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.engine.ide.api.execution.test;
+
+import org.eclipse.collections.api.RichIterable;
+import org.eclipse.collections.api.block.function.Function;
+import org.eclipse.collections.api.block.predicate.Predicate;
+import org.eclipse.collections.api.factory.Sets;
+import org.eclipse.collections.api.list.ListIterable;
+import org.eclipse.collections.api.list.MutableList;
+import org.eclipse.collections.api.set.MutableSet;
+import org.eclipse.collections.api.set.SetIterable;
+import org.eclipse.collections.api.tuple.Pair;
+import org.eclipse.collections.impl.block.factory.Predicates;
+import org.eclipse.collections.impl.utility.ArrayIterate;
+import org.eclipse.collections.impl.utility.StringIterate;
+import org.finos.legend.engine.ide.api.execution.test.TestNode;
+import org.finos.legend.engine.ide.session.PureSession;
+import org.finos.legend.engine.ide.session.SimpleFunction;
+import org.finos.legend.pure.m3.execution.FunctionExecution;
+import org.finos.legend.pure.m3.execution.test.TestCollection;
+import org.finos.legend.pure.m3.execution.test.TestRunner;
+import org.finos.legend.pure.m3.navigation.Instance;
+import org.finos.legend.pure.m3.navigation.M3Paths;
+import org.finos.legend.pure.m3.navigation.M3Properties;
+import org.finos.legend.pure.m3.navigation.PackageableElement.PackageableElement;
+import org.finos.legend.pure.m3.navigation.ProcessorSupport;
+import org.finos.legend.pure.m3.serialization.filesystem.usercodestorage.CodeStorageNode;
+import org.finos.legend.pure.m3.serialization.filesystem.usercodestorage.composite.CompositeCodeStorage;
+import org.finos.legend.pure.m3.serialization.filesystem.usercodestorage.vcs.MutableVersionControlledCodeStorage;
+import org.finos.legend.pure.m3.serialization.runtime.PureRuntime;
+import org.finos.legend.pure.m3.tools.ListHelper;
+import org.finos.legend.pure.m4.coreinstance.CoreInstance;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.OutputStream;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class TestRun implements SimpleFunction
+{
+    private ExecutorService executorService;
+    private final AtomicInteger nextTestId = new AtomicInteger(1);
+
+    public TestRun(ExecutorService executorService)
+    {
+        this.executorService = executorService;
+    }
+
+    @Override
+    public void run(PureSession pureSession, JSONObject extraParams, JSONArray modifiedFiles, HttpServletResponse response, OutputStream outputStream) throws Exception
+    {
+        PureRuntime runtime = pureSession.getPureRuntime();
+        runtime.compile();
+
+        final int newId = this.nextTestId.getAndIncrement();
+
+        String path = getPath(extraParams);
+        String[] filterPaths = getFilterPaths(extraParams);
+        boolean relevantTestsOnly = getRelevantTestsOnly(extraParams);
+        Predicate filterPredicate = getFilterPredicate(runtime, relevantTestsOnly);
+
+        TestCollection collection = getTestCollection(pureSession, path, filterPaths, filterPredicate);
+        TestRunner runner = pureSession.newTestRunner(newId, collection);
+
+        this.executorService.execute(runner);
+
+        org.finos.legend.engine.ide.api.execution.test.TestNode root = new org.finos.legend.engine.ide.api.execution.test.TestNode(runtime.getCoreInstance("::"));
+
+        MutableList> tests = runner.getTestCollection().getAllTestFunctionsWithParameterizations(false);
+        tests.sortThisBy(t -> PackageableElement.getUserPathForPackageableElement(t.getOne()));
+
+        for (Pair test : tests)
+        {
+            ListIterable nodePath = PackageableElement.getUserObjectPathForPackageableElement(test.getOne());
+            org.finos.legend.engine.ide.api.execution.test.TestNode node = root;
+            for (CoreInstance element : ListHelper.tail(nodePath))
+            {
+                node = node.getOrCreateChild(element, element == nodePath.getLast() ? test.getTwo() : null);
+            }
+        }
+
+        outputStream.write("{\"runnerId\":".getBytes());
+        outputStream.write(Integer.toString(newId).getBytes());
+        outputStream.write((",\"path\":\"" + path + "\"").getBytes());
+        outputStream.write((",\"filterPaths\":" + (filterPaths.length == 0 ? "[]" : ArrayIterate.makeString(filterPaths, "[\"", "\",\"", "\"]"))).getBytes());
+        outputStream.write((",\"relevantTestsOnly\":" + relevantTestsOnly).getBytes());
+        outputStream.write(",\"count\":".getBytes());
+        outputStream.write(Integer.toString(tests.size()).getBytes());
+        outputStream.write(",\"tests\":".getBytes());
+        outputStream.write(root.getChildren().asLazy().collect(new Function()
+        {
+            @Override
+            public String valueOf(TestNode testNode)
+            {
+                return testNode.toJson(newId);
+            }
+        }).makeString("[", ",", "]").getBytes());
+        outputStream.write((",\"cached\":" + runtime.getCache().getCacheState().isCached()).getBytes());
+        outputStream.write("}".getBytes());
+        outputStream.close();
+    }
+
+    private String getPath(JSONObject extraParams)
+    {
+        String path = (String)extraParams.get("path");
+        return StringIterate.isEmpty(path) ? "::" : path;
+    }
+
+    private String[] getFilterPaths(JSONObject extraParams)
+    {
+        JSONArray filterPaths = (JSONArray)extraParams.get("filterPaths");
+        if (filterPaths != null)
+        {
+            String[] paths = new String[filterPaths.size()];
+            filterPaths.toArray(paths);
+            return paths;
+        }
+        return new String[0];
+    }
+
+    private boolean getRelevantTestsOnly(JSONObject extraParams)
+    {
+        Boolean relevantTestsOnly = (Boolean)extraParams.get("relevantTestsOnly");
+        return (relevantTestsOnly == null) ? false : relevantTestsOnly;
+    }
+
+    private Predicate getFilterPredicate(PureRuntime runtime, boolean relevantTestsOnly)
+    {
+        if (!relevantTestsOnly)
+        {
+            return null;
+        }
+
+        final MutableVersionControlledCodeStorage codeStorage = (MutableVersionControlledCodeStorage)runtime.getCodeStorage();
+        RichIterable modifiedUserFiles = codeStorage.getModifiedUserFiles();
+        if (modifiedUserFiles.isEmpty())
+        {
+            return Predicates.alwaysFalse();
+        }
+
+        MutableSet repos = Sets.mutable.empty();
+        for (CodeStorageNode node : modifiedUserFiles)
+        {
+            repos.add(codeStorage.getRepositoryForPath(node.getPath()).getName());
+        }
+        if (repos.isEmpty())
+        {
+            return Predicates.alwaysFalse();
+        }
+
+        final SetIterable reposPlusDependents = CompositeCodeStorage.getRepositoriesDependendingOnByName(codeStorage.getAllRepositories(), repos);
+        return new Predicate()
+        {
+            @Override
+            public boolean accept(CoreInstance test)
+            {
+                return reposPlusDependents.contains(codeStorage.getRepositoryForPath(test.getSourceInformation().getSourceId()).getName());
+            }
+        };
+    }
+
+    private TestCollection getTestCollection(PureSession session, String path, String[] filterPaths, Predicate filterPredicate)
+    {
+        PureRuntime runtime = session.getPureRuntime();
+        FunctionExecution functionExecution = session.getFunctionExecution();
+        CoreInstance coreInstance = runtime.getCoreInstance(path);
+        ProcessorSupport processorSupport = runtime.getProcessorSupport();
+
+        CoreInstance pkg;
+        Predicate singleTestFilter;
+        Predicate pathFilter = Predicates.alwaysTrue();
+
+        if (Instance.instanceOf(coreInstance, M3Paths.ConcreteFunctionDefinition, processorSupport))
+        {
+            pkg = Instance.getValueForMetaPropertyToOneResolved(coreInstance, M3Properties._package, processorSupport);
+            singleTestFilter = Predicates.sameAs(coreInstance);
+        }
+        else
+        {
+            pkg = coreInstance;
+            singleTestFilter = Predicates.alwaysTrue();
+        }
+
+        if (filterPaths.length > 0)
+        {
+            pathFilter = Predicates.alwaysFalse();
+            for (String filterPath : filterPaths)
+            {
+                pathFilter = Predicates.or(pathFilter, Predicates.attributeEqual(e -> e.getValueForMetaPropertyToOne(M3Properties._package), runtime.getCoreInstance(filterPath)));
+            }
+        }
+
+        Predicate funcExecPredicate = TestCollection.getFilterPredicateForExecutionPlatformClass(session.getFunctionExecution().getClass(), processorSupport);
+        Predicate predicate = (filterPredicate == null) ? funcExecPredicate : Predicates.and(funcExecPredicate, filterPredicate);
+        Predicate alloyTextModeExclusionPredicate = TestCollection.getFilterPredicateForAlloyTextModeExclusion(processorSupport);
+        predicate = Predicates.and(predicate, singleTestFilter, pathFilter, alloyTextModeExclusionPredicate);
+        return TestCollection.collectTests(pkg, processorSupport, fn -> TestCollection.collectTestsFromPure(fn, functionExecution), predicate);
+    }
+}
diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/find/FindInSources.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/find/FindInSources.java
new file mode 100644
index 00000000000..476a0e7b913
--- /dev/null
+++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/find/FindInSources.java
@@ -0,0 +1,177 @@
+// Copyright 2020 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.engine.ide.api.find;
+
+import io.swagger.annotations.Api;
+import org.eclipse.collections.api.RichIterable;
+import org.eclipse.collections.api.multimap.Multimap;
+import org.finos.legend.engine.ide.session.PureSession;
+import org.finos.legend.pure.m3.serialization.runtime.SourceCoordinates;
+import org.json.simple.JSONValue;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.StreamingOutput;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.regex.Pattern;
+
+@Api(tags = "Find")
+@Path("/")
+public class FindInSources
+{
+    private static final String STRING_PARAM = "string";
+    private static final String REGEX_PARAM = "regex";
+    private static final String SOURCE_REGEX_PARAM = "sourceRegex";
+    private static final String CASE_SENSITIVE_PARAM = "caseSensitive";
+    private static final String MAX_RESULTS_PARAM = "limit";
+
+    private final PureSession session;
+
+    public FindInSources(PureSession session)
+    {
+        this.session = session;
+    }
+
+    @GET
+    @Path("findInSources")
+    public Response findInSources(@Context HttpServletRequest request, @Context HttpServletResponse response) throws IOException
+    {
+        return Response.ok((StreamingOutput) outputStream ->
+        {
+            String string = request.getParameter(STRING_PARAM);
+            boolean regex = Boolean.valueOf(String.valueOf(request.getParameter(REGEX_PARAM)));
+            String sourceRegex = request.getParameter(SOURCE_REGEX_PARAM);
+            String caseSensitiveString = request.getParameter(CASE_SENSITIVE_PARAM);
+            int limit = request.getParameter(MAX_RESULTS_PARAM) != null ? Integer.valueOf(request.getParameter(MAX_RESULTS_PARAM)) : Integer.MAX_VALUE;
+            boolean caseSensitive = (caseSensitiveString == null) ? true : Boolean.valueOf(caseSensitiveString);
+
+            if (string == null)
+            {
+                throw new RuntimeException("Must specify search parameters: " + STRING_PARAM);
+            }
+
+            RichIterable results;
+            try
+            {
+                Pattern sourcePattern = getSourcePattern(sourceRegex);
+                if (regex)
+                {
+                    Pattern pattern = Pattern.compile(string, caseSensitive ? 0 : Pattern.CASE_INSENSITIVE);
+                    results = session.getPureRuntime().getSourceRegistry().find(pattern, sourcePattern);
+                }
+                else
+                {
+                    results = session.getPureRuntime().getSourceRegistry().find(string, caseSensitive, sourcePattern);
+                }
+
+                response.setContentType("application/json");
+                writeResultsJSON(outputStream, results, limit);
+            }
+            catch (IOException | RuntimeException | Error e)
+            {
+                throw e;
+            }
+        }).build();
+    }
+
+    private Pattern getSourcePattern(String sourceRegex)
+    {
+        return (sourceRegex == null) ? null : Pattern.compile(sourceRegex);
+    }
+
+    private int writeResultsJSON(OutputStream stream, RichIterable results, int limit) throws IOException
+    {
+        stream.write("[".getBytes());
+        int count = 0;
+        if (results.notEmpty())
+        {
+            Multimap indexBySource = results.groupBy(SourceCoordinates.SOURCE_ID);
+            boolean first = true;
+            for (String sourceId : indexBySource.keysView().toSortedList())
+            {
+                if (first)
+                {
+                    first = false;
+                    stream.write("{\"sourceId\":\"".getBytes());
+                }
+                else
+                {
+                    stream.write(",{\"sourceId\":\"".getBytes());
+                }
+                stream.write(JSONValue.escape(sourceId).getBytes());
+                stream.write("\",\"coordinates\":[".getBytes());
+                boolean firstSC = true;
+                for (SourceCoordinates sourceCoordinates : indexBySource.get(sourceId))
+                {
+                    if (firstSC)
+                    {
+                        firstSC = false;
+                    }
+                    else
+                    {
+                        stream.write(",".getBytes());
+                    }
+                    writeSourceCoordinatesJSON(stream, sourceCoordinates);
+                    count++;
+                    if (count > limit)
+                    {
+                        break;
+                    }
+                }
+                stream.write("]}".getBytes());
+                if (count > limit)
+                {
+                    break;
+                }
+            }
+        }
+        stream.write("]".getBytes());
+        return count > limit ? limit : count;
+    }
+
+    private void writeSourceCoordinatesJSON(OutputStream stream, SourceCoordinates sourceCoordinates) throws IOException
+    {
+        stream.write("{\"startLine\":".getBytes());
+        stream.write(Integer.toString(sourceCoordinates.getStartLine()).getBytes());
+        stream.write(",\"startColumn\":".getBytes());
+        stream.write(Integer.toString(sourceCoordinates.getStartColumn()).getBytes());
+        stream.write(",\"endLine\":".getBytes());
+        stream.write(Integer.toString(sourceCoordinates.getEndLine()).getBytes());
+        stream.write(",\"endColumn\":".getBytes());
+        stream.write(Integer.toString(sourceCoordinates.getEndColumn()).getBytes());
+        if (sourceCoordinates.getPreview() != null)
+        {
+            stream.write(",\"preview\":".getBytes());
+            writePreviewJSON(stream, sourceCoordinates.getPreview());
+        }
+        stream.write("}".getBytes());
+    }
+
+    private void writePreviewJSON(OutputStream stream, SourceCoordinates.Preview preview) throws IOException
+    {
+        stream.write("{\"before\":\"".getBytes());
+        stream.write(JSONValue.escape(preview.getBeforeText()).getBytes());
+        stream.write("\",\"found\":\"".getBytes());
+        stream.write(JSONValue.escape(preview.getFoundText()).getBytes());
+        stream.write("\",\"after\":\"".getBytes());
+        stream.write(JSONValue.escape(preview.getAfterText()).getBytes());
+        stream.write("\"}".getBytes());
+    }
+}
diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/find/FindPureFile.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/find/FindPureFile.java
new file mode 100644
index 00000000000..3b4b749c843
--- /dev/null
+++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/find/FindPureFile.java
@@ -0,0 +1,87 @@
+// Copyright 2020 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.engine.ide.api.find;
+
+import io.swagger.annotations.Api;
+import org.eclipse.collections.api.RichIterable;
+import org.eclipse.collections.api.block.procedure.Procedure;
+import org.finos.legend.engine.ide.session.PureSession;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.StreamingOutput;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.regex.Pattern;
+
+@Api(tags = "Find")
+@Path("/")
+public class FindPureFile
+{
+    private final PureSession session;
+
+    public FindPureFile(PureSession session)
+    {
+        this.session = session;
+    }
+
+    @GET
+    @Path("findPureFiles")
+    public Response findPureFiles(@Context HttpServletRequest request, @Context HttpServletResponse response) throws IOException
+    {
+        return Response.ok((StreamingOutput) outputStream ->
+        {
+            String fileName = request.getParameter("file");
+            boolean isRegex = Boolean.parseBoolean(String.valueOf(request.getParameter("regex")));
+
+            try
+            {
+                Pattern filePattern = Pattern.compile(fileName);
+                RichIterable fileMatches = isRegex ? session.getPureRuntime().getSourceRegistry().findSourceIds(filePattern)
+                        : session.getPureRuntime().getSourceRegistry().findSourceIds(fileName);
+                response.setContentType("application/json");
+                final StringBuilder sb = new StringBuilder("[");
+                fileMatches.toSortedList().forEach(new Procedure()
+                {
+                    @Override
+                    public void value(String name)
+                    {
+                        sb.append("\"").append(name).append("\"").append(",");
+                    }
+                });
+                if (!fileMatches.isEmpty())
+                {
+                    sb.deleteCharAt(sb.length() - 1);
+                }
+                sb.append("]");
+                outputStream.write(sb.toString().getBytes());
+            }
+            catch (Exception e)
+            {
+                this.writeErrorResponse(outputStream, fileName);
+            }
+
+        }).build();
+    }
+
+    private void writeErrorResponse(OutputStream outStream, String file) throws IOException
+    {
+        outStream.write(("{\"error\":true,\"text\":\"Cannot find source file: " + file + "\"}").getBytes());
+    }
+}
diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/find/FindTextPreview.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/find/FindTextPreview.java
new file mode 100644
index 00000000000..996ec4461a3
--- /dev/null
+++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/find/FindTextPreview.java
@@ -0,0 +1,115 @@
+// Copyright 2022 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.engine.ide.api.find;
+
+import io.swagger.annotations.Api;
+import org.eclipse.collections.api.RichIterable;
+import org.finos.legend.engine.ide.session.PureSession;
+import org.finos.legend.pure.m3.serialization.runtime.SourceCoordinates;
+import org.json.simple.JSONValue;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.StreamingOutput;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.List;
+
+@Api(tags = "Find")
+@Path("/")
+public class FindTextPreview
+{
+    private final PureSession session;
+
+    public FindTextPreview(PureSession session)
+    {
+        this.session = session;
+    }
+
+    @POST
+    @Path("getTextSearchPreview")
+    public Response getTextPreview(@Context HttpServletRequest request, List coordinates, @Context HttpServletResponse response) throws IOException
+    {
+        return Response.ok((StreamingOutput) outputStream ->
+        {
+            try
+            {
+                response.setContentType("application/json");
+                writeResultsJSON(outputStream, session.getPureRuntime().getSourceRegistry().getPreviewTextWithCoordinates(coordinates));
+            }
+            catch (IOException | RuntimeException | Error e)
+            {
+                throw e;
+            }
+        }).build();
+    }
+
+    private void writeResultsJSON(OutputStream stream, RichIterable results) throws IOException
+    {
+        stream.write("[".getBytes());
+        if (results.notEmpty())
+        {
+            boolean firstSC = true;
+            for (SourceCoordinates sourceCoordinates : results)
+            {
+                if (firstSC)
+                {
+                    firstSC = false;
+                }
+                else
+                {
+                    stream.write(",".getBytes());
+                }
+                writeSourceCoordinatesJSON(stream, sourceCoordinates);
+            }
+        }
+        stream.write("]".getBytes());
+    }
+
+    private void writeSourceCoordinatesJSON(OutputStream stream, SourceCoordinates sourceCoordinates) throws IOException
+    {
+        stream.write("{\"sourceId\":\"".getBytes());
+        stream.write(sourceCoordinates.getSourceId().getBytes());
+        stream.write("\",\"startLine\":".getBytes());
+        stream.write(Integer.toString(sourceCoordinates.getStartLine()).getBytes());
+        stream.write(",\"startColumn\":".getBytes());
+        stream.write(Integer.toString(sourceCoordinates.getStartColumn()).getBytes());
+        stream.write(",\"endLine\":".getBytes());
+        stream.write(Integer.toString(sourceCoordinates.getEndLine()).getBytes());
+        stream.write(",\"endColumn\":".getBytes());
+        stream.write(Integer.toString(sourceCoordinates.getEndColumn()).getBytes());
+        if (sourceCoordinates.getPreview() != null)
+        {
+            stream.write(",\"preview\":".getBytes());
+            writePreviewJSON(stream, sourceCoordinates.getPreview());
+        }
+        stream.write("}".getBytes());
+    }
+
+    private void writePreviewJSON(OutputStream stream, SourceCoordinates.Preview preview) throws IOException
+    {
+        stream.write("{\"before\":\"".getBytes());
+        stream.write(JSONValue.escape(preview.getBeforeText()).getBytes());
+        stream.write("\",\"found\":\"".getBytes());
+        stream.write(JSONValue.escape(preview.getFoundText()).getBytes());
+        stream.write("\",\"after\":\"".getBytes());
+        stream.write(JSONValue.escape(preview.getAfterText()).getBytes());
+        stream.write("\"}".getBytes());
+    }
+}
diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/source/UpdateSource.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/source/UpdateSource.java
new file mode 100644
index 00000000000..7704c3aec74
--- /dev/null
+++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/api/source/UpdateSource.java
@@ -0,0 +1,233 @@
+// Copyright 2022 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.engine.ide.api.source;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.Api;
+import org.eclipse.collections.api.RichIterable;
+import org.eclipse.collections.api.block.function.Function;
+import org.eclipse.collections.api.map.MutableMap;
+import org.eclipse.collections.api.multimap.Multimap;
+import org.eclipse.collections.api.set.MutableSet;
+import org.eclipse.collections.impl.factory.Maps;
+import org.eclipse.collections.impl.factory.Sets;
+import org.eclipse.collections.impl.utility.ListIterate;
+import org.finos.legend.engine.ide.session.PureSession;
+import org.finos.legend.pure.m3.serialization.runtime.Source;
+import org.json.simple.JSONValue;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.StreamingOutput;
+import java.io.IOException;
+import java.util.List;
+import java.util.regex.Pattern;
+
+@Api(tags = "Source")
+@Path("/")
+public class UpdateSource
+{
+    private static final Pattern LINE_SPLITTER = Pattern.compile("^", Pattern.MULTILINE);
+
+    private PureSession session;
+
+    public UpdateSource(PureSession session)
+    {
+        this.session = session;
+    }
+
+    @PUT
+    @Path("updateSource")
+    public Response updateSource(@Context HttpServletRequest request, List updateInputs, @Context HttpServletResponse response) throws IOException
+    {
+        return Response.ok((StreamingOutput) outStream ->
+        {
+            response.setContentType("application/json");
+            Multimap indexByPath = ListIterate.groupBy(updateInputs, UpdateSourceInput.PATH);
+
+            for (String path : indexByPath.keysView().toSortedList())
+            {
+                RichIterable inputs = indexByPath.get(path);
+                Source source = this.session.getPureRuntime().getSourceRegistry().getSource(path);
+                MutableMap messageToAddByLines = Maps.mutable.empty();
+                MutableMap messageToRemoveByLines = Maps.mutable.empty();
+                MutableSet linesToAdd = Sets.mutable.empty();
+                MutableSet linesToRemove = Sets.mutable.empty();
+
+                // index source updates by line number
+                for (UpdateSourceInput input : inputs)
+                {
+                    if (input.isAdd())
+                    {
+                        // add
+                        if (linesToAdd.add(input.getLine())) // check for duplication
+                        {
+                            messageToAddByLines.put(input.getLine(), input);
+                        }
+                        else
+                        {
+                            throw new IllegalArgumentException("Invalid file update request - Please combine the same line change");
+                        }
+                    }
+                    else
+                    {
+                        // remove
+                        if (linesToRemove.add(input.getLine()))  // check for duplication
+                        {
+                            messageToRemoveByLines.put(input.getLine(), input);
+                        }
+                        {
+                            throw new IllegalArgumentException("Invalid file update request - Please combine the same line change");
+                        }
+                    }
+                }
+
+                String file = source.getContent();
+                String[] lines = LINE_SPLITTER.split(file);
+                StringBuilder buffer = new StringBuilder();
+
+                for (int i = 0; i < lines.length; i++)
+                {
+                    int lineNumber = i + 1;
+                    // perform add
+                    if (linesToAdd.contains(lineNumber))
+                    {
+                        linesToAdd.remove(lineNumber);
+                        buffer.append(messageToAddByLines.get(lineNumber).getMessage()).append("\r\n");
+                    }
+
+                    // perform remove
+                    if (linesToRemove.contains(lineNumber))
+                    {
+                        linesToRemove.remove(lineNumber);
+                    }
+
+                    // append original line
+                    else
+                    {
+                        buffer.append(lines[i]);
+                    }
+                }
+
+                while (linesToAdd.notEmpty())
+                {
+                    int line = linesToAdd.min();
+                    linesToAdd.remove(line);
+                    if (line < 1)
+                    {
+                        throw new IllegalArgumentException("Invalid file update request - Line number must be greater than 0");
+                    }
+                    else if (line >= lines.length)
+                    {
+                        buffer.append("\r\n");
+                        buffer.append(messageToAddByLines.get(line).getMessage());
+                        buffer.append("\r\n");
+                    }
+                    else
+                    {
+                        throw new IllegalArgumentException("Invalid file update request - Line number out of range");
+                    }
+                }
+
+                if (linesToRemove.notEmpty())
+                {
+                    throw new IllegalArgumentException("Invalid file update request - Line number out of range");
+                }
+
+                session.getPureRuntime().modify(path, buffer.toString());
+            }
+
+            outStream.write("{".getBytes());
+            outStream.write(("\"text\":\"").getBytes());
+            outStream.write(JSONValue.escape("Successfully updated source(s)!").getBytes());
+            outStream.write(JSONValue.escape("\r\nPlease press F9 to compile the code again").getBytes());
+            outStream.write("\",".getBytes());
+            outStream.write(("\"modifiedFiles\":[\"").getBytes());
+            outStream.write(JSONValue.escape(indexByPath.valuesView().collect(UpdateSourceInput::getPath).makeString(",")).getBytes());
+            outStream.write(("\"]").getBytes());
+            outStream.write("}".getBytes());
+            outStream.close();
+        }).build();
+    }
+
+    public static class UpdateSourceInput
+    {
+        public static final Function PATH = new Function()
+        {
+            @Override
+            public String valueOf(UpdateSourceInput input)
+            {
+                return input.getPath();
+            }
+        };
+
+        private final String path;
+        private final int line;
+        private final int column;
+        private final String message;
+        private final boolean add;
+
+        UpdateSourceInput(String path, int line, int column, String message, boolean add)
+        {
+            this.path = path;
+            this.line = line;
+            this.column = column;
+            this.message = message;
+            this.add = add;
+        }
+
+        @JsonCreator
+        public static UpdateSourceInput newInput(
+                @JsonProperty("path") String path,
+                @JsonProperty("line") int line,
+                @JsonProperty("column") int column,
+                @JsonProperty("message") String message,
+                @JsonProperty("add") boolean add
+        )
+        {
+            return new UpdateSourceInput(path, line, column, message, add);
+        }
+
+        public String getPath()
+        {
+            return path;
+        }
+
+        public int getLine()
+        {
+            return line;
+        }
+
+        public int getColumn()
+        {
+            return column;
+        }
+
+        public String getMessage()
+        {
+            return message;
+        }
+
+        public boolean isAdd()
+        {
+            return add;
+        }
+    }
+}
\ No newline at end of file
diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/helpers/JSONResponseTools.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/helpers/JSONResponseTools.java
new file mode 100644
index 00000000000..0e1edf9e01c
--- /dev/null
+++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/helpers/JSONResponseTools.java
@@ -0,0 +1,110 @@
+// Copyright 2020 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.engine.ide.helpers;
+
+import org.eclipse.collections.api.map.MutableMap;
+import org.eclipse.collections.impl.map.mutable.UnifiedMap;
+import org.finos.legend.pure.m4.exception.PureException;
+import org.json.simple.JSONValue;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+public class JSONResponseTools
+{
+    public static final String JSON_CONTENT_TYPE = "application/json";
+
+    private JSONResponseTools()
+    {
+        // Utility class
+    }
+
+    private static void sendJSONResponse(HttpServletResponse response, int status, Object json) throws IOException
+    {
+        response.setStatus(status);
+        response.setContentType(JSON_CONTENT_TYPE);
+        // We call getOutputStream instead of getWriter, as calling getWriter after calling getOutputStream can
+        // cause problems and getOutputStream may have already been called
+        try (PrintWriter writer = new PrintWriter(response.getOutputStream()))
+        {
+            JSONValue.writeJSONString(json, writer);
+        }
+    }
+
+    public static void sendJSONErrorResponse(HttpServletResponse response, int status, Throwable t, boolean includeStackTrace) throws IOException
+    {
+        sendJSONErrorResponse(response, status, t, includeStackTrace, System.currentTimeMillis(), null);
+    }
+
+    private static void sendJSONErrorResponse(HttpServletResponse response, int status, Throwable t, boolean includeStackTrace, long timestamp, String requestId) throws IOException
+    {
+        String message = t.getMessage();
+        String stackTrace = null;
+        if (t instanceof PureException && ((PureException)t).hasPureStackTrace())
+        {
+            stackTrace = ((PureException)t).getPureStackTrace();
+        }
+        else if (includeStackTrace)
+        {
+            StringWriter writer = new StringWriter(512);
+            t.printStackTrace(new PrintWriter(writer));
+            stackTrace = writer.toString();
+        }
+        sendJSONErrorResponse(response, status, message, stackTrace, timestamp, requestId);
+    }
+
+    private static void sendJSONErrorResponse(HttpServletResponse response, int status, String message, String stackTrace, long timestamp, String requestId) throws IOException
+    {
+        MutableMap json = buildJSONErrorMessage(message, stackTrace, timestamp, requestId);
+        sendJSONResponse(response, status, json);
+    }
+
+    private static MutableMap buildJSONErrorMessage(String message, String stackTrace, long timestamp, String requestId)
+    {
+        MutableMap json = UnifiedMap.newMap(5);
+        json.put("error", true);
+        if (message != null)
+        {
+            json.put("message", message);
+        }
+        if (stackTrace != null)
+        {
+            json.put("stackTrace", stackTrace);
+        }
+        json.put("host", getLocalHostName());
+        json.put("timestamp", String.format("%tY-% candidates = exception.getImportCandidates(session.codeStorage.getAllRepositories());
+                MutableMap> sourceInfoAndTypeByPath = Maps.mutable.ofInitialCapacity(candidates.size());
+
+                for (CoreInstance candidate : candidates)
+                {
+                    SourceInformation sourceInfo = candidate.getSourceInformation();
+                    // TODO think about what we should do with candidates with no source info
+                    if ((sourceInfo != null) && (runtime != null))
+                    {
+                        sourceInfoAndTypeByPath.put(PackageableElement.getUserPathForPackageableElement(candidate), Tuples.pair(sourceInfo, candidate.getClassifier().getName()));
+                    }
+                }
+
+                SourceInformation sourceToBeModified = exception.getImportGroup().getSourceInformation();
+                if (sourceToBeModified == null)
+                {
+                    //avoid null pointer exception
+                    sourceToBeModified = DUMMY_SOURCE_INFORMATION;
+                }
+
+                MutableSet pathsInSameSource = Sets.mutable.empty();
+                MutableSet pathsNotInSameSource = Sets.mutable.empty();
+                sourceInfoAndTypeByPath.forEachKeyValue((s, sourceInformationStringPair) ->
+                {
+                    if (sourceInformationStringPair.getOne().getSourceId().equals(exception.getImportGroup().getSourceInformation().getSourceId()))
+                    {
+                        pathsInSameSource.add(s);
+                    }
+                    else
+                    {
+                        pathsNotInSameSource.add(s);
+                    }
+                });
+
+                org.finos.legend.engine.ide.helpers.response.IDEPureUnresolvedIdentifierExceptionResponse unresolvedResponse = new IDEPureUnresolvedIdentifierExceptionResponse();
+                response = unresolvedResponse;
+                unresolvedResponse.candidateName = exception.getIdOrPath();
+                MutableList candidatesOutput = Lists.mutable.of();
+                unresolvedResponse.candidates = candidatesOutput;
+
+                for (String path : pathsInSameSource.toSortedList().withAll(pathsNotInSameSource.toSortedList()))
+                {
+                    Pair pair = sourceInfoAndTypeByPath.get(path);
+                    SourceInformation sourceInfo = pair.getOne();
+                    String type = pair.getTwo();
+                    String id = exception.getIdOrPath();
+                    int index = id.lastIndexOf("::");
+                    if (index != -1)
+                    {
+                        //id contains "::"
+                        id = id.substring(index + 2);
+                    }
+                    index = path.lastIndexOf(id);
+                    if (index == -1)
+                    {
+                        throw new RuntimeException("Unable to find identifier: " + exception.getIdOrPath());
+                    }
+                    String importToAdd = "import " + path.substring(0, index) + "*;";
+
+                    int lineToBeModified = sourceToBeModified.getStartLine();
+                    int columnToBeModified = sourceToBeModified.getStartColumn();
+                    if (columnToBeModified == 0)
+                    {
+                        //special handling for importGroup without any imports, need to add import to the next line
+                        lineToBeModified++;
+                    }
+
+                    org.finos.legend.engine.ide.helpers.response.Candidate candidate = new org.finos.legend.engine.ide.helpers.response.Candidate();
+                    candidate.sourceID = sourceInfo.getSourceId();
+                    candidate.line = sourceInfo.getLine();
+                    candidate.column = sourceInfo.getColumn();
+                    candidate.foundName = path;
+                    candidate.fileToBeModified = sourceToBeModified.getSourceId();
+                    candidate.lineToBeModified = lineToBeModified;
+                    candidate.columnToBeModified = columnToBeModified;
+                    candidate.add = true;
+                    candidate.messageToBeModified = importToAdd;
+                    candidate.type = type;
+                    candidatesOutput.add(candidate);
+                }
+            }
+        }
+        else if (e instanceof PureUnmatchedFunctionException)
+        {
+            final PureUnmatchedFunctionException exception = (PureUnmatchedFunctionException) e;
+            if (0 == exception.getImportCandidatesWithPackageNotImported().size() + exception.getImportCandidatesWithPackageImported().size())
+            {
+                response = new IDEExceptionResponse();
+            }
+            else
+            {
+                SourceInformation sourceToBeModified = exception.getImportGroup().getSourceInformation();
+                if (sourceToBeModified == null)
+                {
+                    // avoid null pointer exception
+                    sourceToBeModified = DUMMY_SOURCE_INFORMATION;
+                }
+
+                org.finos.legend.engine.ide.helpers.response.IDEPureUnmatchedFunctionExceptionResponse ideUnmatchedResponse = new IDEPureUnmatchedFunctionExceptionResponse();
+                response = ideUnmatchedResponse;
+                ideUnmatchedResponse.candidateName = exception.getFunctionName();
+
+                MutableList candidatesOutputWithPackageNotImported = Lists.mutable.of();
+                ideUnmatchedResponse.candidates = candidatesOutputWithPackageNotImported;
+                MutableList candidatesOutputWithPackageImported = Lists.mutable.of();
+                ideUnmatchedResponse.candidatesWithPackageImported = candidatesOutputWithPackageImported;
+                getCandidatesOutput(session, runtime, exception, sourceToBeModified, candidatesOutputWithPackageNotImported, exception.getImportCandidatesWithPackageNotImported());
+                getCandidatesOutput(session, runtime, exception, sourceToBeModified, candidatesOutputWithPackageImported, exception.getImportCandidatesWithPackageImported());
+            }
+        }
+        else if ((e instanceof PureParserException || e instanceof PureCompilationException))
+        {
+            org.finos.legend.engine.ide.helpers.response.IDEParserOrCompilerException parserOrCompilerException = new IDEParserOrCompilerException();
+            parserOrCompilerException.exceptionType = e.getExceptionName();
+            response = parserOrCompilerException;
+        }
+        else
+        {
+            response = new IDEExceptionResponse();
+        }
+
+        if (pureResponse != null)
+        {
+            String pureResponseStr;
+            try
+            {
+                pureResponseStr = pureResponse.toString(StandardCharsets.UTF_8.name()) + "\n";
+            }
+            catch (UnsupportedEncodingException ex)
+            {
+                // this should never happen, but just in case ...
+                pureResponseStr = pureResponse + "\n";
+            }
+            response.appendText(pureResponseStr);
+        }
+
+        if (e.hasPureStackTrace())
+        {
+            response.appendText(original.getMessage() + "\n" + e.getPureStackTrace("    "));
+        }
+        else
+        {
+            response.appendText(original.getMessage());
+        }
+
+        SourceInformation sourceInformation = original.getSourceInformation();
+        if ((sourceInformation != null) && (runtime != null) && (runtime.getSourceById(sourceInformation.getSourceId()) != null))
+        {
+            response.RO = runtime.isSourceImmutable(sourceInformation.getSourceId());
+            response.source = sourceInformation.getSourceId();
+            response.line = sourceInformation.getLine();
+            response.column = sourceInformation.getColumn();
+        }
+
+        if (session != null)
+        {
+            // response.compiler = session.getCompilerLogs();
+        }
+
+        return response;
+    }
+
+    private static void getCandidatesOutput(PureSession session, PureRuntime runtime, final PureUnmatchedFunctionException exception, SourceInformation sourceToBeModified, MutableList candidatesOutput, ListIterable candidates)
+    {
+        MutableMap sourceInfoAndTypeByPath = Maps.mutable.ofInitialCapacity(candidates.size());
+        for (CoreInstance candidate : candidates)
+        {
+            SourceInformation sourceInfo = candidate.getSourceInformation();
+            if ((sourceInfo != null) && (runtime != null))
+            {
+                StringBuilder functionNameStringBuilder = new StringBuilder();
+                try
+                {
+                    org.finos.legend.pure.m3.navigation.function.Function.print(functionNameStringBuilder, candidate, runtime.getProcessorSupport());
+                }
+                catch (Exception functionPrintException)
+                {
+                    // Log error if possible, then ignore the function and continue
+                    if (session != null)
+                    {
+                        //session.log("Error printing: " + candidate, functionPrintException);
+                    }
+                    continue;
+                }
+                sourceInfoAndTypeByPath.put(functionNameStringBuilder.toString(), sourceInfo);
+            }
+        }
+
+        MutableSet pathsInSameSource = Sets.mutable.empty();
+        MutableSet pathsNotInSameSource = Sets.mutable.empty();
+        sourceInfoAndTypeByPath.forEachKeyValue((s, sourceInfo) ->
+        {
+            if (sourceInfo.getSourceId().equals(exception.getImportGroup().getSourceInformation().getSourceId()))
+            {
+                pathsInSameSource.add(s);
+            }
+            else
+            {
+                pathsNotInSameSource.add(s);
+            }
+        });
+
+        pathsInSameSource.toSortedList().withAll(pathsNotInSameSource.toSortedList()).forEach(path ->
+        {
+            SourceInformation sourceInfo = sourceInfoAndTypeByPath.get(path);
+            String functionName = exception.getFunctionName();
+            int index = functionName.lastIndexOf("::");
+            if (index != -1)
+            {
+                //id contains "::"
+                functionName = functionName.substring(index + 2);
+            }
+            index = path.lastIndexOf(functionName);
+            if (index != -1)
+            {
+                String importToAdd = "import " + path.substring(0, index) + "*;";
+
+                int lineToBeModified = sourceToBeModified.getStartLine();
+                int columnToBeModified = sourceToBeModified.getStartColumn();
+                if (0 == columnToBeModified)
+                {
+                    //special handling for importGroup without any imports, need to add import to the next line
+                    lineToBeModified++;
+                }
+
+                org.finos.legend.engine.ide.helpers.response.Candidate candidate = new Candidate();
+                candidate.sourceID = sourceInfo.getSourceId();
+                candidate.line = sourceInfo.getLine();
+                candidate.column = sourceInfo.getColumn();
+                candidate.foundName = path;
+                candidate.fileToBeModified = sourceToBeModified.getSourceId();
+                candidate.lineToBeModified = lineToBeModified;
+                candidate.columnToBeModified = columnToBeModified;
+                candidate.add = true;
+                candidate.messageToBeModified = importToAdd;
+                candidatesOutput.add(candidate);
+            }
+        });
+    }
+}
diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/helpers/response/IDEExceptionResponse.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/helpers/response/IDEExceptionResponse.java
new file mode 100644
index 00000000000..caab0b966df
--- /dev/null
+++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/helpers/response/IDEExceptionResponse.java
@@ -0,0 +1,37 @@
+// Copyright 2020 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.engine.ide.helpers.response;
+
+import org.eclipse.collections.api.map.MutableMap;
+import org.finos.legend.engine.ide.helpers.response.IDEResponse;
+
+public class IDEExceptionResponse extends IDEResponse
+{
+    private final boolean error = true;
+    public boolean RO;
+    public String source;
+    public Integer line;
+    public Integer column;
+
+    @Override
+    public void addJsonKeyValues(MutableMap jsonMap)
+    {
+        jsonMap.put("error", this.error);
+        jsonMap.put("RO", this.RO);
+        jsonMap.put("source", this.source);
+        jsonMap.put("line", this.line);
+        jsonMap.put("column", this.column);
+    }
+}
diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/helpers/response/IDEParserOrCompilerException.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/helpers/response/IDEParserOrCompilerException.java
new file mode 100644
index 00000000000..bce9412557c
--- /dev/null
+++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/helpers/response/IDEParserOrCompilerException.java
@@ -0,0 +1,31 @@
+// Copyright 2020 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.engine.ide.helpers.response;
+
+import org.eclipse.collections.api.map.MutableMap;
+import org.finos.legend.engine.ide.helpers.response.IDEExceptionResponse;
+
+public class IDEParserOrCompilerException extends IDEExceptionResponse
+{
+    public String exceptionType;
+
+    @Override
+    public void addJsonKeyValues(MutableMap jsonMap)
+    {
+        super.addJsonKeyValues(jsonMap);
+        jsonMap.put("exceptionType", this.exceptionType);
+    }
+}
+
diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/helpers/response/IDEPureUnmatchedFunctionExceptionResponse.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/helpers/response/IDEPureUnmatchedFunctionExceptionResponse.java
new file mode 100644
index 00000000000..46c995669c9
--- /dev/null
+++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/helpers/response/IDEPureUnmatchedFunctionExceptionResponse.java
@@ -0,0 +1,59 @@
+// Copyright 2020 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.engine.ide.helpers.response;
+
+import org.eclipse.collections.api.list.ListIterable;
+import org.eclipse.collections.api.map.MutableMap;
+import org.finos.legend.engine.ide.helpers.response.Candidate;
+import org.finos.legend.engine.ide.helpers.response.IDEPureUnresolvedIdentifierExceptionResponse;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+
+public class IDEPureUnmatchedFunctionExceptionResponse extends IDEPureUnresolvedIdentifierExceptionResponse
+{
+    private final boolean PureUnmatchedFunctionException = true;
+    ListIterable candidatesWithPackageImported;
+
+    @Override
+    public void addJsonKeyValues(MutableMap jsonMap)
+    {
+        super.addJsonKeyValues(jsonMap);
+        jsonMap.put("PureUnmatchedFunctionException", this.PureUnmatchedFunctionException);
+    }
+
+    @Override
+    public String toJSONString()
+    {
+        JSONObject object = new JSONObject(this.buildJsonKeyMaps());
+        object.put("candidateName", this.candidateName);
+
+        JSONArray jsonArrayWithPackageNotImported = new JSONArray();
+        object.put("candidatesWithPackageNotImported", jsonArrayWithPackageNotImported);
+        for (Candidate candidate : this.candidates)
+        {
+            jsonArrayWithPackageNotImported.add(candidate.toJSONObject());
+        }
+
+        JSONArray jsonArrayWithPackageImported = new JSONArray();
+        object.put("candidatesWithPackageImported", jsonArrayWithPackageImported);
+        for (Candidate candidate : this.candidatesWithPackageImported)
+        {
+            jsonArrayWithPackageImported.add(candidate.toJSONObject());
+        }
+
+        return object.toJSONString();
+    }
+}
+
diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/helpers/response/IDEPureUnresolvedIdentifierExceptionResponse.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/helpers/response/IDEPureUnresolvedIdentifierExceptionResponse.java
new file mode 100644
index 00000000000..ac95c6202b1
--- /dev/null
+++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/helpers/response/IDEPureUnresolvedIdentifierExceptionResponse.java
@@ -0,0 +1,50 @@
+// Copyright 2020 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.engine.ide.helpers.response;
+
+import org.eclipse.collections.api.list.ListIterable;
+import org.eclipse.collections.api.map.MutableMap;
+import org.finos.legend.engine.ide.helpers.response.Candidate;
+import org.finos.legend.engine.ide.helpers.response.IDEExceptionResponse;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+
+public class IDEPureUnresolvedIdentifierExceptionResponse extends IDEExceptionResponse
+{
+    String candidateName;
+    ListIterable candidates;
+
+    @Override
+    public void addJsonKeyValues(MutableMap jsonMap)
+    {
+        super.addJsonKeyValues(jsonMap);
+        jsonMap.put("candidateName", this.candidateName);
+    }
+
+    @Override
+    public String toJSONString()
+    {
+        JSONObject object = new JSONObject(this.buildJsonKeyMaps());
+        object.put("candidateName", this.candidateName);
+        JSONArray jsonArray = new JSONArray();
+        object.put("candidates", jsonArray);
+
+        for (Candidate candidate : this.candidates)
+        {
+            jsonArray.add(candidate.toJSONObject());
+        }
+        return object.toJSONString();
+    }
+}
diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/helpers/response/IDEResponse.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/helpers/response/IDEResponse.java
new file mode 100644
index 00000000000..0dca6d30f57
--- /dev/null
+++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/helpers/response/IDEResponse.java
@@ -0,0 +1,55 @@
+// Copyright 2020 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.engine.ide.helpers.response;
+
+import org.eclipse.collections.api.factory.Maps;
+import org.eclipse.collections.api.map.MutableMap;
+import org.json.simple.JSONAware;
+import org.json.simple.JSONObject;
+
+import java.util.Map;
+
+public abstract class IDEResponse implements JSONAware
+{
+    private String text;
+    private String compiler;
+
+    @Override
+    public String toJSONString()
+    {
+        return JSONObject.toJSONString(this.buildJsonKeyMaps());
+    }
+
+    Map buildJsonKeyMaps()
+    {
+        MutableMap jsonMap = Maps.mutable.of();
+        jsonMap.put("text", this.text);
+        jsonMap.put("compiler", this.compiler);
+        this.addJsonKeyValues(jsonMap);
+        return jsonMap;
+    }
+
+    public String getText()
+    {
+        return text;
+    }
+
+    public void appendText(String extraText)
+    {
+        this.text = null == this.text ? extraText : this.text + extraText;
+    }
+
+    abstract void addJsonKeyValues(MutableMap jsonMap);
+}
diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/session/PureSession.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/session/PureSession.java
new file mode 100644
index 00000000000..7dcd1ae6bd7
--- /dev/null
+++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/session/PureSession.java
@@ -0,0 +1,325 @@
+// Copyright 2020 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.engine.ide.session;
+
+import org.eclipse.collections.api.factory.Lists;
+import org.eclipse.collections.api.list.MutableList;
+import org.eclipse.collections.api.map.ConcurrentMutableMap;
+import org.eclipse.collections.impl.map.mutable.ConcurrentHashMap;
+import org.eclipse.collections.impl.utility.Iterate;
+import org.finos.legend.engine.ide.SourceLocationConfiguration;
+import org.finos.legend.engine.ide.api.execution.test.CallBack;
+import org.finos.legend.engine.ide.helpers.response.IDEResponse;
+import org.finos.legend.engine.ide.session.SimpleFunction;
+import org.finos.legend.pure.m3.SourceMutation;
+import org.finos.legend.pure.m3.execution.FunctionExecution;
+import org.finos.legend.pure.m3.execution.test.TestCollection;
+import org.finos.legend.pure.m3.execution.test.TestRunner;
+import org.finos.legend.pure.m3.serialization.filesystem.usercodestorage.MutableRepositoryCodeStorage;
+import org.finos.legend.pure.m3.serialization.filesystem.usercodestorage.RepositoryCodeStorage;
+import org.finos.legend.pure.m3.serialization.filesystem.usercodestorage.composite.CompositeCodeStorage;
+import org.finos.legend.pure.m3.serialization.filesystem.usercodestorage.welcome.WelcomeCodeStorage;
+import org.finos.legend.pure.m3.serialization.runtime.*;
+import org.finos.legend.pure.m3.statelistener.VoidExecutionActivityListener;
+import org.finos.legend.pure.m4.coreinstance.CoreInstance;
+import org.finos.legend.pure.m4.coreinstance.SourceInformation;
+import org.finos.legend.pure.runtime.java.interpreted.FunctionExecutionInterpreted;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.nio.file.Paths;
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.regex.Pattern;
+
+import static org.finos.legend.engine.ide.helpers.response.ExceptionTranslation.buildExceptionMessage;
+
+public class PureSession
+{
+    private final PureRuntime pureRuntime;
+    public MutableRepositoryCodeStorage codeStorage;
+    private final FunctionExecution functionExecution;
+    private final SourceLocationConfiguration sourceLocationConfiguration;
+    private final ConcurrentMutableMap testRunnersById = ConcurrentHashMap.newMap();
+    private final AtomicInteger executionCount = new AtomicInteger(0);
+    private static final Pattern LINE_SPLITTER = Pattern.compile("^", Pattern.MULTILINE);
+
+    public Message message = new Message("");
+
+    public MutableList repos;
+
+    public PureSession(SourceLocationConfiguration sourceLocationConfiguration, MutableList repos)
+    {
+        this.sourceLocationConfiguration = sourceLocationConfiguration;
+
+        String rootPath = Optional.ofNullable(sourceLocationConfiguration)
+                .flatMap(s -> Optional.ofNullable(s.welcomeFileDirectory))
+                .orElse(System.getProperty("java.io.tmpdir"));
+
+        this.repos = Lists.mutable.withAll(repos).with(new WelcomeCodeStorage(Paths.get(rootPath)));
+
+        this.functionExecution = new FunctionExecutionInterpreted(VoidExecutionActivityListener.VOID_EXECUTION_ACTIVITY_LISTENER);
+
+        this.codeStorage = new CompositeCodeStorage(this.repos.toArray(new RepositoryCodeStorage[0]));
+        this.pureRuntime = new PureRuntimeBuilder(this.codeStorage).withMessage(this.message).setUseFastCompiler(true).build();
+        this.functionExecution.init(this.pureRuntime, this.message);
+        this.codeStorage.initialize(this.message);
+    }
+
+    public MutableRepositoryCodeStorage getCodeStorage()
+    {
+        return this.codeStorage;
+    }
+
+    public PureRuntime getPureRuntime()
+    {
+        return this.pureRuntime;
+    }
+
+    public FunctionExecution getFunctionExecution()
+    {
+        return this.functionExecution;
+    }
+
+    public TestRunner newTestRunner(int testRunId, TestCollection collection)
+    {
+        TestRunnerWrapper testRunnerWrapper = new TestRunnerWrapper(collection, this.getPureRuntime().executedTestTracker);
+        this.testRunnersById.put(testRunId, testRunnerWrapper);
+        return testRunnerWrapper.testRunner;
+    }
+
+    public CallBack getTestCallBack(int testRunId)
+    {
+        TestRunnerWrapper testRunnerWrapper = this.testRunnersById.get(testRunId);
+        return (testRunnerWrapper == null) ? null : testRunnerWrapper.callBack;
+    }
+
+    public int getTestRunCount()
+    {
+        return this.testRunnersById.size();
+    }
+
+    public TestRunner removeTestRunner(int testRunId)
+    {
+        TestRunnerWrapper testRunnerWrapper = this.testRunnersById.remove(testRunId);
+        return (null == testRunnerWrapper) ? null : testRunnerWrapper.testRunner;
+    }
+
+    public void saveFilesAndExecute(HttpServletRequest request, HttpServletResponse response, OutputStream outputStream, SimpleFunction func) throws IOException
+    {
+        try
+        {
+            this.executionCount.incrementAndGet();
+            JSONObject mainObject = this.saveFiles(request, response);
+            SourceMutation sourceMutation = this.getPureRuntime().compile();
+            JSONArray array = (mainObject.get("modifiedFiles") != null) ? (JSONArray) mainObject.get("modifiedFiles") : new JSONArray();
+            Iterate.addAllIterable(sourceMutation.getModifiedFiles(), array);
+            mainObject.put("modifiedFiles", array);
+            func.run(this, (JSONObject) mainObject.get("extraParams"), (JSONArray) mainObject.get("modifiedFiles"), response, outputStream);
+        }
+        catch (Throwable t)
+        {
+            //todo: refactor this to not need the ByteArrayOutputStream
+            ByteArrayOutputStream pureResponse = new ByteArrayOutputStream();
+            outputStream.write(exceptionToJson(this, t, pureResponse).getBytes());
+            if (t instanceof Error)
+            {
+                throw (Error) t;
+            }
+        }
+        finally
+        {
+            this.executionCount.decrementAndGet();
+        }
+    }
+
+    public void saveOnly(HttpServletRequest request, HttpServletResponse response, OutputStream outputStream, SimpleFunction func) throws IOException
+    {
+        JSONObject mainObj = null;
+        ByteArrayOutputStream pureResponse = new ByteArrayOutputStream();
+        try
+        {
+            this.executionCount.incrementAndGet();
+            try
+            {
+                mainObj = this.saveFiles(request, response);
+                if (null != mainObj)
+                {
+                    //file has been saved
+                    JSONArray array = (null != mainObj.get("modifiedFiles")) ? (JSONArray) mainObj.get("modifiedFiles") : new JSONArray();
+                    mainObj.put("modifiedFiles", array);
+
+                    JSONObject extraParams = (JSONObject) mainObj.get("extraParams");
+                    extraParams.put("saveOutcome", "saved");
+                    func.run(this, extraParams, (JSONArray) mainObj.get("modifiedFiles"), response, outputStream);
+                }
+                else
+                {
+                    //Encountered Error trying to save
+                    JSONObject extraParams = new JSONObject();
+                    extraParams.put("saveOutcome", "Error");
+                    func.run(this, extraParams, new JSONArray(), response, outputStream);
+                }
+            }
+            catch (Exception e)
+            {
+                outputStream.write(exceptionToJson(this, e, pureResponse).getBytes());
+            }
+
+        }
+        catch (Exception e)
+        {
+            outputStream.write(exceptionToJson(this, e, pureResponse).getBytes());
+        }
+        finally
+        {
+            this.executionCount.decrementAndGet();
+        }
+    }
+
+    public JSONObject saveFiles(HttpServletRequest request, HttpServletResponse response) throws IOException
+    {
+        JSONObject mainObject = null;
+        try
+        {
+            mainObject = (JSONObject) new JSONParser().parse(new InputStreamReader(request.getInputStream()));
+            JSONArray openFiles = (JSONArray) mainObject.get("openFiles");
+            if ((null != openFiles) && !openFiles.isEmpty())
+            {
+                PureRuntime pureRuntime = this.getPureRuntime();
+
+                MutableList diagrams = Lists.mutable.empty();
+                for (Object rawOpenFile : openFiles)
+                {
+                    JSONObject openFile = (JSONObject) rawOpenFile;
+                    if (null == openFile.get("diagram"))
+                    {
+                        String path = (String) openFile.get("path");
+                        String code = (String) openFile.get("code");
+                        if (null == pureRuntime.getSourceById(path))
+                        {
+                            pureRuntime.loadSourceIfLoadable(path);
+                        }
+                        pureRuntime.modify(path, code);
+                    }
+                    else
+                    {
+                        diagrams.add(openFile);
+                    }
+                }
+
+                if (diagrams.notEmpty())
+                {
+                    JSONArray modifiedFiles = new JSONArray();
+
+                    for (JSONObject d : diagrams)
+                    {
+                        SourceMutation mutation = pureRuntime.compile();
+                        Iterate.addAllIterable(mutation.getModifiedFiles(), modifiedFiles);
+                        CoreInstance diagram = pureRuntime.getProcessorSupport().package_getByUserPath(d.get("diagram").toString());
+                        if (null != diagram)
+                        {
+                            SourceInformation sourceInformation = diagram.getSourceInformation();
+                            Source source = pureRuntime.getSourceById(sourceInformation.getSourceId());
+                            String content = source.getContent();
+                            String[] lines = LINE_SPLITTER.split(content);
+                            StringBuilder buffer = new StringBuilder(content.length());
+                            for (int i = 0; i < sourceInformation.getStartLine() - 1; i++)
+                            {
+                                buffer.append(lines[i]);
+                            }
+                            buffer.append(lines[sourceInformation.getStartLine() - 1], 0, diagram.getSourceInformation().getStartColumn() - 1);
+                            buffer.append(d.get("code"));
+                            buffer.append(lines[sourceInformation.getEndLine() - 1].substring(sourceInformation.getEndColumn()));
+                            for (int i = sourceInformation.getEndLine(); i < lines.length; i++)
+                            {
+                                buffer.append(lines[i]);
+                            }
+                            pureRuntime.modify(sourceInformation.getSourceId(), buffer.toString());
+                            modifiedFiles.add(diagram.getSourceInformation().getSourceId());
+                        }
+                    }
+                    mainObject.put("modifiedFiles", modifiedFiles);
+                }
+            }
+        }
+        catch (Exception e)
+        {
+            try (OutputStream outputStream = response.getOutputStream())
+            {
+                outputStream.write(exceptionToJson(this, e, null).getBytes());
+            }
+        }
+        return mainObject;
+    }
+
+    public int getCurrentExecutionCount()
+    {
+        return this.executionCount.get();
+    }
+
+    public static String exceptionToJson(PureSession session, Throwable t, ByteArrayOutputStream pureResponse)
+    {
+        IDEResponse response = buildExceptionMessage(session, t, pureResponse);
+        return response.toJSONString();
+    }
+
+    private class TestRunnerWrapper
+    {
+        private TestRunner testRunner;
+        private final CallBack callBack;
+
+        private TestRunnerWrapper(TestCollection collection, CallBack callBack, final ExecutedTestTracker executedTestTracker)
+        {
+            this.testRunner = new TestRunner(collection, false, PureSession.this.getFunctionExecution(), callBack)
+            {
+                @Override
+                public void run()
+                {
+                    super.run();
+                    if (null != executedTestTracker)
+                    {
+                        executedTestTracker.notePassingTests(this.passedTests);
+                        executedTestTracker.noteFailingTests(this.failedTests);
+                    }
+                }
+            };
+            this.callBack = callBack;
+        }
+
+        private TestRunnerWrapper(TestCollection collection, ExecutedTestTracker executedTestTracker)
+        {
+            this(collection, new CallBack(), executedTestTracker);
+        }
+
+        void stopAndClear()
+        {
+            TestRunner tr = this.testRunner;
+            if (null != tr)
+            {
+                tr.stop();
+                this.testRunner = null;
+            }
+            this.callBack.clear();
+        }
+    }
+}
diff --git a/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/session/SimpleFunction.java b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/session/SimpleFunction.java
new file mode 100644
index 00000000000..06180a177a1
--- /dev/null
+++ b/legend-engine-pure/legend-engine-pure-ide/legend-engine-pure-ide-light/src/main/java/org/finos/legend/engine/ide/session/SimpleFunction.java
@@ -0,0 +1,27 @@
+// Copyright 2020 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.engine.ide.session;
+
+import org.finos.legend.engine.ide.session.PureSession;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.OutputStream;
+
+public interface SimpleFunction
+{
+    void run(PureSession pureSession, JSONObject extraParams, JSONArray modifiedFiles, HttpServletResponse response, OutputStream outputStream) throws Exception;
+}
diff --git a/legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-dsl-diagram-java/pom.xml b/legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-dsl-diagram-java/pom.xml
index 7cd6eb65083..f1145c73224 100644
--- a/legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-dsl-diagram-java/pom.xml
+++ b/legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-dsl-diagram-java/pom.xml
@@ -59,7 +59,7 @@
                     
                     
                         org.finos.legend.pure
-                        legend-pure-runtime-java-extension-dsl-diagram
+                        legend-pure-runtime-java-extension-compiled-dsl-diagram
                         ${legend.pure.version}
                     
                 
diff --git a/legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-dsl-graph-java/pom.xml b/legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-dsl-graph-java/pom.xml
index 7271fb124ff..02b28dbc8b4 100644
--- a/legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-dsl-graph-java/pom.xml
+++ b/legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-dsl-graph-java/pom.xml
@@ -59,7 +59,7 @@
                      
                      
                          org.finos.legend.pure
-                         legend-pure-runtime-java-extension-dsl-graph
+                         legend-pure-runtime-java-extension-compiled-dsl-graph
                          ${legend.pure.version}
                      
 
@@ -70,7 +70,7 @@
                      
                      
                          org.finos.legend.pure
-                         legend-pure-runtime-java-extension-functions
+                         legend-pure-runtime-java-extension-compiled-functions-base
                          ${legend.pure.version}
                      
                  
@@ -91,7 +91,6 @@
         
             org.finos.legend.pure
             legend-pure-m2-dsl-graph-pure
-            ${legend.pure.version}
         
 
         
diff --git a/legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-dsl-mapping-java/pom.xml b/legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-dsl-mapping-java/pom.xml
index 3b21b83e564..b1d7d850d8b 100644
--- a/legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-dsl-mapping-java/pom.xml
+++ b/legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-dsl-mapping-java/pom.xml
@@ -64,7 +64,7 @@
                     
                     
                         org.finos.legend.pure
-                        legend-pure-runtime-java-extension-dsl-mapping
+                        legend-pure-runtime-java-extension-compiled-dsl-mapping
                         ${legend.pure.version}
                     
 
@@ -75,7 +75,7 @@
                     
                     
                         org.finos.legend.pure
-                        legend-pure-runtime-java-extension-functions
+                        legend-pure-runtime-java-extension-compiled-functions-base
                         ${legend.pure.version}
                     
                 
diff --git a/legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-dsl-path-java/pom.xml b/legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-dsl-path-java/pom.xml
index af61d56f974..4fd9cca4aa0 100644
--- a/legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-dsl-path-java/pom.xml
+++ b/legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-dsl-path-java/pom.xml
@@ -59,7 +59,7 @@
                     
                     
                         org.finos.legend.pure
-                        legend-pure-runtime-java-extension-dsl-path
+                        legend-pure-runtime-java-extension-compiled-dsl-path
                         ${legend.pure.version}
                     
                 
@@ -80,7 +80,6 @@
         
             org.finos.legend.pure
             legend-pure-m2-dsl-path-pure
-            ${legend.pure.version}
         
 
         
diff --git a/legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-dsl-tds-java/pom.xml b/legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-dsl-tds-java/pom.xml
index 759a8fce132..9c328b67527 100644
--- a/legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-dsl-tds-java/pom.xml
+++ b/legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-dsl-tds-java/pom.xml
@@ -75,7 +75,6 @@
         
             org.finos.legend.pure
             legend-pure-m2-dsl-tds-pure
-            ${legend.pure.version}
         
 
         
diff --git a/legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-functions-java/pom.xml b/legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-functions-java/pom.xml
index eac8092b65f..db35506b68a 100644
--- a/legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-functions-java/pom.xml
+++ b/legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-functions-java/pom.xml
@@ -59,7 +59,7 @@
                     
                     
                         org.finos.legend.pure
-                        legend-pure-runtime-java-extension-functions
+                        legend-pure-runtime-java-extension-compiled-functions-base
                         ${legend.pure.version}
                     
                 
@@ -81,10 +81,6 @@
             org.finos.legend.pure
             legend-pure-runtime-java-engine-compiled
         
-        
-            org.finos.legend.pure
-            legend-pure-runtime-java-extension-functions
-        
         
             org.finos.legend.pure
             legend-pure-runtime-java-engine-shared
@@ -95,6 +91,11 @@
             legend-engine-pure-platform-java
         
 
+        
+            org.finos.legend.pure
+            legend-pure-runtime-java-extension-compiled-functions-base
+        
+
         
             org.eclipse.collections
             eclipse-collections-api
diff --git a/legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-functions-json-java/pom.xml b/legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-functions-json-java/pom.xml
index 1d5f2b66667..b68850df28a 100644
--- a/legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-functions-json-java/pom.xml
+++ b/legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-functions-json-java/pom.xml
@@ -59,7 +59,7 @@
                     
                     
                         org.finos.legend.pure
-                        legend-pure-runtime-java-extension-functions-json
+                        legend-pure-runtime-java-extension-compiled-functions-json
                         ${legend.pure.version}
                     
                 
@@ -87,11 +87,15 @@
 
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-functions-json
+            legend-pure-runtime-java-extension-compiled-functions-json
          
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-functions-shared-conversion
+            legend-pure-runtime-java-extension-shared-functions-json
+        
+        
+            org.finos.legend.pure
+            legend-pure-runtime-java-extension-shared-functions-conversion
         
 
         
diff --git a/legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-functions-relation-java/pom.xml b/legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-functions-relation-java/pom.xml
index a74e96752d8..701736b5a6f 100644
--- a/legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-functions-relation-java/pom.xml
+++ b/legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-functions-relation-java/pom.xml
@@ -59,7 +59,7 @@
                     
                     
                         org.finos.legend.pure
-                        legend-pure-runtime-java-extension-functions-relation
+                        legend-pure-runtime-java-extension-compiled-functions-relation
                         ${legend.pure.version}
                     
                 
@@ -85,16 +85,11 @@
             org.finos.legend.pure
             legend-pure-runtime-java-engine-compiled
         
-
-
-
-
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-functions-relation
+            legend-pure-runtime-java-extension-compiled-functions-relation
         
 
-
         
             org.finos.legend.engine
             legend-engine-pure-platform-java
@@ -103,10 +98,6 @@
             org.finos.legend.engine
             legend-engine-pure-platform-functions-java
         
-
-
-
-
 
         
             org.eclipse.collections
diff --git a/legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-store-relational-java/pom.xml b/legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-store-relational-java/pom.xml
index 948702482b1..7d93bf7af98 100644
--- a/legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-store-relational-java/pom.xml
+++ b/legend-engine-pure/legend-engine-pure-platform-modular-generation/legend-engine-pure-platform-store-relational-java/pom.xml
@@ -59,7 +59,7 @@
                      
                      
                          org.finos.legend.pure
-                         legend-pure-runtime-java-extension-store-relational
+                         legend-pure-runtime-java-extension-compiled-store-relational
                          ${legend.pure.version}
                      
 
@@ -70,7 +70,7 @@
                      
                      
                          org.finos.legend.pure
-                         legend-pure-runtime-java-extension-dsl-mapping
+                         legend-pure-runtime-java-extension-compiled-dsl-mapping
                          ${legend.pure.version}
                      
 
@@ -81,7 +81,7 @@
                      
                      
                          org.finos.legend.pure
-                         legend-pure-runtime-java-extension-functions
+                         legend-pure-runtime-java-extension-compiled-functions-base
                          ${legend.pure.version}
                      
                  
@@ -122,17 +122,20 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-dsl-mapping
+            legend-pure-runtime-java-extension-compiled-dsl-mapping
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-dsl-store
+            legend-pure-runtime-java-extension-compiled-dsl-store
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-store-relational
+            legend-pure-runtime-java-extension-compiled-store-relational
+        
+        
+            org.finos.legend.pure
+            legend-pure-runtime-java-extension-shared-store-relational
         
-
         
             org.finos.legend.engine
             legend-engine-pure-platform-java
@@ -145,6 +148,10 @@
             org.finos.legend.engine
             legend-engine-pure-platform-dsl-mapping-java
         
+        
+            org.finos.legend.engine
+            legend-engine-pure-platform-dsl-store-java
+        
 
         
             org.eclipse.collections
diff --git a/legend-engine-pure/legend-engine-pure-runtime/legend-engine-pure-runtime-compiler/pom.xml b/legend-engine-pure/legend-engine-pure-runtime/legend-engine-pure-runtime-compiler/pom.xml
index 8c32805f2eb..fda32fcda4f 100644
--- a/legend-engine-pure/legend-engine-pure-runtime/legend-engine-pure-runtime-compiler/pom.xml
+++ b/legend-engine-pure/legend-engine-pure-runtime/legend-engine-pure-runtime-compiler/pom.xml
@@ -179,6 +179,16 @@
             legend-engine-xt-text-compiler
             test
         
+        
+            org.finos.legend.pure
+            legend-pure-runtime-java-extension-compiled-functions-base
+            test
+        
+        
+            org.finos.legend.pure
+            legend-pure-runtime-java-extension-interpreted-functions-base
+            test
+        
         
             org.finos.legend.engine
             legend-engine-language-pure-grammar
diff --git a/legend-engine-pure/legend-engine-pure-runtime/legend-engine-pure-runtime-execution/pom.xml b/legend-engine-pure/legend-engine-pure-runtime/legend-engine-pure-runtime-execution/pom.xml
index bac942c4b7e..de3c3549f5c 100644
--- a/legend-engine-pure/legend-engine-pure-runtime/legend-engine-pure-runtime-execution/pom.xml
+++ b/legend-engine-pure/legend-engine-pure-runtime/legend-engine-pure-runtime-execution/pom.xml
@@ -118,7 +118,7 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-dsl-mapping
+            legend-pure-runtime-java-extension-compiled-dsl-mapping
             runtime
         
         
@@ -145,7 +145,7 @@
         
         
             org.finos.legend.engine
-            legend-engine-pure-platform-dsl-mapping-java
+            legend-engine-pure-platform-dsl-store-java
         
 
 
@@ -208,5 +208,25 @@
             legend-pure-m2-dsl-diagram-grammar
             test
         
+        
+            org.finos.legend.pure
+            legend-pure-runtime-java-extension-compiled-functions-base
+            test
+        
+        
+            org.finos.legend.pure
+            legend-pure-runtime-java-extension-interpreted-functions-base
+            test
+        
+        
+            org.finos.legend.pure
+            legend-pure-runtime-java-extension-compiled-functions-json
+            test
+        
+        
+            org.finos.legend.pure
+            legend-pure-runtime-java-extension-interpreted-functions-json
+            test
+        
     
 
diff --git a/legend-engine-pure/legend-engine-pure-runtime/legend-engine-pure-runtime-execution/src/main/resources/core_external_execution.definition.json b/legend-engine-pure/legend-engine-pure-runtime/legend-engine-pure-runtime-execution/src/main/resources/core_external_execution.definition.json
index eac67a5a781..2ab1b307105 100644
--- a/legend-engine-pure/legend-engine-pure-runtime/legend-engine-pure-runtime-execution/src/main/resources/core_external_execution.definition.json
+++ b/legend-engine-pure/legend-engine-pure-runtime/legend-engine-pure-runtime-execution/src/main/resources/core_external_execution.definition.json
@@ -3,7 +3,7 @@
   "pattern": "(meta::legend)(::.*)?",
   "dependencies": [
     "platform",
-    "platform_dsl_mapping",
+    "platform_dsl_store",
     "core"
   ]
 }
diff --git a/legend-engine-pure/legend-engine-pure-runtime/legend-engine-pure-runtime-extensions/pom.xml b/legend-engine-pure/legend-engine-pure-runtime/legend-engine-pure-runtime-extensions/pom.xml
index 8cee9e31258..5b6070abdbc 100644
--- a/legend-engine-pure/legend-engine-pure-runtime/legend-engine-pure-runtime-extensions/pom.xml
+++ b/legend-engine-pure/legend-engine-pure-runtime/legend-engine-pure-runtime-extensions/pom.xml
@@ -118,7 +118,7 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-dsl-mapping
+            legend-pure-runtime-java-extension-compiled-dsl-mapping
             runtime
         
         
@@ -185,5 +185,15 @@
             legend-pure-m2-dsl-diagram-grammar
             test
         
+        
+            org.finos.legend.pure
+            legend-pure-runtime-java-extension-compiled-functions-base
+            test
+        
+        
+            org.finos.legend.pure
+            legend-pure-runtime-java-extension-interpreted-functions-base
+            test
+        
     
 
diff --git a/legend-engine-pure/legend-engine-pure-runtime/legend-engine-xt-java-runtime-compiler/pom.xml b/legend-engine-pure/legend-engine-pure-runtime/legend-engine-xt-java-runtime-compiler/pom.xml
index 6b5810ae59b..c7ce96206a4 100644
--- a/legend-engine-pure/legend-engine-pure-runtime/legend-engine-xt-java-runtime-compiler/pom.xml
+++ b/legend-engine-pure/legend-engine-pure-runtime/legend-engine-xt-java-runtime-compiler/pom.xml
@@ -115,12 +115,12 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-functions-json
+            legend-pure-runtime-java-extension-compiled-functions-json
             runtime
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-dsl-mapping
+            legend-pure-runtime-java-extension-compiled-dsl-mapping
             runtime
         
 
@@ -184,5 +184,15 @@
             test-jar
             test
         
+        
+            org.finos.legend.pure
+            legend-pure-runtime-java-extension-compiled-functions-base
+            test
+        
+        
+            org.finos.legend.pure
+            legend-pure-runtime-java-extension-interpreted-functions-base
+            test
+        
     
 
\ No newline at end of file
diff --git a/legend-engine-xts-analytics/legend-engine-xts-analytics-lineage/legend-engine-xt-analytics-lineage-pure/pom.xml b/legend-engine-xts-analytics/legend-engine-xts-analytics-lineage/legend-engine-xt-analytics-lineage-pure/pom.xml
index ce0fa44313e..1edc2076c41 100644
--- a/legend-engine-xts-analytics/legend-engine-xts-analytics-lineage/legend-engine-xt-analytics-lineage-pure/pom.xml
+++ b/legend-engine-xts-analytics/legend-engine-xts-analytics-lineage/legend-engine-xt-analytics-lineage-pure/pom.xml
@@ -215,6 +215,10 @@
             org.finos.legend.engine
             legend-engine-pure-platform-dsl-mapping-java
         
+        
+            org.finos.legend.engine
+            legend-engine-pure-platform-dsl-store-java
+        
 
         
             org.finos.legend.engine
diff --git a/legend-engine-xts-analytics/legend-engine-xts-analytics-lineage/legend-engine-xt-analytics-lineage-pure/src/main/resources/core_analytics_lineage.definition.json b/legend-engine-xts-analytics/legend-engine-xts-analytics-lineage/legend-engine-xt-analytics-lineage-pure/src/main/resources/core_analytics_lineage.definition.json
index a781c297279..3b94f290130 100644
--- a/legend-engine-xts-analytics/legend-engine-xts-analytics-lineage/legend-engine-xt-analytics-lineage-pure/src/main/resources/core_analytics_lineage.definition.json
+++ b/legend-engine-xts-analytics/legend-engine-xts-analytics-lineage/legend-engine-xt-analytics-lineage-pure/src/main/resources/core_analytics_lineage.definition.json
@@ -4,6 +4,7 @@
   "dependencies": [
     "platform",
     "platform_functions",
+    "platform_dsl_store",
     "platform_dsl_mapping",
     "platform_store_relational",
     "platform_functions_json",
diff --git a/legend-engine-xts-analytics/legend-engine-xts-analytics-search/legend-engine-xt-analytics-search-pure/pom.xml b/legend-engine-xts-analytics/legend-engine-xts-analytics-search/legend-engine-xt-analytics-search-pure/pom.xml
index b7a5a25cfc6..846c8759546 100644
--- a/legend-engine-xts-analytics/legend-engine-xts-analytics-search/legend-engine-xt-analytics-search-pure/pom.xml
+++ b/legend-engine-xts-analytics/legend-engine-xts-analytics-search/legend-engine-xt-analytics-search-pure/pom.xml
@@ -304,6 +304,10 @@
             org.finos.legend.engine
             legend-engine-pure-platform-dsl-mapping-java
         
+        
+            org.finos.legend.engine
+            legend-engine-pure-platform-dsl-store-java
+        
         
             org.finos.legend.engine
             legend-engine-xt-relationalStore-pure
diff --git a/legend-engine-xts-analytics/legend-engine-xts-analytics-store/legend-engine-xt-analytics-store-entitlement-api/pom.xml b/legend-engine-xts-analytics/legend-engine-xts-analytics-store/legend-engine-xt-analytics-store-entitlement-api/pom.xml
index 080b1aab2eb..3d2771efa7f 100644
--- a/legend-engine-xts-analytics/legend-engine-xts-analytics-store/legend-engine-xt-analytics-store-entitlement-api/pom.xml
+++ b/legend-engine-xts-analytics/legend-engine-xts-analytics-store/legend-engine-xt-analytics-store-entitlement-api/pom.xml
@@ -44,7 +44,7 @@
         
         
             org.finos.legend.engine
-            legend-engine-pure-platform-dsl-mapping-java
+            legend-engine-pure-platform-dsl-store-java
         
         
             org.finos.legend.engine
diff --git a/legend-engine-xts-analytics/legend-engine-xts-analytics-store/legend-engine-xt-analytics-store-entitlement/pom.xml b/legend-engine-xts-analytics/legend-engine-xts-analytics-store/legend-engine-xt-analytics-store-entitlement/pom.xml
index 0b7ed8b168b..9a965e38639 100644
--- a/legend-engine-xts-analytics/legend-engine-xts-analytics-store/legend-engine-xt-analytics-store-entitlement/pom.xml
+++ b/legend-engine-xts-analytics/legend-engine-xts-analytics-store/legend-engine-xt-analytics-store-entitlement/pom.xml
@@ -42,7 +42,7 @@
         
         
             org.finos.legend.engine
-            legend-engine-pure-platform-dsl-mapping-java
+            legend-engine-pure-platform-dsl-store-java
         
         
             org.finos.legend.engine
diff --git a/legend-engine-xts-arrow/legend-engine-xt-arrow-runtime/pom.xml b/legend-engine-xts-arrow/legend-engine-xt-arrow-runtime/pom.xml
index 3344f0693d6..04ddda01228 100644
--- a/legend-engine-xts-arrow/legend-engine-xt-arrow-runtime/pom.xml
+++ b/legend-engine-xts-arrow/legend-engine-xt-arrow-runtime/pom.xml
@@ -129,6 +129,11 @@
             legend-engine-pure-platform-dsl-mapping-java
             test
         
+        
+            org.finos.legend.engine
+            legend-engine-pure-platform-dsl-store-java
+            test
+        
         
             org.finos.legend.engine
             legend-engine-xt-relationalStore-pure
diff --git a/legend-engine-xts-avro/legend-engine-xt-avro-pure/pom.xml b/legend-engine-xts-avro/legend-engine-xt-avro-pure/pom.xml
index a3d21689297..23cd7810db0 100644
--- a/legend-engine-xts-avro/legend-engine-xt-avro-pure/pom.xml
+++ b/legend-engine-xts-avro/legend-engine-xt-avro-pure/pom.xml
@@ -153,7 +153,7 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-functions-json
+            legend-pure-runtime-java-extension-shared-functions-json
         
         
             org.finos.legend.engine
diff --git a/legend-engine-xts-changetoken/legend-engine-xt-changetoken-pure/pom.xml b/legend-engine-xts-changetoken/legend-engine-xt-changetoken-pure/pom.xml
index f284b257df9..9d9257680c4 100644
--- a/legend-engine-xts-changetoken/legend-engine-xt-changetoken-pure/pom.xml
+++ b/legend-engine-xts-changetoken/legend-engine-xt-changetoken-pure/pom.xml
@@ -170,7 +170,7 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-functions-json
+            legend-pure-runtime-java-extension-shared-functions-json
         
         
             org.finos.legend.engine
diff --git a/legend-engine-xts-data-space/legend-engine-xt-data-space-compiler/pom.xml b/legend-engine-xts-data-space/legend-engine-xt-data-space-compiler/pom.xml
index 717ee09a9d7..562fba62a42 100644
--- a/legend-engine-xts-data-space/legend-engine-xt-data-space-compiler/pom.xml
+++ b/legend-engine-xts-data-space/legend-engine-xt-data-space-compiler/pom.xml
@@ -42,7 +42,7 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-dsl-mapping
+            legend-pure-runtime-java-extension-compiled-dsl-mapping
         
         
             org.finos.legend.engine
diff --git a/legend-engine-xts-data-space/legend-engine-xt-data-space-generation/pom.xml b/legend-engine-xts-data-space/legend-engine-xt-data-space-generation/pom.xml
index ba61d978b98..4f76f27235c 100644
--- a/legend-engine-xts-data-space/legend-engine-xt-data-space-generation/pom.xml
+++ b/legend-engine-xts-data-space/legend-engine-xt-data-space-generation/pom.xml
@@ -77,7 +77,7 @@
         
         
             org.finos.legend.engine
-            legend-engine-pure-platform-dsl-mapping-java
+            legend-engine-pure-platform-dsl-store-java
         
         
             org.finos.legend.engine
@@ -198,6 +198,11 @@
             legend-engine-xt-relationalStore-store-entitlement-analytics
             test
         
+        
+            com.h2database
+            h2
+            test
+        
         
     
 
diff --git a/legend-engine-xts-elasticsearch/legend-engine-xt-elasticsearch-V7-grammar/pom.xml b/legend-engine-xts-elasticsearch/legend-engine-xt-elasticsearch-V7-grammar/pom.xml
index dbb5fc2bd42..a0b3b4f40ad 100644
--- a/legend-engine-xts-elasticsearch/legend-engine-xt-elasticsearch-V7-grammar/pom.xml
+++ b/legend-engine-xts-elasticsearch/legend-engine-xt-elasticsearch-V7-grammar/pom.xml
@@ -96,7 +96,7 @@
 
         
             org.finos.legend.engine
-            legend-engine-pure-platform-dsl-mapping-java
+            legend-engine-pure-platform-dsl-store-java
         
         
             org.finos.legend.engine
diff --git a/legend-engine-xts-elasticsearch/legend-engine-xt-elasticsearch-V7-pure-metamodel/pom.xml b/legend-engine-xts-elasticsearch/legend-engine-xt-elasticsearch-V7-pure-metamodel/pom.xml
index 9d06092a5d0..f47cca7226a 100644
--- a/legend-engine-xts-elasticsearch/legend-engine-xt-elasticsearch-V7-pure-metamodel/pom.xml
+++ b/legend-engine-xts-elasticsearch/legend-engine-xt-elasticsearch-V7-pure-metamodel/pom.xml
@@ -50,7 +50,7 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-dsl-store
+            legend-pure-runtime-java-extension-compiled-dsl-store
         
         
 
@@ -79,6 +79,10 @@
             org.finos.legend.engine
             legend-engine-pure-platform-dsl-mapping-java
         
+        
+            org.finos.legend.engine
+            legend-engine-pure-platform-dsl-store-java
+        
         
             org.finos.legend.engine
             legend-engine-xt-authentication-pure
diff --git a/legend-engine-xts-elasticsearch/legend-engine-xt-elasticsearch-executionPlan-test/pom.xml b/legend-engine-xts-elasticsearch/legend-engine-xt-elasticsearch-executionPlan-test/pom.xml
index d5a2f9f7aa0..5b26d71f352 100644
--- a/legend-engine-xts-elasticsearch/legend-engine-xt-elasticsearch-executionPlan-test/pom.xml
+++ b/legend-engine-xts-elasticsearch/legend-engine-xt-elasticsearch-executionPlan-test/pom.xml
@@ -46,7 +46,7 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-functions-json
+            legend-pure-runtime-java-extension-shared-functions-json
         
         
             org.finos.legend.engine
@@ -78,7 +78,7 @@
         
         
             org.finos.legend.engine
-            legend-engine-pure-platform-dsl-mapping-java
+            legend-engine-pure-platform-dsl-store-java
         
         
             org.finos.legend.engine
diff --git a/legend-engine-xts-flatdata/legend-engine-xt-flatdata-model/pom.xml b/legend-engine-xts-flatdata/legend-engine-xt-flatdata-model/pom.xml
index 56180505e78..e2715fcf5a5 100644
--- a/legend-engine-xts-flatdata/legend-engine-xt-flatdata-model/pom.xml
+++ b/legend-engine-xts-flatdata/legend-engine-xt-flatdata-model/pom.xml
@@ -179,7 +179,7 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-functions-json
+            legend-pure-runtime-java-extension-compiled-functions-json
             test
         
         
diff --git a/legend-engine-xts-flatdata/legend-engine-xt-flatdata-pure/pom.xml b/legend-engine-xts-flatdata/legend-engine-xt-flatdata-pure/pom.xml
index e501f90538f..32b9f347f4f 100644
--- a/legend-engine-xts-flatdata/legend-engine-xt-flatdata-pure/pom.xml
+++ b/legend-engine-xts-flatdata/legend-engine-xt-flatdata-pure/pom.xml
@@ -177,7 +177,7 @@
         
         
             org.finos.legend.engine
-            legend-engine-pure-platform-dsl-mapping-java
+            legend-engine-pure-platform-dsl-store-java
         
         
 
diff --git a/legend-engine-xts-flatdata/legend-engine-xt-flatdata-runtime/pom.xml b/legend-engine-xts-flatdata/legend-engine-xt-flatdata-runtime/pom.xml
index 3cd8020c0a4..792810a3672 100644
--- a/legend-engine-xts-flatdata/legend-engine-xt-flatdata-runtime/pom.xml
+++ b/legend-engine-xts-flatdata/legend-engine-xt-flatdata-runtime/pom.xml
@@ -194,7 +194,7 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-functions-json
+            legend-pure-runtime-java-extension-compiled-functions-json
             test
         
         
@@ -275,7 +275,7 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-store-relational
+            legend-pure-runtime-java-extension-compiled-store-relational
             test
         
         
diff --git a/legend-engine-xts-graphQL/legend-engine-xt-graphQL-compiler/pom.xml b/legend-engine-xts-graphQL/legend-engine-xt-graphQL-compiler/pom.xml
index 5b3e4f1ac36..064da27af20 100644
--- a/legend-engine-xts-graphQL/legend-engine-xt-graphQL-compiler/pom.xml
+++ b/legend-engine-xts-graphQL/legend-engine-xt-graphQL-compiler/pom.xml
@@ -77,7 +77,7 @@
                     
                     
                         org.finos.legend.pure
-                        legend-pure-runtime-java-extension-store-relational
+                        legend-pure-runtime-java-extension-compiled-store-relational
                         ${legend.pure.version}
                     
                     
@@ -114,7 +114,7 @@
                         
                             
                             
-                                org.finos.legend.pure:legend-pure-runtime-java-extension-dsl-mapping
+                                org.finos.legend.pure:legend-pure-runtime-java-extension-compiled-dsl-mapping
                                 org.finos.legend.pure:legend-pure-m2-dsl-mapping-grammar
                             
                         
diff --git a/legend-engine-xts-graphQL/legend-engine-xt-graphQL-protocol/pom.xml b/legend-engine-xts-graphQL/legend-engine-xt-graphQL-protocol/pom.xml
index a6679ddc99e..e703c98bb62 100644
--- a/legend-engine-xts-graphQL/legend-engine-xt-graphQL-protocol/pom.xml
+++ b/legend-engine-xts-graphQL/legend-engine-xt-graphQL-protocol/pom.xml
@@ -82,7 +82,7 @@
                     
                     
                         org.finos.legend.pure
-                        legend-pure-runtime-java-extension-store-relational
+                        legend-pure-runtime-java-extension-compiled-store-relational
                         ${legend.pure.version}
                     
                     
diff --git a/legend-engine-xts-graphQL/legend-engine-xt-graphQL-pure/pom.xml b/legend-engine-xts-graphQL/legend-engine-xt-graphQL-pure/pom.xml
index 65db00a30dd..88f760c8367 100644
--- a/legend-engine-xts-graphQL/legend-engine-xt-graphQL-pure/pom.xml
+++ b/legend-engine-xts-graphQL/legend-engine-xt-graphQL-pure/pom.xml
@@ -181,7 +181,7 @@
 
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-dsl-graph
+            legend-pure-runtime-java-extension-compiled-dsl-graph
         
 
         
@@ -207,7 +207,7 @@
         
         
             org.finos.legend.engine
-            legend-engine-pure-platform-dsl-mapping-java
+            legend-engine-pure-platform-dsl-store-java
         
 
         
diff --git a/legend-engine-xts-graphQL/legend-engine-xt-graphQL-pure/src/main/resources/core_external_query_graphql.definition.json b/legend-engine-xts-graphQL/legend-engine-xt-graphQL-pure/src/main/resources/core_external_query_graphql.definition.json
index 7064e6a5478..097eab3a9f2 100644
--- a/legend-engine-xts-graphQL/legend-engine-xt-graphQL-pure/src/main/resources/core_external_query_graphql.definition.json
+++ b/legend-engine-xts-graphQL/legend-engine-xt-graphQL-pure/src/main/resources/core_external_query_graphql.definition.json
@@ -6,6 +6,7 @@
     "platform_functions",
     "platform_dsl_graph",
     "platform_dsl_mapping",
+    "platform_dsl_store",
     "core_functions",
     "core",
     "core_generation",
diff --git a/legend-engine-xts-graphQL/legend-engine-xt-graphQL-query/pom.xml b/legend-engine-xts-graphQL/legend-engine-xt-graphQL-query/pom.xml
index b43c0f0efa6..ab93179873d 100644
--- a/legend-engine-xts-graphQL/legend-engine-xt-graphQL-query/pom.xml
+++ b/legend-engine-xts-graphQL/legend-engine-xt-graphQL-query/pom.xml
@@ -59,7 +59,7 @@
         
         
             org.finos.legend.engine
-            legend-engine-pure-platform-dsl-mapping-java
+            legend-engine-pure-platform-dsl-store-java
         
         
             org.finos.legend.engine
diff --git a/legend-engine-xts-graphQL/legend-engine-xt-graphQL-relational-extension/pom.xml b/legend-engine-xts-graphQL/legend-engine-xt-graphQL-relational-extension/pom.xml
index 93f39ff0b00..13e951f204b 100644
--- a/legend-engine-xts-graphQL/legend-engine-xt-graphQL-relational-extension/pom.xml
+++ b/legend-engine-xts-graphQL/legend-engine-xt-graphQL-relational-extension/pom.xml
@@ -56,7 +56,7 @@
         
         
             org.finos.legend.engine
-            legend-engine-pure-platform-dsl-mapping-java
+            legend-engine-pure-platform-dsl-store-java
         
         
             org.finos.legend.engine
diff --git a/legend-engine-xts-haskell/legend-engine-xt-haskell-grammar/pom.xml b/legend-engine-xts-haskell/legend-engine-xt-haskell-grammar/pom.xml
index d7f9581fa11..e3347e3c88f 100644
--- a/legend-engine-xts-haskell/legend-engine-xt-haskell-grammar/pom.xml
+++ b/legend-engine-xts-haskell/legend-engine-xt-haskell-grammar/pom.xml
@@ -80,7 +80,7 @@
                     
                     
                         org.finos.legend.pure
-                        legend-pure-runtime-java-extension-store-relational
+                        legend-pure-runtime-java-extension-compiled-store-relational
                         ${legend.pure.version}
                     
                     
diff --git a/legend-engine-xts-haskell/legend-engine-xt-haskell-protocol/pom.xml b/legend-engine-xts-haskell/legend-engine-xt-haskell-protocol/pom.xml
index 6d717e5d9f6..da6b2eb8f7c 100644
--- a/legend-engine-xts-haskell/legend-engine-xt-haskell-protocol/pom.xml
+++ b/legend-engine-xts-haskell/legend-engine-xt-haskell-protocol/pom.xml
@@ -63,7 +63,7 @@
                     
                     
                         org.finos.legend.pure
-                        legend-pure-runtime-java-extension-store-relational
+                        legend-pure-runtime-java-extension-compiled-store-relational
                         ${legend.pure.version}
                     
                     
diff --git a/legend-engine-xts-hostedService/legend-engine-xt-hostedService-compiler/pom.xml b/legend-engine-xts-hostedService/legend-engine-xt-hostedService-compiler/pom.xml
index f6e93b89d24..f451164fe1c 100644
--- a/legend-engine-xts-hostedService/legend-engine-xt-hostedService-compiler/pom.xml
+++ b/legend-engine-xts-hostedService/legend-engine-xt-hostedService-compiler/pom.xml
@@ -63,7 +63,7 @@
         
         
             org.finos.legend.engine
-            legend-engine-pure-platform-dsl-mapping-java
+            legend-engine-pure-platform-dsl-store-java
         
         
             org.finos.legend.engine
diff --git a/legend-engine-xts-hostedService/legend-engine-xt-hostedService-pure/pom.xml b/legend-engine-xts-hostedService/legend-engine-xt-hostedService-pure/pom.xml
index f4270351f3a..65717898b13 100644
--- a/legend-engine-xts-hostedService/legend-engine-xt-hostedService-pure/pom.xml
+++ b/legend-engine-xts-hostedService/legend-engine-xt-hostedService-pure/pom.xml
@@ -39,7 +39,7 @@
                             
                             
                                  org.finos.legend.engine:legend-engine-pure-platform-dsl-graph-java
-                                 org.finos.legend.pure:legend-pure-runtime-java-extension-dsl-graph
+                                 org.finos.legend.pure:legend-pure-runtime-java-extension-compiled-dsl-graph
                             
                             
                                 org.finos.legend.engine:legend-engine-pure-platform-dsl-graph-java
@@ -186,7 +186,7 @@
 
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-dsl-graph
+            legend-pure-runtime-java-extension-compiled-dsl-graph
 
         
         
@@ -210,7 +210,7 @@
         
         
             org.finos.legend.engine
-            legend-engine-pure-platform-dsl-mapping-java
+            legend-engine-pure-platform-dsl-store-java
         
         
             org.finos.legend.engine
diff --git a/legend-engine-xts-hostedService/legend-engine-xt-hostedService-pure/src/main/resources/core_hostedservice.definition.json b/legend-engine-xts-hostedService/legend-engine-xt-hostedService-pure/src/main/resources/core_hostedservice.definition.json
index 4b56cd2529d..b743e328aab 100644
--- a/legend-engine-xts-hostedService/legend-engine-xt-hostedService-pure/src/main/resources/core_hostedservice.definition.json
+++ b/legend-engine-xts-hostedService/legend-engine-xt-hostedService-pure/src/main/resources/core_hostedservice.definition.json
@@ -5,6 +5,7 @@
     "platform",
     "platform_dsl_graph",
     "platform_dsl_mapping",
+    "platform_dsl_store",
     "platform_store_relational",
     "platform_functions",
     "platform_functions_json",
diff --git a/legend-engine-xts-java/legend-engine-xt-javaPlatformBinding-pure/pom.xml b/legend-engine-xts-java/legend-engine-xt-javaPlatformBinding-pure/pom.xml
index 448235dbae8..56b4b598835 100644
--- a/legend-engine-xts-java/legend-engine-xt-javaPlatformBinding-pure/pom.xml
+++ b/legend-engine-xts-java/legend-engine-xt-javaPlatformBinding-pure/pom.xml
@@ -168,7 +168,7 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-dsl-graph
+            legend-pure-runtime-java-extension-compiled-dsl-graph
         
 
         
@@ -198,6 +198,10 @@
             org.finos.legend.engine
             legend-engine-pure-platform-dsl-mapping-java
         
+        
+            org.finos.legend.engine
+            legend-engine-pure-platform-dsl-store-java
+        
         
             org.finos.legend.engine
             legend-engine-xt-javaGeneration-pure
diff --git a/legend-engine-xts-java/legend-engine-xt-javaPlatformBinding-pure/src/main/resources/core_java_platform_binding.definition.json b/legend-engine-xts-java/legend-engine-xt-javaPlatformBinding-pure/src/main/resources/core_java_platform_binding.definition.json
index 23cb0392aa7..c55502c1c5f 100644
--- a/legend-engine-xts-java/legend-engine-xt-javaPlatformBinding-pure/src/main/resources/core_java_platform_binding.definition.json
+++ b/legend-engine-xts-java/legend-engine-xt-javaPlatformBinding-pure/src/main/resources/core_java_platform_binding.definition.json
@@ -4,6 +4,7 @@
     "dependencies": [
         "platform",
         "platform_functions",
+        "platform_dsl_store",
         "platform_dsl_mapping",
         "platform_dsl_graph",
         "core_functions",
diff --git a/legend-engine-xts-json/legend-engine-xt-json-javaPlatformBinding-pure/pom.xml b/legend-engine-xts-json/legend-engine-xt-json-javaPlatformBinding-pure/pom.xml
index 6450ba45811..477a128188a 100644
--- a/legend-engine-xts-json/legend-engine-xt-json-javaPlatformBinding-pure/pom.xml
+++ b/legend-engine-xts-json/legend-engine-xt-json-javaPlatformBinding-pure/pom.xml
@@ -188,7 +188,7 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-dsl-graph
+            legend-pure-runtime-java-extension-compiled-dsl-graph
         
         
 
diff --git a/legend-engine-xts-json/legend-engine-xt-json-model/pom.xml b/legend-engine-xts-json/legend-engine-xt-json-model/pom.xml
index e656144403d..cba0ae71275 100644
--- a/legend-engine-xts-json/legend-engine-xt-json-model/pom.xml
+++ b/legend-engine-xts-json/legend-engine-xt-json-model/pom.xml
@@ -58,7 +58,7 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-functions-json
+            legend-pure-runtime-java-extension-compiled-functions-json
             runtime
         
         
diff --git a/legend-engine-xts-json/legend-engine-xt-json-pure/pom.xml b/legend-engine-xts-json/legend-engine-xt-json-pure/pom.xml
index 6bb0454c4f9..e1a2297e9ac 100644
--- a/legend-engine-xts-json/legend-engine-xt-json-pure/pom.xml
+++ b/legend-engine-xts-json/legend-engine-xt-json-pure/pom.xml
@@ -183,7 +183,7 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-functions-json
+            legend-pure-runtime-java-extension-shared-functions-json
         
         
 
@@ -213,7 +213,7 @@
         
         
             org.finos.legend.engine
-            legend-engine-pure-platform-dsl-mapping-java
+            legend-engine-pure-platform-dsl-store-java
         
         
             org.finos.legend.engine
diff --git a/legend-engine-xts-json/legend-engine-xt-json-runtime/pom.xml b/legend-engine-xts-json/legend-engine-xt-json-runtime/pom.xml
index 082c85434e2..fa2c1145211 100644
--- a/legend-engine-xts-json/legend-engine-xt-json-runtime/pom.xml
+++ b/legend-engine-xts-json/legend-engine-xt-json-runtime/pom.xml
@@ -219,7 +219,7 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-store-relational
+            legend-pure-runtime-java-extension-compiled-store-relational
             test
         
         
diff --git a/legend-engine-xts-mastery/legend-engine-xt-mastery-grammar/pom.xml b/legend-engine-xts-mastery/legend-engine-xt-mastery-grammar/pom.xml
index 62e5f3d12dc..0c8b9f83d1c 100644
--- a/legend-engine-xts-mastery/legend-engine-xt-mastery-grammar/pom.xml
+++ b/legend-engine-xts-mastery/legend-engine-xt-mastery-grammar/pom.xml
@@ -210,7 +210,7 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-functions-json
+            legend-pure-runtime-java-extension-compiled-functions-json
             test
         
         
diff --git a/legend-engine-xts-mongodb/legend-engine-xt-nonrelationalStore-mongodb-executionPlan-test/pom.xml b/legend-engine-xts-mongodb/legend-engine-xt-nonrelationalStore-mongodb-executionPlan-test/pom.xml
index b26cf69566f..4d7a49b5bbb 100644
--- a/legend-engine-xts-mongodb/legend-engine-xt-nonrelationalStore-mongodb-executionPlan-test/pom.xml
+++ b/legend-engine-xts-mongodb/legend-engine-xt-nonrelationalStore-mongodb-executionPlan-test/pom.xml
@@ -46,7 +46,7 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-functions-json
+            legend-pure-runtime-java-extension-shared-functions-json
         
         
             org.finos.legend.engine
@@ -70,7 +70,7 @@
         
         
             org.finos.legend.engine
-            legend-engine-pure-platform-dsl-mapping-java
+            legend-engine-pure-platform-dsl-store-java
         
         
             org.finos.legend.engine
diff --git a/legend-engine-xts-mongodb/legend-engine-xt-nonrelationalStore-mongodb-executionPlan-test/src/main/resources/core_mongodb_execution_test.definition.json b/legend-engine-xts-mongodb/legend-engine-xt-nonrelationalStore-mongodb-executionPlan-test/src/main/resources/core_mongodb_execution_test.definition.json
index dade81f6b85..a8287c64bc0 100644
--- a/legend-engine-xts-mongodb/legend-engine-xt-nonrelationalStore-mongodb-executionPlan-test/src/main/resources/core_mongodb_execution_test.definition.json
+++ b/legend-engine-xts-mongodb/legend-engine-xt-nonrelationalStore-mongodb-executionPlan-test/src/main/resources/core_mongodb_execution_test.definition.json
@@ -6,6 +6,7 @@
     "platform_functions",
     "platform_functions_json",
     "platform_dsl_mapping",
+    "platform_dsl_store",
     "platform_dsl_graph",
     "core",
     "core_external_compiler",
diff --git a/legend-engine-xts-mongodb/legend-engine-xt-nonrelationalStore-mongodb-grammar-integration/pom.xml b/legend-engine-xts-mongodb/legend-engine-xt-nonrelationalStore-mongodb-grammar-integration/pom.xml
index ebbeb780f1d..878f6cdbe01 100644
--- a/legend-engine-xts-mongodb/legend-engine-xt-nonrelationalStore-mongodb-grammar-integration/pom.xml
+++ b/legend-engine-xts-mongodb/legend-engine-xt-nonrelationalStore-mongodb-grammar-integration/pom.xml
@@ -58,6 +58,10 @@
             org.finos.legend.engine
             legend-engine-pure-platform-dsl-mapping-java
         
+        
+            org.finos.legend.engine
+            legend-engine-pure-platform-dsl-store-java
+        
         
             org.finos.legend.engine
             legend-engine-protocol-pure
@@ -119,7 +123,7 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-dsl-mapping
+            legend-pure-runtime-java-extension-compiled-dsl-mapping
             test
         
         
diff --git a/legend-engine-xts-mongodb/legend-engine-xt-nonrelationalStore-mongodb-javaPlatformBinding-pure/pom.xml b/legend-engine-xts-mongodb/legend-engine-xt-nonrelationalStore-mongodb-javaPlatformBinding-pure/pom.xml
index 1ae82f363b4..8800ff833e8 100644
--- a/legend-engine-xts-mongodb/legend-engine-xt-nonrelationalStore-mongodb-javaPlatformBinding-pure/pom.xml
+++ b/legend-engine-xts-mongodb/legend-engine-xt-nonrelationalStore-mongodb-javaPlatformBinding-pure/pom.xml
@@ -237,7 +237,7 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-dsl-mapping
+            legend-pure-runtime-java-extension-compiled-dsl-mapping
             runtime
         
 
diff --git a/legend-engine-xts-mongodb/legend-engine-xt-nonrelationalStore-mongodb-protocol/pom.xml b/legend-engine-xts-mongodb/legend-engine-xt-nonrelationalStore-mongodb-protocol/pom.xml
index bcadc3d0e4b..09b94320ca2 100644
--- a/legend-engine-xts-mongodb/legend-engine-xt-nonrelationalStore-mongodb-protocol/pom.xml
+++ b/legend-engine-xts-mongodb/legend-engine-xt-nonrelationalStore-mongodb-protocol/pom.xml
@@ -61,7 +61,7 @@
                     
                     
                         org.finos.legend.pure
-                        legend-pure-runtime-java-extension-dsl-mapping
+                        legend-pure-runtime-java-extension-compiled-dsl-mapping
                         ${legend.pure.version}
                     
                     
diff --git a/legend-engine-xts-mongodb/legend-engine-xt-nonrelationalStore-mongodb-pure/pom.xml b/legend-engine-xts-mongodb/legend-engine-xt-nonrelationalStore-mongodb-pure/pom.xml
index 1ccf1fa7d50..6c3d5927d57 100644
--- a/legend-engine-xts-mongodb/legend-engine-xt-nonrelationalStore-mongodb-pure/pom.xml
+++ b/legend-engine-xts-mongodb/legend-engine-xt-nonrelationalStore-mongodb-pure/pom.xml
@@ -182,11 +182,11 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-dsl-store
+            legend-pure-runtime-java-extension-compiled-dsl-store
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-dsl-mapping
+            legend-pure-runtime-java-extension-compiled-dsl-mapping
         
         
 
@@ -207,6 +207,10 @@
             org.finos.legend.engine
             legend-engine-xt-authentication-pure
         
+        
+            org.finos.legend.engine
+            legend-engine-pure-platform-dsl-store-java
+        
         
             org.finos.legend.engine
             legend-engine-pure-platform-dsl-mapping-java
diff --git a/legend-engine-xts-openapi/legend-engine-xt-openapi-pure/pom.xml b/legend-engine-xts-openapi/legend-engine-xt-openapi-pure/pom.xml
index 95f1125b48b..efdb5488772 100644
--- a/legend-engine-xts-openapi/legend-engine-xt-openapi-pure/pom.xml
+++ b/legend-engine-xts-openapi/legend-engine-xt-openapi-pure/pom.xml
@@ -184,18 +184,18 @@
                     
                     
                         org.finos.legend.pure
-                        legend-pure-runtime-java-extension-dsl-mapping
+                        legend-pure-runtime-java-extension-compiled-dsl-mapping
                         ${legend.pure.version}
                     
                     
                         org.finos.legend.pure
-                        legend-pure-runtime-java-extension-dsl-diagram
+                        legend-pure-runtime-java-extension-compiled-dsl-diagram
                         ${legend.pure.version}
                     
 
                     
                         org.finos.legend.pure
-                        legend-pure-runtime-java-extension-functions-json
+                        legend-pure-runtime-java-extension-compiled-functions-json
                         ${legend.pure.version}
                     
                 
@@ -260,6 +260,10 @@
             org.finos.legend.engine
             legend-engine-pure-platform-dsl-mapping-java
         
+        
+            org.finos.legend.engine
+            legend-engine-pure-platform-dsl-store-java
+        
         
 
         
diff --git a/legend-engine-xts-persistence/legend-engine-xt-persistence-cloud-grammar/pom.xml b/legend-engine-xts-persistence/legend-engine-xt-persistence-cloud-grammar/pom.xml
index b1852c936c1..cfd55c49512 100644
--- a/legend-engine-xts-persistence/legend-engine-xt-persistence-cloud-grammar/pom.xml
+++ b/legend-engine-xts-persistence/legend-engine-xt-persistence-cloud-grammar/pom.xml
@@ -193,6 +193,11 @@
             legend-engine-xt-relationalStore-snowflake-grammar
             test
         
+        
+            com.h2database
+            h2
+            test
+        
         
     
 
diff --git a/legend-engine-xts-persistence/legend-engine-xt-persistence-cloud-pure/pom.xml b/legend-engine-xts-persistence/legend-engine-xt-persistence-cloud-pure/pom.xml
index 36ff2f95740..8f79d26dded 100644
--- a/legend-engine-xts-persistence/legend-engine-xt-persistence-cloud-pure/pom.xml
+++ b/legend-engine-xts-persistence/legend-engine-xt-persistence-cloud-pure/pom.xml
@@ -195,7 +195,7 @@
         
         
             org.finos.legend.engine
-            legend-engine-pure-platform-dsl-mapping-java
+            legend-engine-pure-platform-dsl-store-java
         
         
             org.finos.legend.engine
@@ -219,6 +219,11 @@
             junit
             junit
         
+        
+            com.h2database
+            h2
+            test
+        
         
     
 
diff --git a/legend-engine-xts-persistence/legend-engine-xt-persistence-cloud-pure/src/main/resources/core_persistence_cloud.definition.json b/legend-engine-xts-persistence/legend-engine-xt-persistence-cloud-pure/src/main/resources/core_persistence_cloud.definition.json
index 3de82969c78..b993e0f6761 100644
--- a/legend-engine-xts-persistence/legend-engine-xt-persistence-cloud-pure/src/main/resources/core_persistence_cloud.definition.json
+++ b/legend-engine-xts-persistence/legend-engine-xt-persistence-cloud-pure/src/main/resources/core_persistence_cloud.definition.json
@@ -4,7 +4,7 @@
   "dependencies": [
     "platform",
     "platform_functions",
-    "platform_dsl_mapping",
+    "platform_dsl_store",
     "platform_dsl_graph",
     "platform_store_relational",
     "core",
diff --git a/legend-engine-xts-persistence/legend-engine-xt-persistence-grammar/pom.xml b/legend-engine-xts-persistence/legend-engine-xt-persistence-grammar/pom.xml
index 09930b3eaec..592d5c204e4 100644
--- a/legend-engine-xts-persistence/legend-engine-xt-persistence-grammar/pom.xml
+++ b/legend-engine-xts-persistence/legend-engine-xt-persistence-grammar/pom.xml
@@ -40,7 +40,7 @@
                                 org.finos.legend.engine:legend-engine-pure-platform-java
                                 org.finos.legend.engine:legend-engine-pure-platform-dsl-path-java
                                 org.finos.legend.pure:legend-pure-runtime-java-engine-compiled
-                                org.finos.legend.pure:legend-pure-runtime-java-extension-dsl-path
+                                org.finos.legend.pure:legend-pure-runtime-java-extension-compiled-dsl-path
                             
                         
                     
@@ -102,7 +102,7 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-dsl-path
+            legend-pure-runtime-java-extension-compiled-dsl-path
         
         
             org.finos.legend.engine
@@ -153,7 +153,7 @@
         
          
             org.finos.legend.engine
-            legend-engine-pure-platform-dsl-mapping-java
+            legend-engine-pure-platform-dsl-store-java
         
         
             org.finos.legend.engine
@@ -256,6 +256,11 @@
             legend-engine-xt-relationalStore-snowflake-grammar
             test
         
+        
+            com.h2database
+            h2
+            test
+        
         
     
 
diff --git a/legend-engine-xts-persistence/legend-engine-xt-persistence-pure/pom.xml b/legend-engine-xts-persistence/legend-engine-xt-persistence-pure/pom.xml
index cbdd86a1fac..41907261b40 100644
--- a/legend-engine-xts-persistence/legend-engine-xt-persistence-pure/pom.xml
+++ b/legend-engine-xts-persistence/legend-engine-xt-persistence-pure/pom.xml
@@ -231,6 +231,10 @@
             org.finos.legend.engine
             legend-engine-pure-platform-dsl-mapping-java
         
+        
+            org.finos.legend.engine
+            legend-engine-pure-platform-dsl-store-java
+        
         
             org.finos.legend.engine
             legend-engine-xt-relationalStore-pure
@@ -253,7 +257,11 @@
             junit
             junit
         
-
+        
+            com.h2database
+            h2
+            test
+        
         
     
 
diff --git a/legend-engine-xts-persistence/legend-engine-xt-persistence-pure/src/main/resources/core_persistence.definition.json b/legend-engine-xts-persistence/legend-engine-xt-persistence-pure/src/main/resources/core_persistence.definition.json
index d1f08cc5825..1cd5a0626b2 100644
--- a/legend-engine-xts-persistence/legend-engine-xt-persistence-pure/src/main/resources/core_persistence.definition.json
+++ b/legend-engine-xts-persistence/legend-engine-xt-persistence-pure/src/main/resources/core_persistence.definition.json
@@ -5,6 +5,7 @@
     "platform",
     "platform_functions",
     "platform_dsl_mapping",
+    "platform_dsl_store",
     "platform_dsl_graph",
     "platform_dsl_path",
     "platform_store_relational",
diff --git a/legend-engine-xts-persistence/legend-engine-xt-persistence-target-relational-grammar/pom.xml b/legend-engine-xts-persistence/legend-engine-xt-persistence-target-relational-grammar/pom.xml
index 98cdcfee91f..c6b0ad26d50 100644
--- a/legend-engine-xts-persistence/legend-engine-xt-persistence-target-relational-grammar/pom.xml
+++ b/legend-engine-xts-persistence/legend-engine-xt-persistence-target-relational-grammar/pom.xml
@@ -79,7 +79,7 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-dsl-path
+            legend-pure-runtime-java-extension-compiled-dsl-path
         
         
             org.finos.legend.engine
diff --git a/legend-engine-xts-protobuf/legend-engine-xt-protobuf-protocol/pom.xml b/legend-engine-xts-protobuf/legend-engine-xt-protobuf-protocol/pom.xml
index 5e2200b52db..da273ce2077 100644
--- a/legend-engine-xts-protobuf/legend-engine-xt-protobuf-protocol/pom.xml
+++ b/legend-engine-xts-protobuf/legend-engine-xt-protobuf-protocol/pom.xml
@@ -64,7 +64,7 @@
                     
                     
                         org.finos.legend.pure
-                        legend-pure-runtime-java-extension-store-relational
+                        legend-pure-runtime-java-extension-compiled-store-relational
                         ${legend.pure.version}
                     
                     
diff --git a/legend-engine-xts-protobuf/legend-engine-xt-protobuf-pure/pom.xml b/legend-engine-xts-protobuf/legend-engine-xt-protobuf-pure/pom.xml
index 4b9f6e13266..1b67b62a2d4 100644
--- a/legend-engine-xts-protobuf/legend-engine-xt-protobuf-pure/pom.xml
+++ b/legend-engine-xts-protobuf/legend-engine-xt-protobuf-pure/pom.xml
@@ -175,7 +175,7 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-functions-json
+            legend-pure-runtime-java-extension-shared-functions-json
         
 
         
diff --git a/legend-engine-xts-protobuf/legend-engine-xt-protobuf/pom.xml b/legend-engine-xts-protobuf/legend-engine-xt-protobuf/pom.xml
index 35ca1eaa600..86ee431241f 100644
--- a/legend-engine-xts-protobuf/legend-engine-xt-protobuf/pom.xml
+++ b/legend-engine-xts-protobuf/legend-engine-xt-protobuf/pom.xml
@@ -61,7 +61,7 @@
                     
                     
                         org.finos.legend.pure
-                        legend-pure-runtime-java-extension-store-relational
+                        legend-pure-runtime-java-extension-compiled-store-relational
                         ${legend.pure.version}
                     
                     
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-analytics/legend-engine-xt-relationalStore-store-entitlement-analytics/pom.xml b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-analytics/legend-engine-xt-relationalStore-store-entitlement-analytics/pom.xml
index 17bc2126684..08330613de4 100644
--- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-analytics/legend-engine-xt-relationalStore-store-entitlement-analytics/pom.xml
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-analytics/legend-engine-xt-relationalStore-store-entitlement-analytics/pom.xml
@@ -59,7 +59,7 @@
         
         
             org.finos.legend.engine
-            legend-engine-pure-platform-dsl-mapping-java
+            legend-engine-pure-platform-dsl-store-java
         
         
             org.finos.legend.engine
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-analytics/legend-engine-xt-relationalStore-store-entitlement-pure/pom.xml b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-analytics/legend-engine-xt-relationalStore-store-entitlement-pure/pom.xml
index 853b28b666b..e4d8db30598 100644
--- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-analytics/legend-engine-xt-relationalStore-store-entitlement-pure/pom.xml
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-analytics/legend-engine-xt-relationalStore-store-entitlement-pure/pom.xml
@@ -187,7 +187,7 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-store-relational
+            legend-pure-runtime-java-extension-compiled-store-relational
         
         
             org.finos.legend.pure
@@ -218,6 +218,10 @@
             org.finos.legend.engine
             legend-engine-pure-platform-functions-java
         
+        
+            org.finos.legend.engine
+            legend-engine-pure-platform-dsl-store-java
+        
         
             org.finos.legend.engine
             legend-engine-pure-platform-dsl-mapping-java
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-athena/legend-engine-xt-relationalStore-athena-grammar/pom.xml b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-athena/legend-engine-xt-relationalStore-athena-grammar/pom.xml
index 3c22d06b8b4..8b910da2fbc 100644
--- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-athena/legend-engine-xt-relationalStore-athena-grammar/pom.xml
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-athena/legend-engine-xt-relationalStore-athena-grammar/pom.xml
@@ -159,7 +159,7 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-functions-json
+            legend-pure-runtime-java-extension-compiled-functions-json
             test
         
         
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-bigquery/legend-engine-xt-relationalStore-bigquery-grammar/pom.xml b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-bigquery/legend-engine-xt-relationalStore-bigquery-grammar/pom.xml
index 4092875c0a0..83293ad8a2c 100644
--- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-bigquery/legend-engine-xt-relationalStore-bigquery-grammar/pom.xml
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-bigquery/legend-engine-xt-relationalStore-bigquery-grammar/pom.xml
@@ -159,7 +159,7 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-functions-json
+            legend-pure-runtime-java-extension-compiled-functions-json
             test
         
         
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-bigquery/legend-engine-xt-relationalStore-bigquery-pure/pom.xml b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-bigquery/legend-engine-xt-relationalStore-bigquery-pure/pom.xml
index b017c9821d8..563970aa786 100644
--- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-bigquery/legend-engine-xt-relationalStore-bigquery-pure/pom.xml
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-bigquery/legend-engine-xt-relationalStore-bigquery-pure/pom.xml
@@ -202,7 +202,7 @@
         
         
             org.finos.legend.engine
-            legend-engine-pure-platform-dsl-mapping-java
+            legend-engine-pure-platform-dsl-store-java
         
 
         
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-bigquery/legend-engine-xt-relationalStore-bigquery-pure/src/main/resources/core_relational_bigquery.definition.json b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-bigquery/legend-engine-xt-relationalStore-bigquery-pure/src/main/resources/core_relational_bigquery.definition.json
index 5b06468c642..df9dfacb9ba 100644
--- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-bigquery/legend-engine-xt-relationalStore-bigquery-pure/src/main/resources/core_relational_bigquery.definition.json
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-bigquery/legend-engine-xt-relationalStore-bigquery-pure/src/main/resources/core_relational_bigquery.definition.json
@@ -4,7 +4,7 @@
   "dependencies": [
     "platform",
     "platform_functions",
-    "platform_dsl_mapping",
+    "platform_dsl_store",
     "platform_store_relational",
     "core_functions",
     "core",
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-databricks/legend-engine-xt-relationalStore-databricks-grammar/pom.xml b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-databricks/legend-engine-xt-relationalStore-databricks-grammar/pom.xml
index 9b42d883ec6..20510348397 100644
--- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-databricks/legend-engine-xt-relationalStore-databricks-grammar/pom.xml
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-databricks/legend-engine-xt-relationalStore-databricks-grammar/pom.xml
@@ -157,7 +157,7 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-functions-json
+            legend-pure-runtime-java-extension-compiled-functions-json
             test
         
         
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-databricks/legend-engine-xt-relationalStore-databricks-pure/pom.xml b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-databricks/legend-engine-xt-relationalStore-databricks-pure/pom.xml
index fb557a899c8..a51d5715bb1 100644
--- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-databricks/legend-engine-xt-relationalStore-databricks-pure/pom.xml
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-databricks/legend-engine-xt-relationalStore-databricks-pure/pom.xml
@@ -187,7 +187,7 @@
         
         
             org.finos.legend.engine
-            legend-engine-pure-platform-dsl-mapping-java
+            legend-engine-pure-platform-dsl-store-java
         
         
             org.finos.legend.engine
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-databricks/legend-engine-xt-relationalStore-databricks-pure/src/main/resources/core_relational_databricks.definition.json b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-databricks/legend-engine-xt-relationalStore-databricks-pure/src/main/resources/core_relational_databricks.definition.json
index 9f1b5e9e0ba..10540393865 100644
--- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-databricks/legend-engine-xt-relationalStore-databricks-pure/src/main/resources/core_relational_databricks.definition.json
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-databricks/legend-engine-xt-relationalStore-databricks-pure/src/main/resources/core_relational_databricks.definition.json
@@ -1,5 +1,13 @@
 {
-  "name" : "core_relational_databricks",
-  "pattern" : "(meta::relational::functions::sqlQueryToString::databricks|meta::relational::tests::sqlQueryToString::databricks|meta::relational::tests::connEquality|meta::relational::databricks::tests|meta::relational::tests::functions::sqlstring::databricks|meta::pure::alloy::connections|meta::protocols::pure)(::.*)?",
-  "dependencies" : ["platform", "platform_functions", "platform_store_relational", "platform_dsl_mapping", "core_functions", "core", "core_relational"]
+  "name": "core_relational_databricks",
+  "pattern": "(meta::relational::functions::sqlQueryToString::databricks|meta::relational::tests::sqlQueryToString::databricks|meta::relational::tests::connEquality|meta::relational::databricks::tests|meta::relational::tests::functions::sqlstring::databricks|meta::pure::alloy::connections|meta::protocols::pure)(::.*)?",
+  "dependencies": [
+    "platform",
+    "platform_functions",
+    "platform_store_relational",
+    "platform_dsl_store",
+    "core_functions",
+    "core",
+    "core_relational"
+  ]
 }
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-dbExtension-archetype/src/main/resources/archetype-resources/legend-engine-xt-relationalStore-__dbtype__-grammar/pom.xml b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-dbExtension-archetype/src/main/resources/archetype-resources/legend-engine-xt-relationalStore-__dbtype__-grammar/pom.xml
index 2abb90169bd..20441d246e3 100644
--- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-dbExtension-archetype/src/main/resources/archetype-resources/legend-engine-xt-relationalStore-__dbtype__-grammar/pom.xml
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-dbExtension-archetype/src/main/resources/archetype-resources/legend-engine-xt-relationalStore-__dbtype__-grammar/pom.xml
@@ -151,7 +151,7 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-functions-json
+            legend-pure-runtime-java-extension-compiled-functions-json
             test
         
         
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-hive/legend-engine-xt-relationalStore-hive-pure/pom.xml b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-hive/legend-engine-xt-relationalStore-hive-pure/pom.xml
index fd967e07e75..006aeb1cb32 100644
--- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-hive/legend-engine-xt-relationalStore-hive-pure/pom.xml
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-hive/legend-engine-xt-relationalStore-hive-pure/pom.xml
@@ -220,6 +220,11 @@
             jackson-core
             test
         
+        
+            com.h2database
+            h2
+            test
+        
         
             junit
             junit
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-memsql/legend-engine-xt-relationalStore-memsql-pure/pom.xml b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-memsql/legend-engine-xt-relationalStore-memsql-pure/pom.xml
index e9e89d0f5a1..0647a635b2a 100644
--- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-memsql/legend-engine-xt-relationalStore-memsql-pure/pom.xml
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-memsql/legend-engine-xt-relationalStore-memsql-pure/pom.xml
@@ -191,7 +191,7 @@
         
         
             org.finos.legend.engine
-            legend-engine-pure-platform-dsl-mapping-java
+            legend-engine-pure-platform-dsl-store-java
         
         
             org.finos.legend.engine
@@ -244,6 +244,11 @@
             junit
             junit
         
+        
+            com.h2database
+            h2
+            test
+        
         
     
 
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-postgres/legend-engine-xt-relationalStore-postgres-pure/pom.xml b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-postgres/legend-engine-xt-relationalStore-postgres-pure/pom.xml
index 8d0539d7802..25ab76e96cf 100644
--- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-postgres/legend-engine-xt-relationalStore-postgres-pure/pom.xml
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-postgres/legend-engine-xt-relationalStore-postgres-pure/pom.xml
@@ -232,6 +232,11 @@
             jackson-core
             test
         
+        
+            com.h2database
+            h2
+            test
+        
         
             junit
             junit
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-presto/legend-engine-xt-relationalStore-presto-pure/pom.xml b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-presto/legend-engine-xt-relationalStore-presto-pure/pom.xml
index 082be592e7f..5325fb2965f 100644
--- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-presto/legend-engine-xt-relationalStore-presto-pure/pom.xml
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-presto/legend-engine-xt-relationalStore-presto-pure/pom.xml
@@ -193,6 +193,10 @@
             org.finos.legend.engine
             legend-engine-pure-platform-dsl-mapping-java
         
+        
+            org.finos.legend.engine
+            legend-engine-pure-platform-dsl-store-java
+        
         
             org.finos.legend.engine
             legend-engine-pure-platform-java
@@ -240,6 +244,11 @@
             jackson-core
             test
         
+        
+            com.h2database
+            h2
+            test
+        
         
             junit
             junit
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-redshift/legend-engine-xt-relationalStore-redshift-grammar/pom.xml b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-redshift/legend-engine-xt-relationalStore-redshift-grammar/pom.xml
index c4196289bce..8667973d350 100644
--- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-redshift/legend-engine-xt-relationalStore-redshift-grammar/pom.xml
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-redshift/legend-engine-xt-relationalStore-redshift-grammar/pom.xml
@@ -157,7 +157,7 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-functions-json
+            legend-pure-runtime-java-extension-compiled-functions-json
             test
         
         
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-redshift/legend-engine-xt-relationalStore-redshift-pure/pom.xml b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-redshift/legend-engine-xt-relationalStore-redshift-pure/pom.xml
index ff2fe87921b..7668ec0767d 100644
--- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-redshift/legend-engine-xt-relationalStore-redshift-pure/pom.xml
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-redshift/legend-engine-xt-relationalStore-redshift-pure/pom.xml
@@ -187,7 +187,7 @@
         
         
             org.finos.legend.engine
-            legend-engine-pure-platform-dsl-mapping-java
+            legend-engine-pure-platform-dsl-store-java
         
         
             org.finos.legend.engine
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-redshift/legend-engine-xt-relationalStore-redshift-pure/src/main/resources/core_relational_redshift.definition.json b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-redshift/legend-engine-xt-relationalStore-redshift-pure/src/main/resources/core_relational_redshift.definition.json
index 096e8f2231f..5ae3e0350e6 100644
--- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-redshift/legend-engine-xt-relationalStore-redshift-pure/src/main/resources/core_relational_redshift.definition.json
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-redshift/legend-engine-xt-relationalStore-redshift-pure/src/main/resources/core_relational_redshift.definition.json
@@ -1,5 +1,13 @@
 {
-  "name" : "core_relational_redshift",
-  "pattern" : "(meta::relational::functions::sqlQueryToString::redshift|meta::relational::tests::sqlQueryToString::redshift|meta::relational::functions::sqlQueryToString::tests::redshift|meta::pure::executionPlan::tests::redshift|meta::pure::legend::connections::legend::specification|meta::pure::alloy::connections|meta::protocols::pure)(::.*)?",
-  "dependencies" : ["platform", "platform_functions", "platform_store_relational", "platform_dsl_mapping", "core_functions", "core", "core_relational"]
+  "name": "core_relational_redshift",
+  "pattern": "(meta::relational::functions::sqlQueryToString::redshift|meta::relational::tests::sqlQueryToString::redshift|meta::relational::functions::sqlQueryToString::tests::redshift|meta::pure::executionPlan::tests::redshift|meta::pure::legend::connections::legend::specification|meta::pure::alloy::connections|meta::protocols::pure)(::.*)?",
+  "dependencies": [
+    "platform",
+    "platform_functions",
+    "platform_store_relational",
+    "platform_dsl_store",
+    "core_functions",
+    "core",
+    "core_relational"
+  ]
 }
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-snowflake/legend-engine-xt-relationalStore-snowflake-grammar/pom.xml b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-snowflake/legend-engine-xt-relationalStore-snowflake-grammar/pom.xml
index c78840902c0..9aef7b85a39 100644
--- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-snowflake/legend-engine-xt-relationalStore-snowflake-grammar/pom.xml
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-snowflake/legend-engine-xt-relationalStore-snowflake-grammar/pom.xml
@@ -192,7 +192,7 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-functions-json
+            legend-pure-runtime-java-extension-compiled-functions-json
             test
         
         
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-snowflake/legend-engine-xt-relationalStore-snowflake-pure/pom.xml b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-snowflake/legend-engine-xt-relationalStore-snowflake-pure/pom.xml
index e5bd0567f02..fa9e07a1c92 100644
--- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-snowflake/legend-engine-xt-relationalStore-snowflake-pure/pom.xml
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-snowflake/legend-engine-xt-relationalStore-snowflake-pure/pom.xml
@@ -178,7 +178,7 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-store-relational
+            legend-pure-runtime-java-extension-compiled-store-relational
         
         
             org.finos.legend.pure
@@ -197,6 +197,10 @@
             org.finos.legend.engine
             legend-engine-pure-platform-dsl-mapping-java
         
+        
+            org.finos.legend.engine
+            legend-engine-pure-platform-dsl-store-java
+        
         
             org.finos.legend.engine
             legend-engine-pure-platform-java
@@ -244,6 +248,11 @@
             jackson-core
             test
         
+        
+            com.h2database
+            h2
+            test
+        
         
             junit
             junit
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-spanner/legend-engine-xt-relationalStore-spanner-grammar/pom.xml b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-spanner/legend-engine-xt-relationalStore-spanner-grammar/pom.xml
index 601793b10a7..0e6ed5e04ac 100644
--- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-spanner/legend-engine-xt-relationalStore-spanner-grammar/pom.xml
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-spanner/legend-engine-xt-relationalStore-spanner-grammar/pom.xml
@@ -143,7 +143,7 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-functions-json
+            legend-pure-runtime-java-extension-compiled-functions-json
             test
         
         
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sybase/legend-engine-xt-relationalStore-sybase-pure/pom.xml b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sybase/legend-engine-xt-relationalStore-sybase-pure/pom.xml
index b1bbc8f4c3e..0e1a33a88dd 100644
--- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sybase/legend-engine-xt-relationalStore-sybase-pure/pom.xml
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sybase/legend-engine-xt-relationalStore-sybase-pure/pom.xml
@@ -182,7 +182,7 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-store-relational
+            legend-pure-runtime-java-extension-compiled-store-relational
         
 
         
@@ -197,6 +197,10 @@
             org.finos.legend.engine
             legend-engine-pure-platform-dsl-mapping-java
         
+        
+            org.finos.legend.engine
+            legend-engine-pure-platform-dsl-store-java
+        
         
             org.finos.legend.engine
             legend-engine-pure-platform-java
@@ -244,6 +248,11 @@
             jackson-core
             test
         
+        
+            com.h2database
+            h2
+            test
+        
         
             junit
             junit
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sybaseiq/legend-engine-xt-relationalStore-sybaseiq-pure/pom.xml b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sybaseiq/legend-engine-xt-relationalStore-sybaseiq-pure/pom.xml
index d8515cd7499..20b01a8d612 100644
--- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sybaseiq/legend-engine-xt-relationalStore-sybaseiq-pure/pom.xml
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sybaseiq/legend-engine-xt-relationalStore-sybaseiq-pure/pom.xml
@@ -193,6 +193,10 @@
             org.finos.legend.engine
             legend-engine-pure-platform-dsl-mapping-java
         
+        
+            org.finos.legend.engine
+            legend-engine-pure-platform-dsl-store-java
+        
         
             org.finos.legend.engine
             legend-engine-pure-platform-java
@@ -240,6 +244,11 @@
             jackson-core
             test
         
+        
+            com.h2database
+            h2
+            test
+        
         
             junit
             junit
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sybaseiq/legend-engine-xt-relationalStore-sybaseiq-pure/src/main/resources/core_relational_sybaseiq.definition.json b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sybaseiq/legend-engine-xt-relationalStore-sybaseiq-pure/src/main/resources/core_relational_sybaseiq.definition.json
index a02c92891cb..84b154d68b9 100644
--- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sybaseiq/legend-engine-xt-relationalStore-sybaseiq-pure/src/main/resources/core_relational_sybaseiq.definition.json
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-sybaseiq/legend-engine-xt-relationalStore-sybaseiq-pure/src/main/resources/core_relational_sybaseiq.definition.json
@@ -1,5 +1,13 @@
 {
-  "name" : "core_relational_sybaseiq",
-  "pattern" : "(meta::relational::functions::sqlQueryToString::sybaseIQ|meta::relational::tests::sqlQueryToString::sybaseIQ|meta::relational::tests::sqlToString::sybaseIQ|meta::pure::executionPlan::tests::sybaseIQ|meta::relational::tests::mapping::sqlFunction::sybaseIQ|meta::relational::tests::postProcessor::sybaseIQ|meta::relational::tests::query::function::sybaseIQ|meta::relational::tests::functions::sqlstring::sybaseIQ|meta::relational::tests::tds::sybaseIQ|meta::relational::tests::projection::sybaseIQ|meta::pure::alloy::connections|meta::protocols::pure)(::.*)?",
-  "dependencies" : ["platform", "platform_functions", "platform_store_relational", "platform_dsl_mapping", "core_functions", "core", "core_relational"]
+  "name": "core_relational_sybaseiq",
+  "pattern": "(meta::relational::functions::sqlQueryToString::sybaseIQ|meta::relational::tests::sqlQueryToString::sybaseIQ|meta::relational::tests::sqlToString::sybaseIQ|meta::pure::executionPlan::tests::sybaseIQ|meta::relational::tests::mapping::sqlFunction::sybaseIQ|meta::relational::tests::postProcessor::sybaseIQ|meta::relational::tests::query::function::sybaseIQ|meta::relational::tests::functions::sqlstring::sybaseIQ|meta::relational::tests::tds::sybaseIQ|meta::relational::tests::projection::sybaseIQ|meta::pure::alloy::connections|meta::protocols::pure)(::.*)?",
+  "dependencies": [
+    "platform",
+    "platform_functions",
+    "platform_store_relational",
+    "platform_dsl_store",
+    "core_functions",
+    "core",
+    "core_relational"
+  ]
 }
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-trino/legend-engine-xt-relationalStore-trino-grammar/pom.xml b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-trino/legend-engine-xt-relationalStore-trino-grammar/pom.xml
index c3393072f12..396dac8b102 100644
--- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-trino/legend-engine-xt-relationalStore-trino-grammar/pom.xml
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-dbExtension/legend-engine-xt-relationalStore-trino/legend-engine-xt-relationalStore-trino-grammar/pom.xml
@@ -157,7 +157,7 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-functions-json
+            legend-pure-runtime-java-extension-compiled-functions-json
             test
         
         
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-execution/legend-engine-xt-relationalStore-executionPlan-authorizer/pom.xml b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-execution/legend-engine-xt-relationalStore-executionPlan-authorizer/pom.xml
index cb4548132f0..cef28ed5f44 100644
--- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-execution/legend-engine-xt-relationalStore-executionPlan-authorizer/pom.xml
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-execution/legend-engine-xt-relationalStore-executionPlan-authorizer/pom.xml
@@ -115,7 +115,7 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-functions-json
+            legend-pure-runtime-java-extension-compiled-functions-json
             ${legend.pure.version}
             test
         
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-execution/legend-engine-xt-relationalStore-executionPlan/pom.xml b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-execution/legend-engine-xt-relationalStore-executionPlan/pom.xml
index 1816d8476c4..c7bc3b6a6e3 100644
--- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-execution/legend-engine-xt-relationalStore-executionPlan/pom.xml
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-execution/legend-engine-xt-relationalStore-executionPlan/pom.xml
@@ -293,7 +293,7 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-functions-json
+            legend-pure-runtime-java-extension-compiled-functions-json
             test
         
         
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-grammar/pom.xml b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-grammar/pom.xml
index 8b133ba1916..0e49046284f 100644
--- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-grammar/pom.xml
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-grammar/pom.xml
@@ -115,16 +115,16 @@
 
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-store-relational
+            legend-pure-runtime-java-extension-compiled-store-relational
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-dsl-store
+            legend-pure-runtime-java-extension-compiled-dsl-store
         
 
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-dsl-mapping
+            legend-pure-runtime-java-extension-compiled-dsl-mapping
         
 
         
@@ -143,6 +143,10 @@
             org.finos.legend.engine
             legend-engine-pure-platform-dsl-mapping-java
         
+        
+            org.finos.legend.engine
+            legend-engine-pure-platform-dsl-store-java
+        
         
             org.finos.legend.engine
             legend-engine-xt-relationalStore-pure
@@ -268,7 +272,7 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-functions-json
+            legend-pure-runtime-java-extension-compiled-functions-json
             test
         
         
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-javaPlatformBinding-pure/pom.xml b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-javaPlatformBinding-pure/pom.xml
index b1c8e0c315e..dc904cb1299 100644
--- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-javaPlatformBinding-pure/pom.xml
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-javaPlatformBinding-pure/pom.xml
@@ -240,6 +240,10 @@
             org.finos.legend.engine
             legend-engine-pure-platform-dsl-mapping-java
         
+        
+            org.finos.legend.engine
+            legend-engine-pure-platform-dsl-store-java
+        
         
             org.finos.legend.engine
             legend-engine-xt-relationalStore-pure
@@ -277,6 +281,11 @@
             legend-engine-language-pure-compiler
             test
         
+        
+            com.h2database
+            h2
+            test
+        
 
         
     
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/pom.xml b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/pom.xml
index e2a83dd0af3..a4d6ab96d0a 100644
--- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/pom.xml
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-generation/legend-engine-xt-relationalStore-pure/pom.xml
@@ -39,7 +39,7 @@
                             
                             
                                 org.finos.legend.engine:legend-engine-pure-platform-dsl-store-java
-                                org.finos.legend.pure:legend-pure-runtime-java-extension-dsl-store
+                                org.finos.legend.pure:legend-pure-runtime-java-extension-compiled-dsl-store
                             
                         
                     
@@ -195,13 +195,13 @@
 
                     
                         org.finos.legend.pure
-                        legend-pure-runtime-java-extension-store-relational
+                        legend-pure-runtime-java-extension-compiled-store-relational
                         ${legend.pure.version}
                     
 
                     
                         org.finos.legend.pure
-                        legend-pure-runtime-java-extension-functions-relation
+                        legend-pure-runtime-java-extension-compiled-functions-relation
                         ${legend.pure.version}
                     
 
@@ -323,15 +323,15 @@
 
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-store-relational
+            legend-pure-runtime-java-extension-compiled-store-relational
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-functions-json
+            legend-pure-runtime-java-extension-shared-functions-json
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-functions-relation
+            legend-pure-runtime-java-extension-compiled-functions-relation
         
         
             org.finos.legend.engine
@@ -339,30 +339,30 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-dsl-store
+            legend-pure-runtime-java-extension-compiled-dsl-store
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-dsl-mapping
+            legend-pure-runtime-java-extension-compiled-dsl-mapping
             runtime
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-dsl-diagram
+            legend-pure-runtime-java-extension-compiled-dsl-diagram
             runtime
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-dsl-path
+            legend-pure-runtime-java-extension-compiled-dsl-path
             runtime
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-dsl-tds
+            legend-pure-runtime-java-extension-compiled-dsl-tds
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-dsl-graph
+            legend-pure-runtime-java-extension-compiled-dsl-graph
             runtime
         
 
@@ -381,6 +381,11 @@
             junit
             junit
         
+        
+            com.h2database
+            h2
+            test
+        
         
             org.finos.legend.pure
             legend-pure-m2-functions-json-pure
diff --git a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-test/legend-engine-xt-relationalStore-test-mutation/pom.xml b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-test/legend-engine-xt-relationalStore-test-mutation/pom.xml
index 7a091cd975e..fe40868f9fd 100644
--- a/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-test/legend-engine-xt-relationalStore-test-mutation/pom.xml
+++ b/legend-engine-xts-relationalStore/legend-engine-xt-relationalStore-test/legend-engine-xt-relationalStore-test-mutation/pom.xml
@@ -275,6 +275,11 @@
             jackson-core
             test
         
+        
+            com.h2database
+            h2
+            test
+        
         
     
 
diff --git a/legend-engine-xts-service/legend-engine-language-pure-dsl-service-generation/pom.xml b/legend-engine-xts-service/legend-engine-language-pure-dsl-service-generation/pom.xml
index cee43df718c..1f1528b4f9e 100644
--- a/legend-engine-xts-service/legend-engine-language-pure-dsl-service-generation/pom.xml
+++ b/legend-engine-xts-service/legend-engine-language-pure-dsl-service-generation/pom.xml
@@ -71,7 +71,7 @@
         
         
             org.finos.legend.engine
-            legend-engine-pure-platform-dsl-mapping-java
+            legend-engine-pure-platform-dsl-store-java
         
 
         
@@ -164,6 +164,11 @@
             legend-engine-configuration
             test
         
+        
+            com.h2database
+            h2
+            test
+        
         
     
 
\ No newline at end of file
diff --git a/legend-engine-xts-service/legend-engine-language-pure-dsl-service-pure/pom.xml b/legend-engine-xts-service/legend-engine-language-pure-dsl-service-pure/pom.xml
index 90847757e61..f036cd231f1 100644
--- a/legend-engine-xts-service/legend-engine-language-pure-dsl-service-pure/pom.xml
+++ b/legend-engine-xts-service/legend-engine-language-pure-dsl-service-pure/pom.xml
@@ -173,7 +173,7 @@
         
         
             org.finos.legend.engine
-            legend-engine-pure-platform-dsl-mapping-java
+            legend-engine-pure-platform-dsl-store-java
         
         
             org.finos.legend.engine
diff --git a/legend-engine-xts-service/legend-engine-language-pure-dsl-service-pure/src/main/resources/core_service.definition.json b/legend-engine-xts-service/legend-engine-language-pure-dsl-service-pure/src/main/resources/core_service.definition.json
index 708d7b011ee..cef481b5090 100644
--- a/legend-engine-xts-service/legend-engine-language-pure-dsl-service-pure/src/main/resources/core_service.definition.json
+++ b/legend-engine-xts-service/legend-engine-language-pure-dsl-service-pure/src/main/resources/core_service.definition.json
@@ -6,6 +6,7 @@
     "platform_functions",
     "platform_dsl_diagram",
     "platform_dsl_mapping",
+    "platform_dsl_store",
     "core_functions",
     "core",
     "core_data_space_metamodel"
diff --git a/legend-engine-xts-service/legend-engine-language-pure-dsl-service/pom.xml b/legend-engine-xts-service/legend-engine-language-pure-dsl-service/pom.xml
index b469fb07a03..3134bc458da 100644
--- a/legend-engine-xts-service/legend-engine-language-pure-dsl-service/pom.xml
+++ b/legend-engine-xts-service/legend-engine-language-pure-dsl-service/pom.xml
@@ -99,7 +99,7 @@
         
         
             org.finos.legend.engine
-            legend-engine-pure-platform-dsl-mapping-java
+            legend-engine-pure-platform-dsl-store-java
         
         
 
diff --git a/legend-engine-xts-service/legend-engine-service-post-validation-runner/pom.xml b/legend-engine-xts-service/legend-engine-service-post-validation-runner/pom.xml
index 47d70743381..bae7e6deac3 100644
--- a/legend-engine-xts-service/legend-engine-service-post-validation-runner/pom.xml
+++ b/legend-engine-xts-service/legend-engine-service-post-validation-runner/pom.xml
@@ -43,7 +43,7 @@
         
         
             org.finos.legend.engine
-            legend-engine-pure-platform-dsl-mapping-java
+            legend-engine-pure-platform-dsl-store-java
         
         
             org.finos.legend.engine
diff --git a/legend-engine-xts-service/legend-engine-test-runner-service/pom.xml b/legend-engine-xts-service/legend-engine-test-runner-service/pom.xml
index 8703e96b7b2..aba624dd77d 100644
--- a/legend-engine-xts-service/legend-engine-test-runner-service/pom.xml
+++ b/legend-engine-xts-service/legend-engine-test-runner-service/pom.xml
@@ -63,6 +63,10 @@
             org.finos.legend.engine
             legend-engine-pure-platform-dsl-mapping-java
         
+        
+            org.finos.legend.engine
+            legend-engine-pure-platform-dsl-store-java
+        
         
             org.finos.legend.engine
             legend-engine-xt-relationalStore-pure
diff --git a/legend-engine-xts-serviceStore/legend-engine-xt-serviceStore-grammar/pom.xml b/legend-engine-xts-serviceStore/legend-engine-xt-serviceStore-grammar/pom.xml
index e0a65e41955..5dea361e8e5 100644
--- a/legend-engine-xts-serviceStore/legend-engine-xt-serviceStore-grammar/pom.xml
+++ b/legend-engine-xts-serviceStore/legend-engine-xt-serviceStore-grammar/pom.xml
@@ -103,11 +103,11 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-dsl-mapping
+            legend-pure-runtime-java-extension-compiled-dsl-mapping
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-dsl-path
+            legend-pure-runtime-java-extension-compiled-dsl-path
         
         
             org.finos.legend.engine
@@ -119,7 +119,7 @@
         
         
             org.finos.legend.engine
-            legend-engine-pure-platform-dsl-mapping-java
+            legend-engine-pure-platform-dsl-store-java
         
         
             org.finos.legend.engine
diff --git a/legend-engine-xts-serviceStore/legend-engine-xt-serviceStore-javaPlatformBinding-pure/pom.xml b/legend-engine-xts-serviceStore/legend-engine-xt-serviceStore-javaPlatformBinding-pure/pom.xml
index 1ca0fc06283..36b0676b821 100644
--- a/legend-engine-xts-serviceStore/legend-engine-xt-serviceStore-javaPlatformBinding-pure/pom.xml
+++ b/legend-engine-xts-serviceStore/legend-engine-xt-serviceStore-javaPlatformBinding-pure/pom.xml
@@ -214,7 +214,7 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-dsl-mapping
+            legend-pure-runtime-java-extension-compiled-dsl-mapping
             runtime
         
 
diff --git a/legend-engine-xts-serviceStore/legend-engine-xt-serviceStore-pure/pom.xml b/legend-engine-xts-serviceStore/legend-engine-xt-serviceStore-pure/pom.xml
index 914a642739b..7fd5285d44a 100644
--- a/legend-engine-xts-serviceStore/legend-engine-xt-serviceStore-pure/pom.xml
+++ b/legend-engine-xts-serviceStore/legend-engine-xt-serviceStore-pure/pom.xml
@@ -38,9 +38,9 @@
                         
                             
                             
-                                org.finos.legend.pure:legend-pure-runtime-java-extension-store-relational
-                                org.finos.legend.pure:legend-pure-runtime-java-extension-functions-json
-                                org.finos.legend.pure:legend-pure-runtime-java-extension-dsl-store
+                                org.finos.legend.pure:legend-pure-runtime-java-extension-compiled-store-relational
+                                org.finos.legend.pure:legend-pure-runtime-java-extension-compiled-functions-json
+                                org.finos.legend.pure:legend-pure-runtime-java-extension-compiled-dsl-store
                                 org.finos.legend.engine:legend-engine-pure-platform-dsl-store-java
                             
                         
@@ -207,7 +207,7 @@
 
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-dsl-graph
+            legend-pure-runtime-java-extension-compiled-dsl-graph
         
 
         
@@ -256,15 +256,15 @@
 
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-functions-json
+            legend-pure-runtime-java-extension-compiled-functions-json
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-store-relational
+            legend-pure-runtime-java-extension-compiled-store-relational
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-dsl-store
+            legend-pure-runtime-java-extension-compiled-dsl-store
         
         
             org.finos.legend.engine
@@ -272,12 +272,12 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-dsl-mapping
+            legend-pure-runtime-java-extension-compiled-dsl-mapping
             runtime
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-dsl-path
+            legend-pure-runtime-java-extension-compiled-dsl-path
             runtime
         
 
diff --git a/legend-engine-xts-snowflakeApp/legend-engine-xt-snowflakeApp-pure/pom.xml b/legend-engine-xts-snowflakeApp/legend-engine-xt-snowflakeApp-pure/pom.xml
index d3eae4ab0f1..0fc2945624c 100644
--- a/legend-engine-xts-snowflakeApp/legend-engine-xt-snowflakeApp-pure/pom.xml
+++ b/legend-engine-xts-snowflakeApp/legend-engine-xt-snowflakeApp-pure/pom.xml
@@ -130,6 +130,10 @@
             org.finos.legend.engine
             legend-engine-pure-platform-dsl-mapping-java
         
+        
+            org.finos.legend.engine
+            legend-engine-pure-platform-dsl-store-java
+        
         
             org.finos.legend.engine
             legend-engine-pure-platform-store-relational-java
diff --git a/legend-engine-xts-snowflakeApp/legend-engine-xt-snowflakeApp-pure/src/main/resources/core_snowflakeapp.definition.json b/legend-engine-xts-snowflakeApp/legend-engine-xt-snowflakeApp-pure/src/main/resources/core_snowflakeapp.definition.json
index 9fb456e44dd..dbce5169a1f 100644
--- a/legend-engine-xts-snowflakeApp/legend-engine-xt-snowflakeApp-pure/src/main/resources/core_snowflakeapp.definition.json
+++ b/legend-engine-xts-snowflakeApp/legend-engine-xt-snowflakeApp-pure/src/main/resources/core_snowflakeapp.definition.json
@@ -5,7 +5,7 @@
     "core",
     "platform",
     "platform_dsl_graph",
-    "platform_dsl_mapping",
+    "platform_dsl_store",
     "platform_store_relational",
     "platform_functions",
     "platform_functions_json",
diff --git a/legend-engine-xts-sql/legend-engine-xt-sql-compiler/pom.xml b/legend-engine-xts-sql/legend-engine-xt-sql-compiler/pom.xml
index c87cda36c0f..d512d60f17f 100644
--- a/legend-engine-xts-sql/legend-engine-xt-sql-compiler/pom.xml
+++ b/legend-engine-xts-sql/legend-engine-xt-sql-compiler/pom.xml
@@ -109,7 +109,7 @@
                         
                             
                             
-                                org.finos.legend.pure:legend-pure-runtime-java-extension-dsl-mapping
+                                org.finos.legend.pure:legend-pure-runtime-java-extension-compiled-dsl-mapping
 
                             
                         
diff --git a/legend-engine-xts-sql/legend-engine-xt-sql-protocol/pom.xml b/legend-engine-xts-sql/legend-engine-xt-sql-protocol/pom.xml
index 5325c69859c..811439af6c2 100644
--- a/legend-engine-xts-sql/legend-engine-xt-sql-protocol/pom.xml
+++ b/legend-engine-xts-sql/legend-engine-xt-sql-protocol/pom.xml
@@ -82,7 +82,7 @@
                     
                     
                         org.finos.legend.pure
-                        legend-pure-runtime-java-extension-store-relational
+                        legend-pure-runtime-java-extension-compiled-store-relational
                         ${legend.pure.version}
                     
                     
diff --git a/legend-engine-xts-sql/legend-engine-xt-sql-pure/pom.xml b/legend-engine-xts-sql/legend-engine-xt-sql-pure/pom.xml
index 1c4a3b35bfb..4acb93de1ae 100644
--- a/legend-engine-xts-sql/legend-engine-xt-sql-pure/pom.xml
+++ b/legend-engine-xts-sql/legend-engine-xt-sql-pure/pom.xml
@@ -146,7 +146,7 @@
                     
                     
                         org.finos.legend.pure
-                        legend-pure-runtime-java-extension-dsl-mapping
+                        legend-pure-runtime-java-extension-compiled-dsl-mapping
                         ${legend.pure.version}
                     
                     
@@ -205,7 +205,7 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-dsl-mapping
+            legend-pure-runtime-java-extension-compiled-dsl-mapping
         
         
             org.finos.legend.pure
@@ -238,6 +238,10 @@
             org.finos.legend.engine
             legend-engine-pure-platform-dsl-mapping-java
         
+        
+            org.finos.legend.engine
+            legend-engine-pure-platform-dsl-store-java
+        
 
         
             org.finos.legend.engine
@@ -319,6 +323,11 @@
             legend-engine-xt-sql-grammar-integration
             test
         
+        
+            com.h2database
+            h2
+            test
+        
         
     
 
diff --git a/legend-engine-xts-sql/legend-engine-xt-sql-pure/src/main/resources/core_external_query_sql.definition.json b/legend-engine-xts-sql/legend-engine-xt-sql-pure/src/main/resources/core_external_query_sql.definition.json
index 7065dec99ec..37ca03f240d 100644
--- a/legend-engine-xts-sql/legend-engine-xt-sql-pure/src/main/resources/core_external_query_sql.definition.json
+++ b/legend-engine-xts-sql/legend-engine-xt-sql-pure/src/main/resources/core_external_query_sql.definition.json
@@ -5,6 +5,7 @@
     "platform",
     "platform_functions",
     "platform_dsl_mapping",
+    "platform_dsl_store",
     "platform_store_relational",
     "core_functions",
     "core",
diff --git a/legend-engine-xts-sql/legend-engine-xt-sql-query/pom.xml b/legend-engine-xts-sql/legend-engine-xt-sql-query/pom.xml
index f4a14795dc3..328f1093906 100644
--- a/legend-engine-xts-sql/legend-engine-xt-sql-query/pom.xml
+++ b/legend-engine-xts-sql/legend-engine-xt-sql-query/pom.xml
@@ -70,7 +70,7 @@
         
         
             org.finos.legend.engine
-            legend-engine-pure-platform-dsl-mapping-java
+            legend-engine-pure-platform-dsl-store-java
         
         
             org.finos.legend.engine
diff --git a/legend-engine-xts-xml/legend-engine-xt-xml-javaPlatformBinding-pure/pom.xml b/legend-engine-xts-xml/legend-engine-xt-xml-javaPlatformBinding-pure/pom.xml
index 5200dbaefac..c5f3816076f 100644
--- a/legend-engine-xts-xml/legend-engine-xt-xml-javaPlatformBinding-pure/pom.xml
+++ b/legend-engine-xts-xml/legend-engine-xt-xml-javaPlatformBinding-pure/pom.xml
@@ -226,7 +226,7 @@
 
         
             org.finos.legend.engine
-            legend-engine-pure-platform-dsl-mapping-java
+            legend-engine-pure-platform-dsl-store-java
         
         
 
diff --git a/legend-engine-xts-xml/legend-engine-xt-xml-model/pom.xml b/legend-engine-xts-xml/legend-engine-xt-xml-model/pom.xml
index 8a10924f5db..920c71a5748 100644
--- a/legend-engine-xts-xml/legend-engine-xt-xml-model/pom.xml
+++ b/legend-engine-xts-xml/legend-engine-xt-xml-model/pom.xml
@@ -50,7 +50,7 @@
         
         
             org.finos.legend.pure
-            legend-pure-runtime-java-extension-functions-json
+            legend-pure-runtime-java-extension-compiled-functions-json
             runtime
         
         
diff --git a/legend-engine-xts-xml/legend-engine-xt-xml-pure/pom.xml b/legend-engine-xts-xml/legend-engine-xt-xml-pure/pom.xml
index d8ab4ecf264..bc55ef2ca2f 100644
--- a/legend-engine-xts-xml/legend-engine-xt-xml-pure/pom.xml
+++ b/legend-engine-xts-xml/legend-engine-xt-xml-pure/pom.xml
@@ -183,7 +183,7 @@
         
         
             org.finos.legend.engine
-            legend-engine-pure-platform-dsl-mapping-java
+            legend-engine-pure-platform-dsl-store-java
         
         
 
diff --git a/pom.xml b/pom.xml
index 6444e824130..ca58ceef27f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -104,7 +104,7 @@
 
     
         
-        5.1.3
+        5.1.4-SNAPSHOT
         0.25.4
 
         
@@ -1988,7 +1988,12 @@
             
             
                 org.finos.legend.pure
-                legend-pure-runtime-java-extension-functions
+                legend-pure-runtime-java-extension-compiled-functions-base
+                ${legend.pure.version}
+            
+            
+                org.finos.legend.pure
+                legend-pure-runtime-java-extension-interpreted-functions-base
                 ${legend.pure.version}
             
             
@@ -2003,7 +2008,17 @@
             
             
                 org.finos.legend.pure
-                legend-pure-runtime-java-extension-functions-shared-conversion
+                legend-pure-runtime-java-extension-shared-store-relational
+                ${legend.pure.version}
+            
+            
+                org.finos.legend.pure
+                legend-pure-runtime-java-extension-shared-functions-conversion
+                ${legend.pure.version}
+            
+            
+                org.finos.legend.pure
+                legend-pure-runtime-java-extension-shared-functions-json
                 ${legend.pure.version}
             
             
@@ -2320,7 +2335,12 @@
             
             
                 org.finos.legend.pure
-                legend-pure-runtime-java-extension-functions-json
+                legend-pure-runtime-java-extension-compiled-functions-json
+                ${legend.pure.version}
+            
+            
+                org.finos.legend.pure
+                legend-pure-runtime-java-extension-interpreted-functions-json
                 ${legend.pure.version}
             
             
@@ -2370,7 +2390,7 @@
             
             
                 org.finos.legend.pure
-                legend-pure-runtime-java-extension-functions-relation
+                legend-pure-runtime-java-extension-compiled-functions-relation
                 ${legend.pure.version}
             
             
@@ -2390,7 +2410,7 @@
             
             
                 org.finos.legend.pure
-                legend-pure-runtime-java-extension-functions-relation
+                legend-pure-runtime-java-extension-compiled-functions-relation
                 ${legend.pure.version}
             
             
@@ -2405,32 +2425,32 @@
             
             
                 org.finos.legend.pure
-                legend-pure-runtime-java-extension-dsl-diagram
+                legend-pure-runtime-java-extension-compiled-dsl-diagram
                 ${legend.pure.version}
             
             
                 org.finos.legend.pure
-                legend-pure-runtime-java-extension-dsl-graph
+                legend-pure-runtime-java-extension-compiled-dsl-graph
                 ${legend.pure.version}
             
             
                 org.finos.legend.pure
-                legend-pure-runtime-java-extension-dsl-mapping
+                legend-pure-runtime-java-extension-compiled-dsl-mapping
                 ${legend.pure.version}
             
             
                 org.finos.legend.pure
-                legend-pure-runtime-java-extension-dsl-store
+                legend-pure-runtime-java-extension-compiled-dsl-store
                 ${legend.pure.version}
             
             
                 org.finos.legend.pure
-                legend-pure-runtime-java-extension-dsl-path
+                legend-pure-runtime-java-extension-compiled-dsl-path
                 ${legend.pure.version}
             
             
                 org.finos.legend.pure
-                legend-pure-runtime-java-extension-dsl-tds
+                legend-pure-runtime-java-extension-compiled-dsl-tds
                 ${legend.pure.version}
             
             
@@ -2470,7 +2490,7 @@
             
             
                 org.finos.legend.pure
-                legend-pure-runtime-java-extension-store-relational
+                legend-pure-runtime-java-extension-compiled-store-relational
                 ${legend.pure.version}