You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by sp...@apache.org on 2016/02/26 20:36:23 UTC
[1/4] incubator-tinkerpop git commit: Added some more asserts around
variable scoping with interpreter mode.
Repository: incubator-tinkerpop
Updated Branches:
refs/heads/tp31 d83dba4be -> 959378ca8
Added some more asserts around variable scoping with interpreter mode.
Project: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/commit/73489b3a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/tree/73489b3a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/diff/73489b3a
Branch: refs/heads/tp31
Commit: 73489b3a89bab18d59fc5e1dfc9b23a10c5222ab
Parents: 566c488
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Fri Feb 19 10:05:41 2016 -0500
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Thu Feb 25 07:40:47 2016 -0500
----------------------------------------------------------------------
.../jsr223/GremlinGroovyScriptEngineTest.java | 25 ++++++++++++++++++++
1 file changed, 25 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/73489b3a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineTest.java
----------------------------------------------------------------------
diff --git a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineTest.java b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineTest.java
index 17cd809..19ced88 100644
--- a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineTest.java
+++ b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineTest.java
@@ -19,6 +19,8 @@
package org.apache.tinkerpop.gremlin.groovy.jsr223;
import groovy.lang.Closure;
+import groovy.lang.MissingPropertyException;
+import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.apache.tinkerpop.gremlin.groovy.CompilerCustomizerProvider;
import org.apache.tinkerpop.gremlin.groovy.NoImportCustomizerProvider;
@@ -55,6 +57,7 @@ import java.util.stream.IntStream;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsInstanceOf.instanceOf;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -99,6 +102,17 @@ public class GremlinGroovyScriptEngineTest {
assertEquals(4, engine.eval("yyy = xxx + 1"));
assertEquals(7, engine.eval("def zzz = yyy + xxx"));
assertEquals(4, engine.eval("zzz - xxx"));
+ assertEquals("accessible-globally", engine.eval("if (yyy > 0) { def inner = 'should-stay-local'; outer = 'accessible-globally' }\n outer"));
+ assertEquals("accessible-globally", engine.eval("outer"));
+
+ try {
+ engine.eval("inner");
+ fail("Should not have been able to access 'inner'");
+ } catch (Exception ex) {
+ final Throwable root = ExceptionUtils.getRootCause(ex);
+ assertThat(root, instanceOf(MissingPropertyException.class));
+ }
+
assertEquals(10, engine.eval("addItUp(zzz,xxx)"));
}
@@ -112,6 +126,17 @@ public class GremlinGroovyScriptEngineTest {
assertEquals(4, engine.eval("yyy = xxx + 1", b));
assertEquals(7, engine.eval("def zzz = yyy + xxx", b));
assertEquals(4, engine.eval("zzz - xxx", b));
+ assertEquals("accessible-globally", engine.eval("if (yyy > 0) { def inner = 'should-stay-local'; outer = 'accessible-globally' }\n outer", b));
+ assertEquals("accessible-globally", engine.eval("outer", b));
+
+ try {
+ engine.eval("inner", b);
+ fail("Should not have been able to access 'inner'");
+ } catch (Exception ex) {
+ final Throwable root = ExceptionUtils.getRootCause(ex);
+ assertThat(root, instanceOf(MissingPropertyException.class));
+ }
+
assertEquals(10, engine.eval("addItUp(zzz,xxx)", b));
}
[2/4] incubator-tinkerpop git commit: Allow ScriptEngine to accept
scripts in interpreter mode.
Posted by sp...@apache.org.
Allow ScriptEngine to accept scripts in interpreter mode.
Scripts sent with variables normally considered "local" by use of the def keyword or the inclusion of a type will be treated as global variables when the InterpreterModeCustomizerProvider configuration is included in the configuration of the ScriptEngine.
Project: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/commit/566c4889
Tree: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/tree/566c4889
Diff: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/diff/566c4889
Branch: refs/heads/tp31
Commit: 566c4889d05175057ecfa51ebf34cc9aa651b123
Parents: d0005b7
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Thu Feb 18 10:47:28 2016 -0500
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Thu Feb 25 07:40:47 2016 -0500
----------------------------------------------------------------------
CHANGELOG.asciidoc | 1 +
.../jsr223/GremlinVariableAnalyzer.groovy | 104 +++++++++++++++++
.../groovy/jsr223/ast/InterpreterMode.groovy | 30 +++++
.../ast/InterpreterModeASTTransformation.groovy | 115 +++++++++++++++++++
.../jsr223/GremlinGroovyScriptEngine.java | 41 ++++++-
.../InterpreterModeCustomizerProvider.java | 37 ++++++
.../jsr223/GremlinGroovyScriptEngineTest.java | 27 +++++
.../server/GremlinServerIntegrateTest.java | 57 +++++++++
8 files changed, 408 insertions(+), 4 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/566c4889/CHANGELOG.asciidoc
----------------------------------------------------------------------
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 6a57a60..b3a05fe 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -26,6 +26,7 @@ image::https://raw.githubusercontent.com/apache/incubator-tinkerpop/master/docs/
TinkerPop 3.1.2 (NOT OFFICIALLY RELEASED YET)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* Added "interpreter mode" for the `ScriptEngine` and Gremlin Server which allows variables defined with `def` or a type to be recognized as "global".
* Bumped to Apache Groovy 2.4.6.
* Added the `gremlin-archetype-server` archetype that demonstrates
* Added the `gremlin-archetype-tinkergraph` archetype that demonstrates a basic project that uses TinkerGraph.
http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/566c4889/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinVariableAnalyzer.groovy
----------------------------------------------------------------------
diff --git a/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinVariableAnalyzer.groovy b/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinVariableAnalyzer.groovy
new file mode 100644
index 0000000..1d1bcbe
--- /dev/null
+++ b/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinVariableAnalyzer.groovy
@@ -0,0 +1,104 @@
+/*
+ * 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.groovy.jsr223
+
+import org.codehaus.groovy.ast.DynamicVariable
+import org.codehaus.groovy.ast.GroovyClassVisitor
+import org.codehaus.groovy.ast.expr.VariableExpression
+import org.codehaus.groovy.control.CompilationUnit
+import org.codehaus.groovy.control.CompilerConfiguration
+import org.codehaus.groovy.control.Phases
+import org.codehaus.groovy.tools.shell.util.ScriptVariableAnalyzer
+
+import java.security.CodeSource
+
+/**
+ * An extension of Groovy's {@code VariableVisitor} that exposes the bound and unbound variables publicly. This
+ * class can likely be removed with the next update of Groovy (after 2.4.5) as the {code ScriptVariableAnalyzer} ends
+ * up exposing {@code getBoundVars() in such a way as to allow for the {@code ClassLoader} to be supplied.
+ */
+class GremlinVariableAnalyzer {
+ public static class GremlinVariableVisitor extends ScriptVariableAnalyzer.VariableVisitor {
+ String lastBound
+
+ @Override
+ void visitVariableExpression(VariableExpression expression) {
+ if (!(expression.variable in ['args', 'context', 'this', 'super'])) {
+ if (expression.accessedVariable instanceof DynamicVariable) {
+ unbound << expression.variable
+ } else {
+ bound << expression.variable
+ lastBound = bound
+ }
+ }
+ super.visitVariableExpression(expression)
+ }
+
+ @Override
+ public Set<String> getBound() {
+ return super.getBound()
+ }
+
+ @Override
+ public Set<String> getUnbound() {
+ return super.getUnbound()
+ }
+ }
+
+ public static class GremlinVisitorClassLoader extends GroovyClassLoader {
+ private final GroovyClassVisitor visitor
+
+ public GremlinVisitorClassLoader(final GroovyClassVisitor visitor, ClassLoader parent) {
+ super(parent == null ? Thread.currentThread().getContextClassLoader() : parent)
+ this.visitor = visitor
+ }
+
+ @Override
+ protected CompilationUnit createCompilationUnit(final CompilerConfiguration config, final CodeSource source) {
+ CompilationUnit cu = super.createCompilationUnit(config, source)
+ cu.addPhaseOperation(new ScriptVariableAnalyzer.VisitorSourceOperation(visitor), Phases.CLASS_GENERATION)
+ return cu
+ }
+ }
+
+ public static BoundVars getBoundVars(final String scriptText, ClassLoader parent) {
+ assert scriptText != null
+ final GroovyClassVisitor visitor = new GremlinVariableVisitor()
+ new GremlinVisitorClassLoader(visitor, parent).parseClass(scriptText)
+ return new BoundVars(visitor.getLastBound(), visitor.getBound())
+ }
+
+ public static class BoundVars {
+ private String lastBound;
+ private Set<String> bound;
+
+ BoundVars(String lastBound, Set<String> bound) {
+ this.lastBound = lastBound
+ this.bound = bound
+ }
+
+ String getLastBound() {
+ return lastBound
+ }
+
+ Set<String> getBound() {
+ return bound
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/566c4889/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/jsr223/ast/InterpreterMode.groovy
----------------------------------------------------------------------
diff --git a/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/jsr223/ast/InterpreterMode.groovy b/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/jsr223/ast/InterpreterMode.groovy
new file mode 100644
index 0000000..a8da72f
--- /dev/null
+++ b/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/jsr223/ast/InterpreterMode.groovy
@@ -0,0 +1,30 @@
+/*
+ * 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.groovy.jsr223.ast
+
+import org.codehaus.groovy.transform.GroovyASTTransformationClass
+
+import java.lang.annotation.Retention
+import java.lang.annotation.RetentionPolicy
+
+@Retention(RetentionPolicy.SOURCE)
+@GroovyASTTransformationClass(["org.apache.tinkerpop.gremlin.groovy.jsr223.ast.InterpreterModeASTTransformation"])
+public @interface InterpreterMode {
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/566c4889/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/jsr223/ast/InterpreterModeASTTransformation.groovy
----------------------------------------------------------------------
diff --git a/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/jsr223/ast/InterpreterModeASTTransformation.groovy b/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/jsr223/ast/InterpreterModeASTTransformation.groovy
new file mode 100644
index 0000000..66638b8
--- /dev/null
+++ b/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/jsr223/ast/InterpreterModeASTTransformation.groovy
@@ -0,0 +1,115 @@
+/*
+ * 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.groovy.jsr223.ast
+
+import groovy.transform.CompileStatic
+import org.apache.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine
+import org.codehaus.groovy.ast.ASTNode
+import org.codehaus.groovy.ast.ClassHelper
+import org.codehaus.groovy.ast.ClassNode
+import org.codehaus.groovy.ast.MethodNode
+import org.codehaus.groovy.ast.Parameter
+import org.codehaus.groovy.ast.expr.ArgumentListExpression
+import org.codehaus.groovy.ast.expr.BinaryExpression
+import org.codehaus.groovy.ast.expr.ConstantExpression
+import org.codehaus.groovy.ast.expr.DeclarationExpression
+import org.codehaus.groovy.ast.expr.MapExpression
+import org.codehaus.groovy.ast.expr.MethodCallExpression
+import org.codehaus.groovy.ast.expr.VariableExpression
+import org.codehaus.groovy.ast.stmt.BlockStatement
+import org.codehaus.groovy.ast.stmt.CatchStatement
+import org.codehaus.groovy.ast.stmt.EmptyStatement
+import org.codehaus.groovy.ast.stmt.ExpressionStatement
+import org.codehaus.groovy.ast.stmt.Statement
+import org.codehaus.groovy.ast.stmt.TryCatchStatement
+import org.codehaus.groovy.control.CompilePhase
+import org.codehaus.groovy.control.SourceUnit
+import org.codehaus.groovy.syntax.Token
+import org.codehaus.groovy.syntax.Types
+import org.codehaus.groovy.transform.ASTTransformation
+import org.codehaus.groovy.transform.GroovyASTTransformation
+
+/**
+ * An {@code ASTTransformation} that promotes "local" variables to global ones. In this case, "local" refers to those
+ * variables that are defined in a script with "def" at the root of the script. These would typically be interpreted
+ * as local to the script, but this transform changes that, by wrapping the entire script in a try/catch where such
+ * variables are written to a "hidden" {@link Map} so that the {@code ScriptEngine} can later access them to place
+ * them into the global context.
+ */
+@CompileStatic
+@GroovyASTTransformation(phase=CompilePhase.SEMANTIC_ANALYSIS)
+class InterpreterModeASTTransformation implements ASTTransformation {
+
+ @Override
+ void visit(ASTNode[] astNodes, SourceUnit sourceUnit) {
+ ClassNode scriptNode = (ClassNode) astNodes[1]
+ def runMethodOfScript = scriptNode.declaredMethodsMap["java.lang.Object run()"]
+ runMethodOfScript.code = wrap(runMethodOfScript)
+ }
+
+ private static BlockStatement wrap(MethodNode method) {
+ BlockStatement wrappedBlock = new BlockStatement()
+ BlockStatement existingBlock = ((BlockStatement) method.code)
+
+ // the variable names that will be written back to the global context
+ def variableNames = [] as Set<String>
+ variableNames.addAll(findTopLevelVariableDeclarations(existingBlock.statements))
+ method.variableScope.referencedClassVariablesIterator.each{variableNames << it.name}
+
+ // the map to hold the variables and values
+ wrappedBlock.addStatement(createGlobalMapAST())
+
+ // the finally block will capture all the vars in the "globals" map
+ BlockStatement finallyBlock = new BlockStatement()
+ variableNames.each {
+ finallyBlock.addStatement(createAssignToGlobalMapAST(it))
+ }
+
+ wrappedBlock.addStatement(new TryCatchStatement(existingBlock, finallyBlock))
+
+ return wrappedBlock
+ }
+
+ private static List<String> findTopLevelVariableDeclarations(def existingStatements) {
+ existingStatements.findAll{ it instanceof ExpressionStatement }
+ .collect{ ((ExpressionStatement) it).expression }
+ .findAll{ it instanceof DeclarationExpression}
+ .collect{ ((DeclarationExpression) it).leftExpression }
+ .collect{ ((VariableExpression) it).name }
+ }
+
+ private static Statement createAssignToGlobalMapAST(String varName) {
+ def tryCatch = new TryCatchStatement(new ExpressionStatement(
+ new MethodCallExpression(
+ new VariableExpression(GremlinGroovyScriptEngine.COLLECTED_BOUND_VARS_MAP_VARNAME),
+ "put",
+ new ArgumentListExpression(new ConstantExpression(varName), new VariableExpression(varName)))), EmptyStatement.INSTANCE)
+
+ tryCatch.addCatch(new CatchStatement(new Parameter(ClassHelper.make(MissingPropertyException), "ex"), EmptyStatement.INSTANCE))
+ return tryCatch
+ }
+
+ private static Statement createGlobalMapAST() {
+ new ExpressionStatement(
+ new BinaryExpression(
+ new VariableExpression(GremlinGroovyScriptEngine.COLLECTED_BOUND_VARS_MAP_VARNAME),
+ Token.newSymbol(Types.EQUAL, 0, 0),
+ new MapExpression()))
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/566c4889/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngine.java
----------------------------------------------------------------------
diff --git a/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngine.java b/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngine.java
index 72e38c3..23240cb 100644
--- a/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngine.java
+++ b/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngine.java
@@ -23,6 +23,7 @@ import org.apache.tinkerpop.gremlin.groovy.DefaultImportCustomizerProvider;
import org.apache.tinkerpop.gremlin.groovy.EmptyImportCustomizerProvider;
import org.apache.tinkerpop.gremlin.groovy.ImportCustomizerProvider;
import org.apache.tinkerpop.gremlin.groovy.NoImportCustomizerProvider;
+import org.apache.tinkerpop.gremlin.groovy.jsr223.customizer.InterpreterModeCustomizerProvider;
import org.apache.tinkerpop.gremlin.groovy.loaders.GremlinLoader;
import org.apache.tinkerpop.gremlin.groovy.plugin.Artifact;
import org.apache.tinkerpop.gremlin.groovy.plugin.GremlinPlugin;
@@ -125,6 +126,12 @@ public class GremlinGroovyScriptEngine extends GroovyScriptEngineImpl implements
*/
public static final String REFERENCE_TYPE_HARD = "hard";
+ /**
+ * Name of variable that holds local variables to be globally bound if "interpreter mode" is enabled with
+ * {@link InterpreterModeCustomizerProvider}.
+ */
+ public static final String COLLECTED_BOUND_VARS_MAP_VARNAME = "gremlin_script_engine_collected_boundvars";
+
private static final Pattern patternImportStatic = Pattern.compile("\\Aimport\\sstatic.*");
public static final ThreadLocal<Map<String, Object>> COMPILE_OPTIONS = new ThreadLocal<Map<String, Object>>(){
@@ -146,7 +153,7 @@ public class GremlinGroovyScriptEngine extends GroovyScriptEngineImpl implements
private GremlinGroovyClassLoader loader;
- private AtomicLong counter = new AtomicLong(0l);
+ private AtomicLong counter = new AtomicLong(0L);
/**
* The list of loaded plugins for the console.
@@ -164,6 +171,7 @@ public class GremlinGroovyScriptEngine extends GroovyScriptEngineImpl implements
private final List<CompilerCustomizerProvider> customizerProviders;
private final Set<Artifact> artifactsToUse = new HashSet<>();
+ private final boolean interpreterModeEnabled;
/**
* Creates a new instance using the {@link DefaultImportCustomizerProvider}.
@@ -193,9 +201,14 @@ public class GremlinGroovyScriptEngine extends GroovyScriptEngineImpl implements
.map(p -> (ImportCustomizerProvider) p)
.findFirst().orElse(NoImportCustomizerProvider.INSTANCE);
+ // determine if interpreter mode should be enabled
+ interpreterModeEnabled = providers.stream()
+ .anyMatch(p -> p.getClass().equals(InterpreterModeCustomizerProvider.class));
+
// remove used providers as the rest will be applied directly
customizerProviders = providers.stream()
- .filter(p -> p != null && !(p instanceof ImportCustomizerProvider))
+ .filter(p -> p != null &&
+ !((p instanceof ImportCustomizerProvider)))
.collect(Collectors.toList());
createClassLoader();
@@ -531,7 +544,28 @@ public class GremlinGroovyScriptEngine extends GroovyScriptEngineImpl implements
}
}
});
- return scriptObject.run();
+
+ final Object o = scriptObject.run();
+
+ // if interpreter mode is enable then local vars of the script are promoted to engine scope bindings.
+ if (interpreterModeEnabled) {
+ final Map<String, Object> localVars = (Map<String, Object>) context.getAttribute(COLLECTED_BOUND_VARS_MAP_VARNAME);
+ if (localVars != null) {
+ localVars.entrySet().forEach(e -> {
+ // closures need to be cached for later use
+ if (e.getValue() instanceof Closure)
+ globalClosures.put(e.getKey(), (Closure) e.getValue());
+
+ context.setAttribute(e.getKey(), e.getValue(), ScriptContext.ENGINE_SCOPE);
+ });
+
+ // get rid of the temporary collected vars
+ context.removeAttribute(COLLECTED_BOUND_VARS_MAP_VARNAME, ScriptContext.ENGINE_SCOPE);
+ localVars.clear();
+ }
+ }
+
+ return o;
} catch (Exception e) {
throw new ScriptException(e);
}
@@ -642,5 +676,4 @@ public class GremlinGroovyScriptEngine extends GroovyScriptEngineImpl implements
}
return buf.toString();
}
-
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/566c4889/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/customizer/InterpreterModeCustomizerProvider.java
----------------------------------------------------------------------
diff --git a/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/customizer/InterpreterModeCustomizerProvider.java b/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/customizer/InterpreterModeCustomizerProvider.java
new file mode 100644
index 0000000..e3f95f4
--- /dev/null
+++ b/gremlin-groovy/src/main/java/org/apache/tinkerpop/gremlin/groovy/jsr223/customizer/InterpreterModeCustomizerProvider.java
@@ -0,0 +1,37 @@
+/*
+ * 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.groovy.jsr223.customizer;
+
+import org.apache.tinkerpop.gremlin.groovy.CompilerCustomizerProvider;
+import org.apache.tinkerpop.gremlin.groovy.jsr223.ast.InterpreterMode;
+import org.codehaus.groovy.control.customizers.ASTTransformationCustomizer;
+import org.codehaus.groovy.control.customizers.CompilationCustomizer;
+
+/**
+ * Places the {@code ScriptEngine} in "interpreter mode" where local variables of a script are treated as global
+ * bindings. This implementation is technically not a true {@link CompilerCustomizerProvider} instance as the
+ * "interpreter mode" feature does not require a {@code CompilerCustomizer}. This class merely acts as a flag that
+ * tells the {@link org.apache.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine} to turn this feature on.
+ */
+public class InterpreterModeCustomizerProvider implements CompilerCustomizerProvider {
+ @Override
+ public CompilationCustomizer create() {
+ return new ASTTransformationCustomizer(InterpreterMode.class);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/566c4889/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineTest.java
----------------------------------------------------------------------
diff --git a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineTest.java b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineTest.java
index 4740cd2..17cd809 100644
--- a/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineTest.java
+++ b/gremlin-groovy/src/test/java/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinGroovyScriptEngineTest.java
@@ -22,6 +22,7 @@ import groovy.lang.Closure;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.apache.tinkerpop.gremlin.groovy.CompilerCustomizerProvider;
import org.apache.tinkerpop.gremlin.groovy.NoImportCustomizerProvider;
+import org.apache.tinkerpop.gremlin.groovy.jsr223.customizer.InterpreterModeCustomizerProvider;
import org.apache.tinkerpop.gremlin.structure.Vertex;
import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
import org.javatuples.Pair;
@@ -85,7 +86,33 @@ public class GremlinGroovyScriptEngineTest {
@Test
public void shouldEvalWithNoBindings() throws Exception {
final GremlinGroovyScriptEngine engine = new GremlinGroovyScriptEngine();
+ engine.eval("def addItUp(x,y){x+y}");
assertEquals(3, engine.eval("1+2"));
+ assertEquals(3, engine.eval("addItUp(1,2)"));
+ }
+
+ @Test
+ public void shouldPromoteDefinedVarsInInterpreterModeWithNoBindings() throws Exception {
+ final GremlinGroovyScriptEngine engine = new GremlinGroovyScriptEngine(new InterpreterModeCustomizerProvider());
+ engine.eval("def addItUp = { x, y -> x + y }");
+ assertEquals(3, engine.eval("int xxx = 1 + 2"));
+ assertEquals(4, engine.eval("yyy = xxx + 1"));
+ assertEquals(7, engine.eval("def zzz = yyy + xxx"));
+ assertEquals(4, engine.eval("zzz - xxx"));
+ assertEquals(10, engine.eval("addItUp(zzz,xxx)"));
+ }
+
+ @Test
+ public void shouldPromoteDefinedVarsInInterpreterModeWithBindings() throws Exception {
+ final GremlinGroovyScriptEngine engine = new GremlinGroovyScriptEngine(new InterpreterModeCustomizerProvider());
+ final Bindings b = new SimpleBindings();
+ b.put("x", 2);
+ engine.eval("def addItUp = { x, y -> x + y }", b);
+ assertEquals(3, engine.eval("int xxx = 1 + x", b));
+ assertEquals(4, engine.eval("yyy = xxx + 1", b));
+ assertEquals(7, engine.eval("def zzz = yyy + xxx", b));
+ assertEquals(4, engine.eval("zzz - xxx", b));
+ assertEquals(10, engine.eval("addItUp(zzz,xxx)", b));
}
@Test
http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/566c4889/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java
----------------------------------------------------------------------
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java
index 7714a93..61c1a98 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerIntegrateTest.java
@@ -32,6 +32,7 @@ import org.apache.tinkerpop.gremlin.driver.simple.SimpleClient;
import org.apache.tinkerpop.gremlin.driver.simple.WebSocketClient;
import org.apache.tinkerpop.gremlin.groovy.jsr223.GremlinGroovyScriptEngine;
import org.apache.tinkerpop.gremlin.groovy.jsr223.customizer.CompileStaticCustomizerProvider;
+import org.apache.tinkerpop.gremlin.groovy.jsr223.customizer.InterpreterModeCustomizerProvider;
import org.apache.tinkerpop.gremlin.groovy.jsr223.customizer.SimpleSandboxExtension;
import org.apache.tinkerpop.gremlin.groovy.jsr223.customizer.TimedInterruptCustomizerProvider;
import org.apache.tinkerpop.gremlin.structure.T;
@@ -45,6 +46,7 @@ import org.junit.Test;
import java.nio.channels.ClosedChannelException;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -136,6 +138,9 @@ public class GremlinServerIntegrateTest extends AbstractGremlinServerIntegration
case "shouldUseSimpleSandbox":
settings.scriptEngines.get("gremlin-groovy").config = getScriptEngineConfForSimpleSandbox();
break;
+ case "shouldUseInterpreterMode":
+ settings.scriptEngines.get("gremlin-groovy").config = getScriptEngineConfForInterpreterMode();
+ break;
case "shouldReceiveFailureTimeOutOnScriptEvalOfOutOfControlLoop":
settings.scriptEngines.get("gremlin-groovy").config = getScriptEngineConfForTimedInterrupt();
break;
@@ -164,6 +169,58 @@ public class GremlinServerIntegrateTest extends AbstractGremlinServerIntegration
return scriptEngineConf;
}
+ private static Map<String, Object> getScriptEngineConfForInterpreterMode() {
+ final Map<String,Object> scriptEngineConf = new HashMap<>();
+ final Map<String,Object> interpreterProviderConf = new HashMap<>();
+ interpreterProviderConf.put(InterpreterModeCustomizerProvider.class.getName(), Collections.EMPTY_LIST);
+ scriptEngineConf.put("compilerCustomizerProviders", interpreterProviderConf);
+ return scriptEngineConf;
+ }
+
+ @Test
+ public void shouldUseInterpreterMode() throws Exception {
+ final Cluster cluster = Cluster.open();
+ final Client client = cluster.connect(name.getMethodName());
+
+ client.submit("def subtractAway(x,y){x-y};[]").all().get();
+ client.submit("multiplyIt = { x,y -> x * y};[]").all().get();
+
+ assertEquals(2, client.submit("x = 1 + 1").all().get().get(0).getInt());
+ assertEquals(3, client.submit("int y = x + 1").all().get().get(0).getInt());
+ assertEquals(5, client.submit("def z = x + y").all().get().get(0).getInt());
+
+ final Map<String,Object> m = new HashMap<>();
+ m.put("x", 10);
+ assertEquals(-5, client.submit("z - x", m).all().get().get(0).getInt());
+ assertEquals(15, client.submit("addItUp(x,z)", m).all().get().get(0).getInt());
+ assertEquals(5, client.submit("subtractAway(x,z)", m).all().get().get(0).getInt());
+ assertEquals(50, client.submit("multiplyIt(x,z)", m).all().get().get(0).getInt());
+
+ cluster.close();
+ }
+
+ @Test
+ public void shouldNotUseInterpreterMode() throws Exception {
+ final Cluster cluster = Cluster.open();
+ final Client client = cluster.connect(name.getMethodName());
+
+ client.submit("def subtractAway(x,y){x-y};[]").all().get();
+ client.submit("multiplyIt = { x,y -> x * y};[]").all().get();
+
+ assertEquals(2, client.submit("x = 1 + 1").all().get().get(0).getInt());
+ assertEquals(3, client.submit("y = x + 1").all().get().get(0).getInt());
+ assertEquals(5, client.submit("z = x + y").all().get().get(0).getInt());
+
+ final Map<String,Object> m = new HashMap<>();
+ m.put("x", 10);
+ assertEquals(-5, client.submit("z - x", m).all().get().get(0).getInt());
+ assertEquals(15, client.submit("addItUp(x,z)", m).all().get().get(0).getInt());
+ assertEquals(5, client.submit("subtractAway(x,z)", m).all().get().get(0).getInt());
+ assertEquals(50, client.submit("multiplyIt(x,z)", m).all().get().get(0).getInt());
+
+ cluster.close();
+ }
+
@Test
public void shouldUseSimpleSandbox() throws Exception {
final Cluster cluster = Cluster.open();
[3/4] incubator-tinkerpop git commit: With the bump to groovy 2.4.6
this class is no longer needed.
Posted by sp...@apache.org.
With the bump to groovy 2.4.6 this class is no longer needed.
Project: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/commit/3447b02d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/tree/3447b02d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/diff/3447b02d
Branch: refs/heads/tp31
Commit: 3447b02dc2220161bd191b482e95ad709d6571e5
Parents: 73489b3
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Thu Feb 25 09:05:36 2016 -0500
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Thu Feb 25 09:05:36 2016 -0500
----------------------------------------------------------------------
.../jsr223/GremlinVariableAnalyzer.groovy | 104 -------------------
1 file changed, 104 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/3447b02d/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinVariableAnalyzer.groovy
----------------------------------------------------------------------
diff --git a/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinVariableAnalyzer.groovy b/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinVariableAnalyzer.groovy
deleted file mode 100644
index 1d1bcbe..0000000
--- a/gremlin-groovy/src/main/groovy/org/apache/tinkerpop/gremlin/groovy/jsr223/GremlinVariableAnalyzer.groovy
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * 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.groovy.jsr223
-
-import org.codehaus.groovy.ast.DynamicVariable
-import org.codehaus.groovy.ast.GroovyClassVisitor
-import org.codehaus.groovy.ast.expr.VariableExpression
-import org.codehaus.groovy.control.CompilationUnit
-import org.codehaus.groovy.control.CompilerConfiguration
-import org.codehaus.groovy.control.Phases
-import org.codehaus.groovy.tools.shell.util.ScriptVariableAnalyzer
-
-import java.security.CodeSource
-
-/**
- * An extension of Groovy's {@code VariableVisitor} that exposes the bound and unbound variables publicly. This
- * class can likely be removed with the next update of Groovy (after 2.4.5) as the {code ScriptVariableAnalyzer} ends
- * up exposing {@code getBoundVars() in such a way as to allow for the {@code ClassLoader} to be supplied.
- */
-class GremlinVariableAnalyzer {
- public static class GremlinVariableVisitor extends ScriptVariableAnalyzer.VariableVisitor {
- String lastBound
-
- @Override
- void visitVariableExpression(VariableExpression expression) {
- if (!(expression.variable in ['args', 'context', 'this', 'super'])) {
- if (expression.accessedVariable instanceof DynamicVariable) {
- unbound << expression.variable
- } else {
- bound << expression.variable
- lastBound = bound
- }
- }
- super.visitVariableExpression(expression)
- }
-
- @Override
- public Set<String> getBound() {
- return super.getBound()
- }
-
- @Override
- public Set<String> getUnbound() {
- return super.getUnbound()
- }
- }
-
- public static class GremlinVisitorClassLoader extends GroovyClassLoader {
- private final GroovyClassVisitor visitor
-
- public GremlinVisitorClassLoader(final GroovyClassVisitor visitor, ClassLoader parent) {
- super(parent == null ? Thread.currentThread().getContextClassLoader() : parent)
- this.visitor = visitor
- }
-
- @Override
- protected CompilationUnit createCompilationUnit(final CompilerConfiguration config, final CodeSource source) {
- CompilationUnit cu = super.createCompilationUnit(config, source)
- cu.addPhaseOperation(new ScriptVariableAnalyzer.VisitorSourceOperation(visitor), Phases.CLASS_GENERATION)
- return cu
- }
- }
-
- public static BoundVars getBoundVars(final String scriptText, ClassLoader parent) {
- assert scriptText != null
- final GroovyClassVisitor visitor = new GremlinVariableVisitor()
- new GremlinVisitorClassLoader(visitor, parent).parseClass(scriptText)
- return new BoundVars(visitor.getLastBound(), visitor.getBound())
- }
-
- public static class BoundVars {
- private String lastBound;
- private Set<String> bound;
-
- BoundVars(String lastBound, Set<String> bound) {
- this.lastBound = lastBound
- this.bound = bound
- }
-
- String getLastBound() {
- return lastBound
- }
-
- Set<String> getBound() {
- return bound
- }
- }
-}
[4/4] incubator-tinkerpop git commit: Merge remote-tracking branch
'origin/TINKERPOP-1107' into tp31
Posted by sp...@apache.org.
Merge remote-tracking branch 'origin/TINKERPOP-1107' into tp31
Project: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/commit/959378ca
Tree: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/tree/959378ca
Diff: http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/diff/959378ca
Branch: refs/heads/tp31
Commit: 959378ca8820ebb148e314a1fc99dabdae34cb5b
Parents: d83dba4 3447b02
Author: Stephen Mallette <sp...@genoprime.com>
Authored: Fri Feb 26 14:22:21 2016 -0500
Committer: Stephen Mallette <sp...@genoprime.com>
Committed: Fri Feb 26 14:22:21 2016 -0500
----------------------------------------------------------------------
CHANGELOG.asciidoc | 1 +
.../groovy/jsr223/ast/InterpreterMode.groovy | 30 +++++
.../ast/InterpreterModeASTTransformation.groovy | 115 +++++++++++++++++++
.../jsr223/GremlinGroovyScriptEngine.java | 41 ++++++-
.../InterpreterModeCustomizerProvider.java | 37 ++++++
.../jsr223/GremlinGroovyScriptEngineTest.java | 52 +++++++++
.../server/GremlinServerIntegrateTest.java | 57 +++++++++
7 files changed, 329 insertions(+), 4 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-tinkerpop/blob/959378ca/CHANGELOG.asciidoc
----------------------------------------------------------------------