Repository: tinkerpop Updated Branches: refs/heads/master f242289a8 -> 7b3adca39
Made some improvements to the BindingsGremlinPlugin Made it possible to specify scopes to apply the bindings to. Added tests. CTR Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/c958b220 Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/c958b220 Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/c958b220 Branch: refs/heads/master Commit: c958b220b9559bb5fedbcc6e5c17f2dc142fb430 Parents: 91759a5 Author: Stephen Mallette <sp...@genoprime.com> Authored: Thu Jan 26 14:46:36 2017 -0500 Committer: Stephen Mallette <sp...@genoprime.com> Committed: Thu Jan 26 14:46:36 2017 -0500 ---------------------------------------------------------------------- .../gremlin/jsr223/BindingsCustomizer.java | 11 ++- .../gremlin/jsr223/BindingsGremlinPlugin.java | 48 ++++++++-- .../jsr223/DefaultBindingsCustomizer.java | 20 ++++- .../DefaultGremlinScriptEngineManager.java | 16 +++- .../gremlin/jsr223/LazyBindingsCustomizer.java | 20 +++++ .../gremlin/jsr223/ScriptFileGremlinPlugin.java | 4 +- .../jsr223/BindingsScriptEngineTest.java | 95 ++++++++++++++++++++ .../jsr223/GremlinScriptEngineSuite.java | 1 + 8 files changed, 206 insertions(+), 9 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c958b220/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/BindingsCustomizer.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/BindingsCustomizer.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/BindingsCustomizer.java index 02c129e..e8dd9f3 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/BindingsCustomizer.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/BindingsCustomizer.java @@ -21,7 +21,9 @@ package org.apache.tinkerpop.gremlin.jsr223; import javax.script.Bindings; /** - * Provides a way to alter the bindings on a {@link GremlinScriptEngine}. + * Provides a way to alter the bindings on a {@link GremlinScriptEngine}. Those implementing {@link GremlinScriptEngine} + * instances need to be concerned with accounting for this {@link Customizer}. It is handled automatically by the + * {@link DefaultGremlinScriptEngineManager}. * * @author Stephen Mallette (http://stephen.genoprime.com) */ @@ -30,4 +32,11 @@ public interface BindingsCustomizer extends Customizer { * Gets the bindings to add to a {@link GremlinScriptEngine}. */ public Bindings getBindings(); + + /** + * Gets the scope to which the bindings apply. The scope is determined by the {@code ScriptContext} values where + * "100" is {@code EngineScope} (bindings apply to the current {@link GremlinScriptEngine}) and "200" is + * {@code GlobalScope} (bindings apply to the engines created by the current {@link GremlinScriptEngineManager}. + */ + public int getScope(); } http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c958b220/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/BindingsGremlinPlugin.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/BindingsGremlinPlugin.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/BindingsGremlinPlugin.java index feb501d..59304df 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/BindingsGremlinPlugin.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/BindingsGremlinPlugin.java @@ -19,26 +19,48 @@ package org.apache.tinkerpop.gremlin.jsr223; import javax.script.Bindings; +import javax.script.ScriptContext; import javax.script.SimpleBindings; +import java.util.Collection; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import java.util.function.Supplier; /** + * A module that allows {@code Bindings} to be applied to a {@link GremlinScriptEngine}. The bindings are controled by + * their {@code scope} which are determined by the {@code ScriptContext} values where "100" is {@code ENGINE_SCOPE} + * (bindings apply to the current {@link GremlinScriptEngine}) and "200" is {@code GLOBAL_SCOPE} (bindings apply to the + * engines created by the current {@link GremlinScriptEngineManager}. + * <p/> + * Note that bindings are applied in the following order: + * <ol> + * <li>The order in which the {@link GremlinScriptEngine} is requested from the {@link GremlinScriptEngineManager}</li> + * <li>The order in which the {@code BindingsGremlinPlugin} instances are added to the {@link GremlinScriptEngineManager}</li> + * </ol> + * <p/> + * Moreover, they will override one another within a scope and among scopes. For instance, {@code ENGINE_SCOPE} bindings + * will override {@code GLOBAL_SCOPE}. Those bindings that are {@code GLOBAL_SCOPE} and applied to a single + * {@link GremlinScriptEngine} via an {@link Builder#appliesTo} configuration will still appear present to all other + * {@link GremlinScriptEngine} created by the {@link GremlinScriptEngineManager} that the plugin was bound to. + * <p/> + * This {@link GremlinPlugin} is not enabled for the {@code ServiceLoader}. It is designed to be instantiated manually. + * * @author Stephen Mallette (http://stephen.genoprime.com) */ public class BindingsGremlinPlugin extends AbstractGremlinPlugin { private static final String NAME = "tinkerpop.bindings"; private BindingsGremlinPlugin(final Builder builder) { - this(builder.bindings); + super(NAME, builder.appliesTo, new DefaultBindingsCustomizer(builder.bindings, builder.scope)); } - public BindingsGremlinPlugin(final Bindings bindings) { - super(NAME, new DefaultBindingsCustomizer(bindings)); + public BindingsGremlinPlugin(final Bindings bindings, final int scope) { + super(NAME, new DefaultBindingsCustomizer(bindings, scope)); } - public BindingsGremlinPlugin(final Supplier<Bindings> bindingsSupplier) { - super(NAME, new LazyBindingsCustomizer(bindingsSupplier)); + public BindingsGremlinPlugin(final Supplier<Bindings> bindingsSupplier, final int scope) { + super(NAME, new LazyBindingsCustomizer(bindingsSupplier, scope)); } public static BindingsGremlinPlugin.Builder build() { @@ -48,14 +70,30 @@ public class BindingsGremlinPlugin extends AbstractGremlinPlugin { public static final class Builder { private Bindings bindings = new SimpleBindings(); + private int scope = ScriptContext.ENGINE_SCOPE; + private final Set<String> appliesTo = new HashSet<>(); private Builder() {} + /** + * The name of the {@link GremlinScriptEngine} that this module will apply to. Setting no values here will + * make the module available to all the engines. + */ + public BindingsGremlinPlugin.Builder appliesTo(final Collection<String> scriptEngineName) { + this.appliesTo.addAll(scriptEngineName); + return this; + } + public Builder bindings(final Map<String, Object> bindings) { this.bindings = new SimpleBindings(bindings); return this; } + public Builder scope(final int scope) { + this.scope = scope; + return this; + } + public BindingsGremlinPlugin create() { return new BindingsGremlinPlugin(this); } http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c958b220/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/DefaultBindingsCustomizer.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/DefaultBindingsCustomizer.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/DefaultBindingsCustomizer.java index 0073d39..cee5182 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/DefaultBindingsCustomizer.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/DefaultBindingsCustomizer.java @@ -19,22 +19,40 @@ package org.apache.tinkerpop.gremlin.jsr223; import javax.script.Bindings; +import javax.script.ScriptContext; /** - * Default implementation of the {@link BindingsCustomizer}. + * Default implementation of the {@link BindingsCustomizer}. If this customizer is applied directly to a + * {@link GremlinScriptEngine} it will not apply {@code GLOBAL_SCOPE} bindings. Those can only be applied if the + * customizer is applied via the {@link GremlinScriptEngineManager} (which would do so through the + * {@link BindingsGremlinPlugin}. * * @author Stephen Mallette (http://stephen.genoprime.com) */ public class DefaultBindingsCustomizer implements BindingsCustomizer { private final Bindings bindings; + private final int scope; + /** + * Creates a new object with {@code ScriptContext.ENGINE_SCOPE}. + */ public DefaultBindingsCustomizer(final Bindings bindings) { + this(bindings, ScriptContext.ENGINE_SCOPE); + } + + public DefaultBindingsCustomizer(final Bindings bindings, final int scope) { this.bindings = bindings; + this.scope = scope; } @Override public Bindings getBindings() { return bindings; } + + @Override + public int getScope() { + return scope; + } } http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c958b220/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/DefaultGremlinScriptEngineManager.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/DefaultGremlinScriptEngineManager.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/DefaultGremlinScriptEngineManager.java index 436deac..01b4957 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/DefaultGremlinScriptEngineManager.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/DefaultGremlinScriptEngineManager.java @@ -23,7 +23,6 @@ import javax.script.ScriptContext; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -442,8 +441,23 @@ public class DefaultGremlinScriptEngineManager implements GremlinScriptEngineMan private GremlinScriptEngine createGremlinScriptEngine(final GremlinScriptEngineFactory spi) { final GremlinScriptEngine engine = spi.getScriptEngine(); + + // merge in bindings that are marked with global scope. these get applied to all GremlinScriptEngine instances + getCustomizers(spi.getEngineName()).stream() + .filter(p -> p instanceof BindingsCustomizer) + .map(p -> ((BindingsCustomizer) p)) + .filter(bc -> bc.getScope() == ScriptContext.GLOBAL_SCOPE) + .forEach(bc -> globalScope.putAll(bc.getBindings())); engine.setBindings(getBindings(), ScriptContext.GLOBAL_SCOPE); + // merge in bindings that are marked with engine scope. these get applied to only those GremlinScriptEngine + // instances that are of this gremlin language + getCustomizers(spi.getEngineName()).stream() + .filter(p -> p instanceof BindingsCustomizer) + .map(p -> ((BindingsCustomizer) p)) + .filter(bc -> bc.getScope() == ScriptContext.ENGINE_SCOPE) + .forEach(bc -> engine.setBindings(bc.getBindings(), ScriptContext.ENGINE_SCOPE)); + final List<ScriptCustomizer> scriptCustomizers = getCustomizers(spi.getEngineName()).stream() .filter(p -> p instanceof ScriptCustomizer) .map(p -> ((ScriptCustomizer) p)) http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c958b220/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/LazyBindingsCustomizer.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/LazyBindingsCustomizer.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/LazyBindingsCustomizer.java index 01ae662..8feb361 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/LazyBindingsCustomizer.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/LazyBindingsCustomizer.java @@ -19,21 +19,41 @@ package org.apache.tinkerpop.gremlin.jsr223; import javax.script.Bindings; +import javax.script.ScriptContext; import java.util.function.Supplier; /** + * A customizer implementation that provides bindings to a {@link GremlinScriptEngine}. If this customizer is applied + * directly to a {@link GremlinScriptEngine} it will not apply {@code GLOBAL_SCOPE} bindings. Those can only be applied + * if the customizer is applied via the {@link GremlinScriptEngineManager} (which would do so through the + * {@link BindingsGremlinPlugin}. + * * @author Stephen Mallette (http://stephen.genoprime.com) */ public class LazyBindingsCustomizer implements BindingsCustomizer { private final Supplier<Bindings> bindingsSupplier; + private final int scope; + /** + * Creates a new object with {@code ScriptContext.ENGINE_SCOPE}. + */ public LazyBindingsCustomizer(final Supplier<Bindings> bindingsSupplier) { + this(bindingsSupplier, ScriptContext.ENGINE_SCOPE); + } + + public LazyBindingsCustomizer(final Supplier<Bindings> bindingsSupplier, final int scope) { this.bindingsSupplier = bindingsSupplier; + this.scope = scope; } @Override public Bindings getBindings() { return bindingsSupplier.get(); } + + @Override + public int getScope() { + return scope; + } } http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c958b220/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/ScriptFileGremlinPlugin.java ---------------------------------------------------------------------- diff --git a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/ScriptFileGremlinPlugin.java b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/ScriptFileGremlinPlugin.java index 0131ca2..3a3f4be 100644 --- a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/ScriptFileGremlinPlugin.java +++ b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/jsr223/ScriptFileGremlinPlugin.java @@ -28,7 +28,9 @@ import java.util.Set; /** * Loads scripts from one or more files into the {@link GremlinScriptEngine} at startup. This {@link GremlinPlugin} is - * not enabled for the {@code ServiceLoader}. It is designed to be instantiated manually. + * not enabled for the {@code ServiceLoader}. It is designed to be instantiated manually. Those implementing + * {@link GremlinScriptEngine} instances need to be concerned with accounting for this {@link Customizer}. It is + * handled automatically by the {@link DefaultGremlinScriptEngineManager}. * * @author Stephen Mallette (http://stephen.genoprime.com) */ http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c958b220/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/jsr223/BindingsScriptEngineTest.java ---------------------------------------------------------------------- diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/jsr223/BindingsScriptEngineTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/jsr223/BindingsScriptEngineTest.java new file mode 100644 index 0000000..e02b834 --- /dev/null +++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/jsr223/BindingsScriptEngineTest.java @@ -0,0 +1,95 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.tinkerpop.gremlin.jsr223; + +import org.junit.Test; + +import javax.script.Bindings; +import javax.script.ScriptContext; +import javax.script.ScriptException; +import javax.script.SimpleBindings; +import java.util.Collections; + +import static org.apache.tinkerpop.gremlin.jsr223.GremlinScriptEngineSuite.ENGINE_TO_TEST; +import static org.junit.Assert.assertEquals; + +/** + * @author Stephen Mallette (http://stephen.genoprime.com) + */ +public class BindingsScriptEngineTest { + + @Test + public void shouldIncludeGlobalBindings() throws ScriptException { + final GremlinScriptEngineManager manager = new DefaultGremlinScriptEngineManager(); + final Bindings b = new SimpleBindings(); + b.put("x", 1); + b.put("y", 2); + + manager.addPlugin(BindingsGremlinPlugin.build(). + bindings(b). + scope(ScriptContext.GLOBAL_SCOPE). + appliesTo(Collections.singletonList(ENGINE_TO_TEST)).create()); + + final GremlinScriptEngine engine = manager.getEngineByName(ENGINE_TO_TEST); + assertEquals(1, engine.eval("x")); + assertEquals(2, engine.eval("y")); + } + + @Test + public void shouldIncludeEngineBindings() throws ScriptException { + final GremlinScriptEngineManager manager = new DefaultGremlinScriptEngineManager(); + final Bindings b = new SimpleBindings(); + b.put("x", 1); + b.put("y", 2); + + manager.addPlugin(BindingsGremlinPlugin.build(). + bindings(b). + scope(ScriptContext.ENGINE_SCOPE). + appliesTo(Collections.singletonList(ENGINE_TO_TEST)).create()); + + final GremlinScriptEngine engine = manager.getEngineByName(ENGINE_TO_TEST); + assertEquals(1, engine.eval("x")); + assertEquals(2, engine.eval("y")); + } + + @Test + public void shouldIncludeEngineBindingsToOverrideGlobalBindings() throws ScriptException { + final GremlinScriptEngineManager manager = new DefaultGremlinScriptEngineManager(); + + final Bindings b1 = new SimpleBindings(); + b1.put("x", 1); + b1.put("y", 2); + manager.addPlugin(BindingsGremlinPlugin.build(). + bindings(b1). + scope(ScriptContext.GLOBAL_SCOPE). + appliesTo(Collections.singletonList(ENGINE_TO_TEST)).create()); + + final Bindings b2 = new SimpleBindings(); + b2.put("x", 100); + b2.put("y", 200); + manager.addPlugin(BindingsGremlinPlugin.build(). + bindings(b2). + scope(ScriptContext.ENGINE_SCOPE). + appliesTo(Collections.singletonList(ENGINE_TO_TEST)).create()); + + final GremlinScriptEngine engine = manager.getEngineByName(ENGINE_TO_TEST); + assertEquals(100, engine.eval("x")); + assertEquals(200, engine.eval("y")); + } +} http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/c958b220/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/jsr223/GremlinScriptEngineSuite.java ---------------------------------------------------------------------- diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/jsr223/GremlinScriptEngineSuite.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/jsr223/GremlinScriptEngineSuite.java index 8ccde91..70c585c 100644 --- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/jsr223/GremlinScriptEngineSuite.java +++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/jsr223/GremlinScriptEngineSuite.java @@ -29,6 +29,7 @@ public class GremlinScriptEngineSuite extends Suite { static String ENGINE_TO_TEST; private static final Class<?>[] allTests = new Class<?>[]{ + BindingsScriptEngineTest.class, CachedGremlinScriptEngineManagerTest.class, GremlinEnabledScriptEngineTest.class, ScriptEngineLambdaTest.class };