Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[js] use proxy for global bindings #397

Merged
merged 1 commit into from
Jul 16, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
[js] use proxy for global bindings
  • Loading branch information
lburgazzoli committed Jul 15, 2020
commit 29225a8d17654d43c373a85dcf34fe474a579c36
Original file line number Diff line number Diff line change
@@ -16,8 +16,7 @@
*/
package org.apache.camel.k.loader.js;

import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.io.Reader;
import java.util.Collections;
import java.util.List;

@@ -29,10 +28,13 @@
import org.apache.camel.k.SourceLoader;
import org.apache.camel.k.annotation.Loader;
import org.apache.camel.k.loader.js.dsl.IntegrationConfiguration;
import org.apache.camel.k.support.RouteBuilders;
import org.apache.camel.support.LifecycleStrategySupport;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Value;

import static org.graalvm.polyglot.Source.newBuilder;

@Loader("js")
public class JavaScriptSourceLoader implements SourceLoader {
private static final String LANGUAGE_ID = "js";
@@ -44,35 +46,46 @@ public List<String> getSupportedLanguages() {

@Override
public Result load(Runtime runtime, Source source) throws Exception {
RoutesBuilder builder = new EndpointRouteBuilder() {
@Override
public void configure() throws Exception {
final Context context = Context.newBuilder("js").allowAllAccess(true).build();
RoutesBuilder builder = RouteBuilders.endpoint(source, JavaScriptSourceLoader::doLoad);

return SourceLoader.Result.on(builder);
}

try (InputStream is = source.resolveAsInputStream(getContext())) {
Value bindings = context.getBindings(LANGUAGE_ID);
private static void doLoad(Reader reader, EndpointRouteBuilder builder) {
final Context context = Context.newBuilder("js").allowAllAccess(true).build();
final Value bindings = context.getBindings(LANGUAGE_ID);

// configure bindings
bindings.putMember("__dsl", new IntegrationConfiguration(this));
// configure bindings
bindings.putMember("__dsl", new IntegrationConfiguration(builder));

final String script = new String(is.readAllBytes(), StandardCharsets.UTF_8);
final String wrappedScript = "with (__dsl) { " + script + " }";
//
// Expose IntegrationConfiguration methods to global scope.
//
context.eval(LANGUAGE_ID, ""
+ "Object.setPrototypeOf(globalThis, new Proxy(Object.prototype, {"
+ " has(target, key) {"
+ " return key in __dsl || key in target;"
+ " },"
+ " get(target, key, receiver) {"
+ " return Reflect.get((key in __dsl) ? __dsl : target, key, receiver);"
+ " }"
+ "}));");

context.eval(LANGUAGE_ID, wrappedScript);
//
// Run the script.
//
context.eval(
newBuilder(LANGUAGE_ID, reader, "Unnamed").buildLiteral()
);

//
// Close the polyglot context when the camel context stops
//
getContext().addLifecycleStrategy(new LifecycleStrategySupport() {
@Override
public void onContextStop(CamelContext camelContext) {
context.close(true);
}
});
}
//
// Close the polyglot context when the camel context stops
//
builder.getContext().addLifecycleStrategy(new LifecycleStrategySupport() {
@Override
public void onContextStop(CamelContext camelContext) {
context.close(true);
}
};

return Result.on(builder);
});
}
}
Original file line number Diff line number Diff line change
@@ -25,8 +25,7 @@ import org.apache.camel.k.SourceLoader
import org.apache.camel.k.loader.kotlin.dsl.IntegrationConfiguration
import org.apache.camel.k.support.RouteBuilders
import org.slf4j.LoggerFactory
import java.io.InputStream
import java.io.InputStreamReader
import java.io.Reader
import kotlin.script.experimental.api.ResultValue
import kotlin.script.experimental.api.ScriptDiagnostic
import kotlin.script.experimental.api.ScriptEvaluationConfiguration
@@ -45,18 +44,18 @@ class KotlinSourceLoader : SourceLoader {
@Throws(Exception::class)
override fun load(runtime: Runtime, source: Source): SourceLoader.Result {
val builder = RouteBuilders.endpoint(source) {
inputStream, builder -> doLoad(inputStream, builder)
reader, builder -> doLoad(reader, builder)
}

return SourceLoader.Result.on(builder)
}

private fun doLoad(inputStream: InputStream, builder: EndpointRouteBuilder) {
private fun doLoad(reader: Reader, builder: EndpointRouteBuilder) {
val host = BasicJvmScriptingHost()
val config = createJvmCompilationConfigurationFromTemplate<IntegrationConfiguration>()

val result = host.eval(
InputStreamReader(inputStream).readText().toScriptSource(),
reader.readText().toScriptSource(),
config,
ScriptEvaluationConfiguration {
//
12 changes: 12 additions & 0 deletions camel-k-runtime-core/src/main/java/org/apache/camel/k/Source.java
Original file line number Diff line number Diff line change
@@ -17,6 +17,10 @@
package org.apache.camel.k;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Optional;

@@ -28,4 +32,12 @@ public interface Source {
Optional<String> getLoader();
List<String> getInterceptors();
InputStream resolveAsInputStream(CamelContext ctx);

default Reader resolveAsReader(CamelContext ctx) {
return resolveAsReader(ctx, StandardCharsets.UTF_8);
}

default Reader resolveAsReader(CamelContext ctx, Charset charset) {
return new InputStreamReader(resolveAsInputStream(ctx), charset);
}
}
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@
*/
package org.apache.camel.k.support;

import java.io.InputStream;
import java.io.Reader;
import java.util.function.BiConsumer;

import org.apache.camel.builder.endpoint.EndpointRouteBuilder;
@@ -26,12 +26,12 @@ public final class RouteBuilders {
private RouteBuilders() {
}

public static EndpointRouteBuilder endpoint(Source source, BiConsumer<InputStream, EndpointRouteBuilder> consumer) {
public static EndpointRouteBuilder endpoint(Source source, BiConsumer<Reader, EndpointRouteBuilder> consumer) {
return new EndpointRouteBuilder() {
@Override
public void configure() throws Exception {
try (InputStream is = source.resolveAsInputStream(getContext())) {
consumer.accept(is, this);
try (Reader reader = source.resolveAsReader(getContext())) {
consumer.accept(reader, this);
}
}
};