Repository: tinkerpop Updated Branches: refs/heads/TINKERPOP-1489 1f00b7c9f -> 468bba639
TINKERPOP-1489 Added Nashorn ScriptEngine to gremlin-javascript Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/468bba63 Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/468bba63 Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/468bba63 Branch: refs/heads/TINKERPOP-1489 Commit: 468bba6393b26e12fc314eda270b93ec12503dc8 Parents: 1f00b7c Author: Stephen Mallette <[email protected]> Authored: Tue Sep 5 12:36:12 2017 -0400 Committer: Stephen Mallette <[email protected]> Committed: Tue Sep 5 12:36:12 2017 -0400 ---------------------------------------------------------------------- .../jsr223/GremlinJavaScriptScriptEngine.java | 170 ++++++++++++++ .../GremlinJavaScriptScriptEngineFactory.java | 60 +++++ .../javascript/jsr223/JavaScriptTranslator.java | 220 +++++++++++++++++++ .../gremlin/javascript/jsr223/SymbolHelper.java | 51 +++++ .../javascript/gremlin-javascript/package.json | 2 +- ...op.gremlin.jsr223.GremlinScriptEngineFactory | 1 + .../JavaScriptGremlinScriptEngineTest.java | 31 +++ .../src/test/resources/log4j-silent.properties | 23 ++ .../src/test/resources/log4j-test.properties | 23 ++ .../jsr223/BindingsScriptEngineTest.java | 4 +- .../jsr223/GremlinEnabledScriptEngineTest.java | 15 +- .../gremlin/jsr223/ScriptEngineLambdaTest.java | 8 +- 12 files changed, 599 insertions(+), 9 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/468bba63/gremlin-javascript/src/main/java/org/apache/tinkerpop/gremlin/javascript/jsr223/GremlinJavaScriptScriptEngine.java ---------------------------------------------------------------------- diff --git a/gremlin-javascript/src/main/java/org/apache/tinkerpop/gremlin/javascript/jsr223/GremlinJavaScriptScriptEngine.java b/gremlin-javascript/src/main/java/org/apache/tinkerpop/gremlin/javascript/jsr223/GremlinJavaScriptScriptEngine.java new file mode 100644 index 0000000..4268e2a --- /dev/null +++ b/gremlin-javascript/src/main/java/org/apache/tinkerpop/gremlin/javascript/jsr223/GremlinJavaScriptScriptEngine.java @@ -0,0 +1,170 @@ +/* + * 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.javascript.jsr223; + +import jdk.nashorn.api.scripting.NashornScriptEngine; +import jdk.nashorn.api.scripting.NashornScriptEngineFactory; +import org.apache.tinkerpop.gremlin.jsr223.CoreGremlinPlugin; +import org.apache.tinkerpop.gremlin.jsr223.Customizer; +import org.apache.tinkerpop.gremlin.jsr223.GremlinScriptEngine; +import org.apache.tinkerpop.gremlin.jsr223.GremlinScriptEngineFactory; +import org.apache.tinkerpop.gremlin.jsr223.ImportCustomizer; +import org.apache.tinkerpop.gremlin.process.traversal.Bytecode; +import org.apache.tinkerpop.gremlin.process.traversal.Traversal; +import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource; + +import javax.script.Bindings; +import javax.script.ScriptContext; +import javax.script.ScriptException; +import java.io.Reader; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * @author Stephen Mallette (http://stephen.genoprime.com) + */ +public class GremlinJavaScriptScriptEngine implements GremlinScriptEngine { + + private final NashornScriptEngine scriptEngine; + + public GremlinJavaScriptScriptEngine(final Customizer... customizers) { + this.scriptEngine = (NashornScriptEngine) new NashornScriptEngineFactory().getScriptEngine(); + final List<Customizer> listOfCustomizers = new ArrayList<>(Arrays.asList(customizers)); + + // always need this plugin for a scriptengine to be "Gremlin-enabled" + CoreGremlinPlugin.instance().getCustomizers("gremlin-javascript").ifPresent(c -> listOfCustomizers.addAll(Arrays.asList(c))); + + final List<ImportCustomizer> importCustomizers = listOfCustomizers.stream() + .filter(p -> p instanceof ImportCustomizer) + .map(p -> (ImportCustomizer) p) + .collect(Collectors.toList()); + + try { + for (ImportCustomizer ic : importCustomizers) { + for (Class<?> c : ic.getClassImports()) { + if (null == c.getDeclaringClass()) + this.scriptEngine.eval(c.getSimpleName() + " = Java.type(\"" + c.getName() + "\")"); + else + this.scriptEngine.eval(c.getSimpleName() + " = Java.type(\"" + c.getDeclaringClass().getName() + "\")"); + } + + for (Method m : ic.getMethodImports()) { + this.scriptEngine.eval(SymbolHelper.toJavaScript(m.getName()) + " = Java.type(\"" + m.getDeclaringClass().getName() + "\")." + m.getName()); + } + + // enums need to import after methods for some reason or else label comes in as a PyReflectedFunction + for (Enum e : ic.getEnumImports()) { + this.scriptEngine.eval(SymbolHelper.toJavaScript(e.name()) + " = Java.type(\"" + e.getDeclaringClass().getName() + "\")." + e.name()); + } + } + + } catch (Exception ex) { + throw new IllegalStateException(ex); + } + } + + @Override + public Traversal.Admin eval(final Bytecode bytecode, final Bindings bindings) throws ScriptException { + bindings.putAll(bytecode.getBindings()); + String traversalSource = "g"; + for (final Map.Entry<String, Object> entry : bindings.entrySet()) { + if (entry.getValue() instanceof TraversalSource) { + traversalSource = entry.getKey(); + break; + } + } + return (Traversal.Admin) this.eval(JavaScriptTranslator.of(traversalSource).translate(bytecode), bindings); + } + + @Override + public Object eval(final String script, final ScriptContext context) throws ScriptException { + return this.scriptEngine.eval(script, context); + } + + @Override + public Object eval(final Reader reader, final ScriptContext context) throws ScriptException { + return this.scriptEngine.eval(reader, context); + } + + @Override + public Object eval(final String script) throws ScriptException { + return this.scriptEngine.eval(script); + } + + @Override + public Object eval(final Reader reader) throws ScriptException { + return this.scriptEngine.eval(reader); + } + + @Override + public Object eval(final String script, final Bindings n) throws ScriptException { + this.scriptEngine.getBindings(ScriptContext.ENGINE_SCOPE).putAll(n); // TODO: groovy and jython act different + return this.scriptEngine.eval(script); + } + + @Override + public Object eval(final Reader reader, final Bindings n) throws ScriptException { + this.scriptEngine.getBindings(ScriptContext.ENGINE_SCOPE).putAll(n); // TODO: groovy and jython act different + return this.scriptEngine.eval(reader); + } + + @Override + public void put(final String key, final Object value) { + this.scriptEngine.put(key, value); + } + + @Override + public Object get(final String key) { + return this.scriptEngine.get(key); + } + + @Override + public Bindings getBindings(final int scope) { + return this.scriptEngine.getBindings(scope); + } + + @Override + public void setBindings(final Bindings bindings, final int scope) { + this.scriptEngine.setBindings(bindings, scope); + } + + @Override + public Bindings createBindings() { + return this.scriptEngine.createBindings(); + } + + @Override + public ScriptContext getContext() { + return this.scriptEngine.getContext(); + } + + @Override + public void setContext(final ScriptContext context) { + this.scriptEngine.setContext(context); + } + + @Override + public GremlinScriptEngineFactory getFactory() { + return new GremlinJavaScriptScriptEngineFactory(); + } +} http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/468bba63/gremlin-javascript/src/main/java/org/apache/tinkerpop/gremlin/javascript/jsr223/GremlinJavaScriptScriptEngineFactory.java ---------------------------------------------------------------------- diff --git a/gremlin-javascript/src/main/java/org/apache/tinkerpop/gremlin/javascript/jsr223/GremlinJavaScriptScriptEngineFactory.java b/gremlin-javascript/src/main/java/org/apache/tinkerpop/gremlin/javascript/jsr223/GremlinJavaScriptScriptEngineFactory.java new file mode 100644 index 0000000..f1309be --- /dev/null +++ b/gremlin-javascript/src/main/java/org/apache/tinkerpop/gremlin/javascript/jsr223/GremlinJavaScriptScriptEngineFactory.java @@ -0,0 +1,60 @@ +/* + * 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.javascript.jsr223; + +import org.apache.tinkerpop.gremlin.jsr223.AbstractGremlinScriptEngineFactory; +import org.apache.tinkerpop.gremlin.jsr223.Customizer; +import org.apache.tinkerpop.gremlin.jsr223.GremlinScriptEngine; +import org.apache.tinkerpop.gremlin.jsr223.GremlinScriptEngineFactory; + +import java.util.Collections; +import java.util.List; + +/** + * A {@link GremlinScriptEngineFactory} implementation that creates {@link GremlinJavaScriptScriptEngine} instances. + * + * @author Stephen Mallette (http://stephen.genoprime.com) + */ +public class GremlinJavaScriptScriptEngineFactory extends AbstractGremlinScriptEngineFactory { + private static final String ENGINE_NAME = "gremlin-javascript"; + private static final String LANGUAGE_NAME = "gremlin-javascript"; + private static final String PLAIN = "plain"; + private static final List<String> EXTENSIONS = Collections.singletonList("js"); + + public GremlinJavaScriptScriptEngineFactory() { + super(ENGINE_NAME, LANGUAGE_NAME, EXTENSIONS, Collections.singletonList(PLAIN)); + } + + @Override + public String getMethodCallSyntax(final String obj, final String m, final String... args) { + return null; + } + + @Override + public String getOutputStatement(final String toDisplay) { + return "println " + toDisplay; + } + + @Override + public GremlinScriptEngine getScriptEngine() { + final List<Customizer> customizers = manager.getCustomizers(ENGINE_NAME); + return (customizers.isEmpty()) ? new GremlinJavaScriptScriptEngine() : + new GremlinJavaScriptScriptEngine(customizers.toArray(new Customizer[customizers.size()])); + } +} http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/468bba63/gremlin-javascript/src/main/java/org/apache/tinkerpop/gremlin/javascript/jsr223/JavaScriptTranslator.java ---------------------------------------------------------------------- diff --git a/gremlin-javascript/src/main/java/org/apache/tinkerpop/gremlin/javascript/jsr223/JavaScriptTranslator.java b/gremlin-javascript/src/main/java/org/apache/tinkerpop/gremlin/javascript/jsr223/JavaScriptTranslator.java new file mode 100644 index 0000000..aeafd6e --- /dev/null +++ b/gremlin-javascript/src/main/java/org/apache/tinkerpop/gremlin/javascript/jsr223/JavaScriptTranslator.java @@ -0,0 +1,220 @@ +/* + * 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.javascript.jsr223; + +import org.apache.commons.configuration.ConfigurationConverter; +import org.apache.tinkerpop.gremlin.process.traversal.Bytecode; +import org.apache.tinkerpop.gremlin.process.traversal.Operator; +import org.apache.tinkerpop.gremlin.process.traversal.P; +import org.apache.tinkerpop.gremlin.process.traversal.SackFunctions; +import org.apache.tinkerpop.gremlin.process.traversal.Translator; +import org.apache.tinkerpop.gremlin.process.traversal.Traversal; +import org.apache.tinkerpop.gremlin.process.traversal.TraversalSource; +import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; +import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalOptionParent; +import org.apache.tinkerpop.gremlin.process.traversal.strategy.TraversalStrategyProxy; +import org.apache.tinkerpop.gremlin.process.traversal.util.ConnectiveP; +import org.apache.tinkerpop.gremlin.process.traversal.util.OrP; +import org.apache.tinkerpop.gremlin.structure.Element; +import org.apache.tinkerpop.gremlin.structure.T; +import org.apache.tinkerpop.gremlin.structure.VertexProperty; +import org.apache.tinkerpop.gremlin.structure.util.StringFactory; +import org.apache.tinkerpop.gremlin.util.function.Lambda; +import org.apache.tinkerpop.gremlin.util.iterator.ArrayIterator; +import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * @author Stephen Mallette (http://stephen.genoprime.com) + */ +public class JavaScriptTranslator implements Translator.ScriptTranslator { + + private static final boolean IS_TESTING = Boolean.valueOf(System.getProperty("is.testing", "false")); + private static final Set<String> STEP_NAMES = Stream.of(GraphTraversal.class.getMethods()).filter(method -> Traversal.class.isAssignableFrom(method.getReturnType())).map(Method::getName).collect(Collectors.toSet()); + private static final Set<String> NO_STATIC = Stream.of(T.values(), Operator.values()) + .flatMap(arg -> IteratorUtils.stream(new ArrayIterator<>(arg))) + .map(arg -> ((Enum) arg).name()) + .collect(Collectors.toCollection(() -> new HashSet<>(Collections.singleton("not")))); + + private final String traversalSource; + private final boolean importStatics; + + JavaScriptTranslator(final String traversalSource, final boolean importStatics) { + this.traversalSource = traversalSource; + this.importStatics = importStatics; + } + + public static JavaScriptTranslator of(final String traversalSource, final boolean importStatics) { + return new JavaScriptTranslator(traversalSource, importStatics); + } + + public static JavaScriptTranslator of(final String traversalSource) { + return new JavaScriptTranslator(traversalSource, false); + } + + @Override + public String getTraversalSource() { + return this.traversalSource; + } + + @Override + public String translate(final Bytecode bytecode) { + return this.internalTranslate(this.traversalSource, bytecode); + } + + @Override + public String getTargetLanguage() { + return "gremlin-python"; + } + + @Override + public String toString() { + return StringFactory.translatorString(this); + } + + /////// + + private String internalTranslate(final String start, final Bytecode bytecode) { + final StringBuilder traversalScript = new StringBuilder(start); + for (final Bytecode.Instruction instruction : bytecode.getInstructions()) { + final String methodName = instruction.getOperator(); + final Object[] arguments = instruction.getArguments(); + if (IS_TESTING && + instruction.getOperator().equals(TraversalSource.Symbols.withStrategies) && + instruction.getArguments()[0].toString().contains("TranslationStrategy")) + continue; + else if (0 == arguments.length) + traversalScript.append(".").append(SymbolHelper.toJavaScript(methodName)).append("()"); + else if (methodName.equals("values") && 1 == arguments.length && traversalScript.length() > 3 && !STEP_NAMES.contains(arguments[0].toString())) + traversalScript.append(".").append(arguments[0]); + else { + traversalScript.append("."); + String temp = SymbolHelper.toJavaScript(methodName) + "("; + for (final Object object : arguments) { + temp = temp + convertToString(object) + ","; + } + traversalScript.append(temp.substring(0, temp.length() - 1)).append(")"); + } + // clip off __. + if (this.importStatics && traversalScript.substring(0, 3).startsWith("__.") + && !NO_STATIC.stream().filter(name -> traversalScript.substring(3).startsWith(SymbolHelper.toJavaScript(name))).findAny().isPresent()) { + traversalScript.delete(0, 3); + } + } + return traversalScript.toString(); + } + + private String convertToString(final Object object) { + if (object instanceof Bytecode.Binding) + return ((Bytecode.Binding) object).variable(); + else if (object instanceof Bytecode) + return this.internalTranslate("__", (Bytecode) object); + else if (object instanceof Traversal) + return convertToString(((Traversal) object).asAdmin().getBytecode()); + else if (object instanceof String) + return ((String) object).contains("\"") ? "\"\"\"" + object + "\"\"\"" : "\"" + object + "\""; + else if (object instanceof Set) { + final Set<String> set = new LinkedHashSet<>(((Set) object).size()); + for (final Object item : (Set) object) { + set.add(convertToString(item)); + } + return "new Set(" + set.toString() + ")"; // supported in ECMA Script 6 and JDK 9 + } else if (object instanceof List) { + final List<String> list = new ArrayList<>(((List) object).size()); + for (final Object item : (List) object) { + list.add(convertToString(item)); + } + return list.toString(); + } else if (object instanceof Map) { + final StringBuilder map = new StringBuilder("{"); + for (final Map.Entry<?, ?> entry : ((Map<?, ?>) object).entrySet()) { + map.append(convertToString(entry.getKey())). + append(":"). + append(convertToString(entry.getValue())). + append(","); + } + return map.length() > 1 ? map.substring(0, map.length() - 1) + "}" : map.append("}").toString(); + } else if (object instanceof Long) + return object + "L"; + else if (object instanceof TraversalStrategyProxy) { + final TraversalStrategyProxy proxy = (TraversalStrategyProxy) object; + if (proxy.getConfiguration().isEmpty()) + return "TraversalStrategy(\"" + proxy.getStrategyClass().getSimpleName() + "\")"; + else + return "TraversalStrategy(\"" + proxy.getStrategyClass().getSimpleName() + "\"," + convertToString(ConfigurationConverter.getMap(proxy.getConfiguration())) + ")"; + } else if (object instanceof TraversalStrategy) { + return convertToString(new TraversalStrategyProxy((TraversalStrategy) object)); + } else if (object instanceof Boolean) + return object.equals(Boolean.TRUE) ? "true" : "false"; + else if (object instanceof Class) + return ((Class) object).getCanonicalName(); + else if (object instanceof VertexProperty.Cardinality) + return "Cardinality." + SymbolHelper.toJavaScript(object.toString()); + else if (object instanceof SackFunctions.Barrier) + return "Barrier." + SymbolHelper.toJavaScript(object.toString()); + else if (object instanceof TraversalOptionParent.Pick) + return "Pick." + SymbolHelper.toJavaScript(object.toString()); + else if (object instanceof Enum) + return convertStatic(((Enum) object).getDeclaringClass().getSimpleName() + ".") + SymbolHelper.toJavaScript(object.toString()); + else if (object instanceof P) + return convertPToString((P) object, new StringBuilder()).toString(); + else if (object instanceof Element) + return convertToString(((Element) object).id()); // hack + else if (object instanceof Lambda) + return convertLambdaToString((Lambda) object); + else + return null == object ? "undefined" : object.toString(); + } + + private String convertStatic(final String name) { + return this.importStatics ? "" : name; + } + + private StringBuilder convertPToString(final P p, final StringBuilder current) { + if (p instanceof ConnectiveP) { + final List<P<?>> list = ((ConnectiveP) p).getPredicates(); + for (int i = 0; i < list.size(); i++) { + convertPToString(list.get(i), current); + if (i < list.size() - 1) + current.append(p instanceof OrP ? ".or(" : ".and("); + } + current.append(")"); + } else + current.append(convertStatic("P.")).append(p.getBiPredicate().toString()).append("(").append(convertToString(p.getValue())).append(")"); + return current; + } + + protected String convertLambdaToString(final Lambda lambda) { + final String lambdaString = lambda.getLambdaScript().trim(); + return lambdaString.startsWith("lambda") ? lambdaString : "lambda " + lambdaString; + } + +} http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/468bba63/gremlin-javascript/src/main/java/org/apache/tinkerpop/gremlin/javascript/jsr223/SymbolHelper.java ---------------------------------------------------------------------- diff --git a/gremlin-javascript/src/main/java/org/apache/tinkerpop/gremlin/javascript/jsr223/SymbolHelper.java b/gremlin-javascript/src/main/java/org/apache/tinkerpop/gremlin/javascript/jsr223/SymbolHelper.java new file mode 100644 index 0000000..204ec4b --- /dev/null +++ b/gremlin-javascript/src/main/java/org/apache/tinkerpop/gremlin/javascript/jsr223/SymbolHelper.java @@ -0,0 +1,51 @@ +/* + * 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.javascript.jsr223; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author Stephen Mallette (http://stephen.genoprime.com) + */ +public final class SymbolHelper { + + private final static Map<String, String> TO_JS_MAP = new HashMap<>(); + private final static Map<String, String> FROM_JS_MAP = new HashMap<>(); + + static { + // + TO_JS_MAP.put("in", "in_"); + TO_JS_MAP.forEach((k, v) -> FROM_JS_MAP.put(v, k)); + } + + private SymbolHelper() { + // static methods only, do not instantiate + } + + public static String toJavaScript(final String symbol) { + return TO_JS_MAP.getOrDefault(symbol, symbol); + } + + public static String toJava(final String symbol) { + return FROM_JS_MAP.getOrDefault(symbol, symbol); + } + +} http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/468bba63/gremlin-javascript/src/main/javascript/gremlin-javascript/package.json ---------------------------------------------------------------------- diff --git a/gremlin-javascript/src/main/javascript/gremlin-javascript/package.json b/gremlin-javascript/src/main/javascript/gremlin-javascript/package.json index 514663b..1228dd4 100644 --- a/gremlin-javascript/src/main/javascript/gremlin-javascript/package.json +++ b/gremlin-javascript/src/main/javascript/gremlin-javascript/package.json @@ -1,6 +1,6 @@ { "name": "gremlin-javascript", - "version": "3.2.6-alpha1", + "version": "3.2.7-alpha1", "description": "JavaScript Gremlin Language Variant", "author": "Apache TinkerPop team", "keywords": [ http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/468bba63/gremlin-javascript/src/main/resources/META-INF/services/org.apache.tinkerpop.gremlin.jsr223.GremlinScriptEngineFactory ---------------------------------------------------------------------- diff --git a/gremlin-javascript/src/main/resources/META-INF/services/org.apache.tinkerpop.gremlin.jsr223.GremlinScriptEngineFactory b/gremlin-javascript/src/main/resources/META-INF/services/org.apache.tinkerpop.gremlin.jsr223.GremlinScriptEngineFactory new file mode 100644 index 0000000..0363752 --- /dev/null +++ b/gremlin-javascript/src/main/resources/META-INF/services/org.apache.tinkerpop.gremlin.jsr223.GremlinScriptEngineFactory @@ -0,0 +1 @@ +org.apache.tinkerpop.gremlin.javascript.jsr223.GremlinJavaScriptScriptEngineFactory \ No newline at end of file http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/468bba63/gremlin-javascript/src/test/java/org/apache/tinkerpop/gremlin/javascript/jsr223/JavaScriptGremlinScriptEngineTest.java ---------------------------------------------------------------------- diff --git a/gremlin-javascript/src/test/java/org/apache/tinkerpop/gremlin/javascript/jsr223/JavaScriptGremlinScriptEngineTest.java b/gremlin-javascript/src/test/java/org/apache/tinkerpop/gremlin/javascript/jsr223/JavaScriptGremlinScriptEngineTest.java new file mode 100644 index 0000000..0956aa9 --- /dev/null +++ b/gremlin-javascript/src/test/java/org/apache/tinkerpop/gremlin/javascript/jsr223/JavaScriptGremlinScriptEngineTest.java @@ -0,0 +1,31 @@ +/* + * 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.javascript.jsr223; + +import org.apache.tinkerpop.gremlin.jsr223.GremlinScriptEngineSuite; +import org.apache.tinkerpop.gremlin.jsr223.ScriptEngineToTest; +import org.junit.runner.RunWith; + +/** + * @author Stephen Mallette (http://stephen.genoprime.com) + */ +@RunWith(GremlinScriptEngineSuite.class) +@ScriptEngineToTest(scriptEngineName = "gremlin-javascript") +public class JavaScriptGremlinScriptEngineTest { +} http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/468bba63/gremlin-javascript/src/test/resources/log4j-silent.properties ---------------------------------------------------------------------- diff --git a/gremlin-javascript/src/test/resources/log4j-silent.properties b/gremlin-javascript/src/test/resources/log4j-silent.properties new file mode 100644 index 0000000..1825bb0 --- /dev/null +++ b/gremlin-javascript/src/test/resources/log4j-silent.properties @@ -0,0 +1,23 @@ +# 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. + +# this file should always have logging set to OFF. it seems, however, that an appender of some sort is +# required or else some logs throw error and use other log4j.properties files on the path. +log4j.rootLogger=OFF, stdout +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=[%p] %C - %m%n \ No newline at end of file http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/468bba63/gremlin-javascript/src/test/resources/log4j-test.properties ---------------------------------------------------------------------- diff --git a/gremlin-javascript/src/test/resources/log4j-test.properties b/gremlin-javascript/src/test/resources/log4j-test.properties new file mode 100644 index 0000000..79038b1 --- /dev/null +++ b/gremlin-javascript/src/test/resources/log4j-test.properties @@ -0,0 +1,23 @@ +# +# 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. +# + +log4j.rootLogger=WARN, stdout +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=[%p] %C - %m%n \ No newline at end of file http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/468bba63/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 index 8886de9..ae3735e 100644 --- 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 @@ -62,7 +62,7 @@ public class BindingsScriptEngineTest { final GremlinScriptEngine engine1 = manager.getEngineByName(ENGINE_TO_TEST); assertThat(engine1.getBindings(ScriptContext.GLOBAL_SCOPE).size(), is(1)); - assertEquals(101, (int) engine1.eval("x+1")); + assertEquals(101, ((Number) engine1.eval("x+1")).intValue()); manager.getBindings().remove("x"); final GremlinScriptEngine engine2 = manager.getEngineByName(ENGINE_TO_TEST); @@ -79,7 +79,7 @@ public class BindingsScriptEngineTest { manager.addPlugin(plugin); final GremlinScriptEngine engine = manager.getEngineByName(ENGINE_TO_TEST); assertThat(engine.getBindings(ScriptContext.GLOBAL_SCOPE).size(), is(1)); - assertEquals(101, (int) engine.eval("x+1")); + assertEquals(101, ((Number) engine.eval("x+1")).intValue()); } @Test http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/468bba63/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/jsr223/GremlinEnabledScriptEngineTest.java ---------------------------------------------------------------------- diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/jsr223/GremlinEnabledScriptEngineTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/jsr223/GremlinEnabledScriptEngineTest.java index 5a880f8..6a0e5bc 100644 --- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/jsr223/GremlinEnabledScriptEngineTest.java +++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/jsr223/GremlinEnabledScriptEngineTest.java @@ -30,7 +30,9 @@ import java.util.List; import java.util.Optional; import static org.apache.tinkerpop.gremlin.jsr223.GremlinScriptEngineSuite.ENGINE_TO_TEST; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; +import static org.hamcrest.core.Is.is; /** * This is an important test case in that it validates that core features of {@code ScriptEngine} instances that claim @@ -52,7 +54,7 @@ public class GremlinEnabledScriptEngineTest { final GremlinScriptEngine scriptEngine = manager.getEngineByName(ENGINE_TO_TEST); final List<Class> classesToCheck = Arrays.asList(Vertex.class, Edge.class, Graph.class, VertexProperty.class); for (Class clazz : classesToCheck) { - assertEquals(clazz, scriptEngine.eval(clazz.getSimpleName())); + assertClassEquality(scriptEngine.eval(clazz.getSimpleName()), clazz); } } @@ -77,7 +79,7 @@ public class GremlinEnabledScriptEngineTest { final GremlinScriptEngine scriptEngine = mgr.getEngineByName(ENGINE_TO_TEST); final List<Class> classesToCheck = Arrays.asList(java.awt.Color.class, java.sql.CallableStatement.class); for (Class clazz : classesToCheck) { - assertEquals(clazz, scriptEngine.eval(clazz.getSimpleName())); + assertClassEquality(scriptEngine.eval(clazz.getSimpleName()), clazz); } } @@ -89,4 +91,13 @@ public class GremlinEnabledScriptEngineTest { .appliesTo(Collections.singletonList("fake-script-engine")).create()); assertEquals(0, mgr.getCustomizers(ENGINE_TO_TEST).size()); } + + private void assertClassEquality(final Object fromScriptEngine, final Class<?> expected) { + // this should typically equal the Class, but some scriptengines like nashorn create a synthetic class + // to wrap it in. + final boolean matches = fromScriptEngine.equals(expected) || fromScriptEngine.toString().contains(expected.getName()); + + assertThat("Doesn't match for " + fromScriptEngine, matches, is(true)); + + } } http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/468bba63/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/jsr223/ScriptEngineLambdaTest.java ---------------------------------------------------------------------- diff --git a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/jsr223/ScriptEngineLambdaTest.java b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/jsr223/ScriptEngineLambdaTest.java index a1509cb..80998b2 100644 --- a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/jsr223/ScriptEngineLambdaTest.java +++ b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/jsr223/ScriptEngineLambdaTest.java @@ -37,7 +37,7 @@ public class ScriptEngineLambdaTest { public void shouldCallAsFunction() { // Function.apply final ScriptEngineLambda lambda = newLambda("1+a"); - assertEquals(11, Integer.parseInt(lambda.apply(10).toString())); + assertEquals(11, ((Number) lambda.apply(10)).intValue()); } @Test(expected = IllegalArgumentException.class) @@ -130,14 +130,14 @@ public class ScriptEngineLambdaTest { @Test public void shouldCallTrivialFunction() { final ScriptEngineLambda lambda = newLambda("2 + 2"); - assertEquals(lambda.apply("foo"), 4); + assertEquals(4, lambda.apply("foo")); } @Test public void shouldCallAsOneArgFunction() { final ScriptEngineLambda lambda = newLambda("a + 2"); - assertEquals(lambda.apply(3), 5); - assertEquals(lambda.apply(10), 12); + assertEquals(5, ((Number) lambda.apply(3)).intValue()); + assertEquals(12, ((Number) lambda.apply(10)).intValue()); } private static ScriptEngineLambda newLambda(final String script) {
